From: istvan@hhb.UUCP (Istvan Mohos) Newsgroups: alt.sources Subject: Subject: ILIB Unix Toolkit in C Message-ID: <551@hhb.UUCP> Date: 8 Jun 90 20:55:13 GMT ---- Cut Here and unpack ---- #!/bin/sh # This is part 05 of a multipart archive if touch 2>&1 | fgrep '[-amc]' > /dev/null then TOUCH=touch else TOUCH=true fi # ============= iex/untab.c ============== echo "x - extracting iex/untab.c (Text)" sed 's/^X//' << 'SHAR_EOF' > iex/untab.c && X#ifdef NEVER X/bin/cc -O -DIMANFMT -I../i $0 ../i/ilib.a -o $BIN/untab Xexit 0 X#endif X X/* for each tab, substitute spaces until next tabstop, X delete trailing blanks X*/ X#include "ilib.h" X#define SPACE 32 X Xmain (argc, argv) Xint argc; Xchar *argv[]; X{ X X char **file; X int tstop; X int tcount; X X if (argc < 3 || (tstop = atoi (argv[1])) < 1) X fprintf(stderr, "Usage: %s tabstopwidth files\n%s", argv[0], X "Spacefill each tab to next tabstop, delete trailing blanks\n"), X exit(1); X X for (file = &argv[2]; !NULCHARP (*file); file++) { X tcount = untab(tstop, *file); X if (idamage (tcount)) X fprintf (stderr, "%s %s\n%s", ierbuf, *file, X "file damage probable ... aborting\n\n"), exit (1); X if (tcount < 0) X fprintf (stderr, "%s %s\n", ierbuf, *file); X else if (tcount) X printf("%s - %d\n", *file, tcount); X } X X exit(0); X} X Xint Xuntab (tstop, file) Xint tstop; Xchar *file; X{ X FILE *fopen(), *fp; X char *realloc(); X char linebuf[BUFSIZ]; X char *lineptr, *endline; X char *buffer, *bufptr, *tmp; X int insiz, newsiz; X int tcount = 0; X int togo, lpos, fill; X X /* read file into buffer --- no file damage on error */ XQ if ((insiz = iread(file, &buffer)) < 0) X return (ierflag); X X /* count number of tabs */ X for (bufptr = buffer + insiz; --bufptr >= buffer;) X if (*bufptr == '\t') X ++tcount; X X /* assuming maximum expansion of each tab, resize buffer */ X newsiz = insiz + tcount * (tstop - 1); X if (newsiz != insiz) { X tmp = buffer; X if ((buffer = realloc (tmp, (unsigned)newsiz)) == NULL) { X free (tmp); X return (ierror ("while requesting expansion space")); X } X } X X /* reread file line-by-line, paste changes into buffer */ X if ((fp = fopen (file, "r")) == NULL) X return (ierror ("while rereading line-by-line")); X X for (bufptr = buffer; !NULCHARP (fgets (linebuf, BUFSIZ, fp));) { X X /* eliminate trailing white space in linebuf */ X endline = linebuf + strlen (linebuf) - 1; X while (WHITE (*endline)) X --endline; X X /* expand tabs: if tstop == 4, lpos can be 0,1,2,3; tabs become X 4,3,2,1 spaces respectively: tstop == lpos + togo X */ X lpos = 0; X for (lineptr = linebuf; lineptr <= endline; lineptr++) { X if (*lineptr == '\t') { X togo = tstop - lpos; X for (DOUNCOUN (togo, fill); *bufptr++ = SPACE); X lpos = 0; X } X else { X *bufptr++ = *lineptr; X if (++lpos == tstop) X lpos = 0; X } X } X *bufptr++ = '\n'; X } X X fclose (fp); X X /* replace file with buffer contents --- error may destroy file */ XQ if (iwrite (file, buffer, bufptr) < bufptr-buffer) { X free (buffer); X return (ierflag); X } X X free(buffer); X return (tcount); X} SHAR_EOF $TOUCH -am 0605075390 iex/untab.c && chmod 0755 iex/untab.c || echo "restore of iex/untab.c failed" set `wc -c iex/untab.c`;Wc_c=$1 if test "$Wc_c" != "2579"; then echo original size 2579, current size $Wc_c fi # ============= iex/up.c ============== echo "x - extracting iex/up.c (Text)" sed 's/^X//' << 'SHAR_EOF' > iex/up.c && X#ifdef NEVER X/bin/cc -O -DIMANFMT -I../i $0 ../i/ilib.a -o $BIN/up X(/bin/rm -f $BIN/down) Xln $BIN/up $BIN/down Xexit 0 X#endif X X/* toupper/tolower entire files, in place */ X#include "ilib.h" X#define DOWN 312 X Xmain (argc, argv) Xint argc; Xchar *argv[]; X{ X char *fbuf, *fend; X char **file = &argv[1]; X int fsiz; X int down = (ihasharg (argv[0], '/') == DOWN); XQ static int (*cmd[])() = {iupper, ilower}; X X if (argc < 2 ) X fprintf(stderr, "Usage: up|down files\n"), exit(0); X X for (; !NULCHARP (*file); file++, free (fbuf)) { X if ((fsiz = iread (*file, &fbuf)) < 0) X fprintf (stderr, "%s\n", ierbuf), exit (1); X fend = fbuf + fsiz; XQ (*cmd[down])(fbuf, fend); X if (iwrite (*file, fbuf, fend) != fsiz) X fprintf (stderr, "%s\n", ierbuf), exit (1); X } X exit(0); X} SHAR_EOF $TOUCH -am 0605075390 iex/up.c && chmod 0755 iex/up.c || echo "restore of iex/up.c failed" set `wc -c iex/up.c`;Wc_c=$1 if test "$Wc_c" != "780"; then echo original size 780, current size $Wc_c fi # ============= iex/which.c ============== echo "x - extracting iex/which.c (Text)" sed 's/^X//' << 'SHAR_EOF' > iex/which.c && X#ifdef NEVER X/bin/cc -O -DIMANFMT -I../i $0 ../i/ilib.a -o $BIN/which Xexit 0 X#endif X X/* tell if a file is readable/writable/executable/present in $PATH */ X#include "ilib.h" X Xmain (argc, argv) Xchar *argv[]; Xint argc; X{ X char buf[IONEK]; /* interactive input buffer */ X char *tokret; X char **opt = &argv[1]; /* command line options */ X int interactive = 0; X int access = X_OK; /* default permission */ X int optchar; X X if (argc < 2) Xopterr: X fprintf(stderr, X"\nUsage: %s [-m r|w|f] -|file...\n%s%s%s%s%s%s\n", argv[0], X"\tFind full path of each 'file' if it is contained in $PATH and is:\n", X"\t-m r readable by user executing the command\n", X"\t-m w writeable by user executing the command\n", X"\t-m f present (irregardless of its permissions)\n", X"\t executable (no mode option specified on the command line)\n", X"\t- acquire file names interactively\n"), exit(0); X X while ((optchar = iopt (&opt))) X switch (optchar) { X case 'm': X if (**opt == 'r') X access = R_OK; X else if (**opt == 'w') X access = W_OK; X else X access = F_OK; X break; X case '-': X interactive = 1; X break; X default: X goto opterr; X } X X if (interactive) X while (gets (buf) != NULL) XQ if ((tokret = iwhich (buf, access)) != NULL) X puts (tokret); X else X strcat (buf, " not found"), puts (buf); X else X for (; !NULCHARP (*opt); opt++) XQ if ((tokret = iwhich (*opt, access)) != NULL) X puts (tokret); X else X printf ("%s not found\n", *opt); X exit(0); X} SHAR_EOF $TOUCH -am 0605075390 iex/which.c && chmod 0755 iex/which.c || echo "restore of iex/which.c failed" set `wc -c iex/which.c`;Wc_c=$1 if test "$Wc_c" != "1516"; then echo original size 1516, current size $Wc_c fi # ============= iex/xec.c ============== echo "x - extracting iex/xec.c (Text)" sed 's/^X//' << 'SHAR_EOF' > iex/xec.c && X#ifdef NEVER X/bin/cc -O -DIMANFMT -I../i $0 ../i/ilib.a -o $BIN/xec Xexit 0 X#endif X X/* exec a command */ X#include "ilib.h" X Xmain (argc, argv) Xint argc; Xchar *argv[]; X{ X char **arg = argv + 1; X X if (argc < 2) X fprintf (stderr, "Usage: %s command [arg ...]\n%s%s\n", argv[0], X"\tconvert phonetic sequences to real characters in list of\n", X"\, then 'exec' with the converted list.\n"), X exit (1); X X for (++arg; !NULCHARP (*arg); arg++) XQ ifonetic (*arg); XQ execvp (argv[1], argv+1); X X /* exec failed; use ierror to get system error message */ X ierror (""); X fprintf(stderr, "%sduring execvp of '%s'\n", ierbuf, argv[1]); X exit (1); X} SHAR_EOF $TOUCH -am 0605075390 iex/xec.c && chmod 0755 iex/xec.c || echo "restore of iex/xec.c failed" set `wc -c iex/xec.c`;Wc_c=$1 if test "$Wc_c" != "672"; then echo original size 672, current size $Wc_c fi # ============= iex/iexmake ============== echo "x - extracting iex/iexmake (Text)" sed 's/^X//' << 'SHAR_EOF' > iex/iexmake && X# Xforeach file (*.c) X./$file Xend SHAR_EOF $TOUCH -am 0529183990 iex/iexmake && chmod 0755 iex/iexmake || echo "restore of iex/iexmake failed" set `wc -c iex/iexmake`;Wc_c=$1 if test "$Wc_c" != "33"; then echo original size 33, current size $Wc_c fi # ============= iman/driver.tex ============== if test ! -d 'iman'; then echo "x - creating directory iman" mkdir 'iman' fi echo "x - extracting iman/driver.tex (Text)" sed 's/^X//' << 'SHAR_EOF' > iman/driver.tex && X\input man X\def\date{June, 1990} X\def\vers{Version 1.0} X\def\mansection{ILIB (3i)} X X\count0=-1 X\input ifunlines X\input ifunclist X\input iexamplist X X\count0=1 X\input i % may 10 X\input ialntok % may 10 X\input ibcmp % X\input iblank % X\input ibreakl % X\input icopy % X\input icount % X\input icue % X\input idate % X\input idump % X\input iego % X\input ierror % X\input iexpect % X\input ifamily % X\input ifilter % X\input ifonetic % X\input ifrombit % may 24 X\input ihash % X\input ihms % X\input iinput % X\input iline % X\input ilist % may 10 X\input ilower % X\input imatch % X\input imode % X\input inest % X\input ioctal % X\input iopt % X\input iread % X\input irotate % X\input iround % X\input isearch % X\input isort % X\input istripcom % X\input iswap % X\input itok % may 11 X\input iuniq % X\input iwhich % X\input iwrite % X X\bye SHAR_EOF $TOUCH -am 0608095290 iman/driver.tex && chmod 0644 iman/driver.tex || echo "restore of iman/driver.tex failed" set `wc -c iman/driver.tex`;Wc_c=$1 if test "$Wc_c" != "1018"; then echo original size 1018, current size $Wc_c fi # ============= iman/i.tex ============== echo "x - extracting iman/i.tex (Text)" sed 's/^X//' << 'SHAR_EOF' > iman/i.tex && X% XREF ilib X X\def\name{INTRO} X\def\IT{{\bb ilib.a}} X X\S{INTRODUCTION} XProgrammers with some years of experience realize that the Xexcellent mechanism, the very robustness of ``standard I/O'' Xcreates its own programming {\myit gravity well\/} that is Xdifficult to defy, and nearly impossible to escape. XTwo pillars of \stio\ are the ``{\myit null terminated strings\/}'' Xand the terminal discipline of ``{\myit line buffering\/}''. X\L XThe idea of null terminated strings Xenables the system to delimit character sequences Xbetween their start address in memory and the first zero byte Xencountered when reading the contents of byte addresses incrementally Xfrom the start address. An unavoidable side effect of using Xnull terminated strings is the appearance of a ``blind spot'' in Xrecognizing the zero byte (ASCII NUL). Even the ubiquitous X{\myit vi\/} editor---able to manipulate every ASCII Xvalue between 1 and 127---can only report the Xnumber of encountered NUL bytes on its {\myit ex\/} command line. X\L XLine buffering allows Xediting a command or a line of input before transmitting the text Xto a process; and encourages Unix tools to keep process size small Xby managing only a single line of potentially huge amounts of Xdata at any given time. The drawback of line buffering is Xthe tools' reduced ability to process line-terminating {\myit newline\/} Xcharacters (ASCII LF) and the total inability to handle text split Xbetween adjacent lines. A related problem is the preponderance of Xtools structured as a {\myit filter\/}, reading input from the terminal X(instead of directly from a file), and writing output to the terminal X(instead of directly to a file). This of course would create an Xunholy mess on the interactive terminal screen, and could never work Xsave for the {\myit redirection\/} mechanism which ``fools the system'' Xinto accepting a {\myit file\/} as ``terminal input'' and another X{\myit file\/} as X``output from the terminal'', and keeps the screen uncluttered. XWhat is not so obvious is that using the same file for both input and Xoutput would garbage the text of that file the same way concurrent Xscreen I/O would trash the screen, and is disallowed by the system. X\L XIn a typical situation, Xshould one wish to transform the text in twelve Xdistinct files according to the same rules using the X{\myit sed\/} text editor, the limitations inherent in the X{\myit filter\/} structure necessitate that twelve new files be Xcreated first to contain the respective transformed copies of the Xoriginal files. The new files are then made to displace the Xoriginal files in twelve separate processes! XInterestingly, such un-automated tedium raises eyebrows of beginning XUnix users only. The wise already know why things {\bb have to be} Xthe way they are, and don't use {\myit sed\/} to edit twelve files Xat once. X\L XThe author (who enjoys taking an opposing point of view) compiled Xthis collection of C routines as an aid in combatting the yoke Xof \stio. Just as mathematicians overload the ``senseless'' meaning Xof {\myit irrational\/} to describe Xnumbers that can not be expressed as a {\myit ratio\/} of integers, XILIB functions are perceived to be {\myit irrational\/} because Xthey oppose the X{\myit rationale\/} supporting the standard C library and \stio. XHence the {\bb i} as the name of the library and as the leading Xcharacter of each of the function names. X\L XFrom an implementational perspective, Xthe \IT\ archive is simply an extension to Xthe standard library's string function Xset, favoring data manipulation within Xlarge internal character lists in order to facilitate Xin-place, direct file transformation. XThe majority of functions archived in \IT\ directly alter text in Xinternal ``buffers'' passed from the calling function. The Xcaller passes the lowest address of the buffer as the pointer X{\myit start\/}, and the address of the byte Ximmediately beyond the highest address of the buffer as the Xpointer {\myit end\/}. XThe implicit buffer size (the difference of the two addresses) Xallows \IT\ Xfunctions to ignore or bypass notions of ``null terminated strings'' Xand handle ASCII values 0~through~127 in an equal manner. XString size restrictions also disappear (or expand rather, to the Xcount expressed by the system's largest positive {\myit int\/}). X\L XAll ILIB functions with {\myit start, end\/} parameters test against X{\myit (char *)NULL\/} passed for {\myit start\/}, and report an Xerror through ILIB's error function {\myit ierror()\/}. XZero-length buffers may be passed without penalty; however the Xcalled function is not obliged to process an empty buffer, Xbeyond recognizing that the buffer is empty and returning zero or XNULL. XCallers that do not know the precise size of the buffer Xmay pass {\myit (char *)NULL\/} as {\myit end\/}, or Xmay first call the \IT\ function X{\myit inull~(start)\/}. XEither of these methods results in an attempt to find the Xend of the buffer by reading it until the first zero byte. XObviously, in these cases the buffer data will not include XNUL bytes. X\L XBecause \IT\ functions perceive individual files as single strings, Xprograms written with them can attempt Xto escape stream-oriented Unix I/O and transform Xfiles in-place instead. Most programs listed Xin this manual directly alter file contents. XTechnical concerns of direct file transformation are detailed Xin the description of the {\myit mung\/} example Xlisted along with the Xmanual pages of the {\myit ierror()\/} function. X\L XAll function names archived under \IT\ begin with {\myit i\/}. XRelated functionalities are collectively discussed in a Xchapter titled by the name of the main function variant. XChapters are in alphabetical order of title. XSome functions, in spite of being behaviorally or Xstructurally non-orthogonal to typical X\IT\ constituents, gained a firm foothold in \IT\ because of their Xusefulness. In selecting functions for inclusion, practicality Xwas more of a concern than ILIB's ``purity''. XThe functions X{\myit iego()\/}, {\myit ihash()\/}, X{\myit imonth()\/}, {\myit iinput()\/} and {\myit iwhich()\/} Xfor example, Xparse environment variables delimited by null bytes, or Xother strings whose length and range of byte values is implicit in Xthe standard data they contain. XThese functions operate on null terminated strings. XSome \IT\ functions such as {\myit icount()\/}, {\myit igroup()\/}, X{\myit ihms()\/}, {\myit iopt()\/}, {\myit itok()\/}, X{\myit iuniq()\/} are ``dynamic'': they Xmaintain primitive internal Xstate machines. Such functions expect an initializing call, a Xnumber of subsequent operational calls, and in most cases, Xa single terminal call. To utilize Xparallel instances of concurrent state machines (for example two X{\myit icount()\/} machines for counting two Xseparate sets of data simultaneously), clones of the function Xwith changed function names X(from {\myit icount() to icounta()\/}) Xshould be added to \IT. X X\S{MAKING ILIB} XTo create \IT, the Unix {\myit make} Xcommand should be executed in the directory containing the C source Xfor the individual functions. This directory Xis named {\myit i\/} in various example programs of this manual. XThe directory also contains the file dependency list used by X{\myit make\/}, in {\myit makefile\/}. In the BSD environment, Xtype {\myit make\/} on the Xcommand line to compile the ILIB source and to archive Xthe individual {\myit .o\/} files as \IT. XWhen compiling under System~V, the command line should contain X\smallskip X\I{\mytt make -DREALUNIX} X\smallskip Xto guide the preprocessor to Xthe appropriate {\myit include files\/}, and to allow the Xcompile-time resolution of minor incompatibilities between the Xtwo systems. X\L X\IT\ is a Unix library; no provisions were made for porting to other Xoperating systems. XIn particular, the use of the ASCII character set is assumed, precluding Xoperation with EBCDIC or other character arrangements. XSystem calls are used in a transparent manner Xbetween the System~V and Berkeley versions; some system calls Xmay not port to other operating systems. X X\S{COMPILING WITH ILIB} XTo access functions in the library, the compiler should link with X\IT. User code should instruct the preprocessor to X{\myit\#include~''ilib.h''\/}, containing Xfunction declarations and constant definitions. The error routine X{\myit ierror()\/} through which \IT\ functions report failures, also Xdefines storage Xfor the global {\myit ierbuf\/} string, and the Xinteger {\myit ierflag\/}. X\L XSimilarly to when making XILIB, any user code (even the example programs) Xcompiled under System~V should define X{\myit REALUNIX\/} Xat compile time, to guide the preprocessor to Xthe appropriate {\myit include files\/}. X X\S{FORMAT OF THE MANUAL} XThis manual began as {\myit man pages\/} formatted as input for the XUnix {\myit troff~-man\/} command. In spite of being renown and a Xstandard, both the {\myit troff\/} program and the {\myit man\/} Xformatting macros proved to be inflexible and generally an Xencumbrance, hindering the visual precision of the descriptions, Xand producing second-rate output. X({\myit The soapbox, please...\/}) XThe perseverance of old standards is an unfortunate phenomenon; Xrevolutionary, new tools find it impossible to take foothold Xbecause of the fear of not being backward compatible with the X``lowest common denominator'' represented by the Xpedestrian forerunners. X\L XThe manual has been re-written under \TeX. The general format of Xthe Unix {\myit man pages\/} was retained. Technical phrases, Xfile names, function names, shell commands embedded in the manual Xtext are in {\myit italics\/}. XThe name of the currently described manual entry is Xin {\bb bold}. Distinct command lines and program segments are in X{\mytt typewriter font}. XReferences to single key strokes and sometimes to Xcharacter combinations are clarified by Xsurrounding the character or the string with a \dx{rectangular border}. X X\S{EXAMPLE PROGRAMS} XIn an attempt to shield readers from Xincomplete, malformed and mis-printed example text, this manual Xwaives a degree of visual uniformity and topical cohesion, Xin favor of listing complete, standalone (and hopefully useful) XC programs. The entire text of each example program is assumed to Xreside in a single file. Since a full reproduction of program Xtext may still Xleave out crucial compiling and linking information, but a Xseparate {\myit Makefile\/} Xfor each example program would further segment the Xmanual besides being an overkill, the simple expedient of Xprepending example programs with their own compilation script Xis utilized throughout this manual. It is assumed that the X{\myit .c\/} file containing the text would be made executable; Xand by typing the name of the file the user would execute Xthe command script in order to compile and install the object. X\L XThe command structure of most example programs has been kept Xsimple, but extendible. The goal was to provide small and Xuncomplicated tools, and to encourage the user to upgrade the Xexample text by adding more command line options or developing Xalternate functionalities. X\L XThe command scripts listed in the manual assume compilation in the XBerkeley environment. XUnder System~V Xthe {\myit -DREALUNIX\/} definition should be inserted into Xeach compilation script. If the text of the example programs is Xon-line, the entire set could be changed with a single X{\myit mung\/} command ({\myit mung\/} should be made first). XThe compiler will look for ILIB include files X(principally for {\myit ilib.h\/}) in {\myit ../i\/} Xand will attempt to link with {\myit ../i/ilib.a\/}. X\L XExample programs are in typewriter font. The text is Xnot known to contain undocumented, Xembedded non-printing characters, except Xambient white space. Programs of {\myit filter\/} structure X(reading from \stin\ or from a file, and writing to \stout) Xwith no mandatory command line arguments Xwill wait for input if the command name is the only word on the Xcommand line. All other Xprograms print a ``usage'' message to X\stout\ and terminate without error if the program name Xis given solo. The ``on-error'' syntax dump Xprovides an immediate and obvious means of reviewing command Xline particulars, with no chance of causing accidental damage Xto files. In the absence of such review the user can infer the Xfilter structure, and there is no potential for file damage. X\L XLines of program Xlistings that contain calls to the illustrated ILIB functions Xor that are essential in Xthe context of the example are prepended with an arrow. XIn order that the manual may directly include ``live'' program Xlistings (using \TeX's {\mytt\bsl\myit input\/} construct), Xthe arrows seen in the manual were Xdirectly installed in the live text of the example program, Xeach as a capital letter \key{Q} Xin the leftmost column of a program line. The {\myit ilib.h\/} Xinclude file makes a small concession to the manual format, with the Xpreprocessor statements: X\smallskip X\I{\mytt\#ifdef\ \ IMANFMT} X X\I{\mytt\#define\ Q} X X\I{\mytt\#endif} X\smallskip XEach example program utilizes the construct by Xdefining {\myit IMANFMT\/} in its Xcompilation script, making leading \key{Q} tokens in the XC code transparent to the compiler. At the same time Xthe examples avoid using the capital \key{Q} for variable names, Xdefinitions or in text strings, since any occurrence of \key{Q} Xin the program listings would get converted to arrows by the Xmacros that control the format of the manual. X X\S{CROSS REFERENCE OF PROGRAM EXAMPLES} XThe first column of {\bb Table~3.} gives the names of Xcomplete programs used in this manual as Xexamples. Alternate names ({\myit aliases\/}) of a program are Xprinted in plain font, true names of programs are in boldface. XThe last column of each line shows the Xmanual entry that describes and lists the text of the Xexample program. X X\S{AN EXAMPLE EXAMPLE PROGRAM} XThe following listing Xillustrates the compile script merged with the C code, and the use of Xthe preprocessor's {\myit \#include\/} construct for prepending the X{\myit ilib.h\/} file to the program text. XThe example program's name is {\bb q}, and its Xpurpose is the automatic channeling (queuing) of data redirected from X\stout, to temporary files. XOn the command line, {\bb q} simply precedes the full command Xwhose output is to be collected in a temporary file, for example: X\smallskip X\I{\mytt q sort -n unsorted\_file} X\smallskip XIn this invokation, {\bb q} {\myit exec\/}s the {\myit sort\/} command, Xcollects the output in a file, and prints the name of the sorted Xfile to \stout: X\smallskip X\I{\mytt /tmp/qtmp01478} X\L XThe file is created in the {\myit /tmp\/} directory. The file name Xbegins with {\myit qtmp\/}, followed by the {\myit user~ID\/} X(right justified and zero filled to four bytes). The last digit Xof the name Xrepresents a counter counting down from 9 to 0 then restarting back at X9: the program assumes that a user never needs more than ten Xconcurrently active temporary files. The loop provides a self-limiting Xmechanism, automatically Xoverriding the oldest of the user's ten temporary files Xwith the new temporary data. To explicitly clear {\myit /tmp\/} Xof these temporary files, the command name {\bb q} is used without Xtrailing arguments (making this the only example Xthat produces results with a solo token on its command line). X\L XUsing {\bb q} is most convenient for collecting data written to X\stout, for further transformation by a non-filter command. XThe Unix {\myit diff\/} is an example of a non-filter command. XTo {\myit diff\/} two unsorted lists, the normal sequence Xof commands would be: X\smallskip X\I{\mytt sort list1 > sorted\_list1} X\I{\mytt sort list2 > sorted\_list2} X\I{\mytt diff sorted\_list1 sorted\_list2} X\L XThis sequence can be Xsimplified by queuing up the intermediate X{\myit sort\/} outputs directly (quotes in the Xfollowing command are {\myit back quotes\/}): X\smallskip X\I{\mytt diff \ `q sort list1` \ `q sort list2`} X\L XMore complex command strings are the norm when using {\bb q}. XIf the token string {\bb q} is to execute contains \key{\pip} X(pipe) or \key{\les} \key{\gre} (redirection) Xtokens, the command should be enclosed in quotes, otherwise Xthe shell will only pass the command fragment on the left side Xof the pipe/redirection to {\bb q}: X\smallskip X\I{\mytt diff \ `q "grep '\car T' list1 | sort"` \ \ `q sort list2`} X\smallskip XIn this altered version of the above example, the first temporary file Xwill contain the sorted list of only those lines of {\myit list1\/} Xthat began with capital T. X\L XIn the program listing Xthe first four lines comprise the prepended script. XWhen executing this script, the first line will appear to the shell Xto be a comment. The second line is the shell command for compiling Xthe C code. The third line ends the script. XBecasuse {\myit NEVER\/} is intentionally left undefined, the Xpreprocessor skips the second and third lines, and the compiler Xnever sees the shell commands. X\L XAdditionally, Xthe compile-script contains the {\myit -DIMANFMT\/} definition that Xwill render capital \key{Q} tokens of the program transparent to the Xcompiler, while producing an arrow ($\longrightarrow$) in the listing Xof the program. The script also contains the {\myit -I../i\/} path Xthat lets the preprocessor find {\myit ilib.h\/} in its (assumed) Xdirectory {\myit ../i\/} given relative to the current Xdirectory containing the executable {\bb q.c}. XThe {\bb q.c} program calls the {\myit ifonetic()\/} function Xfrom {\bb ilib.a} in order to resolve ``phonetic control sequences'' X(described under the {\myit ifonetic()\/} manual entry). XTo do this, the program has to link with {\bb ilib.a}, whose full path X{\myit ../i/ilib.a\/} is also a part of the script, X\L XThe first task of the {\bb q} process is to produce a name Xtemplate containing the target path {\myit /tmp\/}, the Xconstant string {\myit qtmp\/} and the user's {\myit uid\/}, Xending with an extra {\myit counter\/} byte whose value can vary Xbetween the ASCII '0' and '9'. If there were no command Xline arguments, {\bb q} removes any existing files that match the Xtemplate. Otherwise, if {\myit /tmp\/} does not yet contain all Xten template variants, the new file created will end with the highest Xunused counter byte. If all ten file name variants already exist, Xthe ``oldest'' (least recently modified) is recycled, losing its Xprevious data. All command line arguments that followed {\bb q} Xare then concatenated into a space-separated list of tokens, and Xthe {\myit system()\/} command executes the new string, redirecting Xits \stout\ output to the selected {\myit qtmp\/} file. The Xfull pathname of the {\myit qtmp\/} file is echoed to {\bb q}'s X\stout. X X\S{q.c PROGRAM TEXT} X\listing{../iex/q.c} X\eject SHAR_EOF $TOUCH -am 0601084990 iman/i.tex && chmod 0644 iman/i.tex || echo "restore of iman/i.tex failed" set `wc -c iman/i.tex`;Wc_c=$1 if test "$Wc_c" != "18670"; then echo original size 18670, current size $Wc_c fi # ============= iman/ialntok.tex ============== echo "x - extracting iman/ialntok.tex (Text)" sed 's/^X//' << 'SHAR_EOF' > iman/ialntok.tex && X% XREF ialntok ianytok ictok X X\def\name{IALNTOK} X\def\IT{{\bb ialntok()}} X X\S{NAME} X{\bb ialntok} --- copy first alphanumeric token into word buffer X X{\bb ianytok} --- copy first token of source into word buffer X X{\bb ictok} --- copy first C token of source into word buffer X X\S{SYNOPSIS} X{\obeylines \bb Xchar * Xialntok (start, end, wbuf) Xchar *start; Xchar *end; Xchar *wbuf; X\L Xchar * Xianytok (start, end, wbuf) Xchar *start; Xchar *end; Xchar *wbuf; X\L Xchar * Xictok (start, end, wbuf) Xchar *start; Xchar *end; Xchar *wbuf; X} X X\S{DESCRIPTION} XPrograms operating on text streams inevitably Xorganize bytes into groups of Xprinting characters or {\myit tokens\/}. Text is then handled Xas successive tokens separated by non-printing X{\myit white space\/} characters, Xor made distinct by other token-forming rules. The \IT\ functions Xrecognize and isolate the ``next token'' from {\myit start\/}. X\L XA pointer is advanced from {\myit start\/} to the first printing Xcharacter in the stream. This is the beginning of the token. A Xsecond pointer is advanced to the byte just past the token. The Xthree functions use different character sets for mapping Xprinting characters as part of the recognized token. X\L XEither of the functions return the address of Xthe byte just past the token in the original stream. X(This address may be {\myit end\/}, if no trailing spaces followed Xa single token in the stream.) To get a ``next token'' X(to strip out a sequence of tokens from a stream), the caller Xneed merely to assign the returned address as the new {\myit start\/} Xpoint. X\L XThe text stream containing the token is not disturbed during parsing; Xthe token is Xcopied into a small buffer supplied by the caller via the pointer X{\myit wbuf\/}, and is null terminated in {\myit wbuf\/}. XThe caller passes a X{\myit wbuf\/} of Xsufficient size to hold the maximum expected token plus the Xfinal NUL byte; for X{\bb ictok()} a minimum of {\myit IHALFK\/} (512 bytes) is Xrecommended. X\L X{\bb ianytok()} considers any printing character a legitimate member of Xthe token byte string. The token ends when the next byte is a space, Xa NUL byte, a ``control character'' (including {\myit newline, tab,\/} Xetc.), or the end of the buffer X(pointed to by {\myit end\/}). Thus, the token may contain punctuation Xmarks, hyphenation, math symbols and special printing characters. X\L X\IT\ creates multi-byte tokens from alphanumeric characters only, using Xthe 26 (upper or lower case) characters of the alphabet plus the Xdigits 0~--~9. XThe token ends when the next byte is a space, a non-alphanumeric Xcharacter, Xa NUL byte, a ``control character'', or the end of the buffer X(pointed to by {\myit end\/}). XIf a printing character which is recognized as the beginning Xof a token is itself not alphanumeric, this character is interpreted Xas a single-byte token terminating with the next byte. X\L X{\bb ictok()} is similar to \IT, except that X{\bb ictok()} in the C tradition, moves Xunderscore\key{\und} and dollar\key{\$} characters Xinto the alphanumeric set from which Xto build multi-byte aggregate tokens. Furthermore, Xthe token-forming rules under X{\bb ictok()} permit multi-byte tokens formed of adjacent Xnon-alphanumeric printing characters, if the token thus created is a Xvalid token in the C language. The following Xnon-alphanumeric aggregates are recognized: X\L X{\obeylines XCharacter constants X\smallskip X{\mytt\dx{\bsl }\ \twokey{\bsl "}\ \twokey{\bsl '}\ \dx{\bsl }\ \twokey{\bsl \bsl}\ \twokey{\bsl b}\ \twokey{\bsl f}\ \twokey{\bsl n}\ \twokey{\bsl r}\ \twokey{\bsl t}\ \twokey{\bsl v}} X\L XC operators X\smallskip X{\mytt\twokey{!=}\ \twokey{\%=}\ \twokey{\&\&}\ \twokey{\&=}\ \twokey{*=}\ \twokey{++}\ \twokey{+=}\ \twokey{--}\ \twokey{-=}\ \twokey{->}\ \twokey{/=}\ \twokey{<<}\ \dx{<<=}\ \twokey{<=} X\smallskip X\twokey{==}\ \twokey{>=}\ \twokey{>>}\ \twokey{>>=}\ \twokey{\cir =}\ \twokey{|=}\ \twokey{||}} X\L XArchaic operators X\smallskip X{\mytt\twokey{=*}\ \twokey{=+}\ \twokey{=-}} X\L XDecimal point as a part of decimal digit strings, comment delimiters X\smallskip X{\mytt \dx{\lsq\rsq.\lsq\rsq}\ \twokey{/*}\ \twokey{*/}} X\smallskip X} X\L XAdditionally, strings that begin with a \key{"}\ or \key{'}\ Xcharacter, force X{\bb ictok()} to include all following bytes of the string as part of Xthe currently evaluated token, up to and including the next Xnot-escaped \key{"}\ or \key{'}\ byte, respectively. XIf a matching quote character is not found by the 511th byte, parsing Xstops, and ``{\myit runaway double quote\/}'' or X``{\myit runaway single quote\/}'' is written into {\myit wbuf\/} Xinstead. Parsing can then continue from the 512th byte, or the Xcurrent 512-byte stretch of the buffer can be reexamined to Xanalyze the failure. X\L X{\bb ictok()} makes no special arrangements for preprocessor syntax: X{\myit \#include\/} for example, is seen as two separate tokens X\key{\#}\ and \dx{\mytt include}. X\L XIf no token has been found on encountering {\myit end\/}, a NULL pointer Xis returned as a sentinel. In this case, {\myit wbuf\/} is left Xintact, potentially still Xcontaining the token found during a previous call. XNULL is also returned X(immediately after a call to {\myit ierror()\/}) Xif {\myit start\/} points to NULL. X X\S{SEE ALSO} X{\myit itok, iexpect\/}. X X\S{rewrap EXAMPLE PROGRAM} XThe {\bb rewrap} program is a simple text formatter, producing output Xsimilar to Xthe Unix {\myit fold\/} or {\myit fmt\/} commands, but reorganizing Xand changing the Xoriginal file directly instead of filtering input to \stout. X{\bb rewrap} demonstrates a method of in-place file transformation Xusing a temporary target file instead of internal buffers. XThe source is read Xline-by-line; its tokens are extracted using X{\bb anytok()} and are queued in an intermediate buffer, Xseparated from the previous token by a space (two spaces if the Xprevious token ended with a period). When the addition of Xthe next token would bring the buffer length over Xthe command-given limit, {\bb rewrap} appends the Xbuffer text to the temporary file created in X{\myit /tmp\/}, then restarts the queue with the token that would have Xcaused the buffer overflow. X\L XThus, the original words are re-listed so that all new Xlines contain the maximum number of complete words; and no Xline exceeds the specified line width. XBlank lines of the original text X(lines not containing tokens) Xsignal a new paragraph: the blank line causes an immediate flush of Xthe queue, and the output of a linefeed. XAt the end of the tokenizing process, the original file is removed, Xand the target file is moved into its place. XThe {\bb rewrap} algorithm preserves the indentation X(from the left margin) of the old text. XAs an example, the file {\myit quote\/}, containing X\L X\I{\listing{stanquote.old}} X\L Xcould be re-formatted as 76-column lines with the command: X\L X\I{\mytt rewrap 76 quote} X\medskip X\I{\listing{stanquote.new}} X\L XInstead of using {\myit fopen()\/} to gain access to the source and Xtarget files, {\bb rewrap} calls {\myit freopen()\/}, reusing the Xotherwise idle file pointers \stin\ and \stout. XApart from a better use of Xresources, this would permit the use of the more convenient X{\myit gets(), puts()\/} calls instead of X{\myit fgets(), fputs()\/}, although {\bb rewrap} Xstill calls {\myit fgets()\/} because the second parameter X(the maximum allowed line size) of this Xfunction is a built-in Xsafeguard against buffer overflow. Because the \stout\ stream is Xautomatically buffered by the operating system (not written until Xit accummulates {\myit BUFSIZ\/} bytes) X{\bb rewrap} must explicitly flush \stout\ to Xcomplete partial output to the temporary file. X X\S{rewrap.c PROGRAM TEXT} X\listing{../iex/rewrap.c} X\eject SHAR_EOF $TOUCH -am 0531155190 iman/ialntok.tex && chmod 0644 iman/ialntok.tex || echo "restore of iman/ialntok.tex failed" set `wc -c iman/ialntok.tex`;Wc_c=$1 if test "$Wc_c" != "7693"; then echo original size 7693, current size $Wc_c fi # ============= iman/ibcmp.tex ============== echo "x - extracting iman/ibcmp.tex (Text)" sed 's/^X//' << 'SHAR_EOF' > iman/ibcmp.tex && X% XREF ibcmp ibcopy ilast X X\def\name{IBCMP} X\def\IT{{\bb ibcmp()}} X X\S{NAME} X{\bb ibcmp} --- compare two byte strings X X{\bb ibcopy} --- copy bytes from one place to another X X{\bb ilast} --- find last occurrence of character in a string X X\S{SYNOPSIS} X{\obeylines \bb Xint Xibcmp (s1, s2, bytes) Xchar *s1; Xchar *s2; Xint bytes; X\L Xvoid Xibcopy (tobuf, frombuf, bytes) Xchar *tobuf; Xchar *frombuf; Xint bytes; X\L Xchar * Xilast (ptr, c) Xchar *ptr; Xchar c; X} X X\S{DESCRIPTION} XFrom the caller's point of view, Xonly the names are different between System~V's {\myit memcmp()\/} Xand the Berkeley {\myit bcmp()\/} functions. Both compare a number Xof bytes beginning at {\myit s1\/} against the same number of bytes Xbeginning at {\myit s2\/}, and return the difference of the byte Xvalues at the first byte mismatch (subtracting the X{\myit s2\/} byte from the {\myit s1\/} byte). X{\bb ibcmp()} is a {\myit macro\/} defined in {\myit ilib.h\/}, Xmapping to {\myit memcmp()\/} or X{\myit bcmp()\/} depending on the system under which ILIB Xwas compiled. X\L XThe XSystem~V {\myit memcpy()\/} function and the XBerkeley {\myit bcopy()\/} function both copy a number of Xbytes from one buffer to another. In spite the Xidentical goal, the two functions are named differently, Xreturn different {\myit types\/}, and use source and target Xparameters in opposite order. X{\myit memcpy()\/} and {\myit bcopy()\/} Xare both standard library functions. XOptimized ``to the hilt'', they can easily run ten (or more) Xtimes faster than implementations Xcopying bytes in a {\myit for loop\/} Xin {\myit user space\/}. X{\bb ibcopy()} is a {\myit macro\/} defined in {\myit ilib.h\/}, Xmapping to {\myit memcpy()\/} if ILIB has been compiled with the X{\myit REALUNIX\/} flag, or to BSD's {\myit bcopy()\/} otherwise. X{\bb ibcopy()} retains {\myit memcpy\/}'s Xtarget--source parameter order also employed by the Xstandard string functions {\myit strcat(), strcpy(),\/} etc.. XThere are no errors. X\L X{\bb ilast()} is a true function, Xbypassing the {\myit rindex()\/} versus {\myit strrchr()\/} Xincompatibility between Unix variants, X{\bb ilast()} Xfinds the last occurrence of some character ``{\myit c\/}'' in the Xnull-terminated buffer pointed to by {\myit ptr\/}, and Xreturns a pointer to it or a pointer to NULL on failure. XNULL is returned and {\myit ierflag\/} is set if the passed-in X{\myit ptr\/} is itself the NULL pointer. X\eject SHAR_EOF $TOUCH -am 0601085990 iman/ibcmp.tex && chmod 0644 iman/ibcmp.tex || echo "restore of iman/ibcmp.tex failed" set `wc -c iman/ibcmp.tex`;Wc_c=$1 if test "$Wc_c" != "2388"; then echo original size 2388, current size $Wc_c fi # ============= iman/iblank.tex ============== echo "x - extracting iman/iblank.tex (Text)" sed 's/^X//' << 'SHAR_EOF' > iman/iblank.tex && X% XREF iblank itran X X\def\name{IBLANK} X\def\IT{{\bb iblank()}} X X\S{NAME} X{\bb iblank} --- change all bytes to spaces X X{\bb itran} --- change one character to another everywhere in buffer X X\S{SYNOPSIS} X{\obeylines \bb Xvoid Xiblank (start, end) Xchar *start; Xchar *end; X\L Xint Xitran (start, end, fromc, toc) Xchar *start; Xchar *end; Xchar fromc; Xchar toc; X} X X\S{DESCRIPTION} X\IT\ clears an internal buffer beginning at {\myit start\/} and Xending one byte before {\myit end\/}, by changing each byte in the Xbuffer to the {\myit space\/} character (ASCII 32). The function is Xemployed to ``white out'' comment fields in text, Xso subsequent parsing would encounter meaningful tokens only. XThe user's text is typically pre-scanned Xto locate comments (perhaps using the X{\myit inest()\/} function); the {\myit start\/} and {\myit end\/} Xaddress of each comment are then passed to \IT. X\L XThe more selective {\bb itran()} function searches the passed buffer Xfor {\myit fromc\/} characters; converting each X{\myit fromc\/} value to {\myit toc\/}. X{\bb itran()} returns the count of converted characters. X\L X\IT\ does not report errors. X{\bb itran()} calls {\myit ierror()\/} if {\myit (char *)NULL\/} is Xpassed as {\myit start\/}. X\L X\S{SEE ALSO} XThe {\myit iswapstr()\/} or X{\myit iswapw()\/} functions provide a means for transforming all Xoccurrences of a single, multi-byte source token to a target token, Xglobally Xwithin the passed buffer. The {\myit idump()\/} function can be Xused to print an image of the internal buffer to \stout. X\eject SHAR_EOF $TOUCH -am 0601092690 iman/iblank.tex && chmod 0644 iman/iblank.tex || echo "restore of iman/iblank.tex failed" set `wc -c iman/iblank.tex`;Wc_c=$1 if test "$Wc_c" != "1535"; then echo original size 1535, current size $Wc_c fi # ============= iman/ibreakl.tex ============== echo "x - extracting iman/ibreakl.tex (Text)" sed 's/^X//' << 'SHAR_EOF' > iman/ibreakl.tex && X% XREF ibreakl X X\def\name{IBREAKL} X\def\IT{{\bb ibreakl()}} X X\S{NAME} X{\bb ibreakl} --- break long lines into shorter ones X X\S{SYNOPSIS} X{\obeylines \bb Xint Xibreakl (start, end, tobuf, header, ender, breakc, maxc, all) Xchar *start; Xchar *end; Xchar *tobuf; Xchar *header; Xchar *ender; Xchar *breakc; Xint maxc; Xint all; X} X X\S{DESCRIPTION} XThe \IT\ function serves as a Xline manager of long lines that must be broken at Xsome token boundaries, into shorter lines. X\IT\ has the dubious distinction of featuring the longest Xparameter list among the ILIB functions, as a Xdirect result of the extraordinary computational complexity of even the Xsimplest formatting requests. X\L XAn example source string that required re-formatting could be a XBASIC {\myit data statement\/} automatically generated by a Xprogram writer process: X\L X{\obeylines\mytt\leftskip=20pt XDATA\ "this\ is\ string1",\ "this\ is\ string2",\ "this\ is\ string3",\ "this\ is\ st Xring4",\ "this\ is\ string5",\ "this\ is\ string6",\ "this\ is\ string7",\ "this\ is X\ string8",\ "this\ is\ string9",\ "this\ is\ string10",\ "this\ is\ string11",\ "th Xis\ is\ string12" X} X\L XHaving collected the necessary components of the statement, Xthe program writer would need to {\myit output\/} the statement in a Xvisually clear format: X\L X{\obeylines\mytt\leftskip=20pt XDATA\ "this\ is\ string1",\ "this\ is\ string2",\ "this\ is\ string3", X\ \ \ \ \ "this\ is\ string4",\ "this\ is\ string5",\ "this\ is\ string6", X\ \ \ \ \ "this\ is\ string7",\ "this\ is\ string8",\ "this\ is\ string9", X\ \ \ \ \ "this\ is\ string10",\ "this\ is\ string11",\ "this\ is\ string12" X} X\L XA glance at the output suggests that the original string Xwas broken up into lines by {\myit newline\/} characters placed Ximmediately past {\myit commas\/} Xonce the current target line was relatively full; Xand that extra {\myit white space\/} (apparently four {\myit space\/} Xcharacters) got inserted at the head of each new line to offset the X``DATA'' token from the data strings. X\L XIn the \IT\ parameter list, {\myit start\/} and {\myit end\/} Xdefine the limits of the buffer containing the source string. XTypically to ILIB, {\myit end\/} is set to one byte {\bb past} the Xlast byte of the source string. XThe next parameter {\myit tobuf\/} is a pointer to the destination Xstorage allocated or defined by the process that calls \IT, Xthe buffer where \IT\ is to place the re-formatted result. XThe caller must guarantee that {\myit tobuf\/} is of sufficient size Xto contain the processed, enlarged target string, plus a terminating XNUL byte. X\L X{\myit header\/} points to a string that \IT\ should prepend at Xeach new line before adding more segments of the source string to Xthe line. In the example above, the {\myit header\/} string Xcontained four {\myit space\/} characters. Similarly, Xthe string pointed to by {\myit ender\/} Xis to be appended to each new line; in the above example {\myit ender\/} Xconsisted of a single {\myit newline\/} character. XBoth {\myit header\/} or {\myit ender\/} may be passed as X{\myit (char~*) NULL\/}, suppressing prepended or trailing strings. X\L XThe {\myit breakc\/} pointer points to a string of un-ordered Xcharacters comprising a Xset of delimiters: when parsing the source string, a X{\myit break point\/} is recognized immediately following Xa character of the source string that matches any single character of Xthe delimiter set. XA {\myit break point\/} marks a spot at which the source line Xcan be split. In the above example, the {\myit breakc\/} string Xcontained a single {\myit comma\/} character. X\L X{\myit maxc\/} is the maximum permissible Xbyte count of any newly made line, including {\myit newline\/} Xor other non-printing characters that may already be present in the Xsource string, and also including the newly prepended {\myit header\/} Xand appended {\myit ender\/} strings. X\L XIf the last parameter X{\myit all\/} is TRUE (non-zero), the {\myit header\/} Xstring is prepended to each line of the result, Xeven the first; and X{\myit ender\/} is appended to each line of the result, even the last. XOtherwise, X{\myit header\/} is not prepended to the initial line of the result, Xand X{\myit ender\/} is not appended to the final line of the result. X\L XAtypically to ILIB, the {\myit header, ender, breakc\/} strings passed Xto \IT\ are Xassumed to be null terminated, normal C strings; Xthe piecing-together operations utilize standard string functions X{\myit strcat(), strcmp()\/}, and the like. There seemed to be Xvery little utility in coding this function to accept arbitrary Xstrings potentially containing embedded NUL bytes. X X\S{RETURN VALUES} XThe {\myit int\/} returned from \IT\ is the byte length of the Xprocessed, final string in {\myit tobuf\/}, not including the Xterminal NUL byte. Error returns of Xnegative {\myit sys\_nerr\/} indicate either X\smallskip X{\parindent=40pt X\item{$\bullet$} Xthat the sum of the lengths of {\myit header\/} Xand {\myit ender\/} Xis greater than the maximum specified line length {\myit maxc\/}, X\smallskip X\item{$\bullet$} Xor that \IT\ could not find a {\myit break point\/} within Xthe evaluated source substring (such that the length of the current Xtarget line, Xwith {\myit header\/} and {\myit ender\/} included if appropriate, Xdidn't exceed {\myit maxc\/} bytes) Xat which the source string could have been broken. In this case, X{\myit tobuf\/} may already contain partial results. X\smallskip X} X\eject SHAR_EOF $TOUCH -am 0509104090 iman/ibreakl.tex && chmod 0644 iman/ibreakl.tex || echo "restore of iman/ibreakl.tex failed" set `wc -c iman/ibreakl.tex`;Wc_c=$1 if test "$Wc_c" != "5408"; then echo original size 5408, current size $Wc_c fi # ============= iman/icopy.tex ============== echo "x - extracting iman/icopy.tex (Text)" sed 's/^X//' << 'SHAR_EOF' > iman/icopy.tex && X% XREF icopy X X\def\name{ICOPY} X\def\IT{{\bb icopy()}} X X\S{NAME} X{\bb icopy} --- copy buffer into dynamically allocated memory X X\S{SYNOPSIS} X{\obeylines \bb Xchar * Xicopy (start, end) Xchar *start; Xchar *end; X} X X\S{DESCRIPTION} X\IT\ is used to create a duplicate of an Xinternal buffer by Xdynamically allocating space for the new buffer, and then calling X{\myit ibcopy()\/} to copy the source bytes. XThe source buffer begins at {\myit start\/}, and ends Xwith the byte before {\myit end\/}. XA new buffer one Xbyte greater than the size of the passed buffer, Xis allocated by \IT; Xthe source is copied into the new buffer, and Xthe extra byte at the end of the new buffer is set to NUL. X\IT\ returns a pointer to the allocated memory. XIf the NULL pointer is passed as {\myit start\/} or if X{\myit malloc()\/} fails, \IT\ calls {\myit ierror()\/} and Xreturns {\myit (char~*) NULL\/}. X\eject SHAR_EOF $TOUCH -am 0601094490 iman/icopy.tex && chmod 0644 iman/icopy.tex || echo "restore of iman/icopy.tex failed" set `wc -c iman/icopy.tex`;Wc_c=$1 if test "$Wc_c" != "881"; then echo original size 881, current size $Wc_c fi # ============= iman/icount.tex ============== echo "x - extracting iman/icount.tex (Text)" sed 's/^X//' << 'SHAR_EOF' > iman/icount.tex && X% XREF icount X X\def\name{ICOUNT} X\def\IT{{\bb icount()}} X X\S{NAME} X{\bb icount} --- count how many times a specific parameter was passed X X\S{SYNOPSIS} X{\obeylines \bb Xint Xicount (type) Xint type; X} X X\S{DESCRIPTION} X\IT\ is a dynamic function, expecting a setup call, zero or more Xoperational calls, and a resetting final call. XFor a simple example of a program that may use \IT, Ximagine a routine for a robot arm programmed Xto lift single pieces of fruit out of a basket, and having Xrecognized the type of the fruit, Xkeep separate counts of the apples, the oranges and the bananas. XThe program could just increment Xthree distinct variables when counting the fruit; but Xif the number of types counted in parallel Xwas large, or if the types varied from time to time, Xa discreet subroutine would Xbe defined to allocate and manage the array space Xof the counters. \IT\ is such a subroutine. X\L XThe first call to \IT\ passes the number of array elements Xthat \IT\ should allocate to store the count of Xthe separate types during the following operational calls. XIn the above example, three types X(apples, oranges, bananas) would be counted, set up with Xthe initializing call: X\smallskip X\I{\mytt icount (3);} X\L XThis first call returns zero unless the number of X{\myit type\/}s requested was zero, or the array allocation failed. XEither exception would call {\myit ierror()\/} and return negative, Xleaving \IT\ ready for another initializing call. X\L XAt the end of each operational call, \IT\ returns Xthe tally of previous calls in which the {\myit type\/} of the Xcurrent call was passed. In the fruit example, the robot program Xwould X\smallskip X{\mytt X\I{\#define APPLE \ 0} X\I{\#define BANANA 1} X\I{\#define ORANGE 2} X} X\smallskip Xand on encountering some ``orange orange banana apple orange apple apple Xorange'' sequence, would call \IT\ eight times. The values Xreturned from these calls are shown after each call as comments: X\smallskip X{\mytt X\I{icount (ORANGE); /* 0 */} X\I{icount (ORANGE); /* 1 */} X\I{icount (BANANA); /* 0 */} X\I{icount (APPLE); \ /* 0 */} X\I{icount (ORANGE); /* 2 */} X\I{icount (APPLE); \ /* 1 */} X\I{icount (APPLE); \ /* 2 */} X\I{icount (ORANGE); /* 3 */} X} X\L XThe range of legitimate {\myit type\/} Xvalues for operational calls is from zero through Xone less than the array Xsize specified in the initializing call, directly corresponding to Xindices into the allocated array. Out-of-bound operational Xparameters trigger Xa negative return (via {\myit ierror()\/}) but do not affect X\IT\ internal states. XIn the fruit example, the call X\smallskip X{\mytt X\I{\#define PASSIONFRUIT 3} X\I{icount (PASSIONFRUIT);} X} X\smallskip Xwould return the negative {\myit sys\_nerr\/}, but more APPLEs, XBANANAs and ORANGEs could be counted immediately afterwards. X\L XThe terminating call passes a negative number, to reset Xthe \IT\ state machine and to free dynamically allocated memory. X X\S{SEE ALSO} X{\myit ierror, iuniq\/}. X X\S{distrib EXAMPLE PROGRAM} XThe {\bb distrib\/} program is an aid in Xanalyzing text distribution characteristics of selected strings, words, Xor characters. Each parameter following {\bb distrib\/} Xon the command line is an object on which statistical information is Xsought. The program counts and Xreports how many times each object occurred in the input. Text Xis supplied to {\bb distrib\/} interactively, or by input redirection. XThough the report is produced only after ``end of file'', Xthe program reads a line at a time, so patterns spanning lines Xcannot be discerned. For a given pattern, each byte Xof the examined line is a starting point for a possible Xmatch: in the string ``rococo'' the pattern ``oco'' is found twice. X\L XGiven an input file {\myit pi\/} containing the first hundred decimal Xdigits of \char5, the following {\bb distrib} command would produce Xa distribution of digits: X\smallskip X\I{\mytt distrib 0 1 2 3 4 5 6 7 8 9 \les \ pi} X\medskip X{\mytt \obeylines X\ \ \ \ 0: 8 X\ \ \ \ 1: 8 X\ \ \ \ 2: 12 X\ \ \ \ 3: 12 X\ \ \ \ 4: 10 X\ \ \ \ 5: 8 X\ \ \ \ 6: 9 X\ \ \ \ 7: 8 X\ \ \ \ 8: 12 X\ \ \ \ 9: 13 X} X\L XAnother example checks that the input contains the same number of Xleft and right curly braces, using phonetic control sequences X(described under {\myit ifonetic()\/}) to Xavoid the need to quote: X\smallskip X\I{\mytt distrib Xlcu Xrcu \les \ distrib.c} X\L XA third command produces an ``alphabetic character distribution list'' Xordered by increasing frequency of characters, Xof {\myit /usr/dict/words\/} (the back-quotes execute the X{\myit char\/} program that expands AZ and az to the full alphabet): X\smallskip X\I{\mytt (distrib `char AZ az` \les \ /usr/dict/words) \pip\ sort -n +1} X\L XFor each line of input the {\bb distrib} algorithm recomputes Xthe string lenght of a search pattern specified, and attempts Xto match the pattern at successive bytes of the input. XThe line is then reexamined to find matches to the next search Xpattern, then the next, until a search list is exhausted. XA more efficient implementation of {\bb distrib} Xcould --- at the expense of some Xcode complexity --- dynamically allocate an array for storing the Xlength of the patterns instead of repeatedly Xcomputing them. X X\S{distrib.c PROGRAM TEXT} X\listing{../iex/distrib.c} X\eject SHAR_EOF $TOUCH -am 0601133090 iman/icount.tex && chmod 0644 iman/icount.tex || echo "restore of iman/icount.tex failed" set `wc -c iman/icount.tex`;Wc_c=$1 if test "$Wc_c" != "5214"; then echo original size 5214, current size $Wc_c fi echo "End of part 5, continue with part 6" exit 0 -- Istvan Mohos ...uunet!pyrdc!pyrnj!hhb!istvan RACAL-REDAC/HHB 1000 Wyckoff Ave. Mahwah NJ 07430 201-848-8000 ======================================================================