gry@IDA.LiU.SE.UUCP (Goran Rydquist) (04/01/88)
Submitted-By: "Goran Rydquist" <gry@IDA.LiU.SE.UUCP> Archive-Name: tdp comp.sources.misc: Volume 2, Issue 86 Submitted-By: "Goran Rydquist" <gry@IDA.LiU.SE.UUCP> Archive-Name: tdp [Sent on April 1; it looks legitimate, but caveat programmer.... ++bsa] The following C code determines the troff document type of its parameters, and if requested to, executes it. The code is a fast hack (< 6 hours), but has been found to work quite reliably here for a couple of months. --- Goran Rydqvist gorry@majestix.liu.se Troskareg. 69:22 seismo!enea!liuida!majestix!gorry 583 30 Linkoping Linkoping Institute of Technology Sweden Int +46-13213696 / +46-13282494 --------- #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: README dtp.c dtp.man hash.c hash.h makefile tool.h # Wrapped by gorry@smidefix on Thu Feb 18 14:36:45 1988 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f README -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"README\" else echo shar: Extracting \"README\" \(97 characters\) sed "s/^X//" >README <<'END_OF_README' XSimple instruction on modification of the system can be found Xat the beginning of the file dtp.c END_OF_README if test 97 -ne `wc -c <README`; then echo shar: \"README\" unpacked with wrong size! fi # end of overwriting check fi if test -f dtp.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"dtp.c\" else echo shar: Extracting \"dtp.c\" \(14184 characters\) sed "s/^X//" >dtp.c <<'END_OF_dtp.c' X/* X dtp.c X X Dtp tries to decide the troff document type of the file specified by the X file argument. The program recognizes: X X Changes: X X To change the output of the program, change the strcat's in all_done(). X X To modify the set of commands that invokes a filter, alter the lists X in build_assoc(). X X To add a filter: X Add a constant XX below. X Add a boolean global variable xx below and set it initially to FALSE. X Add a char *xx_opt below and update set_filter_opt() appropriately. X Add the recognizers in build_assoc() - addassoc("yy", XX);. X Add a case XX: xx = TRUE; break; to the switch in getcom(). X Add a recognizer in all_done() of the form: X if (xx) { X ADD_PIPE(command, fnameflag); X strcat(command, " | xx"); X add_opt_and_fname(command, xx_opt, &fnameflag); X } X in the correct position. X Recompile. X X Written by: X X Goran Rydqvist <gorry@majestix.liu.se> X */ X X X#include <stdio.h> X#include "tool.h" X#include "hash.h" X X#define STREQ(s1, s2) (!strcmp(s1, s2)) X X#define EOLN '\n' X X#define REFER 1 X#define PIC 2 X#define TBL 3 X#define EQN 4 X#define MS 5 X#define MAN 6 X#define AMBIG 7 X#define ME 8 X#define SWE 9 X#define PSTROFF 10 X#define PLAIN 11 /* Plain troff - no macros */ X X XFILE *fp; X XBOOL refer = FALSE; XBOOL pic = FALSE; XBOOL tbl = FALSE; XBOOL eqn = FALSE; XBOOL ms = FALSE; XBOOL me = FALSE; XBOOL man = FALSE; XBOOL ambig = FALSE; XBOOL a_ms = FALSE; XBOOL a_me = FALSE; XBOOL a_man = FALSE; XBOOL iptroff = FALSE; XBOOL ditroff = TRUE; XBOOL swe = FALSE; XBOOL pstroff = FALSE; XBOOL plain = FALSE; X XBOOL execute = FALSE; X Xchar *refer_opt = ""; Xchar *pic_opt = ""; Xchar *tbl_opt = ""; Xchar *eqn_opt = ""; Xchar *troff_opt = ""; Xchar *swe_opt = ""; X Xchar *self; Xchar *fnames = (char *) 0; Xchar suffix[40]; X XHASH *assoc; /* Global hash table object */ X X X#define ADD_PIPE(command, flag) if (flag) strcat(command, " | "); X Xvoid add_opt_and_fname(command, opt, flag) Xchar *command, *opt; Xint *flag; X{ X if (opt[0]) { X strcat(command, " "); X strcat(command, opt); X } X if (!(*flag)) { X strcat(command, " "); X strcat(command, fnames); X *flag = 1; X } X} X X X/* AI - part of dtp (ha ha). */ Xvoid all_done() X{ X char command[100]; X int fnamesflag; X X strcpy(command, ""); X fnamesflag = FALSE; X X if (!strcmp(suffix, "ms")) { X if (man || me) X fprintf(stderr, "%s: strange suffix .%s\n", self, suffix); X else X ms = TRUE; X } X if (!strcmp(suffix, "me")) { X if (man || ms) X fprintf(stderr, "%s: strange suffix .%s\n", self, suffix); X else X me = TRUE; X } X if (!strcmp(suffix, "man")) { X if (ms || me) X fprintf(stderr, "%s: strange suffix .%s\n", self, suffix); X else X man = TRUE; X } X X if (a_ms) { X ms = a_ms; me = FALSE; man = FALSE; X } X if (a_me) { X me = a_me; ms = FALSE; man = FALSE; X } X if (a_man) { X man = a_man; ms = FALSE; me = FALSE; X } X X if (!(ms || me || man) && ambig) X fprintf(stderr, "%s: ambigous - use propper suffix .ms, .me, .man\n" X , self), exit(1); X X if (swe) { X if (pstroff) X strcat(command, "swede -Tps"); X else X strcat(command, "swede"); X add_opt_and_fname(command, swe_opt, &fnamesflag); X } X X if (refer) { X ADD_PIPE(command, fnamesflag); X strcat(command, "refer -e"); X add_opt_and_fname(command, refer_opt, &fnamesflag); X } X X if (pic) { X ADD_PIPE(command, fnamesflag); X strcat(command, "pic"); X if (pstroff) X strcat(command, " -Tps"); X strcat(command, " -D"); X add_opt_and_fname(command, pic_opt, &fnamesflag); X } X X if (tbl) { X ADD_PIPE(command, fnamesflag); X strcat(command, "tbl"); X add_opt_and_fname(command, tbl_opt, &fnamesflag); X } X X if (eqn) { X ADD_PIPE(command, fnamesflag); X if (pstroff) X strcat(command, "eqn -Tps"); X else X strcat(command, "eqn"); X add_opt_and_fname(command, eqn_opt, &fnamesflag); X } X X if (pstroff) { X ADD_PIPE(command, fnamesflag); X strcat(command, "pstroff"); X iptroff = FALSE; X ditroff = FALSE; X } else if (iptroff) { X ADD_PIPE(command, fnamesflag); X strcat(command, "iptroff"); X ditroff = FALSE; X } X else if (ditroff) { X ADD_PIPE(command, fnamesflag); X strcat(command, "ditroff"); X } X X if (ms) X strcat(command, " -ms"); X else if (me) X strcat(command, " -me"); X else if (man) X strcat(command, " -man"); X add_opt_and_fname(command, troff_opt, &fnamesflag); X X if (ditroff) { X strcat(command, " > "); X strcat(command, self); X strcat(command, ".out"); X } X X printf("%s\n", command); X if (execute) X system(command); X X exit(0); X} X X Xvoid addassoc(key, value) Xchar *key; Xint value; X{ X inserthentry(assoc, (int) key[0]*256 + (int) key[1], &value, sizeof(int)); X} X X X/* The two-char combinations below are inserted in a hash table. If a line Xbegins with a '.', the following two characters are checked against these. */ Xvoid build_assoc() X{ X /* For refer */ X addassoc("[ ", REFER); X addassoc("] ", REFER); X X /* For pic */ X addassoc("PS", PIC); X addassoc("PE", PIC); X X /* For tbl */ X addassoc("TS", TBL); X addassoc("TE", TBL); X X /* For eqn */ X addassoc("EQ", EQN); X addassoc("EN", EQN); X X /* For ms */ X addassoc("1C", MS); X addassoc("2C", MS); X addassoc("AB", MS); X addassoc("AE", MS); X addassoc("AI", MS); X addassoc("AM", MS); X addassoc("AT", MS); X addassoc("AU", MS); X addassoc("B1", MS); X addassoc("B2", MS); X addassoc("BX", MS); X addassoc("CM", MS); X addassoc("CT", MS); X addassoc("DA", MS); X addassoc("DE", MS); X addassoc("DS", MS); X addassoc("EF", MS); X /* EN, EQ - eqn */ X addassoc("FE", MS); X addassoc("FS", MS); X addassoc("KE", MS); X addassoc("KF", MS); X addassoc("KS", MS); X addassoc("LG", MS); X addassoc("ND", MS); X addassoc("NH", MS); X addassoc("NL", MS); X addassoc("OF", MS); X addassoc("OH", MS); X addassoc("P1", MS); X addassoc("PT", MS); X addassoc("PX", MS); X addassoc("QP", MS); X addassoc("R ", MS); X addassoc("RP", MS); X addassoc("TA", MS); X /* TE - tbl */ X addassoc("TL", MS); X addassoc("TM", MS); X /* TS - tbl */ X addassoc("UL", MS); X addassoc("XA", MS); X addassoc("XE", MS); X addassoc("XS", MS); X addassoc("UL", MS); X X /* For man */ X /* B ambigous */ X addassoc("BI", MAN); X addassoc("BR", MAN); X addassoc("DT", MAN); X addassoc("HP", MAN); X /* I ambigous */ X addassoc("IB", MAN); X /* IP ambigous */ X addassoc("IR", MAN); X /* LP ambigous */ X addassoc("PD", MAN); X /* PP ambigous */ X /* RE ambigous */ X addassoc("RB", MAN); X addassoc("RI", MAN); X /* RS ambigous */ X /* SH ambigous */ X /* SM ambigous */ X /* TH ambigous */ X addassoc("TP", MAN); X X /* For me */ X addassoc("(c", ME); X addassoc("(d", ME); X addassoc("(f", ME); X addassoc("(l", ME); X addassoc("(q", ME); X addassoc("(x", ME); X addassoc("(z", ME); X addassoc(")c", ME); X addassoc(")d", ME); X addassoc(")f", ME); X addassoc(")l", ME); X addassoc(")q", ME); X addassoc(")x", ME); X addassoc(")z", ME); X addassoc("++", ME); X addassoc("+c", ME); X addassoc("1c", ME); X addassoc("2c", ME); X /* EN, EQ - eqn */ X /* TE, TH, TS - tbl*/ X addassoc("ac", ME); X addassoc("b ", ME); X addassoc("ba", ME); X addassoc("bc", ME); X addassoc("bi", ME); X addassoc("bx", ME); X addassoc("ef", ME); X addassoc("eh", ME); X addassoc("fo", ME); X addassoc("he", ME); X addassoc("hl", ME); X addassoc("hx", ME); X addassoc("i ", ME); X addassoc("ip", ME); X addassoc("lp", ME); X addassoc("lo", ME); X addassoc("np", ME); X addassoc("of", ME); X addassoc("oh", ME); X addassoc("pd", ME); X addassoc("pp", ME); X addassoc("r ", ME); X addassoc("re", ME); X addassoc("sc", ME); X addassoc("sh", ME); X addassoc("sk", ME); X addassoc("sz", ME); X addassoc("th", ME); X addassoc("tp", ME); X addassoc("u ", ME); X addassoc("uh", ME); X addassoc("xp", ME); X X /* For swede */ X addassoc("SW", SWE); X addassoc("SE", SWE); X X /* Ambigous - recognized, but not used */ X addassoc("B ", AMBIG); X addassoc("I ", AMBIG); X addassoc("IP", AMBIG); X addassoc("LP", AMBIG); X addassoc("IX", AMBIG); X addassoc("PP", AMBIG); X addassoc("RE", AMBIG); X addassoc("RS", AMBIG); X addassoc("SH", AMBIG); X addassoc("SM", AMBIG); X addassoc("TH", AMBIG); X X /* For troff */ X addassoc("ab", PLAIN); X addassoc("ad", PLAIN); X addassoc("af", PLAIN); X addassoc("am", PLAIN); X addassoc("as", PLAIN); X addassoc("bd", PLAIN); X addassoc("bd", PLAIN); X addassoc("bp", PLAIN); X addassoc("br", PLAIN); X addassoc("c2", PLAIN); X addassoc("cc", PLAIN); X addassoc("ce", PLAIN); X addassoc("ch", PLAIN); X addassoc("cs", PLAIN); X addassoc("cu", PLAIN); X addassoc("da", PLAIN); X addassoc("de", PLAIN); X addassoc("di", PLAIN); X addassoc("ds", PLAIN); X addassoc("dt", PLAIN); X addassoc("ec", PLAIN); X addassoc("el", PLAIN); X addassoc("em", PLAIN); X addassoc("eo", PLAIN); X addassoc("ev", PLAIN); X addassoc("ex", PLAIN); X addassoc("fc", PLAIN); X addassoc("fi", PLAIN); X addassoc("fl", PLAIN); X addassoc("fp", PLAIN); X addassoc("ft", PLAIN); X addassoc("fz", PLAIN); X addassoc("hc", PLAIN); X addassoc("hw", PLAIN); X addassoc("hy", PLAIN); X addassoc("ie", PLAIN); X addassoc("if", PLAIN); X addassoc("ig", PLAIN); X addassoc("in", PLAIN); X addassoc("it", PLAIN); X addassoc("lc", PLAIN); X addassoc("lg", PLAIN); X addassoc("ll", PLAIN); X addassoc("ls", PLAIN); X addassoc("lt", PLAIN); X addassoc("mc", PLAIN); X addassoc("mk", PLAIN); X addassoc("na", PLAIN); X addassoc("ne", PLAIN); X addassoc("nf", PLAIN); X addassoc("nh", PLAIN); X addassoc("nm", PLAIN); X addassoc("nn", PLAIN); X addassoc("nr", PLAIN); X addassoc("ns", PLAIN); X addassoc("nx", PLAIN); X addassoc("os", PLAIN); X addassoc("pc", PLAIN); X addassoc("pi", PLAIN); X addassoc("pm", PLAIN); X addassoc("ps", PLAIN); X addassoc("pl", PLAIN); X addassoc("pn", PLAIN); X addassoc("po", PLAIN); X addassoc("rd", PLAIN); X addassoc("rn", PLAIN); X addassoc("rm", PLAIN); X addassoc("rr", PLAIN); X addassoc("rs", PLAIN); X addassoc("rt", PLAIN); X addassoc("so", PLAIN); X addassoc("sp", PLAIN); X addassoc("ss", PLAIN); X addassoc("sv", PLAIN); X addassoc("ta", PLAIN); X addassoc("tc", PLAIN); X addassoc("ti", PLAIN); X addassoc("tl", PLAIN); X addassoc("tm", PLAIN); X addassoc("tr", PLAIN); X addassoc("uf", PLAIN); X addassoc("ul", PLAIN); X addassoc("vs", PLAIN); X addassoc("wh", PLAIN); X} X X Xint getcom() X{ X register int i; X register int *res; X register char c1, c2; X X if ((c1 = getc(fp)) != '.') X return c1; X X if ((c1 = getc(fp)) == EOF) X return EOF; X if (c1 == EOLN) X return c1; X X if ((c2 = getc(fp)) == EOF) X return EOF; X if (c2 == EOLN) X c2 = ' '; X X i = (int) c1*256 + (int) c2; X if (!(res = (int *) lookuphentry(assoc, i))) X return; /* Unknown */ X X switch (*res) { X case REFER: X refer = TRUE; X break; X case PIC: X pic = TRUE; X break; X case TBL: X tbl = TRUE; X break; X case EQN: X eqn = TRUE; X break; X case MS: X ms = TRUE; X break; X case ME: X me = TRUE; X break; X case MAN: X man = TRUE; X break; X case AMBIG: X ambig = TRUE; X break; X case SWE: X swe = TRUE; X break; X case PLAIN: X plain = TRUE; X break; X default: X printf("getcom: can't happen\n"); X abort(); X } X return 1; X} X X X#define FILL(s, argvp) \ X{ \ X if (STREQ(s, "")) { \ X s = (char *) malloc(240); \ X strcpy(s, *++(*argvp)); \ X } \ X else { \ X strcat(s, " "); \ X strcat(s, *++(*argvp)); \ X } \ X} \ X Xvoid set_filter_opt(argcp, argvp) Xint *argcp; Xchar ***argvp; X{ X (*argvp)++; /* Step to the filter parameter */ X (*argcp)--; X X if (STREQ(**argvp, "refer")) X FILL(refer_opt, argvp) X else if (STREQ(**argvp, "pic")) X FILL(pic_opt, argvp) X else if (STREQ(**argvp, "tbl")) X FILL(tbl_opt, argvp) X else if (STREQ(**argvp, "eqn")) X FILL(eqn_opt, argvp) X else if (STREQ(**argvp, "troff")) X FILL(troff_opt, argvp) X else if (STREQ(**argvp, "swede")) X FILL(swe_opt, argvp) X else X usage(); X (*argcp)--; X} X X Xusage() X{ X fprintf(stderr, "Usage: %s [ -aipx -ms -me -man] files\n", self); X exit(1); X} X X Xmain(argc, argv) Xint argc; Xchar **argv; X{ X int i; X X fnames = (char *) malloc(800); X strcpy(fnames, ""); X X assoc = newhash(273); X build_assoc(); X X self = argv[0]; X X argv++; X argc--; X X for(; argc-- > 0; argv++) X if( argv[0][0] == '-' ) { X if (STREQ(argv[0], "-ms")) { X a_ms = TRUE; a_me = FALSE; a_man = FALSE; X } else if (STREQ(argv[0], "-me")) { X a_me = TRUE; a_ms = FALSE; a_man = FALSE; X } else if (STREQ(argv[0], "-man")) { X a_man = TRUE; a_ms = FALSE; a_me = FALSE; X } else if (STREQ(argv[0], "-a")) { X set_filter_opt(&argc, &argv); X } else for(i = strlen(argv[0]) - 1; i > 0; i--) X switch( argv[0][i] ) { X case 'i': X iptroff = TRUE; X pstroff = FALSE; X ditroff = FALSE; X break; X case 'p': X pstroff = TRUE; X iptroff = FALSE; X ditroff = FALSE; X break; X case 'x': X execute = TRUE; X break; X default: X usage(); X } X } X else { X if (!STREQ(fnames, "")) X strcat(fnames, " "); X strcat(fnames, argv[0]); X troff_scan(argv[0]); X } X X all_done(); X} X X Xtroff_scan(fname) Xchar *fname; X{ X register char c; X X if (fname == (char *) 0) X usage(); X X if ((fp = fopen(fname, "r")) == (FILE *) 0) { X fprintf(stderr, "%s: %s not found\n", self, fname); X exit(1); X } X X sscanf(fname, "%[^.] %1s %s", suffix, suffix, suffix); X X for(;;) { X if (getcom() == EOF) break; /* Get a troff command */ X X /* Skip to next eoln */ X for(c = getc(fp); (c != EOLN) && (c != EOF); c = getc(fp)); X if (c == EOF) break; X X /* Skip eolns */ X for(c = getc(fp); (c == EOLN) && (c != EOF); c = getc(fp)); X if (c == EOF) break; X ungetc(c, fp); X } X fclose(fp); X X if ( !(refer || pic || tbl || eqn || ms || man || me || ambig || plain) ) { X fprintf(stderr, "%s: %s not troff file\n", self, fname); X exit(1); X } X} END_OF_dtp.c if test 14184 -ne `wc -c <dtp.c`; then echo shar: \"dtp.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f dtp.man -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"dtp.man\" else echo shar: Extracting \"dtp.man\" \(3073 characters\) sed "s/^X//" >dtp.man <<'END_OF_dtp.man' X.TH DTP 1 "27 April 1987" X.SH NAME Xdtp \- decide troff document type X.SH SYNOPSIS X.B dtp X[ X.B \-ipxq \-ms \-me \-man X] [ X.B \-a X.I "filter argument" X] \fIfiles X.SH DESCRIPTION XDtp tries to decide the troff document type of \fIfiles\fP. A resulting Xcommand is printed to standard output, including only the filters needed, Xand possibly a macro package. This is decided from recognized unambigous Xcommands/macros in \fIfiles\fP. If nothing in \fIfiles\fP indicates Xthe macro package, the file suffix is checked \- .ms, .me, .man are recognized. X.LP XThe default troff processor is ditroff. When ditroff is used, the Xoutput is redirected to the file dtp.out. The \-i option changes the troff Xprocessor to iptroff, and the \-p option changes it to pstroff. X.SH OPTIONS X.TP 1i X.B \-i XUse iptroff as troff processor instead of ditroff. X.TP X.B \-p XUse pstroff as troff processor. X.TP X.B \-x XExecute the resulting command. X.TP X.B \-ms XForce \-ms as macro package. X.TP X.B \-me XForce \-me. X.TP X.B \-man XForce \-man. X.TP X.B \-a \fIfilter argument\fP XAdd \fIargument\fP to \fIfilter\fP. The refer, swede, pic, tbl, eqn and Xtroff filters are recognized. X.SH WHAT IS RECOGNIZED X.TP 1i X.B refer \-e XThe \-e mode is recognized from .[ and .] X.TP X.B swede XSwede is a special filter that replaces the special characters {, }, |, [, ], \ X\\ with the Swedish equivalents between .SW and .SE. \-Tps is added Xautomatically if pstroff is used as troff processor. X.TP X.B pic \-D XThe undocumented feature of pic \-D is always issued. Pic is recognized Xfrom .PS and .PE X.TP X.B tbl XTbl is recognized from .TS and .TE X.TP X.B eqn XEqn is recognized from .EQ and .EN X.TP X.B \-ms X .1C .2C .AB .AE .AI .AM .AT .AU .B1 \ X .B2 .BX .CM .CT .DA .DE .DS .EF .FE .FS .KE .KF .KS .LG .ND .NH .NL \ X .OF .OH .P1 .PT .PX .QP .R .RP .TA .TL .TM .UL .XA .XS .UL X.TP X.B \-man X .BI .BR .DT .HP .IB .IR .PD .RB .RI .TP X.TP X.B \-me X .(c .(d .(f .(l .(q .(x .(z .)c .)d .)f .)l .)q .)x \ X .)z .++ .1c .2c .ac .b .ba .bc .bi .bx .ef .eh .fo \ X .he .hl .hx .i .ip .lp .lo .np .of .oh .pd .pp .r \ X .re .sc .sh .sk .sz .th .tp .u .uh .xp X.TP X.B Ambiguous X .B .I .IP .LP .IX .PP .RE .RS .SH .SM .TH. \ XThese are not unique to any specific macro package or filter, and causes no Xselection. X.TP X.B Plain Troff X .ab .ad .af .am .as .bd .bp .br .c2 .cc .ce .ch .cs .cu .da .de .di .ds .dt \ X .ec .el .em .eo .ev .ex .fc .fi .fl .fp .ft .fz .hc .hw .hy .ie .if .ig .in \ X .it .lc .lg .ll .ls .lt .mc .mk .na .ne .nf .nh .nm .nn .nr .ns .nx .os .pc \ X .pi .pm .ps .pl .pn .po .rd .rn .rm .rr .rs .rt .so .sp .ss .sv .ta .tc .ti \ X .tl .tm .tr .uf .ul .vs .wh X.LP XIf no filter selection, macro requests or plain troff commands are found, dtp Xassumes that the formatting request was a mistake, and exits. X.SH AUTHOR XG\o"o\(um"ran Rydqvist <gorry@majestix.liu.se> X.br XDepartement of Computer and Information Science, Link\o"o\(um"ping, Sweden. X.SH SEE ALSO X.I "Formatting Documents on the Sun Workstation" X.br Xtroff(1), tbl(1), eqn(1), pic(1), ms(7) X.SH BUGS XThe program was written in about six hours \- don't expect to much. END_OF_dtp.man if test 3073 -ne `wc -c <dtp.man`; then echo shar: \"dtp.man\" unpacked with wrong size! fi # end of overwriting check fi if test -f hash.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"hash.c\" else echo shar: Extracting \"hash.c\" \(3693 characters\) sed "s/^X//" >hash.c <<'END_OF_hash.c' X/* X hash.c X X Handles bucket hash objects of warying size. Each keyed item consists of X an invariant and an arbitrary part. X X Interface: X X A HASH object is declared by: HASH *object; X X HASH *newhash(size) X int size; X Retrurn a pointer to a new HASH object of size. X X void rmhash(object) X HASH *object; X Free memory occupied by a HASH object. X X char *lookuphentry(object, key) X HASH *object; X KEY key; X Return a pointer to the data part of a hash entry. Return NIL if no such key. X X BOOL inserthentry(object, key, data, datasize) X HASH *object; X KEY key; X char *data; X int datasize; X Insert key and data into hash table object. No insertion is performed if key X already exists. Returns true if insertion done. X X BOOL rmhentry(object, key) X HASH *object; X KEY key; X Remove a hash entry matching key. Returns true if entry removed. X X HENTRY firsthentry(object) X HASH *object; X Return the data part of the first key in the hash table object. X X HENTRY nexthentry(object) X HASH *object; X Return the data part of the ensuing key in the hash table object. X X OBS! A firsthentry() call must precede nexthentry() calls between X hashtable manipulation (rmhentry() och inserthentry()). X X */ X X#include <stdio.h> X#include <malloc.h> X#include "tool.h" X#include "hash.h" X X XHASH *newhash(size) Xint size; X{ X HASH *ht; X X CHKMEM(ht = (HASH *) malloc(sizeof(HASH)), "newhash"); X ht -> no_buckets = size; X ht -> no_inhab = 0; X ht -> cur_bucket = 0; X ht -> cur_cell = 0; X CHKMEM(ht -> thetbl = (HENTRY *) calloc(size, sizeof(HENTRY)), "newhash"); X X return ht; X} X X Xvoid rmhash(object) XHASH *object; X{ X register HENTRY *p, hp, prev; X X for(p = object -> thetbl; object -> no_inhab > 0; p++) X for(hp = *p; hp; hp = prev -> next) { X prev = hp; X free(hp); X object -> no_inhab--; X } X X free(object -> thetbl); X free(object); X} X X Xchar *lookuphentry(object, key) XHASH *object; XKEY key; X{ X register HENTRY *p, hp; X X p = object -> thetbl + h(object, key); /* Hash the key */ X for(hp = *p; hp; hp = hp -> next) /* Follow bucket */ X if (hp -> key == key) X return (hp -> data); X return (char *) 0; X} X X Xvoid mvbytes(p1, p2, n) Xregister char *p1, *p2; Xregister int n; X{ X for(; n-- > 0; *p1++ = *p2++); X} X X XBOOL inserthentry(object, key, data, datasize) XHASH *object; XKEY key; Xchar *data; Xint datasize; X{ X register HENTRY *p, hp; X X p = object -> thetbl + h(object, key); X for(hp = *p; hp; hp = hp -> next) X if (hp -> key == key) X return FALSE; X CHKMEM(hp = (HENTRY) malloc(sizeof(struct h_cell) + datasize), X "inserthentry"); X X hp -> key = key; X hp -> next = *p; X mvbytes(hp -> data, data, datasize); X *p = hp; X X return TRUE; X} X X XBOOL rmhentry(object, key) XHASH *object; XKEY key; X{ X register HENTRY *p, hp, prev; X X p = object -> thetbl + h(object, key); X for(hp = *p; hp; prev = hp, hp = hp -> next) X if (hp -> key == key) { X if (hp == *p) /* First bucket is a special case */ X *p = hp -> next; X else X prev -> next = hp -> next; X object -> no_inhab--; X free(hp); X return TRUE; X } X X return FALSE; X} X X X XHENTRY firsthentry(object) XHASH *object; X{ X object -> cur_bucket = 0; X object -> cur_cell = 0; X return nexthentry(object); X} X X XHENTRY nexthentry(object) Xregister HASH *object; X{ X register HENTRY *p, hp; X register int i; X X for(;;) { X p = object -> thetbl + object -> cur_bucket; X i = object -> cur_cell; X for(hp = *p; hp; hp = hp -> next, i--) X if( i < 1 ) { X object -> cur_cell++; X return hp; X } X X if (!hp) { X object -> cur_cell = 0; X if (++object -> cur_bucket >= object -> no_buckets) X return (HENTRY) 0; X } X } X} X END_OF_hash.c if test 3693 -ne `wc -c <hash.c`; then echo shar: \"hash.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f hash.h -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"hash.h\" else echo shar: Extracting \"hash.h\" \(866 characters\) sed "s/^X//" >hash.h <<'END_OF_hash.h' X/* X hash.h X X Include file for hash.c X X Synopsis: X X #include <stdio.h> X #include "tool.h" X #include "hash.h" X */ X Xtypedef struct { X int no_buckets; /* Number of buckets */ X int no_inhab; /* Number of inhabitants */ X int cur_bucket; /* Used by first&nexthentry() */ X int cur_cell; /* As for cur_bucket */ X struct h_cell **thetbl; /* The table itself */ X} HASH; /* A HASH object */ X Xtypedef int KEY; X Xtypedef struct h_cell { X KEY key; /* Hash key */ X struct h_cell *next; /* Next bucket pointer */ X char data[1]; /* Data starts here - variable size struct */ X} *HENTRY; /* A Hash entry (invariant) */ X X/* Hash function */ X#define h(object, key) (key % object -> no_buckets) X X/* Functions */ XHASH *newhash(); Xvoid rmhash(); Xchar *lookuphentry(); XBOOL inserthentry(); XBOOL rmhentry(); XHENTRY firsthentry(); XHENTRY nexthentry(); END_OF_hash.h if test 866 -ne `wc -c <hash.h`; then echo shar: \"hash.h\" unpacked with wrong size! fi # end of overwriting check fi if test -f makefile -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"makefile\" else echo shar: Extracting \"makefile\" \(422 characters\) sed "s/^X//" >makefile <<'END_OF_makefile' X XCFLAGS = -O -pipe X Xdtp: hash.o dtp.o X cc -o dtp hash.o dtp.o X Xhash.o: hash.c hash.h tool.h Xdtp.o: dtp.c hash.h tool.h X Xinstall: X strip dtp X cp dtp /usr/local/bin/. X cp dtp.man /usr/man/manl/dtp.l X cp dtp.c /usr/local/src/dtp/. X cp hash.c /usr/local/src/dtp/. X cp hash.h /usr/local/src/dtp/. X cp tool.h /usr/local/src/dtp/. X cp makefile /usr/local/src/dtp/. X Xclean: X rm dtp *.o #* X mv *~ /usr/majestix/exjobb/gorry/back X END_OF_makefile if test 422 -ne `wc -c <makefile`; then echo shar: \"makefile\" unpacked with wrong size! fi # end of overwriting check fi if test -f tool.h -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"tool.h\" else echo shar: Extracting \"tool.h\" \(503 characters\) sed "s/^X//" >tool.h <<'END_OF_tool.h' X/* X tool.h X X Describes system wide conventions, like pointers and general datatypes etc. X X OBS! stdio.h must be included before tool.h if system_failure isn't defined. X */ X X#ifndef system_failure X#define system_failure(p) fprintf(stderr, "%s\n", p), abort(); X#endif X X#define CHKMEM(p, x) if ( !(p) ) { \ X char s[40]; \ X strcpy(s, x); \ X strcat(s, ": out of memory"); \ X system_failure(s); \ X } X X/* Boolean datatype */ X Xtypedef short BOOL; X#define FALSE 0 X#define TRUE (!FALSE) END_OF_tool.h if test 503 -ne `wc -c <tool.h`; then echo shar: \"tool.h\" unpacked with wrong size! fi # end of overwriting check fi echo shar: End of shell archive. exit 0