From ed at maven.UUCP Fri Jan 19 04:29:56 1990 From: ed at maven.UUCP (Ed Hand) Date: 18 Jan 90 17:29:56 GMT Subject: Patch for - Pcal: postscript/c calendar printer References: <6914@dayton.UUCP> Message-ID: <879@maven.UUCP> In the recent posting of Pcal I found a couple problems. First if I used "pcal | lpr ..." then I would get nothing out. Seems the value of month it was being given was four billion something. Also if I specified the month on the command line (ie. "pcal -m 1 | lpr ...") then I would get the whole year and not just one month. So here are the fixes to both those problems, AND, some extra features. I have added three new command line options and they are as follows: -r This will cause the output to come out in portrait mode instead of landscape. -t This option can be used to change the font the title is printed in. (ie. pcal -t Times-Roman) -d This option is the same as -t except that the font used to print the day numbers is changed. I don't have nroff and know nothing about it so I haven't changed the man page to go with this. In other words, you just read the man pages changes :-) So here is a patch for pcal.c. The patch utility will eat it easily. If you don't have patch there isn't much to change and should be no problem to do by hand, after all, I did :-) Enjoy! _____________________________________________________________________________ Don't pay the ferryman, Ed Hand MS: CR1103 Don't even fix a price, Intergraph Corp. Don't pay the ferryman, Huntsville, Al 35894-0001 Till he gets you to the other side. !uunet!ingr!b11!maven!ed Chris De Burgh b11!maven!ed at Ingr.com _____________________________________________________________________________ -----Cut Here-------------Cut Here--------------Cut Here-------------------- *** /old/pcal.c --- ./pcal.c 22,24d21 < "%!", < "/titlefont /Times-Bold def", < "/dayfont /Helvetica-Bold def", 197,198c194,197 < "\t90 rotate", < "\t50 -120 translate", --- > (char *)0, > }; > > char *pheader2[] = { 264a264,265 > char *titlefont = "Times-Bold"; > char *dayfont = "Times-Bold"; 268a270 > int rotate = 90; 270c272 < int month; --- > int month = 0; 273c275 < while ((m = getopt(argc, argv, "ef:m:y:")) != EOF) --- > while ((m = getopt(argc, argv, "ref:m:y:t:d:")) != EOF) 276a279,282 > case 'r': > rotate = 0; > break; > 288c294 < month = atoi(month); --- > month = atoi(optarg); 296a303,310 > case 't': > titlefont = optarg; > break; > > case 'd': > dayfont = optarg; > break; > 300a315 > 303c318 < "Usage: pcal [ -e | -f ] [ -m month] [ -y ]\n"); --- > "Usage: pcal [ -r ] [ -e | -f ] [ -m month] [ -y ]\n\t\t[ -t ] [ -d <day font> ]\n"); 310c325 < m = lt->tm_mon + 1; --- > month = lt->tm_mon + 1; 339a355,356 > PRT("%%!\n"); > PRT("/titlefont /%s def\n/dayfont /%s def\n", titlefont, dayfont); 340a358,364 > PRT("%s\n", *ap); > PRT("\t%d rotate\n", rotate); > if (rotate) > PRT("\t50 -120 translate\n"); > else > PRT("\t0.75 0.75 scale\n\t50 460 translate\n"); > for (ap = pheader2; *ap; ap++) From davidsen at crdos1.crd.ge.COM Wed Jan 3 05:35:18 1990 From: davidsen at crdos1.crd.ge.COM (Wm E Davidsen Jr) Date: 2 Jan 90 18:35:18 GMT Subject: Bundle 1.1 Message-ID: <1969@crdos1.crd.ge.COM> This is an intermediate version of the "bundle" program I released many years ago. What bundle does is to assist when sending stdout to a multivolume device (like backing up to floppy). This is NOT the final version, please don't redistribute it, I'll put the real thing out in a few days unless people have trouble with this one. To use: for floppy the buffer size should be one cylinder. This can reduce the realtime to do a dump by a factor of two. You will get prompted to mount each new volume. There's a man page... : #!/bin/sh # shar+ created from directory /u/davidsen/tmp/unpack # 13:30 on Tue Jan 02, 1990 by wed echo 'x - bundle.c (text)' sed << 'E!O!F' 's/^X//' > bundle.c X/***************************************************************** X | Program name: bundle.c X |---------------------------------------------------------------- X | accept standard input and write to a device named on the command X | line. The total bytes on the device and the buffer size are X | given on the command line. When the device is full, prompt X | for a new medium in the device and continue. X | X | Command form: X | bundle device Dsize Bsize X |---------------------------------------------------------------- X | Author: Bill Davidsen, 8/16/86 X | Version 1.7 X | Last modified: 1/2/90 X |---------------------------------------------------------------- X | Copyright 1986,87 by Bill Davidsen. This code may be used for X | personal or commercial purposes. It may be freely distributed X | in source form providing this notice is kept intact. X *****************************************************************/ X X#include <stdio.h> X X#ifdef DEBUG X#define debug(f,v) fprintf(stderr, f, v) X#else X#define debug(f,v) X#endif X Xstatic char *SCCS = "@(#) bundle 1.7"; X Xmain (argc, argv) X int argc; X char *argv[]; X{ X char *buffer, /* i/o buffer */ X *malloc (); X register long left; /* room left in the buffer */ X long bufsize, devsize; /* buffer and device size */ X long devleft = 0; /* room left on device */ X int istat, /* stdin read status */ X ostat, /* device write status */ X dev, /* device name from open */ X MediaNum = 1; /* sequential media # */ X FILE *tty, *fopen (); X long getsize (); /* get size from argument */ X int pipex[2]; /* pipe for double buffering */ X int wklen; /* working pie read length */ X X /* validate arguments */ X if (argc != 4) X { /* invalid */ X printf ("Format:\n bundle device DevSize BufSize\n"); X printf ("Where size may be bytes (as 5120) or k (as 5k)\n"); X exit (1); X } X X devsize = getsize (argv[2]); X debug ("Device size %ld", devsize); X bufsize = getsize (argv[3]); X debug (", buffer size %ld\n", bufsize); X if (devsize < 1 || devsize < bufsize) X { /* invalid specification of size */ X printf ("Invalid buffer and/or device size\n"); X exit (1); X } X X /* open the terminal for prompt */ X tty = fopen ("/dev/tty", "r"); X if (tty == NULL) X { /* mystery failure */ X printf ("Unable to open /dev/tty for prompt\n"); X exit (1); X } X X /* open the buffer */ X buffer = malloc (bufsize); X debug ("Buffer allocated\n", 0); X if (buffer == NULL) X { /* can't mallocate */ X printf ("Can't allocate space for the buffer\n"); X exit (1); X } X X /* see if you can open the device */ X printf ("Mount media #1 on %s and press RETURN: ", argv[1]); X while (getc (tty) != '\n'); X dev = open (argv[1], 1); X if (dev < 0) X { /* invalid name */ X printf ("Can't access device %s\n", argv[1]); X exit (1); X } X devleft = devsize; /* set media ready */ X debug ("Enter copy loop\n\n", 0); X X /* open the pipe */ X if (pipe(pipex)) { X fprintf(stderr, "Can't open pipe for double buffering\n"); X exit(1); X } X X if (fork() == 0) { X /* child - copy stdin to pipe */ X for (wklen = 0; X (istat = read(0, buffer+wklen, (int)(bufsize - wklen))) > 0 X || wklen; X ) { X if (istat > 0) wklen += istat; X debug("Child read %5d bytes\n", istat); X debug(" buffer has %d bytes\n", wklen); X X /* output the size read, then the data */ X if (istat <= 0 || wklen == bufsize) { X write(pipex[1], (char *)&wklen, sizeof(int)); X if (write(pipex[1], buffer, wklen) != wklen) { X fprintf(stderr, "Child can't write pipe!\n"); X exit(1); X } X else debug("Child wrote %d bytes\n", wklen); X wklen = 0; X } X } X X /* output a size of zero */ X istat = 0; X write(pipex[1], (char *)&istat, sizeof(int)); X } X else { X /* main copy loop */ X while (read(pipex[0], (char *)&istat, sizeof(int)), istat) { X /* show the size factor and read those bytes */ X debug ("Input read size %d\n", istat); X for (wklen = 0; wklen < istat; ) { X wklen += read(pipex[0], buffer+wklen, istat-wklen); X } X X if (devleft < istat) X { /* change media */ X close (dev); X printf ("\007Mount media #%d on %s and press RETURN: ", X ++MediaNum, argv[1]); X while (getc (tty) != '\n'); X dev = open (argv[1], 1); X devleft = devsize; X } X X /* write the buffer */ X ostat = write (dev, buffer, bufsize); X debug ("Output write size %d\n", ostat); X X if (bufsize != ostat) X { /* error on write */ X printf ("Error on device write!\n"); X exit (1); X } X devleft -= ostat; X } X } X X exit(0); X} X X/***************************************************************** X | Procedure: getsize X |---------------------------------------------------------------- X | Convert the size string to bytes. If the last character is X | 'k', multiply by 1024 X ****************************************************************/ X Xlong Xgetsize (string) X char *string; X{ X register long len = strlen (string), X val = atol (string); X X if (string[len - 1] == 'k') X val *= 1024; X X return val; X} E!O!F newsize=`wc -c < bundle.c` if [ $newsize -ne 5384 ] then echo "File bundle.c was $newsize bytes, 5384 expected" fi echo 'x - unbundle.c (text)' sed << 'E!O!F' 's/^X//' > unbundle.c X/***************************************************************** X | Program: unbundle X | accept input from a device and write to stdout X |---------------------------------------------------------------- X | Arguments: X | 1) device name X | 2) block size in bytes or k X | Version: 1.6 X | Last modified: 3/6/87 X |---------------------------------------------------------------- X | Copyright 1986,87 by Bill Davidsen. This code may be used for X | personal or commercial purposes. It may be freely distributed X | in source form providing this notice is kept intact. X ****************************************************************/ X X#include <stdio.h> X X#ifdef DEBUG X#define debug(f,v) fprintf(stderr, f, v) X#else X#define debug(f,v) X#endif Xmain (argc, argv) X int argc; X char *argv[]; X{ X char *buf, *malloc (); X int bufsize, dn, mnum = 1, ch, readsize; X static char *SCCSid = "@(#)unbundle 1.6"; X long getsize (); /* size of buffer */ X X if (argc != 3) X { /* bad calling sequence */ X fprintf (stderr, "%s: wrong # of arguments\n", argv[0]); X fprintf (stderr, "Calling seq:\n %s device bufsize\n", X argv[0]); X exit (1); X } X X /* try to open the device */ X dn = open (argv[1], 0); X if (dn < 0) X { /* open failed */ X fprintf (stderr, "%s: can't open device %s\n", argv[0], argv[1]); X exit (1); X } X close (dn); /* so I can reopen */ X X /* allocate the buffer */ X bufsize = getsize (argv[2]); X debug ("Bufsize: %d\n", bufsize); X X buf = malloc (bufsize); X if (buf == NULL) X { /* can't allocate the buffer */ X fprintf (stderr, "Can't allocate %d byte buffer\n", bufsize); X exit (1); X } X X for (;;) X { /* get a fresh mount and read it */ X fprintf (stderr, "Mount input medium #%d on %s and press return: ", X mnum++, argv[1]); X read (0, &ch, 1); X open (argv[1], 0); X X while (readsize = read (dn, buf, bufsize)) X write (1, buf, readsize); X close (dn); X } X} X X/* X | Procedure: getsize X |- X | Convert the size string to bytes. If the last character is X | 'k', multiply by 1024 X */ X Xlong Xgetsize (string) X char *string; X{ X register long len = strlen (string), X val = atol (string); X X if (string[len - 1] == 'k') X val *= 1024; X X return val; X} X E!O!F newsize=`wc -c < unbundle.c` if [ $newsize -ne 2271 ] then echo "File unbundle.c was $newsize bytes, 2271 expected" fi echo 'x - buntest.c (text)' sed << 'E!O!F' 's/^X//' > buntest.c X/* X * generate NNk of crap data, read from argv[1] X * X * if the nap() call is not available don't use the 2nd arg X * and don't define HAS_NAP X */ X X#include <stdio.h> X Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X int size; /* size to output, in k */ X int havedone = 0; /* already done */ X#if HAS_NAP X int pause = 0; /* time to pause between writes */ X#endif X X char junkbuf[1024]; /* buffer of junk values */ X X if (argc < 2) { X fprintf(stderr, "No size!\n"); X fprintf(stderr,"\nFormat:\n buntest nn [ k/sec]\n"); X exit(1); X } X X size = atoi(argv[1]); X#if HAS_NAP X if (argc > 2) { X /* get the kb/sec data rate to supply */ X pause = 1000/atoi(argv[2]); X } X#endif X X /* output loop */ X for (havedone = 0; havedone < size; havedone++) { X write(1, junkbuf, 1024); X#if HAS_NAP X if (pause) nap(pause); X#endif X } X X exit(0); X} E!O!F newsize=`wc -c < buntest.c` if [ $newsize -ne 839 ] then echo "File buntest.c was $newsize bytes, 839 expected" fi echo 'x - bundle.1 (text)' sed << 'E!O!F' 's/^X//' > bundle.1 X'\" Copyright 1986,87,90 by Bill Davidsen. This code may be used for X'\" personal or commercial purposes. It may be freely distributed X'\" in unmodified source form providing this notice is kept intact. X.TH bundle 1 (v1.1) X'\" Heading: name(sect) center (paren) name(sect) X.SH NAME Xbundle \- buffer and copy \fIstdin\fR to a physicaql device Xunbundle \- buffer and copy a physical device to \fIstdout\fR X.SH SYNOPSIS X\fBbundle\fR special dev_size buf_size X.br X\fBunbundle\fR special buf_size X.SH DESCRIPTION XThese programs allow a physical device to be the head or end of a pipe, Xallows software which does not know about volumes to operate on Xmulti-volume sets, and improves the performance of programs such as X\fItar\fR and \fIcpio\fR. X.P X\fBSpecial\fR is the name of a raw device, such as /dev/rmt0. X\fBdev_size\fR is the size of the device, given in bytes or kilobytes. XWhen \fBdev_size\fR bytes have been written to the output device, the Xoperator will be prompted for a media change. \fBBuf_size\fR is the size Xof the buffer for the write or read. For tape this should be the desired Xtape block size. For disk this should be a multiple of the size of a Xtrack. For disk output writing a track at a time rather than sectors Xcan reduce real time by a factor of three. X.SH EXAMPLES X ls *.c | cpio -o | bundle /dev/rfp021 395k 5k X unbundle /dev/rfp021 5k | cpio -idm X tar cf - /usr/local | bundle /dev/rmt0 4000k 8k X unbundle /dev/rmt0 8k | tar cf - X.SH WARNINGS X\fIunbundle\fR reads to EOF on the input device. There is no way to read Xonly part of a volume. If the \fBdev_size\fR is not a multiple of the X\fBbuf_size\fR, bizarre errors may occur. X.SH FILES X/dev/\fBspecial\fR X.SH SEE ALSO Xtar, cpio. X.SH AUTHOR XBill Davidsen (davidsen at crdos1.crd.ge.com) X.SH COPYRIGHT XCopyright 1986,87,90 by Bill Davidsen, all rights reserved. This program Xmay be distributed in any manner providing that further distribution is Xnot restricted and the package is kept intact. Modified versions must Xinclude the original source and documentation. X'\" For more details, see man(7), as well as man(1), manroff(1), and mmt(1) E!O!F newsize=`wc -c < bundle.1` if [ $newsize -ne 2121 ] then echo "File bundle.1 was $newsize bytes, 2121 expected" fi echo 'x - Makefile (text)' sed << 'E!O!F' 's/^X//' > Makefile X# makefile for bundle items v%I% %G% X X# distribution and source files XDIST = bundle.c unbundle.c buntest.c bundle.1 Makefile XSCCS = s.bundle.c s.unbundle.c s.Makefile s.bundle.1 X X# which shar to use XSHAR = shar X X# makerule for SCCS which doesn't leave writable files on error X.c~.c: X get $? X X# start makeing here X Xall : bundle unbundle X Xtest : all buntest X Xbundle : bundle.o X $(CC) -o bundle bundle.o X Xunbundle : unbundle.o X $(CC) -o unbundle unbundle.o X Xbuntest : buntest.o X $(CC) -o buntest buntest.o X Xshar : bundle.shar Xbundle.shar : $(DIST) X shar $(DIST) > bundle.shar X Xzoo : $(SCCS) X zoo aunPP bundle.zoo $? E!O!F newsize=`wc -c < Makefile` if [ $newsize -ne 619 ] then echo "File Makefile was $newsize bytes, 619 expected" fi exit 0 -- bill davidsen (davidsen at crdos1.crd.GE.COM -or- uunet!crdgw1!crdos1!davidsen) "The world is filled with fools. They blindly follow their so-called 'reason' in the face of the church and common sense. Any fool can see that the world is flat!" - anon From clewis at eci386.uucp Wed Jan 3 05:38:32 1990 From: clewis at eci386.uucp (Chris Lewis) Date: 2 Jan 90 18:38:32 GMT Subject: Bug in psroff patch 5 Message-ID: <1990Jan2.183832.16897@eci386.uucp> There's a bug in patch 5 for psroff, which causes some directories to not be updated as they should. The file "prepatch" is supposed to move the entire contents of the "font" directory to "fontps". (In addition, somehow the makekit is refusing to build the fontps directory in the first place, and the unshar fails). Since it wouldn't make sense to issue a patch *to* a patch, you'll have to fix the problem manually. If you are about to install patch 5, please "mkdir fontps" before unsharing it. That will alleviate the unshar failure. Then, instead of running "prepatch" (after unsharing): mv font/* fontps rmdir font rm prepatch If you've installed patch 5, please make sure that *all* of the files in the "font" directory are moved to "fontps", and then delete the "font" directory. Eg: run: mv font/* fontps rmdir font Thank you. BTW: patch 6 will be coming out real soon ;-) -- Chris Lewis, Elegant Communications Inc, {uunet!attcan,utzoo}!lsuc!eci386!clewis Ferret mailing list: eci386!ferret-list, psroff mailing list: eci386!psroff-list From petri at digiw.UUCP Tue Jan 9 04:36:44 1990 From: petri at digiw.UUCP (Petri Alhola) Date: 8 Jan 90 17:36:44 GMT Subject: Postscript filter for System V lp and DOS Message-ID: <1139@digiw.UUCP> When i anounced that i have a postscript filter "pscat" for system V lp spooler and MSDOS jne , i got many request about it. I am sory about delays before sending it, but now i have send it out in alt.sources. I have used it in 386/ix 2.0.2 ( system V rel 3.2 ), Petri Alhola petri at digiw.fi #! /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 gpr.c pscat.c Makefile COPYING pscript # Wrapped by petri at digiw on Mon Jan 8 15:33:40 1990 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\" \(1666 characters\) sed "s/^X//" >README <<'END_OF_README' X PSCAT X X X This set contains programs that may be usefull for Xprinting ascii text to postscript printer. The pscat program converts Xascii text to postscript, it does not do any formatting or headers. It Xcan be used as filter of it can be called from lp spooler interface Xscript. There is included interface script "pscript" for system V 3.x Xspooler. Pscat program can be also used in MS-DOS, OS/2 and OS-9 systems. Xit does have minimum number of system dependensies, so it will be very Xeasy to port in to any other system. I have tested it in Interactive systems X386/ix 2.02 that is System V rel 3.2 . I have also used it in MS-DOS X X examples to use pscat: X X if you have not configured pscat inside of your lp script X X cat file | pscat | lp -- Prints text as potrait 72 lines per page X X cat file | pscat -U | lp -- Prints as landskape, two 66 lines pages X X if you have pscat lp script X X cat file | lp -- Prints text as potrait 72 lines per page X X cat file | lp -o-U -- Prints as landskape, two 66 lines pages X X cat file | lp -o-C -- Prints raw postscript to printer X X if you are using it from PC-Interface ( from DOS network ) X you can define X printer lpt1 remote "lp" /t20 -- Text printer X printer lpt2 remote "lp -o-C" /t20 -- Postscript printer for X windows .. etc X XThere is also included program gpr , that is an other pr clone with Xfew new options, that may be useful if you have files/printers that Xdoes like / does not like <cr><lf> or <tab> characters. It also supports Xeuropean date format in headers and it is designed to work also in non Xunix environments like DOS or OS-9. X X Petri Alhola X petri at digiw.fi X END_OF_README if test 1666 -ne `wc -c <README`; then echo shar: \"README\" unpacked with wrong size! fi # end of overwriting check fi if test -f gpr.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"gpr.c\" else echo shar: Extracting \"gpr.c\" \(10876 characters\) sed "s/^X//" >gpr.c <<'END_OF_gpr.c' X/* X X X Generic PRint program X X Author and Copyright Petri Alhola 1987 X X email : petri at digiw.fi X home : tel 358 0 8058958 X address: Joupinmaensyrja 5 b 11 X 02760 Espoo X Finland X X Copyright Petri Alhola 1987 X X email : petri at digiw.fi X home : tel + 358 0 8058958 X address: Joupinmaensyrja 5 b 11 X 02760 Espoo X Finland X X This program is free software; you can redistribute it and/or modify X it under the terms of the GNU General Public License as published by X the Free Software Foundation; either version 1, or (at your option) X any later version. X X This program is distributed in the hope that it will be useful, X but WITHOUT ANY WARRANTY; without even the implied warranty of X MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the X GNU General Public License for more details. X X You should have received a copy of the GNU General Public License X along with this program; if not, write to the Free Software X Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. X X Everyone is granted permission to copy, modify and redistribute X pscat, but only under the conditions described in the GNU General Public X License. A copy of this license is supposed to have been given to you X along with GNU Emacs so you can know your rights and responsibilities. X It should be in a file named COPYING. X X Among other things, the copyright notice and this notice must be X preserved on all copies. X X********************************************************************** X*/ X#define LINES_AFTER_TITLE 2 X#define LINES_PER_PAGE 72 X#define NUM_OF_COL 96 X X#include <stdio.h> X#include <time.h> X#define unbuf(p) ((p)->_flag&=~_UNBUF) X Xint c_opt; /* Produce n column output */ Xint f_opt; /* Use linefeeds instead of formfeed to separete pages */ Xint lines_after_title; /* Set the number of blank lines after title line */ Xint num_of_col; /* Set number of columns */ Xint left_marigin; /* Set the left marigin to <num> ( default = 0 */ Xint m_opt; /* Print all files simultaneously, each in one column */ Xint n_opt; /* Set line numbering inrement ( default=0 , no linenumbers)*/ Xint o_opt; /* Truncates longer lines ( default , lines are not truuncated*/ Xint lines_per_page; /* Sets number of lines per page: <num> ( default=72 ) */ Xint s_opt; /* Separete columns by the single character instead of space*/ Xint t_opt; /* Does not print title */ Xint e_opt; /* Expand tabs */ Xint r_opt; /* Do \r after newline */ Xint u_opt; /* Print USA ( 66 lines ) documents */ Xint z_opt; /* read file names from stdin or <path> if given */ Xint P_opt; /* Page Pause , waits user confirm each page */ X Xchar *z_arg; /* z option argument */ Xint outen; /* Output enable Flag */ X Xint tab; /* Tab size */ Xint row,col,page; /* Row ,column and page number*/ Xint text_lines; /* number of active text lines */ Xint line; /* line number */ Xint files; /* Number of files printed */ Xint tot_pages; /* Total number of pages printed */ X#ifdef MSC Xint errno; /* Define errno here for MSC 4.0 */ X#else Xextern int errno; X#endif X Xchar *s_arg; /* s_option argument */ X XFILE *inf, *fopen(); Xextern char *optarg; Xextern int optind; X/*==========================================================+ X! ! X! PRint files ! X! ! X+===========================================================*/ X Xmain(argc,argv) Xint argc; Xchar *argv[]; X{ X int n,i,c; X FILE *f; X X#ifdef OSK X extern int _memmins; X _memmins=32768; X#endif X tab=8; X tot_pages=files=row=col=0; X f_opt=0; X lines_after_title=LINES_AFTER_TITLE; X lines_per_page=LINES_PER_PAGE; X num_of_col =NUM_OF_COL; X left_marigin=0; X e_opt=0; /* Dont expand tabs as default */ X m_opt=0; X n_opt=0; X t_opt=1; X z_opt=0; X r_opt=0; X u_opt=0; X P_opt=0; X z_arg=NULL; X s_arg=NULL; X outen=1; /* Output is enabled as default */ X X while((c=getopt(argc,argv,"efPuh:k:l:mn:op:rRtz:Z123456789s:?")) != EOF) X switch(c) { X case 'e' : e_opt=1; break; X case 'f' : f_opt=1; break; X case 'h' : n=sscanf(optarg,"=%d",&lines_after_title); break; X case 'm' : m_opt=1; break; X case 'n' : n=sscanf(optarg,"=%d",&n_opt); break; X case 'o' : o_opt=1; break; X case 'k' : n=sscanf(optarg,"=%d",&num_of_col); break; X case 'l' : n=sscanf(optarg,"=%d",&left_marigin); break; X case 't' : t_opt=0; break; X case 'p' : n=sscanf(optarg,"=%d",&lines_per_page); break; X case 's' : s_arg=optarg; break; X case 'u' : u_opt=1; break; X case 'r' : r_opt=1; break; X case 'R' : r_opt=1; e_opt=1; t_opt=0; break; X case 'z' : z_arg=optarg; z_opt=1; break; X case 'Z' : z_opt=1; break; X case 'P' : P_opt=1; break; X case '1' : c_opt=1; break; X case '2' : c_opt=2; break; X case '3' : c_opt=3; break; X case '4' : c_opt=4; break; X case '5' : c_opt=5; break; X case '6' : c_opt=6; break; X case '7' : c_opt=7; break; X case '8' : c_opt=8; break; X case '9' : c_opt=9; break; X case '?' : print_info(); break; X default : break; X } X X text_lines=u_opt ? 66:lines_per_page-lines_after_title-2; X X X if(z_opt) { X if(*z_arg++=='=') { X if((f=fopen(z_arg,"r")) == NULL ) X fprintf(stderr,"Can't open %s Error %d \n",z_arg,errno); X else z_print(f); X } else z_print(stdin); X } else { X for(i=1;i<argc;i++) X if(*argv[i]!='-') { X print_file(argv[i]); X files++; X } X } X if(files==0) print_it(stdin," "); X X putchar('\f'); /* Flush out last page */ X} X Xz_print(f) XFILE *f; X{ X char name[40]; X while(EOF!=fscanf(f,"%s ",name)) print_file(name); X} X X/*==========================================================+ X! ! X! Print named file ! X! ! X+===========================================================*/ X Xprint_file(name) Xchar *name; X{ X FILE *f; X int c; X X if((f=fopen(name,"r")) == NULL ) X fprintf(stderr,"Can't open %s Error %d \n",name,errno); X else { X print_it(f,name); X fclose(f); X }; X} X/*==========================================================+ X! ! X! Print path ! X! ! X+===========================================================*/ Xprint_it(f,name) XFILE *f; Xchar *name; X{ X int c; X X page=1; X line=n_opt; X newpage(name); X while(EOF!=(c=getc(f))) X switch(c) { X#ifdef OSK X case 0x0a : X#endif X case '\n' : newline(name); X break; X case '\f' : newpage(name); X break; X case '\t' : if(e_opt) do if(col< num_of_col) { X if(outen) putchar(' '); X } while(col++ % tab) ; X else if(outen) putchar(c); X break; X default : if(outen) putchar(c); X col+=1; X break; X } X} X/*==========================================================+ X! ! X! Do newline ! X! ! X+===========================================================*/ Xdonewline() X{ X if(r_opt) putchar('\r'); X putchar('\n'); X} X/*==========================================================+ X! ! X! Begin new lline ! X! ! X+===========================================================*/ X Xnewline(title) Xchar *title; X{ X col=0; X row++; X line+=n_opt; X if(outen) donewline(); X if(row>text_lines+lines_after_title) newpage(title); X if(outen) while(col++<left_marigin) putchar(' '); X if(n_opt && outen) printf("%5d ",line); X} X X/*==========================================================+ X! ! X! Begin new page , print header ! X! ! X+===========================================================*/ Xnewpage(title) Xchar *title; X{ X#ifdef OSK X struct sgtbuf t; X#else X struct tm *t; X long ltime; X#endif X char ask[40]; X int i; X char ans; X X if(P_opt) { /* Page pause ? */ X sprintf(ask,"\nPage %d <S> for Skip <cr> to print >",page); X write(2,ask,strlen(ask)); X read(0,&ans,1); X outen=(ans!='S') && (ans!='s'); X }; X row=0; X col=0; X if(tot_pages++) if(outen) putchar('\f'); X if(t_opt) { X#ifdef OSK X getime(&t); X if(outen) printf("%02d-%02d-%02d %2d:%02d:%02d %-40s page %4d",t.t_year, X t.t_month,t.t_day,t.t_hour,t.t_minute,t.t_second,title,page); X#else X time(<ime); X t=localtime(<ime); X if(outen) printf("%02d-%02d-%02d %2d:%02d:%02d %-40s page %4d",t->tm_year, X t->tm_mon,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec,title,page); X#endif X row++; X for(i=1;i<lines_after_title;i++){ X if(outen) donewline(); X row++; X }; X newline(title); X } X page++; X} X/*==========================================================+ X! ! X! Print usage info ! X! ! X+===========================================================*/ Xprint_info() X{ Xprintf("GPR 1.2 Author and Copyright Petri Alhola 1987\n"); Xprintf("gpr comes with ABSOLUTELY NO WARRANTY\n"); Xprintf("-e Expand tabs\n"); Xprintf("-f Use linefeeds instead of formfeed to separete pages\n"); Xprintf("-h=<num> Set the number of blank lines after title line (default=5)\n"); Xprintf("-l=<num> Set the left marigin to <num> ( default = 0 )\n"); Xprintf("-m=<num> Print all files simultaneously, each in one column\n"); Xprintf("-n=<num> Set line numbering inrement ( default=0 , no linenumbers)\n"); Xprintf("-o Truncates longer lines. default, lines are not truncated\n"); Xprintf("-n=<num> Sets number of lines per page: <num> ( default=72 )\n"); Xprintf("-t Does not print title\n"); Xprintf("-u Print USA, 66 text line documents\n"); Xprintf("-<num> Produce n column output 1 <= n <= 9 \n"); Xprintf("-s'char' Separete columns by the single character instead of space\n"); Xprintf("-r Insert \r ( carrige returns to end of lines\n"); Xprintf("-R combines -r -e -t\n"); Xprintf("-z=<path> read file names from <path>\n"); Xprintf("-P Page Pause , waits user confirm eack page\n"); Xprintf("-Z read file names from stdin \n"); X} END_OF_gpr.c if test 10876 -ne `wc -c <gpr.c`; then echo shar: \"gpr.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f pscat.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"pscat.c\" else echo shar: Extracting \"pscat.c\" \(13077 characters\) sed "s/^X//" >pscat.c <<'END_OF_pscat.c' X/* X X Postscript filter ( ascii list to postscript ) X X X Copyright Petri Alhola 1987 X X email : petri at digiw.fi X home : tel + 358 0 8058958 X address: Joupinmaensyrja 5 b 11 X 02760 Espoo X Finland X X This program is free software; you can redistribute it and/or modify X it under the terms of the GNU General Public License as published by X the Free Software Foundation; either version 1, or (at your option) X any later version. X X This program is distributed in the hope that it will be useful, X but WITHOUT ANY WARRANTY; without even the implied warranty of X MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the X GNU General Public License for more details. X X You should have received a copy of the GNU General Public License X along with this program; if not, write to the Free Software X Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. X X Everyone is granted permission to copy, modify and redistribute X pscat, but only under the conditions described in the GNU General Public X License. A copy of this license is supposed to have been given to you X along with GNU Emacs so you can know your rights and responsibilities. X It should be in a file named COPYING. X X Among other things, the copyright notice and this notice must be X preserved on all copies. X X********************************************************************** X*/ X#define LINES_PER_PAGE 72 X#define NUM_OF_COL 96 X X#include <stdio.h> X#include <time.h> X Xint c_opt; /* Produce n column output */ Xint num_of_col; /* Set number of columns */ Xint left_marigin; /* Set the left marigin to <num> ( default = 0 */ Xint m_opt; /* Print all files simultaneously, each in one column */ Xint o_opt; /* Truncates longer lines ( default , lines are not truuncated*/ Xint lines_per_page; /* Sets number of lines per page: <num> ( default=72 ) */ Xint s_opt; /* Separete columns by the single character instead of space*/ Xint z_opt; /* read file names from stdin or <path> if given */ Xint r_opt; /* Print page rotated as 90 degrees */ Xint C_opt; /* Cat direct postscript files */ Xchar *catfile; /* Postscript prologue file */ Xchar *z_arg; /* z option argument */ X Xint files; /* Number of files printed */ Xint row,col,page; /* Row ,column and page number*/ Xint text_lines; /* number of active text lines */ Xint tab; /* Tabulation value */ Xint p_col; /* printing column */ Xint y; /* Y cordinate */ Xint x_left; /* Left x column */ Xint x_ofset; /* x ofset */ Xint y_spacing; /* Row spacing */ Xint y_top; /* Top y cordinate */ Xint fontsize; /* Size of used font */ Xint showflag; /* Show open flag */ X X#ifdef MSC Xint errno; /* Define errno here for MSC 4.0 */ X#else Xextern int errno; X#endif X Xchar *s_arg; /* s_option argument */ X XFILE *inf, *fopen(); Xextern char *optarg; Xextern int optind; X/*==========================================================+ X! ! X! PRint files ! X! ! X+===========================================================*/ X Xmain(argc,argv) Xint argc; Xchar *argv[]; X{ X int n,i,c; X FILE *f; X X#ifdef OSK X extern int _memmins; X _memmins=32768; X#endif X X showflag=files=row=col=0; X X lines_per_page=0; X num_of_col =NUM_OF_COL; X left_marigin=0; X p_col=1; /* Current page column */ X X x_ofset=30; X y_top =772; X fontsize=10; X tab=8; X X m_opt=z_opt=r_opt=C_opt=0; X c_opt=1; X z_arg=NULL; X s_arg=NULL; X X while((c=getopt(argc,argv,"f:rc:RUCk:l:mop:tz:Zs:123456789?")) != EOF) X switch(c) { X case 'm' : m_opt=1; break; X case 'o' : o_opt=1; break; X case 'k' : n=sscanf(optarg,"%d",&num_of_col); break; X case 'l' : n=sscanf(optarg,"%d",&left_marigin); break; X case 'p' : n=sscanf(optarg,"%d",&lines_per_page); break; X case 'f' : n=sscanf(optarg,"%d",&fontsize); break; X case 'x' : n=sscanf(optarg,"%d",&x_ofset); break; X case 'c' : catfile=optarg; print_file(catfile,1); break; X case 'r' : r_opt=1; break; X case 'C' : C_opt=1; break; X case 'R' : r_opt=1; X fontsize=7; X c_opt=2; X o_opt=1; X num_of_col=92; break; X case 'U' : r_opt=1; X fontsize=8; X c_opt=2; X o_opt=1; X num_of_col=80; break; X case 's' : s_arg=optarg; break; X case 'u' : lines_per_page=66; break; X case 'z' : z_arg=optarg; z_opt=1; break; X case 'Z' : z_opt=1; break; X case '1' : c_opt=1; break; X case '2' : c_opt=2; break; X case '3' : c_opt=3; break; X case '4' : c_opt=4; break; X case '5' : c_opt=5; break; X case '6' : c_opt=6; break; X case '7' : c_opt=7; break; X case '8' : c_opt=8; break; X case '9' : c_opt=9; break; X case '?' : print_info(); break; X default : break; X } X X x_left=x_ofset; X y_spacing=-fontsize; X if(!C_opt) prolog(); X X if(r_opt) { /* Rotated picture */ X y_top=-30; X y=y_top; X if(lines_per_page==0) lines_per_page=550 / fontsize; X } else { X if(lines_per_page==0) lines_per_page=760 / fontsize; X } X X X X if(z_opt) { X if(*z_arg++=='=') { X if((f=fopen(z_arg,"r")) == NULL ) X fprintf(stderr,"Can't open %s Error %d \n",z_arg,errno); X else z_print(f); X } else z_print(stdin); X } else { X for(i=1;i<argc;i++) X if(*argv[i]!='-') { X print_file(argv[i],C_opt); X files++; X } X } X if(files==0) print_it(stdin,C_opt); X} X/*==========================================================+ X! ! X! Read filenames from stdin ! X! ! X+===========================================================*/ X Xz_print(f) XFILE *f; X{ X char name[40]; X while(EOF!=fscanf(f,"%s ",name)) print_file(name,C_opt); X} X X/*==========================================================+ X! ! X! Print named file ! X! ! X+===========================================================*/ X Xprint_file(name,cat) Xchar *name; Xint cat; X{ X FILE *f; X int c; X X if((f=fopen(name,"r")) == NULL ) X fprintf(stderr,"Can't open %s Error %d \n",name,errno); X else { X print_it(f,cat); X fclose(f); X } X} X/*==========================================================+ X! ! X! Print path ! X! ! X+===========================================================*/ Xprint_it(f,cat) XFILE *f; Xint cat; X{ X int c; X X page=1; X if(cat) { X cat_it(f); X return; X }; X startpage(); X while(EOF!=(c=getc(f))) X switch(c) { X case '\n' : newline(); X break; X case '\f' : if(col) newline(); X newpage(); X break; X case '\t' : if(col==0) startline(); X do if(!o_opt || (col< num_of_col)) { X if(!showflag) startshow(); X putchar(' '); X col++; X } while(col % tab) ; X break; X case '(':case ')' :case '<' :case '>' : X case '[':case ']' :case '{' :case '}' : X case '/':case '%' : X case '\\': if(col==0) startline(); X if(!o_opt || (col< num_of_col)) { X if(!showflag) startshow(); X putchar('\\'); X putchar(c); X col+=1; X } X break; X case 8 : endshow(); X printf("(A) stringwidth exch neg exch rmoveto\n"); X break; X case 0: case 1: case 2: case 3: X case 4: case 5: case 6: case 7: X case 11: X case 14: case 15: X case 16: case 17: case 18: case 19: X case 20: case 21: case 22: case 23: X case 24: case 25: case 26: case 27: X case 28: case 29: case 30: case 31: break; /* ignore other controll chars */ X X default : if(col==0) startline(); X if(!o_opt || (col< num_of_col)) { X if(!showflag) startshow(); X putchar(c); X col+=1; X } X X break; X } X printf("showpage\n"); X} X/*==========================================================+ X! ! X! cat path ! X! ! X+===========================================================*/ Xcat_it(f) XFILE *f; X{ X int c; X while(EOF!=(c=getc(f))) putchar(c); X}; X X/*==========================================================+ X! ! X! Write postscript prolog ( set font and size ) ! X! ! X+===========================================================*/ Xprolog() X{ X printf("/Courier findfont\n"); X printf("%d scalefont\n",fontsize); X printf("setfont\n"); X y=y_top; X} X/*==========================================================+ X! ! X! Begining of new line ! X! ! X+===========================================================*/ Xstartline() X{ X printf("%d %d moveto\n",x_left,y); X startshow(); X} X/*==========================================================+ X! ! X! Begining show text ! X! ! X+===========================================================*/ Xstartshow() X{ X if(!showflag) printf("("); X showflag=1; X} X/*==========================================================+ X! ! X! end of show text ! X! ! X+===========================================================*/ Xendshow() X{ X if(showflag) printf(") show\n"); X showflag=0; X} X X/*==========================================================+ X! ! X! end of line ! X! ! X+===========================================================*/ X Xnewline() X{ X endshow(); X col=0; X row++; X if(row>lines_per_page) newpage(); X else X y+=y_spacing; X} X/*==========================================================+ X! ! X! Start new page ! X! ! X+===========================================================*/ Xstartpage() X{ X if(r_opt) { X if(p_col==1) printf("90 rotate\n"); X x_left=x_ofset+(p_col-1) * (772 / c_opt); X } else X x_left=x_ofset+(p_col-1) * (572 / c_opt); X X y=y_top; X} X X/*==========================================================+ X! ! X! Print page out ! X! ! X+===========================================================*/ Xnewpage(title) Xchar *title; X{ X row=0; X col=0; X if(++p_col > c_opt) { X printf("showpage\n"); X p_col=1; X } X startpage(); X} X/*==========================================================+ X! ! X! Print usage info ! X! ! X+===========================================================*/ Xprint_info() X{ Xprintf("pcat 1.2 Text to postscript filter. Copyright Petri Alhola 1987\n"); Xprintf("pcat comes with ABSOLUTELY NO WARRANTY\n"); Xprintf("-c<file> Cat file as postscript prologue\n"); Xprintf("-C Cat all files as direct postscript files\n"); Xprintf("-f<num> Set font size to <num> points ( default is 10 )\n"); Xprintf("-k<num> Set number of columns \n"); Xprintf("-l<num> Set the left marigin to <num> ( default = 0 )\n"); Xprintf("-<num> Print file in <num> columns 1..9\n"); Xprintf("-n<num> Sets number of lines per page: <num> ( default=72 )\n"); Xprintf("-o Truncates longer lines. default, lines are not truncated\n"); Xprintf("-p<num> Set number of lines per page\n"); Xprintf("-r Print page rotated 90 degrees ( landscape )\n"); Xprintf("-u Print USA, 66 text line documents\n"); Xprintf("-x<num> Set X offset\n"); Xprintf("-z<path> read file names from <path>\n"); Xprintf("-Z read file names from stdin \n"); Xprintf(" ----- Combination options -----\n"); Xprintf("-R -r -o -c=92 -f=7 -2 ( Prints 92 col * 79 row , 2 pages )\n"); Xprintf("-U -r -o -c=80 -f=8 -2 ( Prints 92 col * 69 row , 2 pages )\n"); X} END_OF_pscat.c if test 13077 -ne `wc -c <pscat.c`; then echo shar: \"pscat.c\" 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\" \(224 characters\) sed "s/^X//" >Makefile <<'END_OF_Makefile' X# X# Make gpr and pr for unix X# XCFLAGS= -O X Xpscat: pscat.o X cc pscat.o -o pscat X X Xgpr: gpr.o X cc gpr.o -o gpr X X Xshar: README gpr.c pscat.c Makefile COPYING pscript X shar README gpr.c pscat.c Makefile COPYING pscript >shar END_OF_Makefile if test 224 -ne `wc -c <Makefile`; then echo shar: \"Makefile\" unpacked with wrong size! fi # end of overwriting check fi if test -f COPYING -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"COPYING\" else echo shar: Extracting \"COPYING\" \(12488 characters\) sed "s/^X//" >COPYING <<'END_OF_COPYING' X X GNU GENERAL PUBLIC LICENSE X Version 1, February 1989 X X Copyright (C) 1989 Free Software Foundation, Inc. X 675 Mass Ave, Cambridge, MA 02139, USA X Everyone is permitted to copy and distribute verbatim copies X of this license document, but changing it is not allowed. X X Preamble X X The license agreements of most software companies try to keep users Xat the mercy of those companies. By contrast, our General Public XLicense is intended to guarantee your freedom to share and change free Xsoftware--to make sure the software is free for all its users. The XGeneral Public License applies to the Free Software Foundation's Xsoftware and to any other program whose authors commit to using it. XYou can use it for your programs, too. X X When we speak of free software, we are referring to freedom, not Xprice. Specifically, the General Public License is designed to make Xsure that you have the freedom to give away or sell copies of free Xsoftware, that you receive source code or can get it if you want it, Xthat you can change the software or use pieces of it in new free Xprograms; and that you know you can do these things. X X To protect your rights, we need to make restrictions that forbid Xanyone to deny you these rights or to ask you to surrender the rights. XThese restrictions translate to certain responsibilities for you if you Xdistribute copies of the software, or if you modify it. X X For example, if you distribute copies of a such a program, whether Xgratis or for a fee, you must give the recipients all the rights that Xyou have. You must make sure that they, too, receive or can get the Xsource code. And you must tell them their rights. X X We protect your rights with two steps: (1) copyright the software, and X(2) offer you this license which gives you legal permission to copy, Xdistribute and/or modify the software. X X Also, for each author's protection and ours, we want to make certain Xthat everyone understands that there is no warranty for this free Xsoftware. If the software is modified by someone else and passed on, we Xwant its recipients to know that what they have is not the original, so Xthat any problems introduced by others will not reflect on the original Xauthors' reputations. X X The precise terms and conditions for copying, distribution and Xmodification follow. X X GNU GENERAL PUBLIC LICENSE X TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION X X 0. This License Agreement applies to any program or other work which Xcontains a notice placed by the copyright holder saying it may be Xdistributed under the terms of this General Public License. The X"Program", below, refers to any such program or work, and a "work based Xon the Program" means either the Program or any work containing the XProgram or a portion of it, either verbatim or with modifications. Each Xlicensee is addressed as "you". X X 1. You may copy and distribute verbatim copies of the Program's source Xcode as you receive it, in any medium, provided that you conspicuously and Xappropriately publish on each copy an appropriate copyright notice and Xdisclaimer of warranty; keep intact all the notices that refer to this XGeneral Public License and to the absence of any warranty; and give any Xother recipients of the Program a copy of this General Public License Xalong with the Program. You may charge a fee for the physical act of Xtransferring a copy. X X 2. You may modify your copy or copies of the Program or any portion of Xit, and copy and distribute such modifications under the terms of Paragraph X1 above, provided that you also do the following: X X a) cause the modified files to carry prominent notices stating that X you changed the files and the date of any change; and X X b) cause the whole of any work that you distribute or publish, that X in whole or in part contains the Program or any part thereof, either X with or without modifications, to be licensed at no charge to all X third parties under the terms of this General Public License (except X that you may choose to grant warranty protection to some or all X third parties, at your option). X X c) If the modified program normally reads commands interactively when X run, you must cause it, when started running for such interactive use X in the simplest and most usual way, to print or display an X announcement including an appropriate copyright notice and a notice X that there is no warranty (or else, saying that you provide a X warranty) and that users may redistribute the program under these X conditions, and telling the user how to view a copy of this General X Public License. X X d) You may charge a fee for the physical act of transferring a X copy, and you may at your option offer warranty protection in X exchange for a fee. X XMere aggregation of another independent work with the Program (or its Xderivative) on a volume of a storage or distribution medium does not bring Xthe other work under the scope of these terms. X X 3. You may copy and distribute the Program (or a portion or derivative of Xit, under Paragraph 2) in object code or executable form under the terms of XParagraphs 1 and 2 above provided that you also do one of the following: X X a) accompany it with the complete corresponding machine-readable X source code, which must be distributed under the terms of X Paragraphs 1 and 2 above; or, X X b) accompany it with a written offer, valid for at least three X years, to give any third party free (except for a nominal charge X for the cost of distribution) a complete machine-readable copy of the X corresponding source code, to be distributed under the terms of X Paragraphs 1 and 2 above; or, X X c) accompany it with the information you received as to where the X corresponding source code may be obtained. (This alternative is X allowed only for noncommercial distribution and only if you X received the program in object code or executable form alone.) X XSource code for a work means the preferred form of the work for making Xmodifications to it. For an executable file, complete source code means Xall the source code for all modules it contains; but, as a special Xexception, it need not include source code for modules which are standard Xlibraries that accompany the operating system on which the executable Xfile runs, or for standard header files or definitions files that Xaccompany that operating system. X X 4. You may not copy, modify, sublicense, distribute or transfer the XProgram except as expressly provided under this General Public License. XAny attempt otherwise to copy, modify, sublicense, distribute or transfer Xthe Program is void, and will automatically terminate your rights to use Xthe Program under this License. However, parties who have received Xcopies, or rights to use copies, from you under this General Public XLicense will not have their licenses terminated so long as such parties Xremain in full compliance. X X 5. By copying, distributing or modifying the Program (or any work based Xon the Program) you indicate your acceptance of this license to do so, Xand all its terms and conditions. X X 6. Each time you redistribute the Program (or any work based on the XProgram), the recipient automatically receives a license from the original Xlicensor to copy, distribute or modify the Program subject to these Xterms and conditions. You may not impose any further restrictions on the Xrecipients' exercise of the rights granted herein. X X 7. The Free Software Foundation may publish revised and/or new versions Xof the General Public License from time to time. Such new versions will Xbe similar in spirit to the present version, but may differ in detail to Xaddress new problems or concerns. X XEach version is given a distinguishing version number. If the Program Xspecifies a version number of the license which applies to it and "any Xlater version", you have the option of following the terms and conditions Xeither of that version or of any later version published by the Free XSoftware Foundation. If the Program does not specify a version number of Xthe license, you may choose any version ever published by the Free Software XFoundation. X X 8. If you wish to incorporate parts of the Program into other free Xprograms whose distribution conditions are different, write to the author Xto ask for permission. For software which is copyrighted by the Free XSoftware Foundation, write to the Free Software Foundation; we sometimes Xmake exceptions for this. Our decision will be guided by the two goals Xof preserving the free status of all derivatives of our free software and Xof promoting the sharing and reuse of software generally. X X NO WARRANTY X X 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY XFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN XOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES XPROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED XOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF XMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS XTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE XPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, XREPAIR OR CORRECTION. X X 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING XWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR XREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, XINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING XOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED XTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY XYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER XPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE XPOSSIBILITY OF SUCH DAMAGES. X X END OF TERMS AND CONDITIONS X X Appendix: How to Apply These Terms to Your New Programs X X If you develop a new program, and you want it to be of the greatest Xpossible use to humanity, the best way to achieve this is to make it Xfree software which everyone can redistribute and change under these Xterms. X X To do so, attach the following notices to the program. It is safest to Xattach them to the start of each source file to most effectively convey Xthe exclusion of warranty; and each file should have at least the X"copyright" line and a pointer to where the full notice is found. X X <one line to give the program's name and a brief idea of what it does.> X Copyright (C) 19yy <name of author> X X This program is free software; you can redistribute it and/or modify X it under the terms of the GNU General Public License as published by X the Free Software Foundation; either version 1, or (at your option) X any later version. X X This program is distributed in the hope that it will be useful, X but WITHOUT ANY WARRANTY; without even the implied warranty of X MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the X GNU General Public License for more details. X X You should have received a copy of the GNU General Public License X along with this program; if not, write to the Free Software X Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. X XAlso add information on how to contact you by electronic and paper mail. X XIf the program is interactive, make it output a short notice like this Xwhen it starts in an interactive mode: X X Gnomovision version 69, Copyright (C) 19xx name of author X Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. X This is free software, and you are welcome to redistribute it X under certain conditions; type `show c' for details. X XThe hypothetical commands `show w' and `show c' should show the Xappropriate parts of the General Public License. Of course, the Xcommands you use may be called something other than `show w' and `show Xc'; they could even be mouse-clicks or menu items--whatever suits your Xprogram. X XYou should also get your employer (if you work as a programmer) or your Xschool, if any, to sign a "copyright disclaimer" for the program, if Xnecessary. Here a sample; alter the names: X X Yoyodyne, Inc., hereby disclaims all copyright interest in the X program `Gnomovision' (a program to direct compilers to make passes X at assemblers) written by James Hacker. X X <signature of Ty Coon>, 1 April 1989 X Ty Coon, President of Vice X XThat's all there is to it! END_OF_COPYING if test 12488 -ne `wc -c <COPYING`; then echo shar: \"COPYING\" unpacked with wrong size! fi # end of overwriting check fi if test -f pscript -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"pscript\" else echo shar: Extracting \"pscript\" \(233 characters\) sed "s/^X//" >pscript <<'END_OF_pscript' X# lp interface for postscript printer X# (c) Petri Alhola 1988 Xoptions=$5 Xcopies=$4 Xshift; shift; shift; shift; shift Xfiles="$*" Xi=1 Xwhile [ $i -le $copies ] Xdo X /usr/local/bin/pscat $options $files 2>&1 X i=`expr $i + 1` Xdone Xexit 0 X END_OF_pscript if test 233 -ne `wc -c <pscript`; then echo shar: \"pscript\" unpacked with wrong size! fi chmod +x pscript # end of overwriting check fi echo shar: End of shell archive. exit 0 From paul at csnz.co.nz Fri Jan 5 08:09:09 1990 From: paul at csnz.co.nz (Paul Gillingwater) Date: 4 Jan 90 21:09:09 GMT Subject: Source code for editor wanted References: <1558@aber-cs.UUCP> <TOM.89Dec31101433@hcx2.ssd.csd.harris.com> Message-ID: <329@csnz.co.nz> There is an absolutely brilliant book called "Advanced C Programming for Displays", by Marc Rochkind. The author provides the full source code for a screen editor that uses the windows tools he presents in the book. He gives an address to write to to obtain the code for a small handling fee, I suspect. The address is: Advanced Programming Institute 1714 Choke Cherry Drive Louisville, CO 80027. Surprisingly, the author does not give an e-mail address (?!). Has anyone obtained this source code, so that they could post it on te me please? I have purchased the book, but don't want to type it all in by hand. Also, the source found in his other book "Advanced UNIX Programming" would be helpful too. I would like the source so that I can use it as the basis for an editor which non-technical people can use with rn, for a Public Access UNIX system run by a non-profit peace and environmental organisation. I assume that if this is infringing the author's rights, I will be flamed appropriately -- but I *did* buy the book! -- Paul Gillingwater, Computer Sciences of New Zealand Limited Domain: paul at csnz.co.nz Bang: uunet!vuwcomp!dsiramd!csnz!paul Call Magic Tower BBS V21/23/22/22bis 24 hrs NZ+64 4 767 326 SpringBoard BBS for Greenies! V22/22bis/HST NZ+64 4 896 016 From jv at mh.nl Thu Jan 4 08:59:19 1990 From: jv at mh.nl (Johan Vromans) Date: 3 Jan 90 21:59:19 GMT Subject: Perl version of from (Was: Re: from.sed (v1.2)) In-Reply-To: jv@mh.nl's message of 22 Dec 89 05:11:43 GMT References: <1989Dec20.222732.5633@trigraph.uucp> <JV.89Dec21221143@mhres.mh.nl> Message-ID: <JV.90Jan3145920@mhres.mh.nl> Note: I have redirected follow-ups to comp.lang.perl. In article <JV.89Dec21221143 at mhres.mh.nl> jv at mh.nl (Johan Vromans) writes: | In article <1989Dec20.222732.5633 at trigraph.uucp> john at trigraph.uucp (John Chew) writes: | Here's a new version of from.sed, my sed script that does the job | of from(1) better and faster. It now truncates long subjects, | correctly handles messages without subjects and From lines with % | or @foo: routing. | | Yes, I tried writing this in Perl. I'm not an expert Perl programmer, | but I couldn't get it to run faster than about 70% slower than sed. To which I replied: | I've been using a perl version of 'from' for a long time, so I trow it | in. [...] | It runs about as fast as the sed version. Typical times for a large | mailbox (46585 lines) real/user/sys 50/16/8 for sed, 50/22/7 for perl. Script fragment: while ( $line = <> ) { chop ($line); # scan until "From_" header found next unless $line =~ /^From\s+(\S+)\s+.*(\w{3}\s+\d+\s+\d+:\d+)/; I was pointed out by John J. Chew <poslfit at gpu.UTCS.UToronto.CA> that tightening the search for "From " would speed up the program by 30%. He suggested: while ( <> ) { next unless /^From /; chop ($line); next unless /^From\s+(\S+)\s+.*(\w{3}\s+\d+\s+\d+:\d+)/; Well, I tried it, and -NOT to my surprise- I found out that the major speedup is caused by leaving out the assignment to the variable $line and postponing the chop. I couldn't imagine (knowing how Larry likes optimisation) that next unless /^From\s+(\S+)\s+.*(\w{3}\s+\d+\s+\d+:\d+)/; would take more time to fail than next unless /^From /; With the speedups, the perl script beats the sed script on both large and small mailboxes: ~ > wc -lc INBOX 163 6927 INBOX ~ > dotime 5 perl src/perl.pl INBOX Avg Pass 1 2 3 4 5 ----- ------- ----- ----- ----- ----- real 0.2 0.4 0.2 0.2 0.2 0.2 user 0.0 0.0 0.0 0.0 0.0 0.0 sys 0.1 0.1 0.1 0.1 0.1 0.1 ~ > dotime 5 sed -f from.sed INBOX Avg Pass 1 2 3 4 5 ----- ------- ----- ----- ----- ----- real 0.5 0.7 0.4 0.5 0.4 0.4 user 0.1 0.1 0.1 0.1 0.1 0.1 sys 0.2 0.2 0.2 0.3 0.2 0.2 ~ > wc -lc maildir/pax 46585 1240000 maildir/pax ~ > dotime 5 perl src/from.pl maildir/pax Avg Pass 1 2 3 4 5 ----- ------- ----- ----- ----- ----- real 21.9 21.9 20.3 21.1 25.7 20.7 user 14.0 14.4 14.3 14.1 13.7 13.6 sys 5.9 5.8 4.9 5.7 7.4 5.9 ~ > dotime 5 sed -f from.sed maildir/pax Avg Pass 1 2 3 4 5 ----- ------- ----- ----- ----- ----- real 23.1 23.4 22.7 22.9 23.1 23.5 user 14.8 14.8 14.9 14.8 14.3 15.2 sys 7.4 7.4 7.1 7.3 7.8 7.2 I have posted the "dotime" program to alt.sources, for whoever thinks she/he can use it. Have fun! Johan -- Johan Vromans jv at mh.nl via internet backbones Multihouse Automatisering bv uucp: ..!{uunet,hp4nl}!mh.nl!jv Doesburgweg 7, 2803 PL Gouda, The Netherlands phone/fax: +31 1820 62944/62500 ------------------------ "Arms are made for hugging" ------------------------- From jv at mh.nl Sat Jan 6 10:27:21 1990 From: jv at mh.nl (Johan Vromans) Date: 5 Jan 90 23:27:21 GMT Subject: 'from' in perl Message-ID: <JV.90Jan5162721@mhres.mh.nl> A number of people have asked me for a (re)post of the perl 'from' program. So here is a new version of it. I added an optional -n switch to show message numbers, to use with Elm's 'readmsg' program. Have fun, Johan >>> Note this article is being cross-posted to alt.sources. Please >>> followup to alt.sources.d for bugs and remarks, and to >>> comp.lang.perl for perl related topics. ------ begin of from.pl -- ascii -- complete ------ #!/usr/bin/perl # This program requires perl version 3.0, patchlevel 4 or higher # @($)@ from 1.5 - from.pl # Show messages from a Unix mailbox. With -n: shown message numbers also. # # Usage "from [-n] MAILBOX..." # # Don't forget: perl is a Practical Extract and Report Language! # # Copyright 1989,1990 Johan Vromans <jv at mh.nl>, no rights reserved. # Usage and redistribution is free and encouraged. # Default output format format = @<<<<<<<<<<< "@<<<<<<<<<<<<" ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<.. $date, $from, $subj . # Output format when sequence numbers are requested format format_n = @>: @<<<<<<<<<<< "@<<<<<<<<<<<<" ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<.. $seq, $date, $from, $subj . # Parse and stash away -n switch, if provided if ($#ARGV >= 0 && $ARGV[0] eq '-n') { shift (@ARGV); $~ = "format_n"; } # Use system mailbox if none was specified on the command line if ( $#ARGV < 0 ) { if ( ! ($user = getlogin)) { @a = getpwuid($<); $user = $a[0]; } if ( -r "/usr/mail/$user" ) { # System V @ARGV = ("/usr/mail/$user"); } elsif ( -r "/usr/spool/mail" ) { # BSD @ARGV = ("/usr/spool/mail/$user"); } else { printf STDERR "No mail for $user.\n"; exit 1; } } $seq = 0; # Read through input file(s) while (<>) { # Look for a "From_" header (See RFC822 and associated documents). next unless /^From\s+(\S+)\s+.*(\w{3}\s+\d+\s+\d+:\d+)/; chop; $from = $1; $date = $2; if ( $date eq "" || $from eq "" ) { print STDERR "Possible garbage: $_\n"; next; } $seq++; # Get user name from uucp path $from = $1 if $from =~ /.*!(.+)/; # Now, scan for Subject or empty line $subj = ""; while ( <> ) { chop ($_); if ( /^$/ || /^From / ) { # force fall-though $subj = "<none>" unless $subj; } else { $subj = $1 if /^Subject\s*:\s*(.*)/i; if ( /^From\s*:\s*/ ) { $_ = $'; if ( /\((.+)\)/i ) { $from = $1; } elsif ( /^\s*(.+)\s*<.+>/i ) { $from = $1; } elsif ( /^<.+>\s*(.+)/i ) { $from = $1; } } } # do we have enough info? if ( $from && $subj ) { write; last; } } } ------ end of from.pl -- ascii -- complete ------ -- Johan Vromans jv at mh.nl via internet backbones Multihouse Automatisering bv uucp: ..!{uunet,hp4nl}!mh.nl!jv Doesburgweg 7, 2803 PL Gouda, The Netherlands phone/fax: +31 1820 62944/62500 ------------------------ "Arms are made for hugging" ------------------------- From aglew at oberon.csg.uiuc.edu Fri Jan 19 10:51:20 1990 From: aglew at oberon.csg.uiuc.edu (Andy Glew) Date: 18 Jan 90 23:51:20 GMT Subject: number recognition tools In-Reply-To: aglew@oberon.csg.uiuc.edu's message of 15 Jan 90 11:53:0 References: <AGLEW.90Jan15115309@oberon.csg.uiuc.edu> Message-ID: <AGLEW.90Jan18175120@oberon.csg.uiuc.edu> This is a repost of the number recognition tools, with a working shar file, and a bug fix courtesy of Joseph Pepin. This post has compiled and successfully completed its test on both a SUN3 and a DECSTATION 3100. ------ CUT HERE ----------------------------------------------------------- #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: Makefile README bug.JDP debug.h getnumber.c getnumber.man # number.c number.man test.c # Wrapped by aglew at rigel.csg.uiuc.edu on Thu Jan 18 17:54:52 1990 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Makefile'\" else echo shar: Extracting \"'Makefile'\" \(237 characters\) sed "s/^X//" >'Makefile' <<'END_OF_FILE' XCFLAGS=-g XCC=FP='' /bin/cc Xall: test number.o getnumber Xtests: test Xtest: test.o number.o X ${CC} -g -DTEST -o test test.o number.o -lm Xgetnumber: getnumber.o number.o X ${CC} -g -o getnumber getnumber.o number.o -lm Xnumber.o: number.c X END_OF_FILE if test 237 -ne `wc -c <'Makefile'`; then echo shar: \"'Makefile'\" unpacked with wrong size! fi # end of 'Makefile' fi if test -f 'README' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'README'\" else echo shar: Extracting \"'README'\" \(967 characters\) sed "s/^X//" >'README' <<'END_OF_FILE' X/* X * number X * X * This is a directory for a family of routines that convert X * a string to an integer. The intention is to be able to freely X * recognize just about any format integer: X * X * Decimal 1342334 X * Hex 0xAB43 X * Octal 01377 X * Binary 0b100100011 X * Arbitrary Radix rrr#vvvvvvvv X * X * Because people often want to provide a special format over and above X * those that are already provided X * X * Eg. Hex 'ABC'Z X * Decimal 10. X * Ignore _ 100_677_888 X * X * the intent is to define a, possibly parametrized, recognizer function X * for each format, and then to pass a list of desired recognizer functions X * for your specific recognizer. X * X * This is not intended to be fast, only general. X * X * All recognizers are of the form: X * X * success = RECOGNIZER( string, resultptr ) X * int success; /* -1 indicates failure */ X * char *string; X * int *result; X * X */ X X X X X END_OF_FILE if test 967 -ne `wc -c <'README'`; then echo shar: \"'README'\" unpacked with wrong size! fi # end of 'README' fi if test -f 'bug.JDP' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'bug.JDP'\" else echo shar: Extracting \"'bug.JDP'\" \(948 characters\) sed "s/^X//" >'bug.JDP' <<'END_OF_FILE' XReturn-Path: <att!cbnewsl!joepepin at uxc.cso.uiuc.edu> XDate: Thu, 18 Jan 90 15:26:53 EST XFrom: jdp at tarpon.att.com (Joseph Pepin) XTo: aglew at oberon.csg.uiuc.edu XSubject: Re: number recognition tools XNewsgroups: alt.sources XIn-Reply-To: <AGLEW.90Jan15115309 at oberon.csg.uiuc.edu> XOrganization: AT&T Bell Laboratories X XTwo serious bugs: X X1) The shar file is corrupt: the END-OF-FILE after each man page Xis preceeded by an "X", causing the next file not to be unshar'ed. XMaybe the original files were not terminated by a NL. X X2) Executing "getnumber -100e-2" dumps core on a 3B2 and a 6386WGS Xrunning SVR3.2. The problem is you don't malloc enough space Xfor the right side of an infix expression: X XLine 218 of number.c: X X right = malloc ... InfixStrLen))); X Xshould be: X X right = malloc ... InfixStrLen))+1); X XI suspect that other systems treat malloc(0) as malloc(1). X XPlease fix these bugs and/or post this message: my newsserver Xdiscourages postings. X END_OF_FILE if test 948 -ne `wc -c <'bug.JDP'`; then echo shar: \"'bug.JDP'\" unpacked with wrong size! fi # end of 'bug.JDP' fi if test -f 'debug.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'debug.h'\" else echo shar: Extracting \"'debug.h'\" \(4128 characters\) sed "s/^X//" >'debug.h' <<'END_OF_FILE' X#ifndef DEBUG_H X X#define DEBUG_H 1 X X#ifdef DEBUG Xint DEBUG_was_defined; X#endif X X/* X * manual NAME debug.h - Andy Glew's debug header X * X * USAGE #define DEBUG 1 #include "debug.h" ... debugf((fmt,vars...)); X * X * DESCRIPTION X * X * The header file "debug.h" may be found in a directory near you. It X * contains macros to make the production of debugging messages more X * pleasant. X * X * debugf X * X * The most important/useful of these macros is debugf((...)). Debugf X * is a printf (to stdout by default, optionally to stderr or X * elsewhere). It accepts standard printf format strings and a X * variable number of arguments. The only syntactic difference is the X * necessity of double parentheses about the parameter list X * (necessary because C macros can't have variable numbers of X * arguments). Debugf usually produces one line of output per call, X * with a distinctive mark like "Debug in file XXX line NNN". X * X * Example: while( ... ) { debugf(("in loop\n")); ... } X * X * DEBUG X * X * To use debugf: #define DEBUG 1 #include "debug.h" DEBUG must be X * defined before debug.h is included, either in code or in a -dDEBUG X * flag when compiled. If DEBUG is not defined when debug.h is X * included, debugf and other debugging macros occupy no space in X * your program. X * X * nodebugf X * X * nodebugf((...)) is syntactic sugar to make it easy to turn debugfs X * off without having to remove them or go through convolutions X * setting a debug control variable. X * X * debugshow X * X * debugshow(var,fmt) produces the quintessential debugging output X * VARIABLE=VALUE_OF_VARIABLE. fmt is the format string you would use X * in printf, without the double quotes. X * X * Example: int Ingrid=77; debugshow(Ingrid,%d); Produces Debug in file X * XXX line NNN: Ingrid = 77 X * X * _debugf X * X * _debugf is the name of the function to be used to print the debugging X * output, printf by default. It can be changed at any time to X * another varargs function. eprintf is useful - just X * fprintf(stderr...) although it must be rewritten as a function due X * to the weaknesses of C. Logging functions, and the like, can also X * be useful. X * X * DebugCondition X * X * There are actually several layers of indirection in this macro X * system: X * X * debugshow -> debugf -> _ifdebugf -> _debugf X * X * _ifdebugf should not be changed; but the condition DebugCondition X * which it tests can usefully be changed. By default DebugCondition X * is defined as (1); it is often nice to set it to a variable that X * you can patch X * X * #define DebugCondition DebugVar int DebugVar = 0; #define DEBUG 1 X * #include "debug.h" X * X * I would have made a variable the default except for awkwardnesses X * some people have about adding modules to the standard C library. X * X * Some people like having multiple debug levels, although I don't. X * These can also be stacked. X * X * The function name __FUNC__ should be printed out as soon as the C X * compiler is fixed. X * X * manual X */ X X#if defined(DEBUG) X# define DEBUGcode( sl ) sl X# define DEBUGdecl( decl ) decl X#else X# define DEBUGcode( sl ) X# define DEBUGdecl( decl ) X#endif X X#define noDEBUGcode( sl ) X#define noDEBUGdecl( sl ) X X/* X * double brackets about _debugf's parmlist so that you can do X * #define _debugf(v) (printf v,uprintf v) which is useful in the X * kernel X */ X# if defined(DEBUG) X# if !defined(_debugf) X# define _debugf(parmlist) (printf parmlist) X# endif X X/* DebugCondition can be controlled by the user */ X# define _ifdebugf(parmlist) ( DebugCondition ? _debugf(parmlist) : 0 ) X# if !defined(DebugCondition) X# define DebugCondition (1) X# endif X# endif /* DEBUG */ X X# if defined(DEBUG) X# define debugf(parmlist) \ X ( _ifdebugf(("Debug in file %s line %d ",__FILE__,__LINE__)), \ X _ifdebugf(parmlist) \ X ) X# else X# define debugf(parmlist) X# endif X# define nodebugf(parmlist) X X /* debugshow - cannot use "s in arguments */ X#ifdef DEBUG X# define debugshow(var,fmt) debugf(("var = fmt\n",var)) X# define nodebugshow(var,fmt) X#else X# define debugshow(var,fmt) X# define nodebugshow(var,fmt) X#endif X X X#endif /* DEBUG_H */ X END_OF_FILE if test 4128 -ne `wc -c <'debug.h'`; then echo shar: \"'debug.h'\" unpacked with wrong size! fi # end of 'debug.h' fi if test -f 'getnumber.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'getnumber.c'\" else echo shar: Extracting \"'getnumber.c'\" \(899 characters\) sed "s/^X//" >'getnumber.c' <<'END_OF_FILE' X/* User level wrapper for Dgetnumber */ X Xvoid exit(); X Xint Igetnumber(); Xint Dgetnumber(); X Xint DorI = 'D'; X Xchar *format = "%g"; X Xmain(argc,argv) X int argc; X char **argv; X{ X double dres; X int ires; X X for(;*++argv;) { X if( !strcmp(*argv,"-i") ) { X DorI = 'I'; X format = "%d"; X } X else if( !strcmp(*argv,"-d") ) { X DorI = 'D'; X format = "%g"; X } X else if( !strcmp(*argv,"-format") ) { X format = *++argv; X } X else { X switch( DorI ) { X default: X exit(-1); X case 'D': X if( Dgetnumber(*argv,&dres) == -1 ) { X (void)printf("invalid\n"); X } X else { X (void)printf(format,dres); X (void)printf("\n"); X } X break; X case 'I': X if( Igetnumber(*argv,&ires) == -1 ) { X (void)printf("invalid\n"); X } X else { X (void)printf(format,ires); X (void)printf("\n"); X } X break; X } X } X } X exit(0); X /*NOTREACHED*/ X} X X END_OF_FILE if test 899 -ne `wc -c <'getnumber.c'`; then echo shar: \"'getnumber.c'\" unpacked with wrong size! fi # end of 'getnumber.c' fi if test -f 'getnumber.man' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'getnumber.man'\" else echo shar: Extracting \"'getnumber.man'\" \(2080 characters\) sed "s/^X//" >'getnumber.man' <<'END_OF_FILE' X.nf X NAME: X getnumber \- read a number in arbitrary notation X X SYNOPSIS: X getnumber [-i|-d|-format '%printf-format'] number-string ... X X DESCRIPTION: X getnumber is a program wrapped around the Dgetnumber and Igetnumber X family of routines (see their man pages). Getnumber converts number X in an almost arbitrary string representation, and prints the number X out on stdout as a decimal integer or double precision value, X or using a printf like string. X X getnumber is intended to be used in shell scripts that would like X to be able to recognize numbers typed in by the user in their natural X format. Eg. X ARG=0.5M-1 X ... X value=`getnumber -i $ARG` X XINTERFACE: X Getnumber processes its command line arguments and prints to stdout. X Stdin is not used. X X The command line option X X -i -- convert to an integer, using %d format to print X -d -- convert to a C double, using %g format to print X X -format %printf-format X -- format to be used in printing the result. X X Exits with error status -1 on a command line error. X Prints "invalid" on conversion errors, but continues to process. X XBACKGROUND: X See the man pages for the Dgetnumber and Igetnumber family X for more deatils (man number). X X The intention is to be able to freely recognize just about any X format number: X X Decimal 1342334 X Hex 0xAB43 X Octal 01377 X Binary 0b100100011 X Arbitrary Radix rrr#vvvvvvvv X H:M:S 1:20:33 X Real 1.45 X "Meg" 4M X Expressions (4M-1)*2 X Exponential 1.2E6 X X Expressions currently include: X infix binary: | ^ & << >> + - * / % **(exponent) X prefix unary: - + ~ X midfix grouping: () [] {} X and it is similarly easy to add new notations. X X All number representations and expressions can be intermixed: X [(2M-1)*4]>>0x03 X X NOTES: X X AUTHOR: X Andy Glew (aglew at uiuc.edu) X X HISTORY: X Originally written by Andy Glew at McGill University, 1983 X X BUGS: X END_OF_FILE if test 2080 -ne `wc -c <'getnumber.man'`; then echo shar: \"'getnumber.man'\" unpacked with wrong size! fi # end of 'getnumber.man' fi if test -f 'number.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'number.c'\" else echo shar: Extracting \"'number.c'\" \(19062 characters\) sed "s/^X//" >'number.c' <<'END_OF_FILE' X/* X * number X * X * This is a directory for a family of routines that convert X * a string to a number. X * X * X * The intention is to be able to freely recognize just about any X * format number: X * X * Decimal 1342334 X * Hex 0xAB43 X * Octal 01377 X * Binary 0b100100011 X * Arbitrary Radix rrr#vvvvvvvv X * H:M:S 1:20:33 X * Real 1.45 X * "Meg" 4M X * Expressions (4M-1)*2 X * Exponential 1.2E6 X * X * Because people often want to provide a special format over and above X * those that are already provided X * X * Eg. Hex 'ABC'Z X * Decimal 10. X * Ignore _ 100_677_888 X * X * the intent is to define a, possibly parametrized, recognizer function X * for each format, and then to pass a list of desired recognizer functions X * for your specific recognizer. X * X * This is not intended to be fast, only general. X * X * All recognizers are of the form: X * X * success = RECOGNIZER( string, resultptr ) X * int success; { -1 indicates failure } X * char *string; X * double *result; X * X * Recognition is done bottom up instead of top-down; X * instead of having a grammar that constrains notation, X * everything is passed to low-level recognizers that try to recognize X * the string, perhaps recursively, passing off to other recognizer X * in case of failure. X * X * The current recognizers are: X * X * Octal0 0<octal> eg. 0377 = 0xFF X * SimpleDecimalString <decimal> eg. 10 = 0xA X * Binary0b 0b<binary> eg. 0b011 = 3 X * Decimal0d 0d<decimal> eq. 10 = 0xA X * Hex0x 0x<hex> eg. 0xA = 10 X * ArbitraryRadix <decimalbase>#<radix> eq. 3#22 = 8 X * colon60 M:S eg. 1:20 = 80 X * colon60colon60 H:M:S eg. 2:1:20 = 7280 X * PowersOf2 <real>[KMG] eg. 0.5K = 512 X * RealDecimalString <real> eg. 0.5 X * Expressions eg. 0.5M-1 X * X * Expressions currently include: X * infix binary: | ^ & << >> + - * / % **(exponent) X * prefix unary: - + ~ X * midfix grouping: () [] {} X * and it is similarly easy to add new notations. X * X * All number representations and expressions can be intermixed: X * [(2M-1)*4]>>0x03 X * X * There are some functions useful in building other recognizers, like X * RadixString(), and the expression building functions. X * X * There are two top level recognizers, X * Dgetnumber(str,res) X * and Igetnumber(str,res); X * the "I" version is basically a call to the "D" version, which rounds, X * and errors if the rounded integer value is more than int_threshold X * away from the non-int value. X * X * Initially, this was integer only, but in Jan 89 I changed it X * to produce a floating point result - if you want integer, just X * integerize. X * This will have some lossage if your floating point format X * cannot represent all integer values exactly. Sorry - in that X * case, you'll just have to go back to the old routine. X * It has the advantage of one family of routines being able X * to handle intermediate cases - like 0.5M. X * It has the advantage of, on a system with decent floating X * point, being able to trap on overflow or underflow. X * Interim: add this for Motorola systems. X * If you can, use your system dependent way of trapping on inexact. X * Interim: if you have IEEE floating point, it would be nice to X * have this same routine read in NaNs. X */ X X#include <stdio.h> X#include <string.h> X#include <math.h> X Xextern double pow(); Xextern double floor(); Xextern double fabs(); Xextern char *malloc(); Xextern void free(); X X#define DEBUG 1 X#include "debug.h" X X#define index strchr Xchar *index(); X#define rindex strrchr Xchar *rindex(); X Xvoid exit(); X X/* Interim: no tree building. all recursive in place. */ X Xint MidfixExpression(str,res,preStr,postStr,MidfixFunc) X char *str; X double *res; X char *preStr, *postStr; X double (*MidfixFunc)(); X{ X char *midStr; X double midVal; X int strLen = strlen(str); X int preStrLen = strlen(preStr); X int postStrLen = strlen(postStr); X int match; X X nodebugf(("In midfix <%s> <%s> <%s>\n", str, preStr, postStr)); X X if( str == 0 || *str == 0) { X return -1; X } X X if( strncmp(str,preStr,preStrLen) != 0 ) { X return -1; X } X if( strcmp(str+strLen-postStrLen, postStr) != 0 ) { X return -1; X } X X midStr = malloc((unsigned)(strLen-preStrLen-postStrLen+1)); X if( !midStr ) { X (void)fprintf(stderr,"Error malloc'ing memory for expressions\n"); X exit(1); X } X (void)strncpy(midStr,str+preStrLen,strLen-preStrLen-postStrLen); X midStr[strLen-preStrLen-postStrLen] = '\0'; X nodebugf(("midStr=<%s>\n",midStr)); X match = (Dgetnumber(midStr,&midVal) != -1); X free(midStr); X if( !match ) { X return -1; X } X *res = MidfixFunc(midVal); X return 0; X} Xdouble Dnop(a) double a; { return a; } X X Xint PrefixExpression(str,res,PrefixStr,PrefixFunc) X char *str; X double *res; X char *PrefixStr; X double (*PrefixFunc)(); X{ X double Darg; X int PrefixStrLen = strlen(PrefixStr); X X if( str == 0 || *str == 0) { X return -1; X } X X if( strncmp(str,PrefixStr,PrefixStrLen) != 0 ) { X return -1; X } X else { X if( Dgetnumber(str+PrefixStrLen,&Darg) == -1 ) { X return -1; X } X *res = PrefixFunc(Darg); X return 0; X } X} Xdouble Dplussign(a) double a; { return a; } Xdouble Dnegsign(a) double a; { return -a; } Xdouble Dinvert(a) double a; { return (double)~(unsigned)a; } X X Xint InfixExpression(str,res,InfixStr,InfixFunc) X char *str; X double *res; X char *InfixStr; X double (*InfixFunc)(); X{ X char *left, *right; X double Dleft, Dright; X char *p1; X int match; X int InfixStrLen = strlen(InfixStr); X X if( str == 0 || *str == 0) { X return -1; X } X X /* Try splitting into subexpressions at all occurrences of the operator, X moving from left to handle 1-1-1. Retries will handle subexpressions. X */ X for( p1 = str + strlen(str);;p1--) { X if( p1 < str ) { X return -1; X } X if( !strncmp(p1,InfixStr,InfixStrLen) ) { X left = malloc((unsigned)(p1-str+1)); X right = malloc((unsigned)(strlen(p1+InfixStrLen))+1); X /* Bug JDP1: found by jdp at tarpon.att.com, X Joseph Pepin - did not malloc enough space for RHS, X missing +1 above. -100e-2 test case. */ X if( !left || !right ) { X (void)fprintf(stderr,"Error malloc'ing memory for expressions\n"); X exit(1); X } X (void)strncpy(left,str,p1-str); X left[p1-str] = '\0'; X (void)strcpy(right, p1+InfixStrLen ); X match = Dgetnumber(left,&Dleft) != -1 X && Dgetnumber(right,&Dright) != -1; X free(left); X free(right); X if( match ) { X *res = InfixFunc(Dleft,Dright); X return 0; X } X } X } X} X Xdouble Dplus(a,b) double a,b; { return a+b; } Xdouble Dsub(a,b) double a,b; { return a-b; } Xdouble Dtimes(a,b) double a,b; { return a*b; } Xdouble Ddivide(a,b) double a,b; { return a/b; } X/* Interim: need to indicate loss of info on these "pesudo-integer" ops */ Xdouble Dor(a,b) double a,b; { return (double)((unsigned)a | (unsigned)b); } Xdouble Dand(a,b) double a,b; { return (double)((unsigned)a & (unsigned)b); } Xdouble Dxor(a,b) double a,b; { return (double)((unsigned)a ^ (unsigned)b); } Xdouble Dremainder(a,b) double a,b; { return (double)((unsigned)a % (unsigned)b); } Xdouble Dlsh(a,b) double a,b; { return (double)((unsigned)a << (unsigned)b); } Xdouble Drsh(a,b) double a,b; { return (double)((unsigned)a >> (unsigned)b); } Xdouble Dexponent(a,b) double a,b; { extern double pow(); return pow(a,b); } X X Xint Expression(str,res) X char *str; X double *res; X{ X if( str == 0 || *str == 0) { X return -1; X } X X if( InfixExpression(str,res,"|",Dor) == 0 ) { X return 0; X } X if( InfixExpression(str,res,"^",Dxor) == 0 ) { X return 0; X } X if( InfixExpression(str,res,"&",Dand) == 0 ) { X return 0; X } X if( InfixExpression(str,res,"<<",Dlsh) == 0 ) { X return 0; X } X if( InfixExpression(str,res,">>",Drsh) == 0 ) { X return 0; X } X if( InfixExpression(str,res,"+",Dplus) == 0 ) { X return 0; X } X if( InfixExpression(str,res,"-",Dsub) == 0 ) { X return 0; X } X if( InfixExpression(str,res,"*",Dtimes) == 0 ) { X return 0; X } X if( InfixExpression(str,res,"/",Ddivide) == 0 ) { X return 0; X } X if( InfixExpression(str,res,"%",Dremainder) == 0 ) { X return 0; X } X if( InfixExpression(str,res,"**",Dexponent) == 0 ) { X return 0; X } X if( PrefixExpression(str,res,"+",Dplussign) == 0 ) { X return 0; X } X if( PrefixExpression(str,res,"-",Dnegsign) == 0 ) { X return 0; X } X if( PrefixExpression(str,res,"~",Dinvert) == 0 ) { X return 0; X } X if( MidfixExpression(str,res,"(",")",Dnop) == 0 ) { X return 0; X } X if( MidfixExpression(str,res,"[","]",Dnop) == 0 ) { X return 0; X } X if( MidfixExpression(str,res,"{","}",Dnop) == 0 ) { X return 0; X } X return -1; X} X X Xint SimpleDecimalString(str,res) X char *str; X double *res; X{ X if( str == 0 || *str == 0) { X return -1; X } X X return RadixString(str,10,res); X} X Xint Binary0b(str,res) X char *str; X double *res; X{ X if( str == 0 || *str == 0) { X return -1; X } X X if( str[0] == '0' && (str[1] == 'b' || str[1] == 'B') ) { X return RadixString(str+2,2,res); X } X return -1; X} X Xint Octal0(str,res) X char *str; X double *res; X{ X if( str == 0 || *str == 0) { X return -1; X } X X if( str[0] == '0' ) { X return RadixString(str+1,8,res); X } X return -1; X} X Xint Decimal0d(str,res) X char *str; X double *res; X{ X if( str == 0 || *str == 0) { X return -1; X } X X if( str[0] == '0' && (str[1] == 'd' || str[1] == 'D') ) { X return RadixString(str+2,10,res); X } X return -1; X} X Xint Hex0x(str,res) X char *str; X double *res; X{ X if( str == 0 || *str == 0) { X return -1; X } X X if( str[0] == '0' && (str[1] == 'x' || str[1] == 'X') ) { X return RadixString(str+2,16,res); X } X return -1; X} X Xint ArbitraryRadix(str,res) X char *str; X double *res; X{ X int radix; X int digval; X X if( str == 0 || *str == 0) { X return -1; X } X X for( radix = 0; (digval = DECIMAL_DIGIT_VALUE(*str)) != -1; str++ ) { X radix = radix*10 + digval; X } X if( *str != '#' ) X return -1; X return RadixString(str+1,radix,res); X} X Xint RadixString(str,radix,res) X char *str; X int radix; X double *res; X{ X int val; X int digval; X X if( str == 0 || *str == 0) { X return -1; X } X X val = 0; X for(;;) { X if( !IGNORE(*str) ) { X digval = DIGIT_VALUE(*str); X if( digval < 0 || digval >= radix ) X return -1; X val = val*radix + digval; X } X str++; X if( *str == '\0' ) X break; X } X *res = val; X X return 0; X} X X/* Recognisers for M:S and H:M:S forms */ X X#define PRECOLON() { \ X if( (colonpos = index(str,':')) == 0 ) { \ X return -1; \ X } \ X precolon_len = colonpos-str; \ X if( precolon_len > 128-1 ) { \ X /* string too long */ \ X return -1; \ X } \ X /* Copy the precolon string and interpret as a decimal number */ \ X (void)strncpy( precolon_str, str, precolon_len ); \ X precolon_str[precolon_len] = '\0'; \ X \ X if( SimpleDecimalString(precolon_str,&precolon_val) == -1 ) { \ X return -1; \ X } \ X if( precolon_val != (int) precolon_val || precolon_val < 0 ) { \ X return -1; \ X } \ X} X Xint colon60(str,res) X char *str; X double *res; X{ X char *colonpos; X char precolon_str[128]; X int precolon_len; X double precolon_val; X double postcolon_val; X X X if( str == 0 || *str == 0) { X return -1; X } X X PRECOLON(); X X if( DecimalString(colonpos+1,&postcolon_val) == -1 ) { X return -1; X } X if( postcolon_val < 0 || 60 <= postcolon_val ) { X return -1; X } X X *res = precolon_val*60 + postcolon_val; X return 0; X} Xint colon60colon60(str,res) X char *str; X double *res; X{ X char *colonpos; X char precolon_str[128]; X int precolon_len; X double precolon_val; X double postcolon_val; X X if( str == 0 || *str == 0) { X return -1; X } X X PRECOLON(); X X if( colon60(colonpos+1,&postcolon_val) == -1 ) { X return -1; X } X if( postcolon_val < 0 || 60*60 <= postcolon_val) { X return -1; X } X X *res = precolon_val*(60*60) + postcolon_val; X return 0; X} X X/* Recognize common powers of 2: 2^10=K, 2^20=M, 2^30=G X Interim: would handle 2^40=T if it didn't overflow */ X Xint PowersOf2(str,res) X char *str; X double *res; X{ X int sl = strlen(str); X double val; X char buf[128]; X X if( str == 0 || *str == 0) { X return -1; X } X X if( sl <= 0 || sl > 128-1 ) { X return -1; X } X (void)strcpy(buf,str); X buf[sl-1] = '\0'; X X if( str[sl-1] == 'K' ) { X if( DecimalString(buf,&val) == -1 ) { X return -1; X } X *res = val * 1024; X return 0; X } X else if( str[sl-1] == 'M' ) { X if( DecimalString(buf,&val) == -1 ) { X return -1; X } X *res = val * 1024*1024; X return 0; X } X else if( str[sl-1] == 'G' ) { X if( DecimalString(buf,&val) == -1 ) { X return -1; X } X *res = val * 1024*1024*1024; X return 0; X } X return -1; X} X X/* Floating point recognizer. X Interim: decimal floating point only. X iii.fffff form only. X Interim: should recognize scientific notation iii.fffEeeee */ X Xint RealDecimalString(str,res) X char *str; X double *res; X{ X double val; X int sl; X int infraction; X int scale; X X if( str == 0 || *str == 0) { X return -1; X } X X sl = strlen(str); X X if( sl <= 0 ) { X return -1; X } X X if( index(str,'.') == 0 ) { X return -1; X } X X /* accumulation of value down from least significant end X first, to reduce errors */ X val = 0; X infraction = 1; X scale = 1; X for(;sl-->0;) { X int d = DECIMAL_DIGIT_VALUE(str[sl]); X if( d == -1 ) { X if( str[sl] == '.' ) { X infraction = 0; X continue; X } X else { X return -1; X } X } X if( infraction ) { X val += d; X val /= 10.0; X } X else { X val = d*scale + val; X scale = scale*10; X } X } X *res = val; X return 0; X} X X X X Xint DecimalString(str,res) X char *str; X double *res; X{ X if( str == 0 || *str == 0) { X return -1; X } X X if( SimpleDecimalString(str,res) == -1 X && RealDecimalString(str,res) == -1 ) { X return -1; X } X return 0; X} X X X/* Generic routine for signs */ Xint Signed(func,str,res) X int (*func) (); X char *str; X double *res; X{ X double value; X int ret; X int neg; X X if( str == 0 || *str == 0) { X return -1; X } X X switch( str[0] ) { X case '+': X neg = 0; X ret = func(str+1,&value); X break; X case '-': X neg = 1; X ret = func(str+1,&value); X break; X default: X neg = 0; X ret = func(str,&value); X break; X } X if( ret == -1 ) { X return -1; X } X else { X if( neg ) value = -value; X *res = value; X return 0; X } X X} X X X X/* Scientific notation recognizer */ X Xint ScientificExponentialNotation(str,res) X char *str; X double *res; X{ X char *dupptr; X char *expptr; X double exponent; X double mantissa; X int retval; X extern char *strdup(); X X if( str == 0 || *str == 0) { X return -1; X } X X if( (dupptr = strdup(str)) == 0 ) { X (void)fprintf(stderr,"insufficient free memory to duplicate string\n"); X exit(1); X } X if( (expptr = strchr(dupptr,'E')) == 0 X && (expptr = strchr(dupptr,'e')) == 0 X ) { X retval = -1; X goto cleanup; X } X X *expptr++ = '\0'; X X /* dupptr is now a pointer to the mantissa, expptr to the exponent, X both null terminated strings */ X if( Signed(SimpleDecimalString,expptr,&exponent) == -1 ) { X retval = -1; X goto cleanup; X } X X if( Signed(RealDecimalString,dupptr,&mantissa) == -1 X && Signed(SimpleDecimalString,dupptr,&mantissa) == -1 ) { X retval = -1; X goto cleanup; X } X X *res = mantissa * pow(10.0,exponent); X retval = 0; X X cleanup: X free(dupptr); X X return retval; X} X X X/* Utility functions */ Xchar *IGNORE_CHARS = "_"; X Xint IGNORE(c) X char c; X{ X return index(IGNORE_CHARS,c) != 0; X} X Xint DIGIT_VALUE(d) X char d; X{ X int val; X X switch( d ) { X default: val = -1; break; X case '0': val = 0; break; X case '1': val = 1; break; X case '2': val = 2; break; X case '3': val = 3; break; X case '4': val = 4; break; X case '5': val = 5; break; X case '6': val = 6; break; X case '7': val = 7; break; X case '8': val = 8; break; X case '9': val = 9; break; X case 'a': case 'A': val = 0xA; break; X case 'b': case 'B': val = 0xB; break; X case 'c': case 'C': val = 0xC; break; X case 'd': case 'D': val = 0xD; break; X case 'e': case 'E': val = 0xE; break; X case 'f': case 'F': val = 0xF; break; X } X return val; X} X Xint DECIMAL_DIGIT_VALUE(d) X char d; X{ X int val = DIGIT_VALUE(d); X if( val < 0 || val >= 10 ) X return -1; X else X return val; X} X X X X Xtypedef int (*Recognizer)(); X XRecognizer DefaultRecognizers[] = { X Octal0, X SimpleDecimalString, X Binary0b, X Decimal0d, X Hex0x, X ArbitraryRadix, X colon60, X colon60colon60, X PowersOf2, X RealDecimalString, X Expression, X ScientificExponentialNotation, X 0 X}; X X/* Flags for DgetnumberList */ X#define PRIO_RESOLVE_AMBIGUITY 1 X Xint DgetnumberList(str,res,flags,RecognizerList) X char *str; X double *res; X int flags; X Recognizer RecognizerList[]; X{ X int found; X double oldval = 0; /* to silence lint "oldval may be used before set" */ X double newval; X Recognizer *fp; X X /* Special test for null strings. X All recognizers should really handle this, but... X */ X if( str == 0 || str[0] == 0 ) { X return -1; X } X X for(fp = RecognizerList, found=0; *fp; fp++) { X if( (*fp)(str,&newval) != -1 ) { X if( flags & PRIO_RESOLVE_AMBIGUITY ) { X found = 1; X break; X } X if( found ) { X if( newval != oldval ) { X return -1; X } X } X else { X oldval = newval; X found = 1; X } X } X } X if( found ) { X *res = newval; X return 0; X } X else { X return -1; X } X} X X X/* Recognizer form of the above, with the default list */ X Xint Dgetnumber(str,res) X char *str; X double *res; X{ X if( DgetnumberList(str,res, X PRIO_RESOLVE_AMBIGUITY, X DefaultRecognizers) X == -1 ) { X return -1; X } X return 0; X} X X X/* Integer version of the above. X Includes a threshold because arithmetic may be inexact (sigh) */ X/* Interim: should this be parametrized for "D" function to call, X threshold, and list of recognizers? I'm not sure. */ X Xdouble int_threshold = 0.00000001; X Xint Igetnumber(str,res) X char *str; X int *res; X{ X extern double floor(); X extern double fabs(); X double dres; X double delta; X X if( Dgetnumber(str,&dres) == -1 ) { X return -1; X } X *res = (int)floor(dres+0.5); X delta = (double)*res - dres; X if( fabs(delta) > int_threshold ) { X return -1; X } X return 0; X} X X X X/* interim: strdup for BSD. remove if you already have it */ Xchar *strdup(s) X char *s; X{ X char *mp = malloc(strlen(s)+1); X if( mp == 0 ) { X (void)fprintf(stderr,"Error malloc'ing in strdup\n"); X exit(1); X } X (void)strcpy(mp,s); X return mp; X} X END_OF_FILE if test 19062 -ne `wc -c <'number.c'`; then echo shar: \"'number.c'\" unpacked with wrong size! fi # end of 'number.c' fi if test -f 'number.man' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'number.man'\" else echo shar: Extracting \"'number.man'\" \(5263 characters\) sed "s/^X//" >'number.man' <<'END_OF_FILE' X.nf X NAME: X Dgetnumber, Igetnumber \- a family of string to number conversion routines X X SYNOPSIS: X X /* Default double precision recognizer */ X success = Dgetnumber( string, resultptr ) X int success; { -1 indicates failure } X char *string; X double *result; X X /* Default integer recognizer */ X success = Igetnumber( string, resultptr ) X int success; { -1 indicates failure } X char *string; X int *result; X X /* Threshold used for integerizing double precision values. */ X double int_threshold; X X DESCRIPTION: X X Dgetnumber and Igetnumber are two representatives (probably all that a typical X use may ever encounter) of a family of routines for string representations of X numbers to numbers in machine internal representation. X X They were written out of frustration with programs and routines that seldom X accept all of the "natural" representations of numbers for a problem -- X disk utilities that require decimal numbers as input, while disk error loggers X produce hex numbers on output, times that need to be converted from H:M:S X before they can be used, etc. X X The intention is to be able to freely recognize just about any X format number: X X Decimal 1342334 X Hex 0xAB43 X Octal 01377 X Binary 0b100100011 X Arbitrary Radix rrr#vvvvvvvv X H:M:S 1:20:33 X Real 1.45 X "Meg" 4M X Expressions (4M-1)*2 X Exponential 1.2E6 X X Because people often want to provide a special format over and above X those that are already provided X X Eg. Hex 'ABC'Z X Decimal 10. X Ignore _ 100_677_888 X X the intent is to define a, possibly parametrized, recognizer function X for each format, and then to pass a list of desired recognizer functions X for your specific recognizer. X X This is not intended to be fast, only general. X X All recognizers are of the form: X X success = RECOGNIZER( string, resultptr ) X int success; { -1 indicates failure } X char *string; X double *result; X X Recognition is done bottom up instead of top-down; X instead of having a grammar that constrains notation, X everything is passed to low-level recognizers that try to recognize X the string, perhaps recursively, passing off to other recognizer X in case of failure. X X The current recognizers are: X X Octal0 0<octal> eg. 0377 = 0xFF X SimpleDecimalString <decimal> eg. 10 = 0xA X Binary0b 0b<binary> eg. 0b011 = 3 X Decimal0d 0d<decimal> eq. 10 = 0xA X Hex0x 0x<hex> eg. 0xA = 10 X ArbitraryRadix <decimalbase>#<radix> eq. 3#22 = 8 X colon60 M:S eg. 1:20 = 80 X colon60colon60 H:M:S eg. 2:1:20 = 7280 X PowersOf2 <real>[KMG] eg. 0.5K = 512 X RealDecimalString <real> eg. 0.5 X Expressions eg. 0.5M-1 X X Expressions currently include: X infix binary: | ^ & << >> + - * / % **(exponent) X prefix unary: - + ~ X midfix grouping: () [] {} X and it is similarly easy to add new notations. X X All number representations and expressions can be intermixed: X [(2M-1)*4]>>0x03 X X There are some functions useful in building other recognizers, like X RadixString(), and the expression building functions. X X There are two top level recognizers, X Dgetnumber(str,res) X and Igetnumber(str,res); X the "I" version is basically a call to the "D" version, which rounds, X and errors if the rounded integer value is more than int_threshold X away from the non-int value. X X These use an internal function X X typedef int (*Recognizer)(); X X int DgetnumberList(str,res,flags,RecognizerList) X char *str; X double *res; X int flags; X Recognizer RecognizerList[]; X X which is called by default with X X Recognizer DefaultRecognizers[] X X An easy way for users to customize these routines is to X create a private list of recognizers, deleting standard recognizers X that are undesired, and adding user coded recognizers that have X not been provided (eg. nnCnnTnnB cylinder/track/block notation) X and then call DgetnumberList() from their own top-level wrapper. X X (Internal detail: a flag controls whether conflicting matches X should be an error or not). X X NOTES: X Initially, this was integer only, but in Jan 89 I changed it X to produce a floating point result - if you want integer, just X integerize. X This will have some lossage if your floating point format X cannot represent all integer values exactly. Sorry - in that X case, you'll just have to go back to the old routine. X It has the advantage of one family of routines being able X to handle intermediate cases - like 0.5M. X It has the advantage of, on a system with decent floating X point, being able to trap on overflow or underflow. X But this is not added. X If you can, use your system dependent way of trapping on inexact. X Interim: if you have IEEE floating point, it would be nice to X have this same routine read in NaNs. X X AUTHOR: X Andy Glew (aglew at uiuc.edu) X X HISTORY: X Originally written by Andy Glew at McGill University, 1983 X X BUGS: X END_OF_FILE if test 5263 -ne `wc -c <'number.man'`; then echo shar: \"'number.man'\" unpacked with wrong size! fi # end of 'number.man' fi if test -f 'test.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'test.c'\" else echo shar: Extracting \"'test.c'\" \(4677 characters\) sed "s/^X//" >'test.c' <<'END_OF_FILE' Xvoid exit(); X Xint verbose = 1; X Xint StopOnError = 1; X Xmain(argc,argv) X int argc; X char **argv; X{ X int aval; X int gval; X int gret; X X if( argc == 1 ) { X AutoTests(); X } X else for(;*++argv;) { X if(0) ; X else if( !strcmp(*argv,"-auto") ) { X AutoTests(); X } X else if( !strcmp(*argv,"-verbose") ) { X verbose = 1; X } X else if( !strcmp(*argv,"-noverbose") ) { X verbose = 0; X } X else if( !strcmp(*argv,"-stoponerror") ) { X StopOnError = 1; X } X else if( !strcmp(*argv,"-nostoponerror") ) { X StopOnError = 0; X } X else if( !strcmp(*argv,"-test") ) { X gret = Igetnumber(argv[1],&gval); X X if( !strcmp(argv[2],"invalid") ) { X if( gret == -1 ) X exit(0); X else { X (void)printf("<%s> <%s> failed - invalid\n",argv[1],argv[2]); X exit(1); X } X } X else { X aval = atoi(argv[2]); X if( gret == -1 ) { X (void)printf("<%s> invalid - should be <%s> %d\n",argv[1],argv[2],aval); X exit(1); X } X else { X if( aval != gval ) { X (void)printf("<%s> %d should be <%s> %d\n", X argv[1],gval,argv[2],aval); X exit(1); X } X else X exit(0); X } X } X } X else { X (void)printf("Unknown argument <%s>\n",*argv); X exit(1); X } X } X exit(0); X /*NOTREACHED*/ X} X Xstruct TestVec { X char *str; X int value; X int valid; X} TV[] = { X { "-100e-2", -1, 1 }, /* Bug JDP1: X found by jdp at tarpon.att.com, X Joseph Pepin - did not malloc X enough space for RHS X */ X { "-111E0A", 0, 0 }, X { "-111E0", -111, 1 }, X { "+121E0", 121, 1 }, X { "100E-2", 1, 1 }, X { "-100E-2", -1, 1 }, X { "+100E-2", 1, 1 }, X { "1E+1", 10, 1 }, X { "1.2E1", 12, 1 }, X { "0.5E6", 500000, 1 }, X { "-111e0A", 0, 0 }, X { "-111e0", -111, 1 }, X { "+121e0", 121, 1 }, X { "100e-2", 1, 1 }, X { "-100e-2", -1, 1 }, X { "+100e-2", 1, 1 }, X { "1e+1", 10, 1 }, X { "1.2e1", 12, 1 }, X { "0.5e6", 500000, 1 }, X { "2**4+1", 17, 1 }, X { "(0xFF>>2)+1", 64, 1 }, X { "(1<<2)+1", 5, 1 }, X { "1<<2+1", 8, 1 }, X /* replicated because of an old stateful error */ X { "-(-(-(-(-(-3)))))", 3, 1 }, X { "-(-(-(-(-(-3)))))", 3, 1 }, X { "-(-(-(-(-(-3)))))", 3, 1 }, X { "[1+(2*3)]*{1+2}", 21, 1 }, X { "1+(2+3)", 6, 1 }, X { "1-1-1", -1, 1 }, X { "(0)", 0, 1 }, X { "(1K)+1", 1025, 1 }, X { "2*(1K)+1", 2049, 1 }, X { "2*(2K+1)+(2M/1K)", 6146, 1 }, X { "(0)", 0, 1 }, X { "(0)", 0, 1 }, X { "0b0000", 0, 1 }, X { "0b11", 3, 1 }, X { "-0b101", -5, 1 }, X { "-5K", -5120, 1 }, X { "0.5K", 512, 1 }, X { "13M", 13631488, 1 }, X { "1G", 1073741824, 1 }, X { "1:20", 80, 1 }, X { "2:1:20", 7280, 1 }, X { "I-0b101", 0, 0 }, X { "10.3", 0, 0 }, X { "x0", 0, 0 }, X { "0x", 0, 0 }, X { "-1-", 0, 0 }, X { "-1+", 0, 0 }, X { "-", 0, 0 }, X { "+", 0, 0 }, X { "-4+1", -3, 1 }, X { "-4*-3", 12, 1 }, X { "4*-3", -12, 1 }, X { "-4*3", -12, 1 }, X { 0, 0 } X}; X XAutoTests() X{ X int i; X struct TestVec *tv; X X for( tv=TV; tv->str; tv++ ) { X int val; X if( Igetnumber(tv->str,&val) == -1 ) { X if( tv->valid ) { X (void)printf("Error: <%s> invalid, should be %d\n", X tv->str, tv->value ); X if( StopOnError ) { X exit(1); X } X } X else { X if( verbose ) (void)printf("Passed: <%s> invalid\n",tv->str); X } X } X else { X if( tv->valid ) { X if( val != tv->value ) { X (void)printf("Error: <%s> %d, should be %d\n", X tv->str, val, tv->value ); X if( StopOnError ) { X exit(1); X } X } X else { X if( verbose ) (void)printf("Passed: <%s> %d\n", tv->str, val); X } X } X else { X (void)printf("Error: <%s> %d, should be invalid\n", X tv->str, val ); X if( StopOnError ) { X exit(1); X } X } X } X } X X X for(i=0;i<100;i++) X TestAllPatterns(i); X for(i=132;i<1000000000;i+=12331) X TestAllPatterns(i); X X} X XTestAllPatterns(i) X{ X TestFormat(i,"%d"); X TestFormat(i,"0%o"); X TestFormat(i,"0x%x"); X TestFormat(i,"0d%d"); X} XTestFormat(i,fstr) X int i; X char *fstr; X{ X char buf[128]; X X /* With no sign */ X (void)sprintf(buf+1,fstr,i); X TestBufferValue(buf+1,i); X /* With sign */ X buf[0]='+'; X TestBufferValue(buf,i); X buf[0]='-'; X TestBufferValue(buf,-i); X} XTestBufferValue(buf,i) X char *buf; X int i; X{ X int val; X if( Igetnumber(buf,&val) == -1 ) { X (void)printf("error - <%s> invalid, should be %d\n",buf,i); X if( StopOnError ) { X exit(1); X } X } X else if( val != i ) { X (void)printf("error - <%s> %d, should be %d\n",buf,val,i); X if( StopOnError ) { X exit(1); X } X } else { X if( verbose ) (void)printf("Passed: <%s> %d\n",buf,i); X } X} X X X END_OF_FILE if test 4677 -ne `wc -c <'test.c'`; then echo shar: \"'test.c'\" unpacked with wrong size! fi # end of 'test.c' fi echo shar: End of shell archive. exit 0 -- Andy Glew, aglew at uiuc.edu From joe at dayton.UUCP Fri Jan 12 09:32:22 1990 From: joe at dayton.UUCP (Joseph P. Larson) Date: 11 Jan 90 22:32:22 GMT Subject: Pcal: postscript/c calendar printer Message-ID: <6914@dayton.UUCP> (This is an enhanced and repaired version of a program by the same name posted by Ken Keirnan last summer or so.) This is "pcal", a program that lets you print a monthly calendar complete with text taken from a calendar file. See the two ReadMe files and the man page for more information. -Joe #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # Makefile # ReadMe # ReadMe.orig # pcal.c # pcal.man # This archive created: Thu Jan 11 16:22:36 1990 export PATH; PATH=/bin:/usr/bin:$PATH if test -f 'Makefile' then echo shar: "will not over-write existing file 'Makefile'" else cat << \SHAR_EOF > 'Makefile' # # Normally the day numbers for Saturday and Sunday are printed in gray # instead of black. If you want only Sundays in gray, uncomment the # following line. # # COPTS = -DSATBLK MANDIR=/usr1/jad/man pcal: pcal.c $(CC) $(CFLAGS) $(LDFLAGS) $(COPTS) -o pcal pcal.c man: pcal.man nroff -man pcal.man > pcal.1 pack pcal.1 mv pcal.1.z $(MANDIR) SHAR_EOF fi if test -f 'ReadMe' then echo shar: "will not over-write existing file 'ReadMe'" else cat << \SHAR_EOF > 'ReadMe' This is pcal as posted some time ago. However, the "for" loops didn't always use their arguments. I found this when I tried to allow a full-year to be dumped at once. I'd get through 3 months and *wham*: stack overflow. Surprise! Anyways, I put in a couple of pop's, modified the command line a little and hopefully, the man page enough, and here it is. The accompanying file called "ReadMe.orig" came with the original distribution as README and states this program is copyrighted but with permission to modify and redistribute. Note: if I had the time, I'd pull the PostScript code back out of the program and include a PS prolog file; as is, this is ugly and a little more difficult to modify. Ah well. It may be easier sometimes to include log prolog inside the C program, but it's an awful lot easier to modify the prolog when it's a separate file. Whatever. -Joe SHAR_EOF fi if test -f 'ReadMe.orig' then echo shar: "will not over-write existing file 'ReadMe.orig'" else cat << \SHAR_EOF > 'ReadMe.orig' "Pcal" is a program to print PostScript calendars for any month and year. By default, it looks for a file in the home directory named "calendar" for entries with leading dates matching dates on the calendar, and prints any following text under the appropriate day. The program may be a little System V flavored (getopt, time routines) but should be easily portable to other vintages of UNIX. Pcal is the combined effort of several people, most notably Patrick Wood of Pipeline Associates, Inc. for the original PostScript code and Bill Vogel of AT&T for the calendar file mechanism. My part was simple translation to a "C" program, the addition of a couple options and a more generalized date searching routine (oh yes, and a manual page :-). The original calendar PostScript was Copyright (c) 1987 by Patrick Wood and Pipeline Associates, Inc. with permission to modify and redistribute. Please retain this README file with the package. Ken Keirnan Pacific Bell San Ramon, CA. SHAR_EOF fi if test -f 'pcal.c' then echo shar: "will not over-write existing file 'pcal.c'" else cat << \SHAR_EOF > 'pcal.c' #include <stdio.h> #include <ctype.h> #include <time.h> #include <string.h> #define PRT (void)printf #define FPR (void)fprintf char *words[100]; /* maximum number of words on a line */ char lbuf[512]; /* maximum line size */ char *months[] = { /* used to match alpha months */ "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec", (char *)0, }; /* * pheader - provides the PostScript routines */ char *pheader[] = { "%!", "/titlefont /Times-Bold def", "/dayfont /Helvetica-Bold def", "/month_names [ (January) (February) (March) (April) (May) (June) (July)", "\t\t(August) (September) (October) (November) (December) ] def", "/prtnum { 3 string cvs show} def", "/drawgrid {\t\t% draw calendar boxes", "\tdayfont findfont 10 scalefont setfont", "\t0 1 6 {", "\t\tdup dup 100 mul 40 moveto", "\t\t[ (Sunday) (Monday) (Tuesday) (Wednesday) (Thursday) (Friday) (Saturday) ] exch get", "\t\t100 center", "\t\t100 mul 35 moveto", "\t\t1.0 setlinewidth", "\t\t0 1 5 {", "\t\t\tgsave", "\t\t\t100 0 rlineto ", "\t\t\t0 -80 rlineto", "\t\t\t-100 0 rlineto", "\t\t\tclosepath stroke", "\t\t\tgrestore", "\t\t\t0 -80 rmoveto", "\t\t pop } for", "\t} for", "} def", "/drawnums {\t\t% place day numbers on calendar", "\tdayfont findfont 30 scalefont setfont", "\t/start startday def", "\t/days ndays def", "\tstart 100 mul 5 add 10 rmoveto", "\t1 1 days {", "\t\t/day exch def", "\t\tgsave", #ifndef SATBLK "\t\tday start add 7 mod 0 eq", "\t\t{", "\t\t\tsubmonth 0 eq", "\t\t\t{", "\t\t\t\t.8 setgray", "\t\t\t} if", "\t\t} if", #endif "\t\tday start add 7 mod 1 eq", "\t\t{", "\t\t\tsubmonth 0 eq", "\t\t\t{", "\t\t\t\t.8 setgray", "\t\t\t} if", "\t\t} if", "\t\tday prtnum", "\t\tgrestore", "\t\tday start add 7 mod 0 eq", "\t\t{", "\t\t\tcurrentpoint exch pop 80 sub 5 exch moveto", "\t\t}", "\t\t{", "\t\t\t100 0 rmoveto", "\t\t} ifelse", "\t} for", "} def", "/drawfill {\t\t% place fill squares on calendar", "\t/start startday def", "\t/days ndays def", "\t0 35 rmoveto", "\t1.0 setlinewidth", "\t0 1 start 1 sub {", "\t\tgsave", "\t\t.9 setgray", "\t\t100 0 rlineto ", "\t\t0 -80 rlineto", "\t\t-100 0 rlineto", "\t\tclosepath fill", "\t\tgrestore", "\t\t100 0 rmoveto", "\tpop } for", "\tsubmonth 1 eq", "\t{", "\t\t/lastday 42 def", "\t\t600 -365 moveto", "\t}", "\t{", "\t\t/lastday 40 def", "\t\t400 -365 moveto", "\t} ifelse", "\tlastday -1 ndays start 1 add add", "\t{", "\t\t/day exch def", "\t\tgsave", "\t\t.9 setgray", "\t\t100 0 rlineto ", "\t\t0 -80 rlineto", "\t\t-100 0 rlineto", "\t\tclosepath fill", "\t\tgrestore", "\t\tday 7 mod 1 eq", "\t\t{", "\t\t\t600 -365 80 add moveto", "\t\t}", "\t\t{", "\t\t\t-100 0 rmoveto", "\t\t} ifelse", "\t} for", "} def", "/isleap {\t\t% is this a leap year?", "\tyear 4 mod 0 eq\t\t% multiple of 4", "\tyear 100 mod 0 ne \t% not century", "\tyear 1000 mod 0 eq or and\t% unless it's a millenia", "} def", "/days_month [ 31 28 31 30 31 30 31 31 30 31 30 31 ] def", "/ndays {\t\t% number of days in this month", "\tdays_month month 1 sub get", "\tmonth 2 eq\t% Feb", "\tisleap and", "\t{", "\t\t1 add", "\t} if", "} def", "/startday {\t\t% starting day-of-week for this month", "\t/off year 2000 sub def\t% offset from start of epoch", "\toff", "\toff 4 idiv add\t\t% number of leap years", "\toff 100 idiv sub\t% number of centuries", "\toff 1000 idiv add\t% number of millenia", "\t6 add 7 mod 7 add \t% offset from Jan 1 2000", "\t/off exch def", "\t1 1 month 1 sub {", "\t\t/idx exch def", "\t\tdays_month idx 1 sub get", "\t\tidx 2 eq", "\t\tisleap and", "\t\t{", "\t\t\t1 add", "\t\t} if", "\t\t/off exch off add def", "\t} for", "\toff 7 mod\t\t% 0--Sunday, 1--monday, etc.", "} def", "/center {\t\t% center string in given width", "\t/width exch def", "\t/str exch def width str ", "\tstringwidth pop sub 2 div 0 rmoveto str show", "} def", "/calendar", "{", "\ttitlefont findfont 48 scalefont setfont", "\t0 60 moveto", "\t/month_name month_names month 1 sub get def", "\tmonth_name show", "\t/yearstring year 10 string cvs def", "\t700 yearstring stringwidth pop sub 60 moveto", "\tyearstring show", "\t0 0 moveto", "\tdrawnums", "\t0 0 moveto", "\tdrawfill", "\t0 0 moveto", "\tdrawgrid", "} def", "/daytext {", "\t/Helvetica-Narrow findfont 6 scalefont setfont", "\t/mytext\texch def /myday exch def", "\tstartday myday 1 sub add dup 7 mod 100 mul 5 add % gives column", "\texch 7 idiv -80 mul % gives row", "\tdup /ypos exch def moveto", "\t/LM currentpoint pop def /RM LM 95 add def", " mytext { dup (.p) eq { crlf pop} {prstr ( ) show} ifelse } forall", "} def", "/crlf {", " ypos 8 sub /ypos exch def LM ypos moveto", "} def", "/prstr {", " dup stringwidth pop currentpoint pop", " add RM gt {crlf} if show", "} def", "/printmonth {", "\t90 rotate", "\t50 -120 translate", "\t/submonth 0 def", "\tcalendar", "\tmonth 1 sub 0 eq", "\t{", "\t\t/lmonth 12 def", "\t\t/lyear year 1 sub def", "\t}", "\t{", "\t\t/lmonth month 1 sub def", "\t\t/lyear year def", "\t} ifelse", "\tmonth 1 add 13 eq", "\t{", "\t\t/nmonth 1 def", "\t\t/nyear year 1 add def", "\t} ", "\t{", "\t\t/nmonth month 1 add def", "\t\t/nyear year def", "\t} ifelse", "\t/savemonth month def", "\t/saveyear year def", "\t/submonth 1 def", "\t/year lyear def", "\t/month lmonth def", "\tgsave", "\t500 -365 translate", "\tgsave", "\t.138 .138 scale", "\t10 -120 translate", "\tcalendar", "\tgrestore", "\t/submonth 1 def", "\t/year nyear def", "\t/month nmonth def", "\t100 0 translate", "\tgsave", "\t.138 .138 scale", "\t10 -120 translate", "\tcalendar", "\tgrestore", "\t/month savemonth def", "\t/year saveyear def", "\t/submonth 0 def", "\tgrestore", "} def", (char *)0, }; FILE *cfp = NULL; int year; int cyear; void exit(); char *getenv(); main(argc, argv) int argc; char **argv; { extern char *optarg; extern int optind; register struct tm *lt; register char **ap; register char *cp; char *cfile = NULL; char cbuf[80]; long t, time(); int errflg = 0; int nocal = 0; int m; int month; char doyear = 0; while ((m = getopt(argc, argv, "ef:m:y:")) != EOF) switch (m) { case 'e': nocal++; cfile = NULL; break; case 'f': cfile = optarg; nocal = 0; break; case 'm': month = atoi(month); if (!month) doyear = 1; break; case 'y': year = atoi(optarg); if (year < 1900) year = year % 100 + 1900; break; case '?': errflg = 1; break; } if (errflg) { FPR(stderr, "Usage: pcal [ -e | -f <cal> ] [ -m month] [ -y <year> ]\n"); exit(1); } t = time((long *)0); lt = localtime(&t); if (!month && !doyear) m = lt->tm_mon + 1; if (!year) year = lt->tm_year + 1900; /* * In case we don't encounter any year data in the * calendar file, assume the current year. */ cyear = year; /* * Open a supplied calendar file (if any) */ if (cfile != NULL) { if ((cfp = fopen(cfile, "r")) == NULL) { FPR(stderr, "pcal: can't open file: %s\n", cfile); exit(1); } } /* * Else see if a calendar file exists in the home directory */ else if (nocal == 0 && (cp = getenv("HOME")) != NULL) { (void)strcpy(cbuf, cp); (void)strcat(cbuf, "/calendar"); cfp = fopen(cbuf, "r"); } /* * Write out PostScript prolog */ for (ap = pheader; *ap; ap++) PRT("%s\n", *ap); if (month) pmonth(month); else for (month = 1; month <= 12; month++) pmonth(month); return(0); } /* * pmonth - do calendar for month "m" */ pmonth(m) int m; { register char **s; register oldday = -1; register day; /* * Do the calendar */ PRT("/year %d def\n", year); PRT("/month %d def\n", m); PRT("printmonth\n"); /* * Browse through the calendar file looking for day info */ if ((day = getday(m)) == 0) { /* no info */ PRT("showpage\n"); return; } do { if (day != oldday) { if (oldday == -1) PRT("%d [ \n", day); else PRT(" ] daytext %d [ \n", day); oldday = day; } else PRT("(.p)\n"); for (s = words; *s; s++) PRT("(%s)\n", *s); } while (day = getday(m)); PRT("] daytext\n"); PRT("showpage\n"); } /* * getday - find next day entry for desired month in the calendar file */ getday(m) register m; { static mon = 0; static eof = 0; register char *cp; register c; if (cfp == NULL) /* whoops, no calendar file */ return(0); if (m != mon) { /* new month, rewind */ rewind(cfp); eof = 0; mon = m; } if (eof) return(0); nextline: cp = lbuf; do { while ((c = getc(cfp)) != '\n' && c != EOF) { /* ignore leading white space */ if (cp == lbuf && (c == ' ' || c == '\t')) continue; *cp++ = c; } if (c == EOF) { eof = 1; return(0); } } while (cp == lbuf); /* ignore empty lines */ *cp = 0; /* examine the line, see if its one we want */ if ((c = parse(m)) == 0) goto nextline; return(c); } /* * parse - check calendar entry for desired month, break line into fields */ parse(m) register m; { register char *cp; register i; cp = strtok(lbuf, " \t"); /* get first field */ while (*cp) { if (isupper(*cp)) *cp = tolower(*cp); cp++; } cp = lbuf; /* * Check for "year" line */ if (strcmp(cp, "year") == 0) { cp = strtok((char *)0, " \t"); if ((i = atoi(cp)) > 0) { if (i < 100) i += 1900; cyear = i; } return(0); } /* * If field begins with alpha, try to decode month name */ if (isalpha(*cp)) { if (cyear != year) return(0); for (i = 0; months[i]; i++) if (strncmp(cp, months[i], 3) == 0) { if (++i != m) return(0); /* month found, get day */ if ((cp = strtok((char *)0, " \t")) == NULL) return(0); if ((i = atoi(cp)) < 1 || i > 31) return(0); if (loadwords()) return(i); return(0); } return(0); } /* * Not alpha month, try numeric */ if ((i = atoi(cp)) != m) return(0); while (isdigit(*cp)) cp++; while (*cp && !isdigit(*cp)) cp++; /* now get day */ if ((i = atoi(cp)) < 1 || i > 31) return(0); /* Numeric dates may have a year */ while (isdigit(*cp)) cp++; while (*cp && !isdigit(*cp)) cp++; if ((m = atoi(cp)) > 0) { if (m < 100) m += 1900; cyear = m; } if (cyear != year) return(0); if (loadwords()) return(i); return(0); } /* * loadwords - tokenize line buffer into word array */ loadwords() { register char **ap = words, *c; register i; for (i = 0; *ap = strtok((char *)0, " \t") ; ap++, i++); /* { if ((*ap = strtok((char *)0, " \t")) == NULL) break; while ((c = strpbrk(*ap, "()")) != NULL) { if (c != *ap) ap++; if (*c == '(') *ap = "\\("; else *ap = "\\)"; *c = 0; c++; if (*c) *(++ap) = c; } } */ return(i); } SHAR_EOF fi if test -f 'pcal.man' then echo shar: "will not over-write existing file 'pcal.man'" else cat << \SHAR_EOF > 'pcal.man' .TH PCAL 1 .SH NAME pcal \- generate PostScript calendars .SH SYNOPSIS .B pcal [ .BR \-e | .BR \-f <cal> ] [ .B \-m <month> [ .B \-y <year> ]] .SH DESCRIPTION .I Pcal generates PostScript to produce landscape calendars for any month and year. The arguments .B <month> and .BR <year> , if provided, should be numeric. The month should be in the range 1 - 12, and year should be specified as 1 or 2 digits or as the full 4 digit year. The defaults for month and year are the current month and year. If month is provided, but zero, the entire year is printed. .P If a file named .I calendar resides in the callers home directory, it will be searched for lines with leading dates matching the requested month and year (current by default). Any text following the date will be printed on the calendar under the appropriate day of the month. Dates in the .I calendar file may consist of a numeric or alpha month (at least the first 3 characters for month names) followed by a numeric day and optionally followed by a year. Any non-numeric character may separate numeric dates. Lines in the .I calendar file consisting of "year xxxx" (where xxxx is a numeric year) can be used to set the year for following entries. This assumes that the following entries do not contain a year. Any date entries containing year information will set the remembered year to that year. .P .I Pcal has two options: .P .TP .B \-e Print an empty calendar. Do not print entries from a calendar file. .TP .BR \-f <cal> Directs .I pcal to use the file name <cal> as the input file in place of the default calendar file in the callers home directory. .SH SEE ALSO cal(1) .SH CAVEATS The original PostScript code to generate the calendars was written by Patrick Wood (Copywrite (c) 1987 by Patrick Wood of Pipeline Associates, Inc.), and authorized for modification and redistribution. The calendar file inclusion code was originally written in "bs(1)" by Bill Vogel of AT&T. Patricks original PostScript was modified and enhanced several times by others whos names have regrettably been lost. I am responsible for assembling this "C" version, but the lion's share of the work was done by others. .sp Ken Keirnan .br Pacific Bell .br San Ramon, CA. SHAR_EOF fi exit 0 # End of shell archive -- UUCP: rutgers!dayton!joe (Picts 1-16 are DHDSC - Joe Larson/MIS 1060 ATT : (612) 375-3537 now ready.) 700 on the Mall, Mpls, Mn. 55402 From bjaspan at athena.mit.edu Tue Jan 16 12:41:31 1990 From: bjaspan at athena.mit.edu (Barr3y Jaspan) Date: 16 Jan 90 01:41:31 GMT Subject: A Dynamic Object library for C Message-ID: <1990Jan16.014131.18734@athena.mit.edu> The following is a library that implements "dynamic objects" in C. A dynamic object is basically an array that resizes itself automatically as elements are added to it (thus freeing the programmer from having to deal with it). It is similar the GNU's opstack code, except my library isn't covered by the gnu license. The code is not complicated, and you could probably hit ten people with a rope on a crowded street that could have written it as well. However, I actually got around to doing it right and testing and documenting it. #! /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 archive 1 (of 1)." # Contents: Makefile README dyn.h dyn.man dynP.h dyn_create.c # dyn_debug.c dyn_delete.c dyn_put.c dyn_size.c test.c # Wrapped by bjaspan at steve-dallas on Mon Jan 15 19:17:43 1990 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Makefile'\" else echo shar: Extracting \"'Makefile'\" \(804 characters\) sed "s/^X//" >'Makefile' <<'END_OF_FILE' X# This file is part of libdyn.a, the C Dynamic Object library. It X# contains the Makefile. X# X# There are no restrictions on this code; however, if you make any X# changes, I request that you document them so that I do not get X# credit or blame for your modifications. X# X# Written by Barr3y Jaspan, Student Information Processing Board (SIPB) X# and MIT-Project Athena, 1989. X XCC = cc XCFLAGS = -O XLDFLAGS = XDEST = libdyn.a X XSRCS = dyn_create.c dyn_put.c dyn_debug.c dyn_delete.c dyn_size.c XOBJS = dyn_create.o dyn_put.o dyn_debug.o dyn_delete.o dyn_size.o XHDRS = dyn.h dynP.h X Xall: $(DEST) X X$(DEST): $(OBJS) X rm -f $(DEST) X ar rc $(DEST) $(OBJS) X ranlib $(DEST) X Xclean: X rm -f $(OBJS) $(DEST) *~ X Xdepend: X makedepend -- $(CLFAGS) -- $(HDRS) $(SRCS) X X# DO NOT DELETE THIS LINE -- make depend depends on it. END_OF_FILE if test 804 -ne `wc -c <'Makefile'`; then echo shar: \"'Makefile'\" unpacked with wrong size! fi # end of 'Makefile' fi if test -f 'README' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'README'\" else echo shar: Extracting \"'README'\" \(1376 characters\) sed "s/^X//" >'README' <<'END_OF_FILE' XA C Dynamic Object is an array that takes care of resizing itself as Xelements are added and deleted from it. It can be of any type for Xwhich sizeof is defined and for which an address of a variable of that Xtype can be passed to a function. X XTo build libdyn.a, simply type "make depend all" (if you don't have Xthe program makedepend, of course, leave out the "depend" part). If Xyour system's bcopy() cannot handle left-copying overlapping regions, Xadd -DLOCAL_BCOPY to the CFLAGS macro in the Makefile. (Look at the Xsource code for dyn_delete.c if you don't understand that.) X XThe library should compile and work without modification on a vast Xnumber of systems. It only uses 5 external functions: malloc, Xrealloc, free, bcopy, and fprintf (to stderr). Of these, only bcopy Xshould need to be changed for other systems (such as MS-DOS) and it Xcould probably be done with a -D flag to the compiler. X XTo build the test/demo program, do "cc -L. -o test test.c -ldyn". XThis program produces the library's debugging output (to stderr) as Xwell as some of its own output (to stdout). X XThe library has been tested (with test.c) on a VAX VSII, VAXstation X3100, DECstation 3100, and IBM RT all running BSD4.3 (except for the XDECstation, which was running (Ultrix V2.1). X XBarr3y Jaspan, Student Information Processing Board (SIPB) and XMIT-Project Athena, bjaspan at athena.mit.edu, 1989 END_OF_FILE if test 1376 -ne `wc -c <'README'`; then echo shar: \"'README'\" unpacked with wrong size! fi # end of 'README' fi if test -f 'dyn.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'dyn.h'\" else echo shar: Extracting \"'dyn.h'\" \(949 characters\) sed "s/^X//" >'dyn.h' <<'END_OF_FILE' X/* X * This file is part of libdyn.a, the C Dynamic Object library. It X * contains the public header file. X * X * There are no restrictions on this code; however, if you make any X * changes, I request that you document them so that I do not get X * credit or blame for your modifications. X * X * Written by Barr3y Jaspan, Student Information Processing Board (SIPB) X * and MIT-Project Athena, 1989. X */ X X X/* X * dyn.h -- header file to be included by programs linking against X * libdyn.a. X */ X X#ifndef _Dyn_h X#define _Dyn_h X Xtypedef struct _DynObject DynObjectRec, *DynObject; X X/* Function macros */ X#define DynHigh(obj) (DynSize(obj) - 1) X#define DynLow(obj) (0) X X/* Return status codes */ X#define DYN_OK -1000 X#define DYN_NOMEM -1001 X#define DYN_BADINDEX -1002 X X/* Function declarations */ XDynObject DynCreate(); Xint DynAdd(), DynDelete(), DynDestroy(), DynDebug(); Xchar *DynGet(); X X#endif /* _Dyn_h */ X/* DO NOT ADD ANYTHING AFTER THIS #endif */ END_OF_FILE if test 949 -ne `wc -c <'dyn.h'`; then echo shar: \"'dyn.h'\" unpacked with wrong size! fi # end of 'dyn.h' fi if test -f 'dyn.man' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'dyn.man'\" else echo shar: Extracting \"'dyn.man'\" \(4567 characters\) sed "s/^X//" >'dyn.man' <<'END_OF_FILE' X.TH DYN 3M "22 October 1989" X X.SH NAME Xdyn \- the C Dynamic Object library X X.SH DESCRIPTION X XA C Dynamic Object is an array that takes care of resizing Xitself as you add and delete elements from it. It can be of any type Xfor which sizeof is defined and for which an address of a variable of Xthat type can be passed to a function. The library containing the Xfunctions described below is called X.IR libdyn.a , Xand the necessary declarations to use them are in X.RI < dyn.h >. X.PP XA DynObject is actually a structure that contains an array and a Xcouple of integers to maintain necessary state information. When a XDyn function is said to operate on "the object" or "the array", it is Xoperating on the array stored in the structure while at the same time Xupdating internal state information. X X.SH LIST OF FUNCTIONS X.nf XDynObject DynCreate(size, increment) X int size, increment; X.fi X.PP X.IR Requires : X.I size Xand X.I increment Xare greater than zero. X.PP X.IR Effects : XCreates a new DynObject that will store elements of size X.I size Xand will allocate memory in blocks large enough to hold exactly X.I increment Xelements. For example, if you are storing 8-byte double Xprecision numbers and X.I increment Xis 5, each 5th element you add to the object will cause it to request X40 more bytes (8 * 5) from the operating system. If X.I increment Xis zero, a default value is used (currently 100). This is the only Xtime the programmer deals with a dynamic object's memory allocation. X.PP X.IR Returns : X.B DynCreate Xreturns the new DynObject, or NULL if there is insufficient memory. X.PP X.nf Xint DynDestroy(obj) X DynObject obj; X.fi X.PP X.IR Modifies : Xobj X.PP X.IR Effects : XFrees all memory associated with X.IR obj . XThe results of calling any Dyn function on a destroyed object are Xundefined (except for DynCreate, which resets the object). X.PP X.IR Returns : X.B DynDestroy Xreturns DYN_OK. X.PP X.nf Xint DynAdd(obj, el) X DynObject obj; X char *el; X.fi X.PP X.IR Modifies : Xobj X.PP X.IR Effects : XAdds the element pointed to by X.I el Xto the object X.IR obj , Xresizing the object if necessary. XThe new element becomes the last element in obj's array. X.PP X.IR Returns : X.B DynAdd Xreturns DYN_OK on success or DYN_NOMEM if there is insufficient Xmemory. X.PP X.nf Xint DynGet(obj, index) X DynObject obj; X int index; X.fi X.PP X.IR Effects : XReturns the address of the element X.I index Xin the array of X.IR obj . XThis pointer can be treated as a normal array of the type specified to X.BR DynCreate . XThe order of elements in this array is the order in which they were Xadded to the object. The returned pointer is guaranteed to be valid Xonly until obj is modified. X.PP X.IR Returns : X.B DynGet Xreturns NULL if X.I index Xis larger than the number of elements in the array of less than zero. X.PP X.nf Xint DynDelete(obj, index) X DynObject obj; X int index; X.fi X.PP X.IR Modifies : Xobj X.PP X.IR Effects : XThe element X.I index Xis deleted from the object X.IR obj . XNote that the element is actually removed permanently from the array. XIf you have the array "1 2 3 4 5" and delete the third element, you Xwill have the array "1 2 4 5". The order of elements in not affected. X.PP X.IR Returns : X.B DynDelete Xwill return DYN_OK on success or DYN_BADINDEX if the element X.I index Xdoes not exist in the array or is less than zero. X.PP X.nf Xint DynSize(obj) X DynObject obj; X.fi X.PP X.IR Effects : XReturns the number of elements in the object X.IR obj . X.PP X.nf Xint DynHigh(obj) X DynObject obj; X.fi X.PP X.IR Effects : XReturns the index of the highest element in the object X.IR obj . XIn this version, X.B DynHigh Xis macro that expands to X.B DynSize X- 1. X.PP X.nf Xint DynLow(obj) X DynObject obj; X.fi X.PP X.IR Effects : XReturns the index of the lowest element in the object X.IR obj . XIn this version, X.B DynLow Xis macro that expands to 0. X.PP X.nf Xint DynDebug(obj, state) X DynObject obj; X int state; X.fi X.PP X.IR Modifies : Xobj X.PP X.IR Effects : XSets the debugging state of X.I obj Xto X.I state Xand prints a message on stderr saying what state debugging was set to. XAny non-zero value for X.I state Xturns debugging ``on''. When debugging is on, all Dyn functions will Xproduce (hopefully useful) output describing what is going on on Xstderr. X.PP X.IR Returns : X.B DynDebug Xreturns DYN_OK. X.SH BUGS XDynGet should return DYN_BADINDEX instead of NULL but since it can Xalso return a pointer.. X.PP XThe entire library should work in terms of void * instead of char *, Xbut some compilers don't understand the ANSI types. X.SH AUTHOR XBarr3y Jaspan, Student Information Processing Board (SIPB) and XMIT-Project Athena, bjaspan at athena.mit.edu END_OF_FILE if test 4567 -ne `wc -c <'dyn.man'`; then echo shar: \"'dyn.man'\" unpacked with wrong size! fi # end of 'dyn.man' fi if test -f 'dynP.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'dynP.h'\" else echo shar: Extracting \"'dynP.h'\" \(744 characters\) sed "s/^X//" >'dynP.h' <<'END_OF_FILE' X/* X * This file is part of libdyn.a, the C Dynamic Object library. It X * contains the private header file. X * X * There are no restrictions on this code; however, if you make any X * changes, I request that you document them so that I do not get X * credit or blame for your modifications. X * X * Written by Barr3y Jaspan, Student Information Processing Board (SIPB) X * and MIT-Project Athena, 1989. X */ X X X/* X * dynP.h -- private header file included by source files for libdyn.a. X */ X X#ifndef _DynP_h X#define _DynP_h X X#include "dyn.h" X X#define ARRAY char * X Xtypedef struct _DynObject { X ARRAY array; X int el_size, num_el, size, inc, debug; X} Int_DynObjectRec, *Int_DynObject; X X#endif /* _DynP_h */ X/* DON'T ADD STUFF AFTER THIS #endif */ END_OF_FILE if test 744 -ne `wc -c <'dynP.h'`; then echo shar: \"'dynP.h'\" unpacked with wrong size! fi # end of 'dynP.h' fi if test -f 'dyn_create.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'dyn_create.c'\" else echo shar: Extracting \"'dyn_create.c'\" \(1057 characters\) sed "s/^X//" >'dyn_create.c' <<'END_OF_FILE' X/* X * This file is part of libdyn.a, the C Dynamic Object library. It X * contains the source code for the functions DynCreate() and X * DynDestroy(). X * X * There are no restrictions on this code; however, if you make any X * changes, I request that you document them so that I do not get X * credit or blame for your modifications. X * X * Written by Barr3y Jaspan, Student Information Processing Board (SIPB) X * and MIT-Project Athena, 1989. X */ X X#include <stdio.h> X X#include "dynP.h" X X#ifndef DEFAULT_INC X#define DEFAULT_INC 100 X#endif X Xstatic int default_increment = DEFAULT_INC; X XInt_DynObject DynCreate(el_size, inc) X int el_size, inc; X{ X Int_DynObject obj; X X obj = (Int_DynObject) malloc(sizeof(Int_DynObjectRec)); X if (obj == NULL) X return NULL; X X obj->array = (ARRAY) malloc(0); X obj->el_size = el_size; X obj->num_el = obj->size = obj->debug = 0; X obj->inc = (!! inc) ? inc : default_increment; X X return obj; X} X Xint DynDestroy(obj) X Int_DynObject obj; X{ X free(obj->array); X free(obj); X return DYN_OK; X} END_OF_FILE if test 1057 -ne `wc -c <'dyn_create.c'`; then echo shar: \"'dyn_create.c'\" unpacked with wrong size! fi # end of 'dyn_create.c' fi if test -f 'dyn_debug.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'dyn_debug.c'\" else echo shar: Extracting \"'dyn_debug.c'\" \(643 characters\) sed "s/^X//" >'dyn_debug.c' <<'END_OF_FILE' X/* X * This file is part of libdyn.a, the C Dynamic Object library. It X * contains the source code for the function DynDebug(). X * X * There are no restrictions on this code; however, if you make any X * changes, I request that you document them so that I do not get X * credit or blame for your modifications. X * X * Written by Barr3y Jaspan, Student Information Processing Board (SIPB) X * and MIT-Project Athena, 1989. X */ X X#include <stdio.h> X X#include "dynP.h" X Xint DynDebug(obj, state) X Int_DynObject obj; X int state; X{ X obj->debug = state; X X fprintf(stderr, "dyn: debug: Debug state set to %d.\n", state); X return DYN_OK; X} END_OF_FILE if test 643 -ne `wc -c <'dyn_debug.c'`; then echo shar: \"'dyn_debug.c'\" unpacked with wrong size! fi # end of 'dyn_debug.c' fi if test -f 'dyn_delete.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'dyn_delete.c'\" else echo shar: Extracting \"'dyn_delete.c'\" \(1595 characters\) sed "s/^X//" >'dyn_delete.c' <<'END_OF_FILE' X/* X * This file is part of libdyn.a, the C Dynamic Object library. It X * contains the source code for the function DynDelete(). X * X * There are no restrictions on this code; however, if you make any X * changes, I request that you document them so that I do not get X * credit or blame for your modifications. X * X * Written by Barr3y Jaspan, Student Information Processing Board (SIPB) X * and MIT-Project Athena, 1989. X */ X X#include <stdio.h> X X#include "dynP.h" X X#ifdef LOCAL_BCOPY Xstatic bcopy(src, dst, length) X char *src, *dest; X int length; X{ X while (length--) X *dst++ = *src++; X} X#endif X Xint DynDelete(obj, index) X Int_DynObject obj; X int index; X{ X if (index < 0) { X if (obj->debug) X fprintf(stderr, "dyn: delete: bad index %d\n", index); X return DYN_BADINDEX; X } X X if (index >= obj->num_el) { X if (obj->debug) X fprintf(stderr, "dyn: delete: Highest index is %d.\n", X obj->num_el); X return DYN_BADINDEX; X } X X if (index == obj->num_el-1) { X if (obj->debug) X fprintf(stderr, "dyn: delete: last element, doing nothing.\n"); X } X else { X if (obj->debug) X fprintf(stderr, X "dyn: delete: copying %d bytes from %d + %d to + %d.\n", X obj->el_size*(obj->num_el - index), obj->array, X (index+1)*obj->el_size, index*obj->el_size); X X bcopy(obj->array + (index+1)*obj->el_size, X obj->array + index*obj->el_size, X obj->el_size*(obj->num_el - index)); X } X X --obj->num_el; X X if (obj->debug) X fprintf(stderr, "dyn: delete: done.\n"); X X return DYN_OK; X} END_OF_FILE if test 1595 -ne `wc -c <'dyn_delete.c'`; then echo shar: \"'dyn_delete.c'\" unpacked with wrong size! fi # end of 'dyn_delete.c' fi if test -f 'dyn_put.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'dyn_put.c'\" else echo shar: Extracting \"'dyn_put.c'\" \(2680 characters\) sed "s/^X//" >'dyn_put.c' <<'END_OF_FILE' X/* X * This file is part of libdyn.a, the C Dynamic Object library. It X * contains the source code for the functions DynGet() and DynAdd(). X * X * There are no restrictions on this code; however, if you make any X * changes, I request that you document them so that I do not get X * credit or blame for your modifications. X * X * Written by Barr3y Jaspan, Student Information Processing Board (SIPB) X * and MIT-Project Athena, 1989. X */ X X#include <stdio.h> X X#include "dynP.h" X Xstatic int _DynRealloc(), DynPut(); X Xchar *DynGet(obj, num) X Int_DynObject obj; X int num; X{ X if (num < 0) { X if (obj->debug) X fprintf(stderr, "dyn: get: bad index %d\n", num); X return NULL; X } X X if (num >= obj->num_el) { X if (obj->debug) X fprintf(stderr, "dyn: get: highest element is %d.\n", X obj->num_el); X return NULL; X } X X if (obj->debug) X fprintf(stderr, "dyn: get: Returning address %d + %d.\n", X obj->array, obj->el_size*num); X X return obj->array + obj->el_size*num; X} X Xint DynAdd(obj, el) X Int_DynObject obj; X char *el; X{ X int ret; X X ret = DynPut(obj, el, obj->num_el); X if (ret != DYN_OK) X return ret; X X ++obj->num_el; X return ret; X} X X/* X * This function is not exported because if index is large enough to X * cause two or more increments to be allocated the rep invariant X * is not preserved. X */ Xstatic int DynPut(obj, el, index) X Int_DynObject obj; X char *el; X int index; X{ X if (obj->debug) X fprintf(stderr, "dyn: put: Writing %d bytes from %d to %d + %d\n", X obj->el_size, el, obj->array, index*obj->el_size); X X if (obj->size <= index) { X int num_incs, ret; X X num_incs = ((index - obj->size) / obj->inc) + 1; X if ((ret = _DynRealloc(obj, num_incs)) != DYN_OK) X return ret; X } X X bcopy(el, obj->array + index*obj->el_size, obj->el_size); X X if (obj->debug) X fprintf(stderr, "dyn: put: done.\n"); X X return DYN_OK; X} X Xstatic int _DynRealloc(obj, num_incs) X Int_DynObject obj; X int num_incs; X{ X ARRAY temp; X int new_size_in_bytes; X X new_size_in_bytes = obj->el_size*(obj->size + obj->inc*num_incs); X X if (obj->debug) X fprintf(stderr, X "dyn: alloc: Increasing object by %d bytes (%d incs).\n", X obj->el_size*obj->inc*num_incs, num_incs); X X temp = (ARRAY) realloc(obj->array, new_size_in_bytes); X if (temp == NULL) { X if (obj->debug) X fprintf(stderr, "dyn: alloc: Out of memory.\n"); X return DYN_NOMEM; X } X else { X obj->array = temp; X obj->size += obj->inc*num_incs; X } X X if (obj->debug) X fprintf(stderr, "dyn: alloc: done.\n"); X X return DYN_OK; X} END_OF_FILE if test 2680 -ne `wc -c <'dyn_put.c'`; then echo shar: \"'dyn_put.c'\" unpacked with wrong size! fi # end of 'dyn_put.c' fi if test -f 'dyn_size.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'dyn_size.c'\" else echo shar: Extracting \"'dyn_size.c'\" \(618 characters\) sed "s/^X//" >'dyn_size.c' <<'END_OF_FILE' X/* X * This file is part of libdyn.a, the C Dynamic Object library. It X * contains the source code for the function DynSize(). X * X * There are no restrictions on this code; however, if you make any X * changes, I request that you document them so that I do not get X * credit or blame for your modifications. X * X * Written by Barr3y Jaspan, Student Information Processing Board (SIPB) X * and MIT-Project Athena, 1989. X */ X X#include <stdio.h> X X#include "dynP.h" X Xint DynSize(obj) X Int_DynObject obj; X{ X if (obj->debug) X fprintf(stderr, "dyn: size: returning size %d.\n", obj->num_el); X X return obj->num_el; X} END_OF_FILE if test 618 -ne `wc -c <'dyn_size.c'`; then echo shar: \"'dyn_size.c'\" unpacked with wrong size! fi # end of 'dyn_size.c' fi if test -f 'test.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'test.c'\" else echo shar: Extracting \"'test.c'\" \(2228 characters\) sed "s/^X//" >'test.c' <<'END_OF_FILE' X/* X * This file is a (rather silly) demonstration of the use of the X * C Dynamic Object library. It is a also reasonably thorough test X * of the library (except that it only tests it with one data size). X * X * There are no restrictions on this code; however, if you make any X * changes, I request that you document them so that I do not get X * credit or blame for your modifications. X * X * Written by Barr3y Jaspan, Student Information Processing Board (SIPB) X * and MIT-Project Athena, 1989. X */ X X#include <stdio.h> X X#include "dyn.h" X Xmain(argc, argv) X int argc; X char **argv; X{ X DynObject obj; X int i, s; X char d, *data; X X obj = DynCreate(sizeof(char), 8); X if (! obj) { X fprintf(stderr, "test: create failed.\n"); X exit(1); X } X X DynDebug(obj, 1); X X if (DynGet(obj, -5) || DynGet(obj, 0) || DynGet(obj, 1000)) { X fprintf(stderr, "test: Get did not fail when it should have.\n"); X exit(1); X } X X if (DynDelete(obj, -1) != DYN_BADINDEX || X DynDelete(obj, 0) != DYN_BADINDEX || X DynDelete(obj, 100) != DYN_BADINDEX) { X fprintf(stderr, "test: Delete did not fail when it should have.\n"); X exit(1); X } X X printf("Size of empty object: %d\n", DynSize(obj)); X X for (i=0; i<14; i++) { X d = (char) i; X if (DynAdd(obj, &d) != DYN_OK) { X fprintf(stderr, "test: Adding %d failed.\n", i); X exit(1); X } X } X X if (DynDelete(obj, DynHigh(obj) / 2) != DYN_OK) { X fprintf(stderr, "test: deleting element failed.\n"); X exit(1); X } X X if (DynDelete(obj, DynHigh(obj) * 2) == DYN_OK) { X fprintf(stderr, "test: delete should have failed here.\n"); X exit(1); X } X X d = 200; X if (DynAdd(obj, &d) != DYN_OK) { X fprintf(stderr, "test: Adding %d failed.\n", i); X exit(1); X } X X data = (char *) DynGet(obj, 0); X s = DynSize(obj); X for (i=0; i < s; i++) X printf("Element %d is %d.\n", i, (unsigned char) data[i]); X X data = (char *) DynGet(obj, 13); X printf("Element 13 is %d.\n", (unsigned char) *data); X X data = (char *) DynGet(obj, 14); X if (data) { X fprintf(stderr, "DynGet did not return NULL when it should have.\n"); X exit(1); X } X X DynDestroy(obj); X X return 0; X} END_OF_FILE if test 2228 -ne `wc -c <'test.c'`; then echo shar: \"'test.c'\" unpacked with wrong size! fi # end of 'test.c' fi echo shar: End of archive 1 \(of 1\). cp /dev/null ark1isdone MISSING="" for I in 1 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have the archive. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 Barry Jaspan, MIT-Project Athena bjaspan at athena.mit.edu From woods at robohack.UUCP Mon Jan 1 09:45:12 1990 From: woods at robohack.UUCP (Greg A. Woods) Date: 31 Dec 89 22:45:12 GMT Subject: SysV versions of finger and last, with lastlog. Message-ID: <1989Dec31.224512.16306@robohack.UUCP> Sorry, I didn't have the finger or last manual pages, and I haven't written one for lastlog. The finger and last sources didn't have the BSD copyright, but I assume they apply. Lastlog is PD. ----------- Cut Here ---------- #! /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.finger Makefile finger.c last.c lastlog.c # Wrapped by woods at robohack on Sun Dec 31 17:36:05 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'ReadMe.finger' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'ReadMe.finger'\" else echo shar: Extracting \"'ReadMe.finger'\" \(3255 characters\) sed "s/^X//" >'ReadMe.finger' <<'END_OF_FILE' Xwoods at robohack -- Sun Dec 31 16:45:30 EST 1989 X XI finally have managed to find time to get finger working nicely on my XSysV machine (an AT&T 3B2/400 running SysVr3.1v2). This holiday Xseason has been quite relaxing! X XWhile I tried to make as few changes as possible, I ended up making Xquite a few, and as such the complete source is provided, not just the Xdiffs. I have removed almost all of the special localizations and I Xhave generalized the GECOS field format a bit. (See the comment at Xthe top of the source for the GECOS field format description.) X X 1. There is now a macro, ISMODEM(), which should be defined to X indicate which tty's are dialup. X X 2. The "office" field now has no special character flags, and X now the first 14 chars are simply printed as the office. X X 3. There is a general info field which is always read and X printed if it exists. X X 3. The TTY field in the -l and -w displays is now LMAX-1 chars X wide (sizeof utmp.ut_line - 1), and special recognition of tty X is gone. X X 4. The messages indicator in the -l and -w displays now has X its own field (M), but is still displayed in the same manner. X X 5. Various changes to the code which formats and prints the X reports. The long form is considerably more consistent for X various forms of the GECOS field. X XI have written a companion programme, lastlog, to be called from X/etc/profile, which updates the entry for the calling user in X/usr/adm/lastlog. The records in this file are copies of the X/etc/utmp record for the current login session, and finger has been Xmodified to understand the new format. This programme is designed to Xwork the way it does, such that it can't be fooled too easily. XLastlog should be setgid to adm, and /usr/adm/lastlog should be Xwriteable by the group adm for the best results! X XAlso included is a port of 'last'. This is handy, but when running XSysV Accounting, not all that great. X XThere were a few more fixes and changes to finger as well, including Xone courtesy of Steve Blasingame, who also did an initial port to SysV. X XI doubt this is derived from the most recent version of finger, as it Xhas no support for remote fingering. For a large part of the current XSysV community this won't be a big loss. However, as networking Xbecomes more widespread, this feature will be required everywhere. X XAfter spending some time in the guts of finger, I would suggest that Xit not be worked on too much more, but rather it should be Xre-written. It is far better than some BSD utilities, but it has Xquite a few hacks, most of which seem to have been done in order to Xconform to some existing practice on the author's machine. Perhaps a Xbetter thought out standard would help. In addition, the formatting Xcode seems to have been hacked to make a pleasing output, not Xdesigned. There are some pretty silly things, such as printf's for Xblanks, and the worst of them I've removed. I almost ran the source Xthrough cb or indent, and you'll notice slight variances in style Xwhere my changes were thickest, but I did resist the temptation. X XAnyway, here it is. It does what I want, and works well for me! XLet me know if you find any bugs. If there is a great demand for Xfinger, perhaps I could re-post it to comp.sources.{misc|unix}. X X HAPPY NEW YEAR! END_OF_FILE if test 3255 -ne `wc -c <'ReadMe.finger'`; then echo shar: \"'ReadMe.finger'\" unpacked with wrong size! fi # end of 'ReadMe.finger' fi if test -f 'Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Makefile'\" else echo shar: Extracting \"'Makefile'\" \(895 characters\) sed "s/^X//" >'Makefile' <<'END_OF_FILE' X# X# Makefile - general makefile for normal one-file commands X# X# This file should not require editing when new commands are added. X# X# To install a new command: X# X# 'make CMD=<command_name> install' X# X# Created: X# X# woods at tslanpar: Tue May 19 22:33:14 EDT 1987 X# X# BUGS: X# X# Unfortunately, this breaks the 'make cat cmp diff grep' idiom when X# attempting to install. To do that would require a 'supermake'(?) and X# may require a makefile for each command, and/or changes to built-in X# rules in make. X# X XSRCDIR = /usr/src/local/cmd XBINDIR = /usr/local/bin XMANDIR = /usr/local/man/man1 XMANDEST = man1 X XCFLAGS = -O -DSYSV -DSYSVR3 $(DEBUG) $(PROF) XLDFLAGS = X Xinstall: $(BINDIR)/$(CMD) $(MANDIR)/$(MANDEST)/$(CMD).1 X X$(BINDIR)/$(CMD): $(CMD) X install -c -m 755 $(CMD) $(BINDIR) X X$(MANDIR)/$(MANDEST)/$(CMD).1: $(CMD).1 X install -c -m 644 $(CMD).1 $(MANDIR)/$(MANDEST) X Xclean: X rm -f a.out core *.o END_OF_FILE if test 895 -ne `wc -c <'Makefile'`; then echo shar: \"'Makefile'\" unpacked with wrong size! fi # end of 'Makefile' fi if test -f 'finger.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'finger.c'\" else echo shar: Extracting \"'finger.c'\" \(32249 characters\) sed "s/^X//" >'finger.c' <<'END_OF_FILE' X#ifdef SYSVR3 X# ident "@(#)finger.c 4.1 (Berkeley) 10/1/80"; X# ident "@(#)finger.c 1.1.1.1 89/12/31 17:30:03 [LOCAL] (Greg A. Woods)" X#else X# ifndef lint Xstatic char *sccsid = "@(#)finger.c 4.1 (Berkeley) 10/1/80"; Xstatic cahr *sccsloc= "@(#)finger.c 1.1.1.1\t89/12/31 17:30:03 [LOCAL] (Greg A. Woods)"; X# endif X#endif X X/* This is a finger program. It prints out useful information about users X * by digging it up from various system files. It is not very portable X * because the most useful parts of the information (the full user name, X * office, and phone numbers) are all stored in the VAX-unused gecos field X * of /etc/passwd, which, unfortunately, other UNIXes use for other things. X * X * There are three output formats, all of which give login name, teletype X * line number, and login time. The short output format is reminiscent X * of finger on ITS, and gives one line of information per user containing X * in addition to the minimum basic requirements (MBR), the full name of X * the user, his idle time and office location and phone number. The X * quick style output is UNIX who-like, giving only name, teletype and X * login time. Finally, the long style output give the same information X * as the short (in more legible format), the home directory and shell X * of the user, and, if it exits, a copy of the file .plan in the users X * home directory. Finger may be called with or without a list of people X * to finger -- if no list is given, all the people currently logged in X * are fingered. X * X * The program is validly called by one of the following: X * X * finger {short form list of users} X * finger -l {long form list of users} X * finger -b {briefer long form list of users} X * finger -q {quick list of users} X * finger -i {quick list of users with idle times} X * finger namelist {long format list of specified users} X * finger -s namelist {short format list of specified users} X * finger -w namelist {narrow short format list of specified users} X * X * where 'namelist' is a list of users login names. X * The other options can all be given after one '-', or each can have its X * own '-'. The -f option disables the printing of headers for short and X * quick outputs. The -b option briefens long format outputs. The -p X * option turns off plans for long format outputs. X */ X X/* X * The GECOS field should have the following format: X * X * :Real Name,location,office,home,extra: X * X * where: X * location is text describing office location (14 chars) X * office and home are phone numbers (7 or 10 digits only, no -'s) X * extra is text for misc. data (1 line's worth) X * X * If the first field is not a phone #, then it will be the office. If there X * is no office, it may be left blank (",,"). Any other, or all, field(s) X * may be omitted. If there is only one phone number, no distinction will be X * made between home and office, unless there is an office, in which case the X * phone number defaults to home, unless a blank home field is given.s X */ X X/* X * Fixes: X * Steve Blasingame 09/01/86 X * fixed bug associated with reads from .plan and .project files X * stored in a char. This prevented recognition of EOF. X * X * Greg Woods 12/31/89 X * Various changes to update for generic use and final porting X * to SysV. Fixed arg2 in call to lseek, casting it to long. X */ X X#include <sys/types.h> X#include <sys/stat.h> X#include <utmp.h> X#include <signal.h> X#include <pwd.h> X#include <stdio.h> X#ifndef SYSV X# include <sgtty.h> X# include <sccs.h> X# include <lastlog.h> X#else X# include <string.h> X# include <memory.h> X# include <unistd.h> X#endif X#include <time.h> X X#ifndef SEEK_SET /* from unistd.h */ X/* Symbolic constants for the "lseek" routine: */ X# define SEEK_SET 0 /* Set file pointer to "offset" */ X# define SEEK_CUR 1 /* Set file pointer to current plus "offset" */ X# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ X#endif X X#define ASTERISK '*' /* ignore this in real name */ X#define BLANK ' ' /* blank character (i.e. space) */ X#define CAPITALIZE 0137& /* capitalize character macro */ X#define COMMA ',' /* separator in pw_gecos field */ X#define COMMAND '-' /* command line flag char */ X#define LINEBREAK 012 /* line feed */ X#define NULLSTR "" /* the null string, opposed to NULL */ X#define SAMENAME '&' /* repeat login name in real name */ X#define TALKABLE 0222 /* tty is writeable if 222 mode */ X#ifndef LASTLOG_FILE X# define LASTLOG_FILE "/usr/adm/lastlog" X#endif X#ifndef ISMODEM X# define ISMODEM(tty) (strncmp(tty, "tty13", 5) == 0) X#endif X Xstruct utmp utmp; /* for sizeof */ X#define NMAX sizeof(utmp.ut_name) X#define LMAX sizeof(utmp.ut_line) X Xstruct person { /* one for each person fingered */ X char name[NMAX+1]; /* login name */ X char tty[LMAX+1]; /* NULL terminated tty line */ X long loginat; /* time of login (possibly last) */ X long idletime; /* how long idle (if logged in) */ X short int loggedin; /* flag for being logged in */ X short int writeable; /* flag for tty being writeable */ X char *realname; /* pointer to full name */ X char *office; /* pointer to office name */ X char *officephone; /* pointer to office phone no. */ X char *homephone; /* pointer to home phone no. */ X char *random; /* for any random stuff in pw_gecos */ X struct passwd *pwd; /* structure of /etc/passwd stuff */ X struct person *link; /* link to next person */ X}; X Xstruct passwd *NILPWD = 0; Xstruct person *NILPERS = 0; X Xint persize = sizeof( struct person ); Xint pwdsize = sizeof( struct passwd ); X Xchar LASTLOG[] = LASTLOG_FILE; /* last login info */ X#ifndef SYSV Xchar USERLOG[] = "/etc/utmp"; /* who is logged in */ X#else Xchar USERLOG[] = UTMP_FILE; /* who is logged in */ X#endif Xchar outbuf[BUFSIZ]; /* output buffer */ Xchar *ctime(); X Xint unbrief = 1; /* -b option default */ Xint header = 1; /* -f option default */ Xint hack = 1; /* -h option default */ Xint idle = 0; /* -i option default */ Xint large = 0; /* -l option default */ Xint match = 1; /* -m option default */ Xint plan = 1; /* -p option default */ Xint unquick = 1; /* -q option default */ Xint small = 0; /* -s option default */ Xint wide = 1; /* -w option default */ X Xint lf; Xint llopenerr; X Xlong tloc; /* current time */ X X X Xmain( argc, argv ) X Xint argc; Xchar *argv[]; X X{ X FILE *fp, *fopen(); /* for plans */ X struct passwd *getpwent(); /* read /etc/passwd */ X struct person *person1, *p, *pend; /* people */ X struct passwd *pw; /* temporary */ X struct utmp user; /* ditto */ X char *malloc(); X char *s, *pn, *ln; X int c; /* storage for getc */ X char *PLAN = "/.plan"; /* what plan file is */ X char *PROJ = "/.project"; /* what project file */ X int PLANLEN = strlen( PLAN ); X int PROJLEN = strlen( PROJ ); X int numnames = 0; X int orgnumnames; X int uf; X int usize = sizeof user; X int unshort; X int i, j; X int fngrlogin; X X setbuf( stdout, outbuf ); /* buffer output */ X X /* parse command line for (optional) arguments */ X X i = 1; X if( strcmp( *argv, "sh" ) ) { X fngrlogin = 0; X while( i++ < argc && (*++argv)[0] == COMMAND ) { X for( s = argv[0] + 1; *s != NULL; s++ ) { X switch (*s) { X X case 'b': X unbrief = 0; X break; X X case 'f': X header = 0; X break; X X case 'h': X hack = 0; X break; X X case 'i': X idle = 1; X unquick = 0; X break; X X case 'l': X large = 1; X break; X X case 'm': X match = 0; X break; X X case 'p': X plan = 0; X break; X X case 'q': X unquick = 0; X break; X X case 's': X small = 1; X break; X X case 'w': X wide = 0; X break; X X default: X fprintf( stderr, "finger: Usage -- 'finger [-bfhilmpqsw] [login1 [login2 ...] ]'\n" ); X exit( 1 ); X } X } X } X } X else { X fngrlogin = 1; X } X if( unquick ) { X time( &tloc ); X } X else { X if( idle ) { X time( &tloc ); X } X } X X /* i > argc means no login names given so get them by reading USERLOG */ X X if( (i > argc) || fngrlogin ) { X unshort = large; X if( ( uf = open(USERLOG, 0) ) >= 0 ) { X#ifndef SYSV X user.ut_name[0] = NULL; X while( user.ut_name[0] == NULL ) { X if( read( uf, (char *) &user, usize ) != usize ) { X printf( "\nNo one logged on\n" ); X exit( 0 ); X } X } X#else X /* SYSV has lots of entry types */ X user.ut_type = EMPTY; X while( user.ut_type != USER_PROCESS ) { X if( read( uf, (char *) &user, usize ) != usize ) { X printf( "\nNo one logged on\n" ); X exit( 0 ); X } X } X#endif X person1 = (struct person *) malloc( persize ); X for( j = 0; j < NMAX; j++ ) { X person1->tty[j] = user.ut_line[j]; X person1->name[j] = user.ut_name[j]; X } X person1->name[NMAX] = NULL; X person1->tty[NMAX] = NULL; X person1->loginat = user.ut_time; X person1->pwd = NILPWD; X person1->loggedin = 1; X numnames++; X p = person1; X while( read( uf, (char *) &user, usize ) == usize ) { X#ifndef SYSV X if( user.ut_name[0] == NULL ) continue; X#else X if( user.ut_type != USER_PROCESS ) continue; X#endif X p->link = (struct person *) malloc( persize ); X p = p->link; X for( j = 0; j < NMAX; j++ ) { X p->tty[j] = user.ut_line[j]; X p->name[j] = user.ut_name[j]; X } X p->name[NMAX] = NULL; X p->tty[NMAX] = NULL; X p->loginat = user.ut_time; X p->pwd = NILPWD; X p->loggedin = 1; X numnames++; X } X p->link = NILPERS; X close( uf ); X } X else { X fprintf( stderr, "finger: error opening %s\n", USERLOG ); X exit( 2 ); X } X X /* if we are doing it, read /etc/passwd for the useful info */ X X if( unquick ) { X setpwent(); X fwopen(); X i = numnames; X while( ( (pw = getpwent()) != NILPWD ) && ( i > 0 ) ) { X p = person1; X do { X if( p->pwd == NILPWD ) { X if( strcmp( p->name, pw->pw_name ) == 0 ) { X p->pwd = (struct passwd *) malloc( pwdsize ); X pwdcopy( p->pwd, pw ); X decode( p ); X i--; X } X } X p = p->link; X } X while( p != NILPERS ); X } X fwclose(); X endpwent(); X } X } X X /* get names from command line and check to see if they're logged in */ X X else { X unshort = ( small == 1 ? 0 : 1 ); X i++; X person1 = (struct person *) malloc( persize ); X strcpy( person1->name, (argv++)[ 0 ] ); X person1->loggedin = 0; X person1->pwd = NILPWD; X numnames++; X p = person1; X while( i++ <= argc ) { X p->link = (struct person *) malloc( persize ); X p = p->link; X strcpy( p->name, (argv++)[ 0 ] ); X p->loggedin = 0; X p->pwd = NILPWD; X numnames++; X } X p->link = NILPERS; X pend = p; X X /* if we are doing it, read /etc/passwd for the useful info */ X X orgnumnames = numnames; X if( unquick ) { X setpwent(); X while( ( pw = getpwent() ) != NILPWD ) { X p = person1; X i = 0; X do { X if( strcmp( p->name, pw->pw_name ) == 0 || X matchcmp( pw->pw_gecos, pw->pw_name, p->name ) ) { X if( p->pwd == NILPWD ) { X p->pwd = (struct passwd *) malloc( pwdsize ); X pwdcopy( p->pwd, pw ); X } X else { /* handle multiple logins -- append new X "duplicate" entry to end of list */ X pend->link = (struct person *) malloc(persize); X pend = pend->link; X pend->link = NILPERS; X strcpy( pend->name, p->name ); X pend->pwd = (struct passwd *) malloc(pwdsize); X pwdcopy( pend->pwd, pw ); X numnames++; X } X } X p = p->link; X } X while( ++i < orgnumnames ); X } X endpwent(); X } X X /* Now get login information */ X X if( ( uf = open(USERLOG, 0) ) >= 0 ) { X while( read( uf, (char *) &user, usize ) == usize ) { X#ifndef SYSV X if( user.ut_name[0] == NULL ) continue; X#else X if( user.ut_type != USER_PROCESS ) continue; X#endif X p = person1; X do { X pw = p->pwd; X if( pw == NILPWD ) { X i = ( strcmp( p->name, user.ut_name ) ? 0 : NMAX ); X } X else { X i = 0; X while( (i < NMAX) && X ( pw->pw_name[i] == user.ut_name[i]) ) { X if( pw->pw_name[i] == NULL ) { X i = NMAX; X break; X } X i++; X } X } X if( i == NMAX ) { X if( p->loggedin == 1 ) { X pend->link = (struct person *) malloc(persize); X pend = pend->link; X pend->link = NILPERS; X strcpy( pend->name, p->name ); X for( j = 0; j < NMAX; j++ ) { X pend->tty[j] = user.ut_line[j]; X } X pend->tty[ NMAX ] = NULL; X pend->loginat = user.ut_time; X pend->loggedin = 2; X if( pw == NILPWD ) { X pend ->pwd = NILPWD; X } X else { X pend->pwd = (struct passwd *) malloc(pwdsize); X pwdcopy( pend->pwd, pw ); X } X numnames++; X } X else { X if( p->loggedin != 2 ) { X for( j = 0; j < NMAX; j++ ) { X p->tty[j] = user.ut_line[j]; X } X p->tty[ NMAX ] = NULL; X p->loginat = user.ut_time; X p->loggedin = 1; X } X } X } X p = p->link; X } X while( p != NILPERS ); X } X fwopen(); X p = person1; X while( p != NILPERS ) { X if( p->loggedin == 2 ) { X p->loggedin = 1; X } X decode( p ); X p = p->link; X } X fwclose(); X close( uf ); X } X else { X fprintf( stderr, "finger: error opening %s\n", USERLOG ); X exit( 2 ); X } X } X X /* print out what we got */ X X if( header ) { X if( unquick ) { X if( !unshort ) { X if( wide ) { X printf( X "Login Name M%*.*s Idle When Office\n", LMAX-1, LMAX-1, "TTY" ); X } X else { X printf( X "Login M%*.*s Idle When Office\n", LMAX-1, LMAX-1, "TTY" ); X } X } X } X else { X printf( "Login TTY When" ); X if( idle ) { X printf( " Idle" ); X } X printf( "\n" ); X } X } X p = person1; X do { X if( unquick ) { X if( unshort ) { X personprint( p ); X if( p->pwd != NILPWD ) { X if( hack ) { X s = malloc(strlen((p->pwd)->pw_dir) + PROJLEN + 1 ); X strcpy( s, (p->pwd)->pw_dir ); X strcat( s, PROJ ); X if( ( fp = fopen( s, "r") ) != NULL ) { X printf( "Project: " ); X while( ( c = getc(fp) ) != EOF ) { X if( c == LINEBREAK ) { X break; X } X putc( (char) c, stdout ); X } X fclose( fp ); X printf( "\n" ); X } X } X if( plan ) { X s = malloc( strlen( (p->pwd)->pw_dir ) + PLANLEN + 1 ); X strcpy( s, (p->pwd)->pw_dir ); X strcat( s, PLAN ); X if( ( fp = fopen( s, "r") ) == NULL ) { X printf( "No Plan.\n" ); X } X else { X printf( "Plan:\n" ); X while( ( c = getc(fp) ) != EOF ) { X putc((char) c, stdout ); X } X fclose( fp ); X } X } X } X if( p->link != NILPERS ) { X printf( "\n" ); X } X } X else { X shortprint( p ); X } X } X else { X quickprint( p ); X } X p = p->link; X } X while( p != NILPERS ); X exit(0); X} X X X/* given a pointer to a pwd (pfrom) copy it to another one, allocating X * space for all the stuff in it. Note: Only the useful (what the X * program currently uses) things are copied. X */ X Xpwdcopy( pto, pfrom ) /* copy relevant fields only */ X Xstruct passwd *pto, *pfrom; X{ X pto->pw_name = malloc( strlen( pfrom->pw_name ) + 1 ); X strcpy( pto->pw_name, pfrom->pw_name ); X pto->pw_uid = pfrom->pw_uid; X pto->pw_gecos = malloc( strlen( pfrom->pw_gecos ) + 1 ); X strcpy( pto->pw_gecos, pfrom->pw_gecos ); X pto->pw_dir = malloc( strlen( pfrom->pw_dir ) + 1 ); X strcpy( pto->pw_dir, pfrom->pw_dir ); X pto->pw_shell = malloc( strlen( pfrom->pw_shell ) + 1 ); X strcpy( pto->pw_shell, pfrom->pw_shell ); X} X X X/* print out information on quick format giving just name, tty, login time X * and idle time if idle is set. X */ X Xquickprint( pers ) X Xstruct person *pers; X{ X int idleprinted; X X printf( "%-*.*s", NMAX, NMAX, pers->name ); X printf( " " ); X if( pers->loggedin ) { X if( idle ) { X findidle( pers ); X if( pers->writeable ) { X printf( " %-*.*s %-16.16s", LMAX, LMAX, X pers->tty, ctime( &pers->loginat ) ); X } X else { X printf( "*%-*.*s %-16.16s", LMAX, LMAX, X pers->tty, ctime( &pers->loginat ) ); X } X printf( " " ); X idleprinted = ltimeprint( &pers->idletime ); X } X else { X printf( " %-*.*s %-16.16s", LMAX, LMAX, X pers->tty, ctime( &pers->loginat ) ); X } X } X else { X printf( " Not Logged In" ); X } X printf( "\n" ); X} X X X/* print out information in short format, giving login name, full name, X * tty, idle time, login time, office location and phone. X */ X Xshortprint( pers ) X Xstruct person *pers; X X{ X struct passwd *pwdt = pers->pwd; X char buf[ 26 ]; X int i, len, offset, dialup; X X if( pwdt == NILPWD ) { X printf( "%-*.*s", NMAX, NMAX, pers->name ); X printf( " ???\n" ); X return; X } X printf( "%-*.*s", NMAX, NMAX, pwdt->pw_name ); X dialup = 0; X if( wide ) { X if( strlen( pers->realname ) > 0 ) { X printf( " %-20.20s", pers->realname ); X } X else { X printf( " ??? " ); X } X } X if( pers->loggedin ) { X if( pers->writeable ) { X printf( " " ); X } X else { X printf( " *" ); X } X } X else { X printf( " " ); X } X if( strlen( pers->tty ) > 0 ) { X if( ISMODEM(pers->tty) && pers->loggedin ) { X dialup = 1; X } X printf( "%*.*s ", LMAX-1, LMAX-1, pers->tty ); X } X else { X printf( "%*.*s ", LMAX-1, LMAX-1, " " ); X } X strcpy( buf, ctime( &pers->loginat ) ); X if( pers->loggedin ) { X stimeprint( &pers->idletime ); X offset = 7; X for( i = 4; i < 19; i++ ) { X buf[i] = buf[i + offset]; X } X printf( " %-9.9s ", buf ); X } X else { X printf( " " ); X offset = 4; X for( i = 0; i <22; i++ ) { X buf[i] = buf[i + offset]; X } X printf( "<%-12.12s>", buf ); X } X len = strlen( pers->homephone ); X if( dialup && (len > 0) ) { X if( len == 8 ) { X printf( " " ); X } X else { X if( len == 12 ) { X printf( " " ); X } X else { X for( i = 1; i <= 21 - len; i++ ) { X printf( " " ); X } X } X } X printf( "%s", pers->homephone ); X } X else { X if( strlen( pers->office ) > 0 ) { X printf( " %-11.11s", pers->office ); X if( strlen( pers->officephone ) > 0 ) { X printf( " %8.8s", pers->officephone ); X } X else { X if( len == 8 ) { X printf( " %8.8s", pers->homephone ); X } X } X } X else { X if( strlen( pers->officephone ) > 0 ) { X printf( " %8.8s", pers->officephone ); X } X else { X if( len == 8 ) { X printf( " %8.8s", pers->homephone ); X } X else { X if( len == 12 ) { X printf( " %12.12s", pers->homephone ); X } X } X } X } X } X printf( "\n" ); X} X X X/* print out a person in long format giving all possible information. X * directory and shell are inhibited if unbrief is clear. X */ X Xpersonprint( pers ) X Xstruct person *pers; X{ X struct passwd *pwdt = pers->pwd; X int idleprinted; X X if( pwdt == NILPWD ) { X printf( "Login name: %-10s\t\t\tIn real life: ???\n", pers->name ); X return; X } X printf( "Login name: %-10s", pwdt->pw_name ); X if( pers->loggedin && !pers->writeable ) { X printf( " (messages off)\t" ); X } X else { X printf( "\t\t\t" ); X } X if( strlen( pers->realname ) > 0 ) { X printf( "In real life: %s", pers->realname ); X } X if( strlen( pers->office ) > 0 ) { X char pbuf[40]; X X printf("\nOffice: "); X if( strlen( pers->officephone ) > 0 ) { X sprintf(pbuf, "%-.14s, %-.12s", pers->office, pers->officephone ); X printf( "%-26.26s", pbuf ); X if( strlen( pers->homephone ) > 0 ) { X printf( "\tHome phone: %-.12s", pers->homephone ); X } X } X else { X printf("%-14.14s", pers->office); X if( strlen( pers->homephone ) > 0 ) { X printf("\t\t\tHome phone: %-.12s", pers->homephone); X } X } X } X else { X if( strlen( pers->officephone ) > 0 ) { X printf( "\nOffice Phone: %-12.12s", pers->officephone ); X if( strlen( pers->homephone ) > 0 ) { X printf( "\t\tHome Phone: %-.12s", pers->homephone ); X } X } X else { X if( strlen( pers->homephone ) > 0 ) { X printf( "\nPhone: %-.12s", pers->homephone ); X } X } X } X if( strlen( pers->random ) > 0 ) { X printf( "\n%s", pers->random ); X } X if( unbrief ) { X printf( "\nDirectory: %-25s", pwdt->pw_dir ); X if( strlen( pwdt->pw_shell ) > 0 ) { X printf( "\tShell: %-s", pwdt->pw_shell ); X } X } X if( pers->loggedin ) { X register char *ep = ctime( &pers->loginat ); X printf("\nOn since %15.15s on %-*.*s\t", &ep[4], LMAX, LMAX, pers->tty ); X idleprinted = ltimeprint( &pers->idletime ); X if( idleprinted ) { X printf( " Idle Time" ); X } X } X else { X register char *ep = ctime( &pers->loginat ); X printf("\nLast login %16.16s on %.*s", ep, LMAX, pers->tty ); X } X printf( "\n" ); X} X X X/* X * very hacky section of code to format phone numbers. filled with X * magic constants like 4, 7 and 10. X */ X Xchar *phone( s, len ) X Xchar *s; Xint len; X{ X char *strsave(); X char fonebuf[ 15 ]; X int i; X X switch( len ) { X X case 7: X for( i = 0; i <= 2; i++ ) { X fonebuf[ i ] = *s++; X } X fonebuf[ 3 ] = '-'; X for( i = 0; i <= 3; i++ ) { X fonebuf[ 4 + i ] = *s++; X } X fonebuf[ 8 ] = NULL; X return( strsave( &fonebuf[0] ) ); X break; X X case 10: X for( i = 0; i <= 2; i++ ) { X fonebuf[ i ] = *s++; X } X fonebuf[ 3 ] = '-'; X for( i = 0; i <= 2; i++ ) { X fonebuf[ 4 + i ] = *s++; X } X fonebuf[ 7 ] = '-'; X for( i = 0; i <= 3; i++ ) { X fonebuf[ 8 + i ] = *s++; X } X fonebuf[ 12 ] = NULL; X return( strsave( &fonebuf[0] ) ); X break; X X default: X fprintf( stderr, "finger: error in phone numbering\n" ); X return( strsave(s) ); X break; X } X} X X X/* decode the information in the gecos field of /etc/passwd X * another hacky section of code, but given the format the stuff is in... X */ X Xdecode( pers ) X Xstruct person *pers; X X{ X struct passwd *pwdt = pers->pwd; X char buffer[ 40 ], *bp, *gp, *lp; X char *phone(); X int alldigits; X int len; X int i; X X pers->realname = NULLSTR; X pers->office = NULLSTR; X pers->officephone = NULLSTR; X pers->homephone = NULLSTR; X pers->random = NULLSTR; X if( pwdt != NILPWD ) { X gp = pwdt->pw_gecos; X bp = &buffer[ 0 ]; X if( *gp == ASTERISK ) X gp++; X while( (*gp != NULL) && (*gp != COMMA) ) { /* name */ X if( *gp == SAMENAME ) { X lp = pwdt->pw_name; X *bp++ = CAPITALIZE(*lp++); X while( *lp != NULL ) X *bp++ = *lp++; X } else X *bp++ = *gp; X gp++; X } X *bp = NULL; X len = strlen( &buffer[0] ); X if ( len ) { X pers->realname = malloc( len + 1 ); X strcpy( pers->realname, &buffer[0] ); X } X if( *gp++ == COMMA ) { /* office, supposedly */ X alldigits = 1; X bp = &buffer[ 0 ]; X while( (*gp != NULL) && (*gp != COMMA) ) { X *bp = *gp++; X alldigits = alldigits && ('0' <= *bp) && (*bp <= '9'); X bp++; X } X *bp = NULL; X len = strlen( &buffer[0] ); X if( alldigits ) { /* not the office, a phone number? */ X if( (len == 7) || (len == 10) ) { X pers->homephone = phone( &buffer[0], len ); X } else if ( len ) { /* must be random stuff */ X pers->random = malloc( len + 1 ); X strcpy( pers->random, &buffer[0] ); X } X } else if ( len ) { /* yes!, the office! */ X pers->office = malloc( len + 1 ); X strcpy( pers->office, &buffer[0] ); X } X if( *gp++ == COMMA ) { /* office phone, if not already found */ X bp = &buffer[ 0 ]; X alldigits = 1; X while( (*gp != NULL) && (*gp != COMMA) ) { X *bp = *gp++; X alldigits = alldigits && ('0' <= *bp) && (*bp <= '9'); X bp++; X } X *bp = NULL; X len = strlen( &buffer[0] ); X if( alldigits && ( (len == 7) || (len == 10) ) ) { X if( *pers->homephone != NULL ) X pers->officephone = pers->homephone; X pers->homephone = phone( &buffer[0], len ); X } else if ( len ) { /* nope, random stuff */ X pers->random = malloc( len + 1 ); X strcpy( pers->random, &buffer[0] ); X } X if( *gp++ == COMMA ) { /* home phone?? */ X bp = &buffer[ 0 ]; X alldigits = 1; X while( (*gp != NULL) && (*gp != COMMA) ) { X *bp = *gp++; X alldigits = alldigits && ('0' <= *bp) && (*bp <= '9'); X bp++; X } X *bp = NULL; X len = strlen( &buffer[0] ); X if( alldigits && ( (len == 7) || (len == 10) ) ) { X /* lose first if 3 numbers */ X if( *pers->homephone != NULL ) X pers->officephone = pers->homephone; X pers->homephone = phone( &buffer[0], len ); X } else if ( len ) { /* random stuff */ X pers->random = malloc( strlen( &buffer[0] ) + 1 ); X strcpy( pers->random, &buffer[0] ); X } else { X if( *pers->homephone != NULL ) { X pers->officephone = pers->homephone; X pers->homephone = NULLSTR; X } X } X if( *gp++ == COMMA ) { /* real random stuff?? */ X bp = &buffer[ 0 ]; X while( *gp != NULL ) { X *bp = *gp++; X bp++; X } X *bp = NULL; X len = strlen( &buffer[0] ); X if ( len ) { X pers->random = malloc( len + 1 ); X strcpy( pers->random, &buffer[0] ); X } X } X } X } X } X if( pers->loggedin == 0 ) { X findwhen( pers ); X } X else { X findidle( pers ); X } X } X} X X X/* find the last log in of a user by checking the LASTLOG file. X * the entry is indexed by the uid, so this can only be done if X * the uid is known (which it isn't in quick mode) X */ X Xfwopen() X{ X if( ( lf = open(LASTLOG, 0) ) >= 0 ) { X llopenerr = 0; X } X else { X fprintf( stderr, "finger: lastlog open error\n" ); X llopenerr = 1; X } X} X X Xfindwhen( pers ) X Xstruct person *pers; X{ X struct passwd *pwdt = pers->pwd; X#ifndef SYSV X struct lastlog ll; X#else X struct utmp ll; X#endif X int llsize = sizeof ll; X int i; X X if( !llopenerr ) { X lseek( lf, (long) (pwdt->pw_uid*llsize), SEEK_SET ); X if( read( lf, (char *) &ll, llsize ) == llsize ) { X#ifndef SYSV X for( i = 0; i < LMAX; i++ ) { X pers->tty[ i ] = ll.ll_line[ i ]; X } X pers->tty[ LMAX ] = NULL; X pers->loginat = ll.ll_time; X#else X for( i = 0; i < LMAX; i++ ) { X pers->tty[ i ] = ll.ut_line[ i ]; X } X pers->tty[ LMAX ] = NULL; X pers->loginat = ll.ut_time; X#endif X } X else { X fprintf( stderr, "finger: lastlog read error\n" ); X pers->tty[ 0 ] = NULL; X pers->loginat = 0L; X } X } X else { X pers->tty[ 0 ] = NULL; X pers->loginat = 0L; X } X} X X Xfwclose() X{ X if( !llopenerr ) { X close( lf ); X } X} X X X/* find the idle time of a user by doing a stat on /dev/histty, X * where histty has been gotten from USERLOG, supposedly. X */ X Xfindidle( pers ) X Xstruct person *pers; X{ X struct stat ttystatus; X struct passwd *pwdt = pers->pwd; X char buffer[ 20 ]; X char *TTY = "/dev/"; X int TTYLEN = strlen( TTY ); X int i; X X strcpy( &buffer[0], TTY ); X i = 0; X do { X buffer[ TTYLEN + i ] = pers->tty[ i ]; X } while( ++i <= LMAX ); X if( stat( &buffer[0], &ttystatus ) >= 0 ) { X time( &tloc ); X if( tloc < ttystatus.st_atime ) { X pers->idletime = 0L; X } X else { X pers->idletime = tloc - ttystatus.st_atime; X } X if( (ttystatus.st_mode & TALKABLE) == TALKABLE ) { X pers->writeable = 1; X } X else { X pers->writeable = 0; X } X } X else { X fprintf( stderr, "finger: error STATing %s\n", &buffer[0] ); X exit( 4 ); X } X} X X X/* print idle time in short format; this program always prints 4 characters; X * if the idle time is zero, it prints 4 blanks. X */ X Xstimeprint( dt ) X Xlong *dt; X{ X struct tm *gmtime(); X struct tm *delta; X X delta = gmtime( dt ); X if( delta->tm_yday == 0 ) { X if( delta->tm_hour == 0 ) { X if( delta->tm_min >= 10 ) { X printf( " %2.2d ", delta->tm_min ); X } X else { X if( delta->tm_min == 0 ) { X printf( " " ); X } X else { X printf( " %1.1d ", delta->tm_min ); X } X } X } X else { X if( delta->tm_hour >= 10 ) { X printf( "%3.3d:", delta->tm_hour ); X } X else { X printf( "%1.1d:%02.2d", delta->tm_hour, delta->tm_min ); X } X } X } X else { X printf( "%3dd", delta->tm_yday ); X } X} X X X/* print idle time in long format with care being taken not to pluralize X * 1 minutes or 1 hours or 1 days. X */ X Xltimeprint( dt ) X Xlong *dt; X{ X struct tm *gmtime(); X struct tm *delta; X int printed = 1; X X delta = gmtime( dt ); X if( delta->tm_yday == 0 ) { X if( delta->tm_hour == 0 ) { X if( delta->tm_min >= 10 ) { X printf( "%2d minutes", delta->tm_min ); X } X else { X if( delta->tm_min == 0 ) { X if( delta->tm_sec > 10 ) { X printf( "%2d seconds", delta->tm_sec ); X } X else { X printed = 0; X } X } X else { X if( delta->tm_min == 1 ) { X if( delta->tm_sec == 1 ) { X printf( "%1d minute %1d second", X delta->tm_min, delta->tm_sec ); X } X else { X printf( "%1d minute %d seconds", X delta->tm_min, delta->tm_sec ); X } X } X else { X if( delta->tm_sec == 1 ) { X printf( "%1d minutes %1d second", X delta->tm_min, delta->tm_sec ); X } X else { X printf( "%1d minutes %d seconds", X delta->tm_min, delta->tm_sec ); X } X } X } X } X } X else { X if( delta->tm_hour >= 10 ) { X printf( "%2d hours", delta->tm_hour ); X } X else { X if( delta->tm_hour == 1 ) { X if( delta->tm_min == 1 ) { X printf( "%1d hour %1d minute", X delta->tm_hour, delta->tm_min ); X } X else { X printf( "%1d hour %2d minutes", X delta->tm_hour, delta->tm_min ); X } X } X else { X if( delta->tm_min == 1 ) { X printf( "%1d hours %1d minute", X delta->tm_hour, delta->tm_min ); X } X else { X printf( "%1d hours %2d minutes", X delta->tm_hour, delta->tm_min ); X } X } X } X } X } X else { X if( delta->tm_yday >= 10 ) { X printf( "%2d days", delta->tm_yday ); X } X else { X if( delta->tm_yday == 1 ) { X if( delta->tm_hour == 1 ) { X printf( "%1d day %1d hour", X delta->tm_yday, delta->tm_hour ); X } X else { X printf( "%1d day %2d hours", X delta->tm_yday, delta->tm_hour ); X } X } X else { X if( delta->tm_hour == 1 ) { X printf( "%1d days %1d hour", X delta->tm_yday, delta->tm_hour ); X } X else { X printf( "%1d days %2d hours", X delta->tm_yday, delta->tm_hour ); X } X } X } X } X return( printed ); X} X X Xmatchcmp( gname, login, given ) X Xchar *gname; Xchar *login; Xchar *given; X{ X char buffer[ 20 ]; X char c; X int flag, i, unfound; X X if( !match ) { X return( 0 ); X } X else { X if( namecmp( login, given ) ) { X return( 1 ); X } X else { X if( *gname == ASTERISK ) { X gname++; X } X flag = 1; X i = 0; X unfound = 1; X while( unfound ) { X if( flag ) { X c = *gname++; X if( c == SAMENAME ) { X flag = 0; X c = *login++; X } X else { X unfound = (*gname != COMMA) && (*gname != NULL); X } X } X else { X c = *login++; X if( c == NULL ) { X if( (*gname == COMMA) || (*gname == NULL) ) { X break; X } X else { X flag = 1; X continue; X } X } X } X if( c == BLANK ) { X buffer[i++] = NULL; X if( namecmp( buffer, given ) ) { X return( 1 ); X } X i = 0; X flag = 1; X } X else { X buffer[ i++ ] = c; X } X } X buffer[i++] = NULL; X if( namecmp( buffer, given ) ) { X return( 1 ); X } X else { X return( 0 ); X } X } X } X} X X Xnamecmp( name1, name2 ) X Xchar *name1; Xchar *name2; X{ X char c1, c2; X X c1 = *name1; X if( (('A' <= c1) && (c1 <= 'Z')) || (('a' <= c1) && (c1 <= 'z')) ) { X c1 = CAPITALIZE( c1 ); X } X c2 = *name2; X if( (('A' <= c2) && (c2 <= 'Z')) || (('a' <= c2) && (c2 <= 'z')) ) { X c2 = CAPITALIZE( c2 ); X } X while( c1 == c2 ) { X if( c1 == NULL ) { X return( 1 ); X } X c1 = *++name1; X if( (('A'<=c1) && (c1<='Z')) || (('a'<=c1) && (c1<='z')) ) { X c1 = CAPITALIZE( c1 ); X } X c2 = *++name2; X if( (('A'<=c2) && (c2<='Z')) || (('a'<=c2) && (c2<='z')) ) { X c2 = CAPITALIZE( c2 ); X } X } X if( *name1 == NULL ) { X while( ('0' <= *name2) && (*name2 <= '9') ) { X name2++; X } X if( *name2 == NULL ) { X return( 1 ); X } X } X else { X if( *name2 == NULL ) { X while( ('0' <= *name1) && (*name1 <= '9') ) { X name1++; X } X if( *name1 == NULL ) { X return( 1 ); X } X } X } X return( 0 ); X} X X Xchar *strsave( s ) X Xchar *s; X{ X char *malloc(); X char *p; X X p = malloc( strlen( s ) + 1 ); X strcpy( p, s ); X return( p ); X} END_OF_FILE if test 32249 -ne `wc -c <'finger.c'`; then echo shar: \"'finger.c'\" unpacked with wrong size! fi # end of 'finger.c' fi if test -f 'last.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'last.c'\" else echo shar: Extracting \"'last.c'\" \(4274 characters\) sed "s/^X//" >'last.c' <<'END_OF_FILE' X#ifdef SYSVR3 X# ident "@(#)last.c 4.3 (Berkeley) 2/28/81"; X# ident "@(#)last.c 1.1.1.1 89/12/31 17:34:32 [LOCAL] (Greg A. Woods)" X#else X# ifndef lint Xstatic char *sccsid = "@(#)last.c 4.3 (Berkeley) 2/28/81"; Xstatic cahr *sccsloc= "@(#)last.c 1.1.1.1\t89/12/31 17:34:32 [LOCAL] (Greg A. Woods)"; X# endif X#endif X/* X * last X */ X#include <sys/types.h> X#include <stdio.h> X#include <signal.h> X#ifdef SYSV X# include <sys/stat.h> X#else X# include <stat.h> X#endif X#include <utmp.h> X X#define NMAX sizeof(buf[0].ut_name) X#define LMAX sizeof(buf[0].ut_line) X#define SECDAY (24*60*60) X X#define lineq(a,b) (!strncmp(a,b,LMAX)) X#define nameq(a,b) (!strncmp(a,b,NMAX)) X X#define MAXTTYS 256 X X#ifndef WTMP_FILE X# define WTMP_FILE "/usr/adm/wtmp" X#endif X Xchar **argv; Xint argc; X Xstruct utmp buf[128]; Xchar ttnames[MAXTTYS][LMAX+1]; Xlong logouts[MAXTTYS]; X Xchar *ctime(), *strspl(); Xint onintr(); X Xmain(ac, av) X char **av; X{ X register int i, k; X int bl, wtmp; X char *ct; X register struct utmp *bp; X long otime; X struct stat stb; X int print; X char * crmsg = (char *)0; X long crtime; X X time(&buf[0].ut_time); X ac--, av++; X argc = ac; X argv = av; X for (i = 0; i < argc; i++) { X if (strlen(argv[i])>2) X continue; X if (!strcmp(argv[i], "~")) X continue; X if (getpwnam(argv[i])) X continue; X argv[i] = strspl("tty", argv[i]); X } X wtmp = open(WTMP_FILE, 0); X if (wtmp < 0) { X perror(WTMP_FILE); X exit(1); X } X fstat(wtmp, &stb); X bl = (stb.st_size + sizeof (buf)-1) / sizeof (buf); X if (signal(SIGINT, SIG_IGN) != SIG_IGN) { X signal(SIGINT, onintr); X signal(SIGQUIT, onintr); X } X for (bl--; bl >= 0; bl--) { X lseek(wtmp, bl * sizeof (buf), 0); X bp = &buf[read(wtmp, buf, sizeof (buf)) / sizeof(buf[0]) - 1]; X for ( ; bp >= buf; bp--) { X print = want(bp); X if (print) { X ct = ctime(&bp->ut_time); X printf("%-*.*s %-*.*s %10.10s %5.5s ", X NMAX, NMAX, bp->ut_name, X LMAX, LMAX, bp->ut_line, ct, 11+ct); X } X for (i = 0; i < MAXTTYS; i++) { X if (ttnames[i][0] == 0) { X strncpy(ttnames[i], bp->ut_line, X sizeof(bp->ut_line)); X otime = logouts[i]; X logouts[i] = bp->ut_time; X break; X } X if (lineq(ttnames[i], bp->ut_line)) { X otime = logouts[i]; X logouts[i] = bp->ut_time; X break; X } X } X if (print) { X if (otime == 0) X printf(" still logged in\n"); X else { X long delta; X if (otime < 0) { X otime = -otime; X printf("- %s", crmsg); X } else X printf("- %5.5s", X ctime(&otime)+11); X delta = otime - bp->ut_time; X if (delta < SECDAY) X printf(" (%5.5s)\n", X asctime(gmtime(&delta))+11); X else X printf(" (%ld+%5.5s)\n", X delta / SECDAY, X asctime(gmtime(&delta))+11); X } X fflush(stdout); X } X if (lineq(bp->ut_line, "~")) { X for (i = 0; i < MAXTTYS; i++) X logouts[i] = -bp->ut_time; X if (nameq(bp->ut_name, "shutdown")) X crmsg = "down "; X else X crmsg = "crash"; X } X } X } X ct = ctime(&buf[0].ut_time); X printf("\nwtmp begins %10.10s %5.5s \n", ct, ct + 11); X exit(0); X} X Xonintr(signo) X int signo; X{ X char *ct; X X if (signo == SIGQUIT) X signal(SIGQUIT, onintr); X ct = ctime(&buf[0].ut_time); X printf("\ninterrupted %10.10s %5.5s \n", ct, ct + 11); X if (signo == SIGINT) X exit(1); X} X Xwant(bp) X struct utmp *bp; X{ X register char **av; X register int ac; X X#ifdef SYSV X switch (bp->ut_type) { X case BOOT_TIME: X /* sizeof(BOOT_MSG) > sizeof ut_name */ X strcpy(bp->ut_name, "reboot"); X break; X case EMPTY: X case RUN_LVL: X case OLD_TIME: X case NEW_TIME: X case INIT_PROCESS: X case LOGIN_PROCESS: X case DEAD_PROCESS: X case ACCOUNTING: X bp->ut_name[0] = '\0'; /* ignore these ones */ X break; X case USER_PROCESS: X break; /* normal */ X default: X strcpy(bp->ut_name, "unknown"); /* weird? */ X break; X } X#else X if (bp->ut_line[0] == '~' && bp->ut_name[0] == '\0') X strcpy(bp->ut_name, "reboot"); /* bandaid */ X#endif X if (bp->ut_name[0] == 0) X return (0); X if (argc == 0) X return (1); X av = argv; X for (ac = 0; ac < argc; ac++) { X if (nameq(*av, bp->ut_name) || lineq(*av, bp->ut_line)) X return (1); X av++; X } X return (0); X} X Xchar * Xstrspl(left, right) X char *left, *right; X{ X char *res = (char *)malloc(strlen(left)+strlen(right)+1); X X strcpy(res, left); X strcat(res, right); X return (res); X} END_OF_FILE if test 4274 -ne `wc -c <'last.c'`; then echo shar: \"'last.c'\" unpacked with wrong size! fi # end of 'last.c' fi if test -f 'lastlog.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'lastlog.c'\" else echo shar: Extracting \"'lastlog.c'\" \(3399 characters\) sed "s/^X//" >'lastlog.c' <<'END_OF_FILE' X#ifdef SYSVR3 X# ident "@(#)lastlog.c 1.1 89/12/30 17:49:02 [LOCAL] (Greg A. Woods)" X#endif X X#ifndef SYSVR3 X# ifndef lint X static char *SCCS_ID = "@(#)lastlog.c 1.1\t89/12/30 17:49:02 [LOCAL] (Greg A. Woods)"; X# endif X#endif X X/* X * lastlog - update the lastlog file X */ X X#include <sys/types.h> X#include <stdio.h> X#include <unistd.h> X#include <string.h> X#include <time.h> X#include <fcntl.h> X#include <utmp.h> X X#define LASTLOG "/usr/adm/lastlog" X Xchar *progname = NULL; X Xint Xmain(argc, argv, envp) X int argc; X char *argv[]; X char *envp[]; X{ X unsigned short uid; X int lfd; X int ufd; X char *ltm; X struct utmp ut; X int utent; X int rec_sz = sizeof(ut); X X extern unsigned short getuid(); X X if (!(progname = strrchr(argv[0], '/'))) X progname = argv[0]; X else X progname++; X if (argc > 1) { X fprintf(stderr, "Usage: %s\n", progname); X exit(2); X } X if ((lfd = open(LASTLOG, O_RDWR)) < 0 ) { X fprintf(stderr, "%s: open(%s, O_RDWR): ", progname, LASTLOG); X perror(""); X exit(1); X } X uid = getuid(); X if (uid > 0) { X if (lseek(lfd, (off_t) (uid * rec_sz), SEEK_SET) == EOF) { X fprintf(stderr, "%s: lseek(%d): ", progname, uid * rec_sz); X perror(LASTLOG); X exit(1); X } X } X if (read(lfd, (char *) &ut, rec_sz) == rec_sz) { X ltm = ctime(&ut.ut_time); X ltm[24] = '\0'; X printf("Last login at %s on %s.\n", ltm, ut.ut_line); X } else X printf("No last login info found.\n"); X if ((ufd = open(UTMP_FILE, O_RDONLY)) < 0 ) { X fprintf(stderr, "%s: open(%s, O_RDONLY): ", progname, UTMP_FILE); X perror(""); X exit(1); X } X utent = ttyslot(); X if (utent > 0) { X if (lseek(ufd, (off_t) (utent * rec_sz), SEEK_SET) == EOF) { X fprintf(stderr, "%s: lseek(%d): ", progname, uid * rec_sz); X perror(UTMP_FILE); X exit(1); X } X } else { X fprintf(stderr, "%s: I can't find your tty slot!\n", progname); X exit(1); X } X if (read(ufd, (char *) &ut, rec_sz) < rec_sz) { X fprintf(stderr, "%s: read(): ", progname); X perror(UTMP_FILE); X exit(1); X } X if (close(ufd) == EOF) { X fprintf(stderr, "%s: close(): ", progname); X perror(UTMP_FILE); X exit(1); X } X#ifdef DEBUG X printf("%d:%s:%s:%s:%d:", utent, ut.ut_user, ut.ut_id, ut.ut_line, ut.ut_pid); X switch (ut.ut_type) { X case BOOT_TIME: X printf("BOOT_TIME"); X break; X case EMPTY: X printf("EMPTY"); X break; X case RUN_LVL: X printf("RUN_LVL"); X break; X case OLD_TIME: X printf("OLD_TIME"); X break; X case NEW_TIME: X printf("NEW_TIME"); X break; X case INIT_PROCESS: X printf("INIT_PROCESS"); X break; X case LOGIN_PROCESS: X printf("LOGIN_PROCESS"); X break; X case DEAD_PROCESS: X printf("DEAD_PROCESS"); X break; X case ACCOUNTING: X printf("ACCOUNTING"); X break; X case USER_PROCESS: X printf("USER_PROCESS"); X break; X default: X printf("unknown"); /* weird? */ X break; X } X if (ut.ut_type == DEAD_PROCESS) X printf(":%d:%d", ut.ut_exit.e_termination, ut.ut_exit.e_exit); X printf(":%s", ctime(&ut.ut_time)); X#endif X if (ut.ut_type != USER_PROCESS) { X fprintf(stderr, "%s: your utmp entry isn't right.\n", progname); X exit(1); X } X if (lseek(lfd, (off_t) (uid * rec_sz), SEEK_SET) == EOF) { X fprintf(stderr, "%s: lseek(%d): ", progname, uid * rec_sz); X perror(LASTLOG); X exit(1); X } X if (write(lfd, (char *) &ut, rec_sz) < rec_sz) { X fprintf(stderr, "%s: write(): ", progname); X perror(LASTLOG); X exit(1); X } X if (close(lfd) == EOF) { X fprintf(stderr, "%s: close(): ", progname); X perror(LASTLOG); X exit(1); X } X exit(0); X /* NOTREACHED */ X} END_OF_FILE if test 3399 -ne `wc -c <'lastlog.c'`; then echo shar: \"'lastlog.c'\" unpacked with wrong size! fi # end of 'lastlog.c' fi echo shar: End of shell archive. exit 0 -- Greg A. Woods woods@{robohack,gate,tmsoft,ontmoh,utgpu,gpu.utcs.Toronto.EDU,utorgpu.BITNET} +1 416 443-1734 [h] +1 416 595-5425 [w] VE3-TCP Toronto, Ontario; CANADA From tneff at bfmny0.UU.NET Sat Jan 13 12:30:04 1990 From: tneff at bfmny0.UU.NET (Tom Neff) Date: 13 Jan 90 01:30:04 GMT Subject: ago 1.1 Message-ID: <15094@bfmny0.UU.NET> #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # README # ago.1 # ago.c # This archive created: Fri Jan 12 20:25:03 1990 export PATH; PATH=/bin:/usr/bin:$PATH if test -f 'README' then echo shar: "will not over-write existing file 'README'" else sed 's/^X//' << \SHAR_EOF > 'README' X XAGO is a System V command to display formatted date/time strings for Xtimes in the past or future. I needed to do this and couldn't find Xanything out there, so voila! X XYou will need getopt(3C) to parse the command line. If this isn't Xin your standard C library, get one of the PD versions and link it in. X X X X@(#) README $Revision: 1.1 $ $Date: 90/01/12 20:15:47 $ SHAR_EOF fi if test -f 'ago.1' then echo shar: "will not over-write existing file 'ago.1'" else sed 's/^X//' << \SHAR_EOF > 'ago.1' X'\" @(#) $Id: ago.1,v 1.1 90/01/12 20:22:39 tneff Exp $ X.TH AGO 1 X.SH NAME X\fBago\fR \- display date for times in the past or future X.SH USAGE X.B ago X.B [-s secs] X.B [-m mins] X.B [-h hrs] X.B [-d days] X.B [-w wks] X.B [+fmt] X.SH DESCRIPTION XThe X.I ago Xcommand is an extension to date(1) that displays a formatted date/time Xstring for a moment in the past or future, specified in seconds, minutes, Xhours, days and/or weeks relative to now. X.I ago Xaccepts the same format string as date(1). X.sp XWith no parameters specified, Xor with only X.I +fmt Xspecified, X.I ago Xbehaves exactly like date(1). XIf any of X.I \-s \-m \-h \-d \-w Xare specified, X.I ago X.B subtracts Xthe argument values from the current time before display. X(Specifying negative arguments will X.B add Xthe values to the current time, i.e., point into the future.) X.sp XFor further details on the format string, see date(1). X.SH EXAMPLES X.sp X$ ago X.br XFri Jan 12 17:22:05 EST 1990 X.sp X$ ago -d20 -h3 X.br XSat Dec 23 14:23:00 EST 1989 X.sp X$ ago -w-3 X.br XFri Feb 2 17:23:41 EST 1990 X.sp X$ ago -d-1 +'Tomorrow the time zone will be "%Z"' X.br XTomorrow the time zone will be "EST" X.SH SEE ALSO X.BR date(1), cftime(3C). SHAR_EOF fi if test -f 'ago.c' then echo shar: "will not over-write existing file 'ago.c'" else sed 's/^X//' << \SHAR_EOF > 'ago.c' X/* X * ago - display date for times in the past or future X * X * usage: X * ago [-s secs] [-m mins] [-h hrs] [-d days] [-w wks] [+fmt] X * X * where: X * -s secs Specifies how far into the past to look. X * -m mins A negative argument looks into the future. X * -h hrs X * -d days X * -w wks X * X * +fmt is a cftime(3C) format string with a leading '+' X * for compatibility with date(1). If omitted, the X * date(1) default of "%a %b %e %T %Z %Y" is used. X * X * NOTE: X * Uses getopt(3C) to parse the command line. X * X * $Log: ago.c,v $ X * Revision 1.1 90/01/12 20:20:13 tneff X * Initial revision X * X */ X X#ident "@(#) $Id: ago.c,v 1.1 90/01/12 20:20:13 tneff Exp $" X X#include <sys/types.h> X#include <time.h> X#include <stdio.h> X X/* The command mainline. */ X Xmain(argc, argv) Xint argc; Xchar **argv; X{ X int c; X int errflg = 0; X extern char *optarg; X extern int optind; X X time_t when; X char *fmt; X X char buf[1024]; X X int secs, mins, hrs, days, wks = 0; X X /* Collect option switches */ X X while ((c = getopt(argc, argv, "s:m:h:d:w:?")) != -1) X switch (c) X { X case 's': X if ((secs = atol(optarg)) == 0) X errflg++; X break; X case 'm': X if ((mins = atol(optarg)) == 0) X errflg++; X break; X case 'h': X if ((hrs = atol(optarg)) == 0) X errflg++; X break; X case 'd': X if ((days = atol(optarg)) == 0) X errflg++; X break; X case 'w': X if ((wks = atol(optarg)) == 0) X errflg++; X break; X X default: X errflg++; X } X X /* Validate args and print usage message if bad */ X X switch(argc-optind) X { X case 0: X fmt = "%a %b %e %T %Z %Y"; X break; X case 1: X if (argv[optind][0] == '+') X fmt = argv[optind]+1; X else X errflg++; X break; X default: X errflg++; X } X X if (errflg) X { X fprintf(stderr, "usage: %s [-s secs] [-m mins] [-h hrs] [-d days] [-w wks] [+fmt]\n", argv[0]); X exit(1); X } X X /* Start with 'now' */ X X when = time(NULL); X X /* Adjust */ X X when -= secs*1; X when -= mins*60; X when -= hrs*60*60; X when -= days*60*60*24; X when -= wks*60*60*24*7; X X /* Format and output */ X X cftime(buf, fmt, &when); X printf("%s\n", buf); X} SHAR_EOF fi exit 0 # End of shell archive -- 'We have luck only with women -- not spacecraft!' \\ Tom Neff -- R. Kremnev, builder of failed Soviet FOBOS probes // tneff at bfmny0.UU.NET From root at cca.ucsf.edu Fri Jan 12 11:35:57 1990 From: root at cca.ucsf.edu (Systems Staff) Date: 12 Jan 90 00:35:57 GMT Subject: Wanted: 1990 "sc" 1040 forms References: <MDF0.90Jan9121142@shemesh.gte.com> Message-ID: <2711@ucsfcca.ucsf.edu> Two recent postings to comp.sources.misc contain sc templates for 1989 1040's (the latest is v10i005, the other is for Schedule A). The "sc" spreadsheet is available from any comp.sources.unix archive in volume 18 (release 6.1). Thos Sumner Internet: thos at cca.ucsf.edu (The I.G.) UUCP: ...ucbvax!ucsfcgl!cca.ucsf!thos BITNET: thos at ucsfcca U.S. Mail: Thos Sumner, Computer Center, Rm U-76, UCSF San Francisco, CA 94143-0704 USA I hear nothing in life is certain but death and taxes -- and they're working on death. #include <disclaimer.std> From scott at csusac.csus.edu Sun Jan 7 05:34:28 1990 From: scott at csusac.csus.edu (L. Scott Emmons) Date: 6 Jan 90 18:34:28 GMT Subject: 'from' alias in csh Message-ID: <1990Jan6.183428.11336@csusac.csus.edu> I've noticed some recent postings regarding 'from' type programs for mail. For those of us without perl (yet!), the following csh alias will list who mail is from, with a date and a subject (an improvement over /usr/ucb/from). If someone has already posted something like this then Sorry! Note a couple of things: - This assumes mail headers are like they are at our site -- if it doesn't work for you change it or don't use it...don't tell me there's a bug, cuz there ain't... - The environment variable MAIL should read '/usr/spool/mail/YOURLOGINHERE' --- alias from "^From |^Subject:" $MAIL -- L. Scott Emmons --------------- ...[!ucbvax]!ucdavis!csusac!scott ucdavis!csusac!scott at ucbvax.berkeley.edu From joe at dayton.UUCP Fri Jan 5 08:08:33 1990 From: joe at dayton.UUCP (Joseph P. Larson) Date: 4 Jan 90 21:08:33 GMT Subject: lin: solve systems of linear equations (new version) Message-ID: <6904@dayton.UUCP> Okay. Included is "lin", my rather small, cute program that solves systems of n linear equations in m variables. This version has been changed since my very recent posting in that it solves systems with more than one solution. Of course, that means it'll say "all values" for certain variables. For instance, the solution for: 1*X0 + 3*X2 = 4 2*X1 + 1*X2 = -2 will be: X0: 4 - 3*X2 X1: -1 - 0.5*X2 X2: all values This program may be handy for people who are about to study Linear Algebra. However, I would not recommend you use lin as a substitute for doing your problem sets by hand. Of course, you *can* use it to check your answers... To create an executable, save to lin.c, edit off the header and the .sig at the end, and type "make lin". The program isn't very nice about how it displays floating point values. Unfortunately, printf() is pretty stupid when you use the "%f" option and I didn't feel like writing my own. Thus, I just use "%8.4f". If this isn't enough precision for you -- change it or write your own routine to convert floating point values to strings. If you find this program helpful, drop me a line and pat me on the back. It's nice to know sometimes that you aren't feeding an empty software pit. -Joe /* * lin: solve systems of linear equations. This program is public domain. * * Description: * * lin solves systems of linear equations. * * See the code or the "usage" line for any help you need running it. * * Author: * * Joe Larson * (currently joe at dayton.dhdsc.mn.org) * * Revision History * * 12-89 jpl. Created. * 1-90 jpl. Handle systems w/ infinite solutions. */ #include <stdio.h> #include <ctype.h> #define MAXVAR 20 #define MAXEQN 20 double strtod(); short vcount, ecount, solved[MAXVAR]; double matrix[MAXEQN][MAXVAR+1]; char showstep = 0; main(argc,argv) int argc; char **argv; { char *c, line[132], x; short i,j, evmin; for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-s")) showstep = 1; else usage(argv[0]); } printf("This program solves systems of linear equations involving\n"); printf("n variables and m unknowns.\n"); while(1) { while (1) { printf("Number of variables: "); fflush(stdout); gets(line); vcount = atoi(line); if (vcount > MAXVAR) { printf("Max variables = %d. ", MAXVAR); continue; } if (vcount) break; exit(0); } while (1) { printf("Number of equations: "); fflush(stdout); gets(line); ecount = atoi(line); if (ecount > MAXEQN) { printf("Max equations = %d. ", MAXEQN); continue; } if (ecount) break; exit(0); } evmin = (ecount < vcount) ? ecount : vcount; printf("Equations are of the form: \n"); for (i = 0; i < vcount; i++) { if (i) printf("+ "); printf(" c%d * x%d ", i, i); } printf("= result\n"); printf("For each equation, enter the %d constants plus the result,\n", vcount); printf("separated by spaces.\n"); for (i = 0; i < ecount; i++) { printf("\nEquation %d\n", i+1); gets(line); for (c = line, j = 0; *c && j < vcount; j++) matrix[i][j] = strtod(c, &c); matrix[i][vcount] = strtod(c, &c); } printf("The system: \n"); show(); /* * Now solve the equation in the following manner: * * for each variable: * find an equation with a 1 for constant. * (if non, find one with a non-zero for constant * and multiply to make it a 1.) * add multiples of this equiation to others as needed * to zero-out their constants. */ for (i = 0; i < evmin; i++) { /* Find an equation to place here */ x = 0; for (j = i; j < ecount; j++) if (matrix[j][i] == 1.0) { swap(i, j); x = 1; break; } if (!x) for (j = i; j < ecount; j++) if (matrix[j][i] != 0.0) { swap(i,j); x = 1; mult(i, 1.0 / matrix[i][i]); break; } if (!x) { /* This variable doesn't matter. */ continue; } /* * Now -- zero out everyone else. */ for (j = 0; j < ecount; j++) { if (j == i) continue; if (matrix[j][i] == 0.0) continue; add(j, i, -matrix[j][i]); } } /* * Now -- solve for each of the variables. */ solvecomplex(); printf("The system: \n"); show(); } } solvecomplex() /* * */ { short i, j, k, lastj; for (i = 0; i < ecount; ) { for (j = 0; j < vcount; j++) if (matrix[i][j]) break; if (j == vcount) { if (matrix[i][j]) /* No solutions. */ { printf("The set has no real-number solutions.\n"); return; } swap(i,ecount-1); ecount--; continue; } i++; } if (!ecount) { printf("System works for all values.\n"); return; } lastj = -1; for (i = 0; i < ecount; i++) { for (j = 0; j < vcount; j++) if (matrix[i][j] != 0.0) break; if (j != i) for (lastj++; lastj < j; lastj++) printf("X(%d): all values.\n"); lastj = j; printf("X(%d): %8.4f", j, matrix[i][vcount]); for (k = j+1; k < vcount; k++) if (matrix[i][k] != 0.0) printf(" - [%8.4f * X(%d)]", matrix[i][k], k); printf("\n"); } for (i = lastj + 1; i < vcount; i++) printf("X(%d): all values\n", i); } swap(i,j) short i,j; /* * Swap two rows of the matrix. */ { double temp; short x; if (i == j) return; for (x = 0; x <= vcount; x++) { temp = matrix[i][x]; matrix[i][x] = matrix[j][x]; matrix[j][x] = temp; } if (showstep) { printf("Swap row %d and %d leaving:\n", i, j); show(); } } mult(i, f) short i; double f; /* * Multiply row i by constant f. */ { short x; for (x = 0; x <= vcount; x++) matrix[i][x] *= f; if (showstep) { printf("Multiply row %d by %f leaving:\n", i, f); show(); } } add(i,j,f) short i,j; double f; /* * Add to row i row (j*f). */ { short x; for (x = 0; x <= vcount; x++) matrix[i][x] += matrix[j][x] * f; if (showstep) { printf("Add (%f times row %d) to row %d:\n", f, j, i); show(); } } show() /* * Show the equation */ { short i,j; for (i = 0; i < ecount; i++) { for (j = 0; j < vcount; j++) printf(" %8.4f", matrix[i][j]); printf(" %8.4f\n", matrix[i][j]); } } usage(arg) char *arg; { fprintf(stderr, "\ Usage: %d [-s]\n\ where -s selects display of steps used to solve the set of equations.\n", arg); exit(0); } -- UUCP: rutgers!dayton!joe (Picts 1-16 are DHDSC - Joe Larson/MIS 1060 ATT : (612) 375-3537 now ready.) 700 on the Mall, Mpls, Mn. 55402 Newsgroups: alt.source Subject: lin: solve systems of linear equations (new version) Reply-To: joe at dayton.UUCP (Joseph P. Larson) Distribution: alt Organization: Dayton-Hudson Dept. Store Co. Okay. Included is "lin", my rather small, cute program that solves systems of n linear equations in m variables. This version has been changed since a very recent posting in that it solves systems with more than one solution. Of course, that means it'll say "all values" for certain variables. For instance, the solution for: 1*X0 + 3*X2 = 4 2*X1 + 1*X2 = -2 will be: X0: 4 - 3*X2 X1: -1 - 0.5*X2 X2: all values This program may be handy for people who are about to study Linear Algebra. However, I would not recommend you use lin as a substitute for doing your problem sets by hand. Of course, you *can* use it to check your answers... To create an executable, save to lin.c, edit off the header and the .sig at the end, and type "make lin". The program isn't very nice about how it displays floating point values. Unfortunately, printf() is pretty stupid when you use the "%f" option and I didn't feel like writing my own. Thus, I just use "%8.4f". If this isn't enough precision for you -- change it or write your own routine to convert floating point values to strings. If you find this program helpful, drop me a line and pat my on the back. It's nice to know sometimes that you aren't feeding an empty software pit. -Joe /* * lin: solve systems of linear equations. This program is public domain. * * Description: * * lin solves systems of linear equations. * * See the code or the "usage" line for any help you need running it. * * Author: * * Joe Larson * (currently joe at dayton.dhdsc.mn.org) * * Revision History * * 12-89 jpl. Created. * 1-90 jpl. Handle systems w/ infinite solutions. */ #include <stdio.h> #include <ctype.h> #define MAXVAR 20 #define MAXEQN 20 double strtod(); short vcount, ecount, solved[MAXVAR]; double matrix[MAXEQN][MAXVAR+1]; char showstep = 0; main(argc,argv) int argc; char **argv; { char *c, line[132], x; short i,j, evmin; for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-s")) showstep = 1; else usage(argv[0]); } printf("This program solves systems of linear equations involving\n"); printf("n variables and m unknowns.\n"); while(1) { while (1) { printf("Number of variables: "); fflush(stdout); gets(line); vcount = atoi(line); if (vcount > MAXVAR) { printf("Max variables = %d. ", MAXVAR); continue; } if (vcount) break; exit(0); } while (1) { printf("Number of equations: "); fflush(stdout); gets(line); ecount = atoi(line); if (ecount > MAXEQN) { printf("Max equations = %d. ", MAXEQN); continue; } if (ecount) break; exit(0); } evmin = (ecount < vcount) ? ecount : vcount; printf("Equations are of the form: \n"); for (i = 0; i < vcount; i++) { if (i) printf("+ "); printf(" c%d * x%d ", i, i); } printf("= result\n"); printf("For each equation, enter the %d constants plus the result,\n", vcount); printf("separated by spaces.\n"); for (i = 0; i < ecount; i++) { printf("\nEquation %d\n", i+1); gets(line); for (c = line, j = 0; *c && j < vcount; j++) matrix[i][j] = strtod(c, &c); matrix[i][vcount] = strtod(c, &c); } printf("The system: \n"); show(); /* * Now solve the equation in the following manner: * * for each variable: * find an equation with a 1 for constant. * (if non, find one with a non-zero for constant * and multiply to make it a 1.) * add multiples of this equiation to others as needed * to zero-out their constants. */ for (i = 0; i < evmin; i++) { /* Find an equation to place here */ x = 0; for (j = i; j < ecount; j++) if (matrix[j][i] == 1.0) { swap(i, j); x = 1; break; } if (!x) for (j = i; j < ecount; j++) if (matrix[j][i] != 0.0) { swap(i,j); x = 1; mult(i, 1.0 / matrix[i][i]); break; } if (!x) { /* This variable doesn't matter. */ continue; } /* * Now -- zero out everyone else. */ for (j = 0; j < ecount; j++) { if (j == i) continue; if (matrix[j][i] == 0.0) continue; add(j, i, -matrix[j][i]); } } /* * Now -- solve for each of the variables. */ solvecomplex(); printf("The system: \n"); show(); } } solvecomplex() /* * */ { short i, j, k, lastj; for (i = 0; i < ecount; ) { for (j = 0; j < vcount; j++) if (matrix[i][j]) break; if (j == vcount) { if (matrix[i][j]) /* No solutions. */ { printf("The set has no real-number solutions.\n"); return; } swap(i,ecount-1); ecount--; continue; } i++; } if (!ecount) { printf("System works for all values.\n"); return; } lastj = -1; for (i = 0; i < ecount; i++) { for (j = 0; j < vcount; j++) if (matrix[i][j] != 0.0) break; if (j != i) for (lastj++; lastj < j; lastj++) printf("X(%d): all values.\n"); lastj = j; printf("X(%d): %8.4f", j, matrix[i][vcount]); for (k = j+1; k < vcount; k++) if (matrix[i][k] != 0.0) printf(" - [%8.4f * X(%d)]", matrix[i][k], k); printf("\n"); } for (i = lastj + 1; i < vcount; i++) printf("X(%d): all values\n", i); } swap(i,j) short i,j; /* * Swap two rows of the matrix. */ { double temp; short x; if (i == j) return; for (x = 0; x <= vcount; x++) { temp = matrix[i][x]; matrix[i][x] = matrix[j][x]; matrix[j][x] = temp; } if (showstep) { printf("Swap row %d and %d leaving:\n", i, j); show(); } } mult(i, f) short i; double f; /* * Multiply row i by constant f. */ { short x; for (x = 0; x <= vcount; x++) matrix[i][x] *= f; if (showstep) { printf("Multiply row %d by %f leaving:\n", i, f); show(); } } add(i,j,f) short i,j; double f; /* * Add to row i row (j*f). */ { short x; for (x = 0; x <= vcount; x++) matrix[i][x] += matrix[j][x] * f; if (showstep) { printf("Add (%f times row %d) to row %d:\n", f, j, i); show(); } } show() /* * Show the equation */ { short i,j; for (i = 0; i < ecount; i++) { for (j = 0; j < vcount; j++) printf(" %8.4f", matrix[i][j]); printf(" %8.4f\n", matrix[i][j]); } } usage(arg) char *arg; { fprintf(stderr, "\ Usage: %d [-s]\n\ where -s selects display of steps used to solve the set of equations.\n", arg); exit(0); } -- UUCP: rutgers!dayton!joe (Picts 1-16 are DHDSC - Joe Larson/MIS 1060 ATT : (612) 375-3537 now ready.) 700 on the Mall, Mpls, Mn. 55402 From jmasters at pcocd2.intel.com Wed Jan 31 12:10:33 1990 From: jmasters at pcocd2.intel.com (Justin Masters ~) Date: 31 Jan 90 01:10:33 GMT Subject: pcal Message-ID: <1546@mipos3.intel.com> Is there any idea why pcal does not seem to work properly on a Sun386i? ----------------------------------------------------------------------------- "Beatings will continue until morale | Justin Masters improves." | - management | jmasters at fmdgr1.intel.com From john at frog.UUCP Tue Jan 30 11:46:00 1990 From: john at frog.UUCP (John Woods) Date: 30 Jan 90 00:46:00 GMT Subject: brilliance References: <21982@uflorida.cis.ufl.EDU> Message-ID: <11566@frog.UUCP> In article <21982 at uflorida.cis.ufl.EDU>, gary at oak.circa.ufl.edu writes: > In article <5192 at solo8.cs.vu.nl>, maart at cs.vu.nl (Maarten Litmaath) writes... > |Cancelling a posted message means posting a cancel message. > Uh, what exactly does posting a cancel message involve? > A message with the subject CANCEL #xxxxx? Or the same message with the topic > CANCEL? Or what. > A cancel message is essentially an ordinary message distinguished by having a header line such as Control: cancel <nincompoop at frog.UUCP> Such messages will be found in the "control" group, even if the Newsgroups: line reads differently (I was hoping to put such a control line in this message, but tried it out first and discovered that it doesn't do exactly what I wanted...). Other than that, the message has exactly the same format as a regular news article. Any text in the body will be ignored, but that tends to be the fate for many regular messages, too :-). When a system receives such a control message: if the referenced article is present, it is removed, and the cancel message is propagated downstream to other sites. If the article is not present, B news sites simply leave a note in the "history" file to junk the article if seen; C news (I believe) also forwards the cancel message in any case. -- John Woods, Charles River Data Systems, Framingham MA, (508) 626-1101 ...!decvax!frog!john, john at frog.UUCP, ...!mit-eddie!jfw, jfw at eddie.mit.edu From michaele at vice.ICO.TEK.COM Wed Jan 31 05:56:59 1990 From: michaele at vice.ICO.TEK.COM (Michael Enkelis) Date: 30 Jan 90 18:56:59 GMT Subject: Repost of unzip for BSD (? SYS-V ?) unix. Message-ID: <4644@vice.ICO.TEK.COM> #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # Makefile # unzipbsd.c # crc32.c # patchlevel.h # unzip.doc # This archive created: Thu Jan 25 09:38:11 1990 export PATH; PATH=/bin:$PATH echo shar: extracting "'Makefile'" '(928 characters)' if test -f 'Makefile' then echo shar: will not over-write existing file "'Makefile'" else sed 's/^ X//' << \SHAR_EOF > 'Makefile' X# Makefile for unzipbsd X X X# "make unzip" -- makes unzip in current directory X# "make install" -- makes unzip, then moves it into DESTDIR defined below X# "make clean" -- deletes object files and executable unzip from current dir X# "make shar" -- make a SHell ARchive X# "make arc" -- make a DOS archive X X# Directory where we want to move executable unzip on "make install" XDESTDIR=/usr/public X X# CFLAGS are flags for the C compiler. LDFLAGS are flags for the loader. XCFLAGS= -O X# This is used for DBX X#CFLAGS= -g X XLDFLAGS= -s X XCC=cc X X.c.o: X $(CC) -c $(CFLAGS) $*.c X XSRCS = unzipbsd.c crc32.c patchlevel.h XOBJS = unzipbsd.o crc32.o X Xunzip: $(OBJS) X cc $(LDFLAGS) -o unzip $(OBJS) X Xunzip.o: unzip.c X Xcrc32.o: crc32.c X Xinstall: unzip X mv unzip $(DESTDIR)/unzip X Xclean: X /bin/rm -f $(OBJS) core unzip X Xshar: X @shar -a Makefile $(SRCS) unzip.doc > unzipbsd.shar X Xarc: X @arc -a unzipbsd.arc Makefile $(SRCS) unzip.doc X SHAR_EOF if test 928 -ne "`wc -c < 'Makefile'`" then echo shar: error transmitting "'Makefile'" '(should have been 928 characters)' fi fi # end of overwriting check echo shar: extracting "'unzipbsd.c'" '(43256 characters)' if test -f 'unzipbsd.c' then echo shar: will not over-write existing file "'unzipbsd.c'" else sed 's/^ X//' << \SHAR_EOF > 'unzipbsd.c' X X/* X * Copyright 1989 Samuel H. Smith; All rights reserved X * X * Do not distribute modified versions without my permission. X * Do not remove or alter this notice or any other copyright notice. X * If you use this in your own program you must distribute source code. X * Do not use any of this in a commercial product. X * X */ X X/* X * Unix mods by Michael Enkelis X * X * 01/25/90 -- Fix segment fault when reading corrupted file. X * X * 11/20/89 -- Try to use timezone info to correct for local time X * when extracting files & setting there mod time. X */ X X/* X * UnZip - A simple zipfile extract utility X * X * To compile: X * tcc -B -O -Z -G -mc unzip.c ;turbo C 2.0, compact model X * X */ X X#include "patchlevel.h" X#define VERSION "2.0" X Xtypedef unsigned char byte; /* code assumes UNSIGNED bytes */ Xtypedef long longint; Xtypedef unsigned word; Xtypedef char boolean; X X#define STRSIZ 256 X X#include <stdio.h> X /* this is your standard header for all C compiles */ X#include <ctype.h> X X#ifdef MSDOS || M_XENIX X#include <stdlib.h> X /* this include defines various standard library prototypes */ X#endif X X X/* X * SEE HOST OPERATING SYSTEM SPECIFICS SECTION STARTING NEAR LINE 180 X * X */ X X X/* ----------------------------------------------------------- */ X/* X * Zipfile layout declarations X * X */ X X Xchar local_file_header_signature[] = {0x50,0x4b,0x03,0x04}; X X Xtypedef struct local_file_header { X word version_needed_to_extract; X word general_purpose_bit_flag; X word compression_method; X word last_mod_file_time; X word last_mod_file_date; X longint crc32; X longint compressed_size; X longint uncompressed_size; X word filename_length; X word extra_field_length; X} local_file_header; X X Xchar central_file_header_signature[] = {0x50,0x4b,0x01,0x02}; X X Xtypedef struct central_directory_file_header { X word version_made_by; X word version_needed_to_extract; X word general_purpose_bit_flag; X word compression_method; X word last_mod_file_time; X word last_mod_file_date; X longint crc32; X longint compressed_size; X longint uncompressed_size; X word filename_length; X word extra_field_length; X word file_comment_length; X word disk_number_start; X word internal_file_attributes; X longint external_file_attributes; X longint relative_offset_local_header; X} central_directory_file_header; X X Xchar end_central_dir_signature[] = {0x50,0x4b,0x05,0x06}; X X Xtypedef struct end_central_dir_record { X word number_this_disk; X word number_disk_with_start_central_directory; X word total_entries_central_dir_on_this_disk; X word total_entries_central_dir; X longint size_central_directory; X longint offset_start_central_directory; X word zipfile_comment_length; X} end_central_dir_record; X X X X/* ----------------------------------------------------------- */ X/* X * input file variables X * X */ X X#define INBUFSIZ 0x2000 Xbyte *inbuf; /* input file buffer - any size is legal */ Xbyte *inptr; Xbyte *comment; X Xint incnt; Xunsigned bitbuf; Xint bits_left; Xboolean zipeof; X Xint zipfd; Xchar zipfn[STRSIZ]; Xlocal_file_header lrec; X X X/* ----------------------------------------------------------- */ X/* X * output stream variables X * X */ X X#define OUTBUFSIZ 0x6000 Xbyte *outbuf; /* buffer for rle look-back */ Xbyte *outptr; X Xlongint outpos; /* absolute position in outfile */ Xint outcnt; /* current position in outbuf */ X Xint outfd; Xchar filename[STRSIZ]; Xchar extra[STRSIZ]; X X#define DLE 144 X X X/* ----------------------------------------------------------- */ X/* X * shrink/reduce working storage X * X */ X Xint factor; Xbyte followers[256][64]; Xbyte Slen[256]; X X#define max_bits 13 X#define init_bits 9 X#define hsize 8192 X#define first_ent 257 X#define clear 256 X Xtypedef int hsize_array_integer[hsize+1]; Xtypedef byte hsize_array_byte[hsize+1]; X Xhsize_array_integer prefix_of; Xhsize_array_byte suffix_of; Xhsize_array_byte stack; X Xint codesize; Xint maxcode; Xint free_ent; Xint maxcodemax; Xint offset; Xint sizex; X X X X/* ============================================================= */ X/* X * Host operating system details X * X */ X X#include <strings.h> X /* this include defines strcpy, strchr, etc. */ X X#include <sys/time.h> X#include <sys/types.h> X#include <sys/timeb.h> X /* X * this include file defines X * struct ftime ... (* file time/date stamp info *) X */ X X#ifdef MSDOS || M_XENIX X#include <io.h> X /* X * this include file defines X * struct ftime ... (* file time/date stamp info *) X * int setftime (int handle, struct ftime *ftimep); X * #define SEEK_CUR 1 (* lseek() modes *) X * #define SEEK_END 2 X * #define SEEK_SET 0 X */ X#else X#include <sys/file.h> X /* X * this include file defines X * #define L_SET 0 (* Seek to absolute record *) X */ X#define SEEK_SET L_SET X#endif X X X X#ifdef MSDOS || M_XENIX X#include <fcntl.h> X /* X * this include file defines X * #define O_BINARY 0x8000 (* no cr-lf translation *) X * as used in the open() standard function X */ X#ifndef L_SET X#define L_SET 1 X#endif X#endif X X#ifndef O_BINARY X#define O_BINARY 0 /* BSD don't have a Open_BINARY mode */ X#endif X X#include <sys/types.h> X#include <sys/stat.h> X /* X * this include file defines X * #define S_IREAD 0x0100 (* owner may read *) X * #define S_IWRITE 0x0080 (* owner may write *) X * as used in the creat() standard function X */ X Xvoid set_file_time() X /* X * set the output file date/time stamp according to information from the X * zipfile directory record for this file X */ X{ X /* X * set output file date and time - this is optional and can be X * deleted X */ X X#define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0) X#define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400) X X byte yr, mo, dy; /* parts of a date */ X byte hh, mm, ss; /* parts of a time */ X static char month_lengths[] = X { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; X int day_of_year, year; X struct utimbuf { X time_t actime; /* file accessed time */ X time_t modtime; /* file updated time */ X } times; X#ifndef HAVE_TZ X struct timeb info; /* local timezone info */ X#endif X X yr = (lrec.last_mod_file_date >> 9) & 0x7f; /* dissect the date */ X mo = (lrec.last_mod_file_date >> 5) & 0x0f; X dy = lrec.last_mod_file_date & 0x1f; X X hh = (lrec.last_mod_file_time >> 11) & 0x1f; /* dissect the time */ X mm = (lrec.last_mod_file_time >> 5) & 0x3f; X ss = (lrec.last_mod_file_time & 0x1f) * 2; X X yr = (yr + 80) % 100; X year = yr + 1900; X X /* X * this is the standard Unix implementation (also fully X * compatible with MSC) X */ X X close(outfd); X if (mo < 1 || mo > 12 || dy < 1 || dy > month_lengths[mo-1] X && !(mo == 2 && dy == 29 && leap (year)) X || hh > 23 || mm > 59 || ss > 59) X return; X X day_of_year = dy - 1; X if (mo > 2 && leap(year)) X ++day_of_year; X X while (--mo > 0) X day_of_year += month_lengths[mo - 1]; X X times.modtime = (86400 * (long)(day_of_year + 365 * (year - 1970) X + nleap (year)) + 3600 * (hh-1) + 60 * mm + ss); X X/* SYS-V compat code */ X#ifdef HAVE_TZ X tzset(); X times.modtime += timezone; X#else X (void)ftime(&info); /* Find timezone */ X times.modtime += (info.timezone*60); /* Correct to local time */ X#endif X times.actime = times.modtime; X utime(filename, ×); X} X X/* X * Some defines to use the GETOPT functions X * that are on most systems, even TURBO-C has these. X */ X#define USE_GETOPT /* Use the GETOPT package */ Xint extract = 1; /* Extract contents */ Xint debugging = 0; /* debug enable */ Xint verbose = 0; /* be verbose */ Xint list_zip = 0; /* list contents only */ Xint test_zip = 0; /* test CRC's only */ Xint unixfy = 1; /* Convert filename to lowercase */ Xint dsp_comment = 1; /* Display comments */ X Xlong crc32val; /* The CRC value we calculate */ Xint numbad =0; Xint Total_files =0; Xlong Total_bytes =0; Xlong Total_length =0; X X/* ============================================================= */ X Xint create_output_file() X /* return non-0 if creat failed */ X{ X if (!extract) X return 0; X X /* create the output file with READ and WRITE permissions */ X outfd = creat(filename, S_IWRITE | S_IREAD); X if (outfd < 1) { X printf("Can't create output: %s\n", filename); X return 1; X } X X /* X * close the newly created file and reopen it in BINARY mode to X * disable all CR/LF translations X */ X close(outfd); X outfd = open(filename, O_RDWR | O_BINARY); X X /* write a single byte at EOF to pre-allocate the file */ X lseek(outfd, lrec.uncompressed_size - 1L, SEEK_SET); X write(outfd, "?", 1); X lseek(outfd, 0L, SEEK_SET); X return 0; X} X X Xint open_input_file() X /* return non-0 if creat failed */ X{ X /* X * open the zipfile for reading and in BINARY mode to prevent cr/lf X * translation, which would corrupt the bitstreams X */ X X zipfd = open(zipfn, O_RDONLY | O_BINARY); X if (zipfd < 1) { X printf("Can't open input file: %s\n", zipfn); X return (1); X } X return 0; X} X X Xint FillBuffer() X /* fill input buffer if possible */ X{ X int readsize; X X if (lrec.compressed_size <= 0) X return incnt = 0; X X if (lrec.compressed_size > INBUFSIZ) X readsize = INBUFSIZ; X else X readsize = (int) lrec.compressed_size; X incnt = read(zipfd, inbuf, readsize); X X if (incnt <= 0) /* Corrupted file test */ X return incnt = 0; X X lrec.compressed_size -= incnt; X inptr = inbuf; X return incnt--; X} X Xint ReadByte(x) Xunsigned *x; X /* read a byte; return 8 if byte available, 0 if not */ X{ X if (incnt-- == 0) X if (FillBuffer() == 0) X return 0; X X *x = *inptr++; X return 8; X} X X X/* ------------------------------------------------------------- */ Xstatic unsigned mask_bits[] = X {0, 0x0001, 0x0003, 0x0007, 0x000f, X 0x001f, 0x003f, 0x007f, 0x00ff, X 0x01ff, 0x03ff, 0x07ff, 0x0fff, X 0x1fff, 0x3fff, 0x7fff, 0xffff X }; X X Xint FillBitBuffer(bits) Xregister int bits; X{ X /* get the bits that are left and read the next word */ X unsigned temp; X register int result = bitbuf; X int sbits = bits_left; X bits -= bits_left; X X /* read next word of input */ X bits_left = ReadByte(&bitbuf); X bits_left += ReadByte(&temp); X bitbuf |= (temp << 8); X if (bits_left == 0) X zipeof = 1; X X /* get the remaining bits */ X result = result | (int) ((bitbuf & mask_bits[bits]) << sbits); X bitbuf >>= bits; X bits_left -= bits; X return result; X} X X#define READBIT(nbits,zdest,ztype) \ X { if (nbits <= bits_left) \ X { zdest = ztype(bitbuf & mask_bits[nbits]);\ X bitbuf >>= nbits; bits_left -= nbits; }\ X else zdest = ztype(FillBitBuffer(nbits));} X X/* X * macro READBIT(nbits,zdest,ztype) X * { X * if (nbits <= bits_left) { X * zdest = ztype(bitbuf & mask_bits[nbits]); X * bitbuf >>= nbits; X * bits_left -= nbits; X * } else X * zdest = ztype(FillBitBuffer(nbits)); X * } X * X */ X X X/* ------------------------------------------------------------- */ X Xvoid Write_file() X{ X if (extract) X write(outfd, outbuf, outcnt); X} X X/* ------------------------------------------------------------- */ X Xvoid FlushOutput() X /* flush contents of output buffer */ X{ X UpdateCRC(outbuf, outcnt); X Write_file(); X outpos += outcnt; X outcnt = 0; X outptr = outbuf; X} X X#define OUTB(intc) { *outptr++=intc; if (++outcnt==OUTBUFSIZ) FlushOutput(); } X X/* X * macro OUTB(intc) X * { X * *outptr++=intc; X * if (++outcnt==OUTBUFSIZ) X * FlushOutput(); X * } X * X */ X X X/* ----------------------------------------------------------- */ X Xvoid LoadFollowers() X{ X register int x; X register int i; X X for (x = 255; x >= 0; x--) { X READBIT(6,Slen[x],(byte)); X for (i = 0; i < Slen[x]; i++) { X READBIT(8,followers[x][i],(byte)); X } X } X} X X/* ----------------------------------------------------------- */ X/* X * The Reducing algorithm is actually a combination of two X * distinct algorithms. The first algorithm compresses repeated X * byte sequences, and the second algorithm takes the compressed X * stream from the first algorithm and applies a probabilistic X * compression method. X */ X Xint L_table[] = {0, 0x7f, 0x3f, 0x1f, 0x0f}; X Xint D_shift[] = {0, 0x07, 0x06, 0x05, 0x04}; Xint D_mask[] = {0, 0x01, 0x03, 0x07, 0x0f}; X Xint B_table[] = {8, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, X 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, X 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, X 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, X 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, X 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, X 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, X 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, X 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, X 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, X 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, X 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, X 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, X 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, X 8, 8, 8, 8}; X X/* ----------------------------------------------------------- */ X Xvoid unReduce() X /* expand probablisticly reduced data */ X{ X register int lchar; X int nchar; X int ExState; X int V; X int Len; X X factor = lrec.compression_method - 1; X ExState = 0; X lchar = 0; X LoadFollowers(); X X while (((outpos + outcnt) < lrec.uncompressed_size) && (!zipeof)) { X if (Slen[lchar] == 0) X READBIT(8,nchar,(int)) /* ; */ X else X { X READBIT(1,nchar,(int)); X if (nchar != 0) X READBIT(8,nchar,(int)) /* ; */ X else X { X int follower; X int bitsneeded = B_table[Slen[lchar]]; X READBIT(bitsneeded,follower,(int)); X nchar = followers[lchar][follower]; X } X } X X /* expand the resulting byte */ X switch (ExState) { X X case 0: X if (nchar != DLE) X OUTB(nchar) /*;*/ X else X ExState = 1; X break; X X case 1: X if (nchar != 0) { X V = nchar; X Len = V & L_table[factor]; X if (Len == L_table[factor]) X ExState = 2; X else X ExState = 3; X } X else { X OUTB(DLE); X ExState = 0; X } X break; X X case 2: { X Len += nchar; X ExState = 3; X } X break; X X case 3: { X register int i = Len + 3; X int offset = (((V >> D_shift[factor]) & X D_mask[factor]) << 8) + nchar + 1; X longint op = outpos + outcnt - offset; X X /* special case- before start of file */ X while ((op < 0L) && (i > 0)) { X OUTB(0); X op++; X i--; X } X X /* normal copy of data from output buffer */ X { X register int ix = (int) (op % OUTBUFSIZ); X X /* do a block memory copy if possible */ X if ( ((ix +i) < OUTBUFSIZ) && X ((outcnt+i) < OUTBUFSIZ) ) { X MEMCPY(outptr,&outbuf[ix],i); X outptr += i; X outcnt += i; X } X X /* otherwise copy byte by byte */ X else while (i--) { X OUTB(outbuf[ix]); X if (++ix >= OUTBUFSIZ) X ix = 0; X } X } X X ExState = 0; X } X break; X } X X /* store character for next iteration */ X lchar = nchar; X } X} X X X/* ------------------------------------------------------------- */ X/* X * Shrinking is a Dynamic Ziv-Lempel-Welch compression algorithm X * with partial clearing. X * X */ X Xvoid partial_clear() X{ X register int pr; X register int cd; X X /* mark all nodes as potentially unused */ X for (cd = first_ent; cd < free_ent; cd++) X prefix_of[cd] |= 0x8000; X X /* unmark those that are used by other nodes */ X for (cd = first_ent; cd < free_ent; cd++) { X pr = prefix_of[cd] & 0x7fff; /* reference to another node? */ X if (pr >= first_ent) /* flag node as referenced */ X prefix_of[pr] &= 0x7fff; X } X X /* clear the ones that are still marked */ X for (cd = first_ent; cd < free_ent; cd++) X if ((prefix_of[cd] & 0x8000) != 0) X prefix_of[cd] = -1; X X /* find first cleared node as next free_ent */ X cd = first_ent; X while ((cd < maxcodemax) && (prefix_of[cd] != -1)) X cd++; X free_ent = cd; X} X X X/* ------------------------------------------------------------- */ X Xvoid unShrink() X{ X#define GetCode(dest) READBIT(codesize,dest,(int)) X X register int code; X register int stackp; X int finchar; X int oldcode; X int incode; X X X /* decompress the file */ X maxcodemax = 1 << max_bits; X codesize = init_bits; X maxcode = (1 << codesize) - 1; X free_ent = first_ent; X offset = 0; X sizex = 0; X X for (code = maxcodemax; code > 255; code--) X prefix_of[code] = -1; X X for (code = 255; code >= 0; code--) { X prefix_of[code] = 0; X suffix_of[code] = code; X } X X GetCode(oldcode); X if (zipeof) X return; X finchar = oldcode; X X OUTB(finchar); X X stackp = hsize; X X while (!zipeof) { X GetCode(code); X if (zipeof) X return; X X while (code == clear) { X GetCode(code); X switch (code) { X X case 1:{ X codesize++; X if (codesize == max_bits) X maxcode = maxcodemax; X else X maxcode = (1 << codesize) - 1; X } X break; X X case 2: X partial_clear(); X break; X } X X GetCode(code); X if (zipeof) X return; X } X X X /* special case for KwKwK string */ X incode = code; X if (prefix_of[code] == -1) { X stack[--stackp] = finchar; X code = oldcode; X } X X X /* generate output characters in reverse order */ X while (code >= first_ent) { X stack[--stackp] = suffix_of[code]; X code = prefix_of[code]; X } X X finchar = suffix_of[code]; X stack[--stackp] = finchar; X X X /* and put them out in forward order, block copy */ X if ((hsize-stackp+outcnt) < OUTBUFSIZ) { X MEMCPY(outptr,&stack[stackp],hsize-stackp); X outptr += hsize-stackp; X outcnt += hsize-stackp; X stackp = hsize; X } X X /* output byte by byte if we can't go by blocks */ X else while (stackp < hsize) X OUTB(stack[stackp++]); X X X /* generate new entry */ X code = free_ent; X if (code < maxcodemax) { X prefix_of[code] = oldcode; X suffix_of[code] = finchar; X X do X code++; X while ((code < maxcodemax) && (prefix_of[code] != -1)); X X free_ent = code; X } X X /* remember previous code */ X oldcode = incode; X } X X} X X/* ------------------------------------------------------------- */ X/* X * Imploding X * --------- X * X * The Imploding algorithm is actually a combination of two distinct X * algorithms. The first algorithm compresses repeated byte sequences X * using a sliding dictionary. The second algorithm is used to compress X * the encoding of the sliding dictionary ouput, using multiple X * Shannon-Fano trees. X * X */ X X#define maxSF 256 X X typedef struct sf_entry { X word Code; X byte Value; X byte BitLength; X } sf_entry; X X typedef struct sf_tree { /* a shannon-fano tree */ X sf_entry entry[maxSF]; X int entries; X int MaxLength; X } sf_tree; X X typedef sf_tree *sf_treep; X X sf_tree lit_tree; X sf_tree length_tree; X sf_tree distance_tree; X boolean lit_tree_present; X boolean eightK_dictionary; X int minimum_match_length; X int dict_bits; X X Xvoid SortLengths(tree) Xsf_tree *tree; X /* Sort the Bit Lengths in ascending order, while retaining the order X of the original lengths stored in the file */ X{ X int x; X int gap; X sf_entry t; X boolean noswaps; X int a, b; X X gap = tree->entries / 2; X X do { X do { X noswaps = 1; X for (x = 0; x <= (tree->entries - 1) - gap; x++) X { X a = tree->entry[x].BitLength; X b = tree->entry[x + gap].BitLength; X if ((a > b) || ((a == b) && (tree->entry[x].Value > tree->entry[x + gap].Value))) X { X t = tree->entry[x]; X tree->entry[x] = tree->entry[x + gap]; X tree->entry[x + gap] = t; X noswaps = 0; X } X } X } while (!noswaps); X X gap = gap / 2; X } while (gap > 0); X} X X X/* ----------------------------------------------------------- */ X Xvoid ReadLengths(tree) Xsf_tree *tree; X{ X int treeBytes; X int i; X int num, len; X X /* get number of bytes in compressed tree */ X READBIT(8,treeBytes,(int)); X treeBytes++; X i = 0; X X tree->MaxLength = 0; X X /* High 4 bits: Number of values at this bit length + 1. (1 - 16) X Low 4 bits: Bit Length needed to represent value + 1. (1 - 16) */ X while (treeBytes > 0) X { X READBIT(4,len,(int)); len++; X READBIT(4,num,(int)); num++; X X while (num > 0) X { X if (len > tree->MaxLength) X tree->MaxLength = len; X tree->entry[i].BitLength = (byte) len; X tree->entry[i].Value = (byte) i; X i++; X num--; X } X X treeBytes--; X } X} X X X/* ----------------------------------------------------------- */ X Xvoid GenerateTrees(tree) Xsf_tree *tree; X /* Generate the Shannon-Fano trees */ X{ X word Code; X int CodeIncrement; X int LastBitLength; X int i; X X X Code = 0; X CodeIncrement = 0; X LastBitLength = 0; X X i = tree->entries - 1; /* either 255 or 63 */ X while (i >= 0) X { X Code += CodeIncrement; X if (tree->entry[i].BitLength != (byte) LastBitLength) X { X LastBitLength = tree->entry[i].BitLength; X CodeIncrement = 1 << (16 - LastBitLength); X } X X tree->entry[i].Code = Code; X i--; X } X} X X X/* ----------------------------------------------------------- */ X Xvoid ReverseBits(tree) Xsf_tree *tree; X /* Reverse the order of all the bits in the above ShannonCode[] X vector, so that the most significant bit becomes the least X significant bit. For example, the value 0x1234 (hex) would become X 0x2C48 (hex). */ X{ X int i; X word mask; X word revb; X word v; X word o; X int b; X X X for (i = 0; i <= tree->entries - 1; i++) X { X /* get original code */ X o = tree->entry[i].Code; X X /* reverse each bit */ X mask = 0x0001; X revb = 0x8000; X v = 0; X for (b = 0; b <= 15; b++) X { X /* if bit set in mask, then substitute reversed bit */ X if ((o & mask) != 0) X v = v | revb; X X /* advance to next bit */ X revb = (revb >> 1); X mask = (mask << 1); X } X X /* store reversed bits */ X tree->entry[i].Code = v; X } X} X X X/* ----------------------------------------------------------- */ X Xvoid LoadTree(tree, treesize) Xsf_tree *tree; Xint treesize; X /* allocate and load a shannon-fano tree from the compressed file */ X{ X tree->entries = treesize; X ReadLengths(tree); X SortLengths(tree); X GenerateTrees(tree); X ReverseBits(tree); X} X X X/* ----------------------------------------------------------- */ X Xvoid LoadTrees() X{ X /* bit 1... */ X eightK_dictionary = (boolean) ((lrec.general_purpose_bit_flag & 0x02) != 0); X /* bit 2... */ X lit_tree_present = (boolean) ((lrec.general_purpose_bit_flag & 0x04) != 0); X X if (eightK_dictionary) X dict_bits = 7; X else X dict_bits = 6; X X if (lit_tree_present) X { X minimum_match_length = 3; X LoadTree(&lit_tree,256); X } X else X minimum_match_length = 2; X X LoadTree(&length_tree,64); X LoadTree(&distance_tree,64); X} X X X/* ----------------------------------------------------------- */ X Xvoid ReadTree(tree, dest) Xsf_tree *tree; Xint *dest; X /* read next byte using a shannon-fano tree */ X{ X int bits = 0; X word cv = 0; X int cur = 0; X int b; X X *dest = -1; /* in case of error */ X X for (;;) X { X READBIT(1,b,(int)); X cv = cv | (b << bits); X bits++; X X /* this is a very poor way of decoding shannon-fano. two quicker X methods come to mind: X a) arrange the tree as a huffman-style binary tree with X a "leaf" indicator at each node, X and X b) take advantage of the fact that s-f codes are at most 8 X bits long and alias unused codes for all bits following X the "leaf" bit. X */ X X while (tree->entry[cur].BitLength < (byte) bits) X { X cur++; X if (cur >= tree->entries) X return; /* data error */ X } X X while (tree->entry[cur].BitLength == (byte) bits) X { X if (tree->entry[cur].Code == cv) X { X *dest = tree->entry[cur].Value; X return; X } X X cur++; X if (cur >= tree->entries) X return; /* data error */ X } X } X} X X X/* ----------------------------------------------------------- */ X Xvoid unImplode() X /* expand imploded data */ X X{ X int lout; X longint op; X int Length; X int Distance; X X LoadTrees(); X X while ((!zipeof) && ((outpos+outcnt) < lrec.uncompressed_size)) X { X READBIT(1,lout,(int)); X X if (lout != 0) /* encoded data is literal data */ X { X if (lit_tree_present) /* use Literal Shannon-Fano tree */ X ReadTree(&lit_tree,&lout); X else X READBIT(8,lout,(int)); X X OUTB((byte) lout); X } X else /* encoded data is sliding dictionary match */ X { X READBIT(dict_bits,lout,(int)); X Distance = lout; X X ReadTree(&distance_tree,&lout); X Distance |= (lout << dict_bits); X /* using the Distance Shannon-Fano tree, read and decode the X upper 6 bits of the Distance value */ X X ReadTree(&length_tree,&Length); X /* using the Length Shannon-Fano tree, read and decode the X Length value */ X X Length += minimum_match_length; X if (Length == (63 + minimum_match_length)) X { X READBIT(8,lout,(int)); X Length += lout; X } X X /* move backwards Distance+1 bytes in the output stream, and copy X Length characters from this position to the output stream. X (if this position is before the start of the output stream, X then assume that all the data before the start of the output X stream is filled with zeros) */ X X op = (outpos+outcnt) - Distance - 1L; X X /* special case- before start of file */ X while ((op < 0L) && (Length > 0)) { X OUTB(0); X op++; X Length--; X } X X /* normal copy of data from output buffer */ X { X register int ix = (int) (op % OUTBUFSIZ); X X /* do a block memory copy if possible */ X if ( ((ix +Length) < OUTBUFSIZ) && X ((outcnt+Length) < OUTBUFSIZ) ) { X MEMCPY(outptr,&outbuf[ix],Length); X outptr += Length; X outcnt += Length; X } X X /* otherwise copy byte by byte */ X else while (Length--) { X OUTB(outbuf[ix]); X if (++ix >= OUTBUFSIZ) X ix = 0; X } X } X } X } X} X X/* ---------------------------------------------------------- */ X Xvoid extract_member() X{ X unsigned b; X X bits_left = 0; X bitbuf = 0; X incnt = 0; X outpos = 0L; X outcnt = 0; X outptr = outbuf; X zipeof = 0; X crc32val = 0xFFFFFFFFL; X X X /* create the output file with READ and WRITE permissions */ X if (create_output_file()) X exit(1); X X switch (lrec.compression_method) { X X case 0: /* stored */ X { X if (test_zip) X printf("Testing: %-12s ", filename); X if (extract) X printf(" Extracting: %-12s ", filename); X while (ReadByte(&b)) X OUTB(b); X } X break; X X case 1: { /* shrunk */ X if (test_zip) X printf("Testing: %-12s ", filename); X if (extract) X printf("UnShrinking: %-12s ", filename); X unShrink(); X } X break; X X case 2: /* reduced, factor:1 */ X case 3: /* reduced, factor:2 */ X case 4: /* reduced, factor:3 */ X case 5: { /* reduced, factor:4 */ X if (test_zip) X printf("Testing: %-12s ", filename); X if (extract) X printf(" Expanding: %-12s ", filename); X unReduce(); X } X break; X X case 6: { /* imploded */ X if (test_zip) X printf("Testing: %-12s ", filename); X if (extract) X printf(" Exploding: %-12s ", filename); X unImplode(); X } X break; X X X default: X printf("Unknown compression method."); X } X X X /* write the last partial buffer, if any */ X if (outcnt > 0) { X UpdateCRC(outbuf, outcnt); X Write_file(); X } X X /* set output file date and time */ X set_file_time(); X X close(outfd); X X crc32val = -1 - crc32val; X if (!list_zip) { X if (crc32val != lrec.crc32) { X numbad++; X printf(" Bad"); X if(verbose) X printf(", CRC %08lx (should be %08lx)", lrec.crc32, crc32val); X } else { X printf(" Ok"); X if (verbose) X printf(", CRC = %08lx", lrec.crc32); X } X printf("\n"); X } X} X X X/* ---------------------------------------------------------- */ X Xvoid get_string(len, s) Xint len; Xchar *s; X{ X read(zipfd, s, len); X s[len] = 0; X} X X/* UNIX support routines: Michael Enkelis */ Xget_byte() X{ X byte nibble; X read(zipfd,&nibble,1); X return (byte) (nibble & 0xff); X} X Xget_word() X{ X byte nibble[2]; X nibble[0] = get_byte(); X nibble[1] = get_byte(); X return (word) (nibble[0] | nibble[1] << 8); X} X Xget_long() X{ X byte nibble[4]; X nibble[0] = get_byte(); X nibble[1] = get_byte(); X nibble[2] = get_byte(); X nibble[3] = get_byte(); X return (longint) ((unsigned long) nibble[0] | X ((unsigned long) nibble[1] << 8) | X ((unsigned long) nibble[2] << 16) | X ((unsigned long) nibble[3] << 24)); X} X XMEMCPY(s1, s2, n) /* Use our simple version of memcpy */ Xregister byte *s1, *s2; Xregister n; X{ X while (--n >= 0) X *s1++ = *s2++; X} X XSTRCHR(sp, c) /* Use our simple version of strchr */ Xregister char *sp, c; X{ X do { X if (*sp == c) X return(sp); X } while (*sp++); X return(NULL); X} X X/** End of added support routines **/ X X X/* ---------------------------------------------------------- */ X Xvoid process_local_file_header() X{ X byte Temp; X byte yr, mo, dy; /* parts of a date */ X byte hh, mm, ss; /* parts of a time */ X X static char *mon[] = /* month abbreviations */ X { X "Jan", "Feb", "Mar", "Apr", X "May", "Jun", "Jul", "Aug", X "Sep", "Oct", "Nov", "Dec" X }; X X lrec.version_needed_to_extract = get_word(); X lrec.general_purpose_bit_flag = get_word(); X lrec.compression_method = get_word(); X lrec.last_mod_file_time = get_word(); X lrec.last_mod_file_date = get_word(); X lrec.crc32 = get_long(); X lrec.compressed_size = get_long(); X lrec.uncompressed_size = get_long(); X lrec.filename_length = get_word(); X lrec.extra_field_length = get_word(); X X get_string(lrec.filename_length,filename); X if (unixfy) { X char *cp; X for (cp = filename; *cp; ++cp) X if (isupper(*cp)) *cp = tolower(*cp); X } X X get_string(lrec.extra_field_length,extra); X X yr = (lrec.last_mod_file_date >> 9) & 0x7f; /* dissect the date */ X mo = (lrec.last_mod_file_date >> 5) & 0x0f; X dy = lrec.last_mod_file_date & 0x1f; X X hh = (lrec.last_mod_file_time >> 11) & 0x1f; /* dissect the time */ X mm = (lrec.last_mod_file_time >> 5) & 0x3f; X ss = (lrec.last_mod_file_time & 0x1f) * 2; X X if (debugging) { X printf("\n\nProcess LOCAL file header.\n"); X Temp = lrec.version_needed_to_extract; X printf("Version used : %d\n",Temp); X printf("Bit flags : "); X Temp = (lrec.general_purpose_bit_flag & 3); X if (Temp & 1) X printf("Encrypted\n"); X if (lrec.compression_method == 6) { X printf("%dK sliding dictionary, ", (Temp & 2)? 8 : 4); X printf("%d Shannon-Fano trees", (Temp & 4)? 3 : 2); X } X printf("\n"); X X printf("Compression : %d\n",lrec.compression_method); X printf("Mod time :"); X printf("%2d:%02d%cm\n", X (hh > 12 ? hh - 12 : hh), mm, (hh > 11 ? 'p' : 'a')); X printf("Mod date :"); X printf("%2d %3s %02d\n", dy, mon[mo - 1], (yr + 80) % 100); X printf("Crc32 : %d\n",~lrec.crc32); X printf("Compressed size : %d\n",lrec.compressed_size); X printf("Normal file size: %d\n",lrec.uncompressed_size); X printf("File name : %s.%s\n",filename,extra); X } X X extract_member(); X} X X X/* ---------------------------------------------------------- */ X Xvoid process_central_file_header() X{ X central_directory_file_header rec; X char filename[STRSIZ]; X char extra[STRSIZ]; X X byte Temp; X byte yr, mo, dy; /* parts of a date */ X byte hh, mm, ss; /* parts of a time */ X X static char *mon[] = /* month abbreviations */ X { X "Jan", "Feb", "Mar", "Apr", X "May", "Jun", "Jul", "Aug", X "Sep", "Oct", "Nov", "Dec" X }; X X rec.version_made_by = get_word(); X rec.version_needed_to_extract = get_word(); X rec.general_purpose_bit_flag = get_word(); X rec.compression_method = get_word(); X rec.last_mod_file_time = get_word(); X rec.last_mod_file_date = get_word(); X rec.crc32 = get_long(); X rec.compressed_size = get_long(); X rec.uncompressed_size = get_long(); X rec.filename_length = get_word(); X rec.extra_field_length = get_word(); X rec.file_comment_length = get_word(); X rec.disk_number_start = get_word(); X rec.internal_file_attributes = get_word(); X rec.external_file_attributes = get_long(); X rec.relative_offset_local_header = get_long(); X X get_string(rec.filename_length,filename); X if (unixfy) { X char *cp; X for (cp = filename; *cp; ++cp) X if (isupper(*cp)) *cp = tolower(*cp); X } X X get_string(rec.extra_field_length,extra); X comment = (byte *) (realloc(comment, rec.file_comment_length)); X get_string(rec.file_comment_length,comment); X X yr = (rec.last_mod_file_date >> 9) & 0x7f; /* dissect the date */ X mo = (rec.last_mod_file_date >> 5) & 0x0f; X dy = rec.last_mod_file_date & 0x1f; X X hh = (rec.last_mod_file_time >> 11) & 0x1f; /* dissect the time */ X mm = (rec.last_mod_file_time >> 5) & 0x3f; X ss = (rec.last_mod_file_time & 0x1f) * 2; X X if (debugging) { X printf("\n\nProcess CENTRAL file header.\n"); X printf("Version made by : "); X Temp = rec.version_made_by; X switch ((Temp >> 8) & 7) { X case 0: printf("MS-DOS");break; X case 1: printf("Amiga");break; X case 2: printf("VMS");break; X case 3: printf("Unix");break; X case 4: printf("VM/CMS");break; X case 5: printf("Atari");break; X case 6: printf("OS/2");break; X case 7: printf("Macintosh");break; X default: X printf("Unknown"); X } X printf(" Version %d.%d\n",(Temp & 255)/10,(Temp & 255) % 10); X X Temp = rec.version_needed_to_extract; X printf("Ver to extract : %d\n",Temp); X X printf("Bit flags : "); X Temp = (rec.general_purpose_bit_flag & 3); X if (Temp & 1) X printf("Encrypted\n"); X if (rec.compression_method == 6) { X printf("%dK sliding dictionary, ", (Temp & 2)? 8 : 4); X printf("%d Shannon-Fano trees", (Temp & 4)? 3 : 2); X } X printf("\n"); X X printf("Compression : %d\n",rec.compression_method); X printf("Mod time :"); X printf("%2d:%02d%cm\n", X (hh > 12 ? hh - 12 : hh), mm, (hh > 11 ? 'p' : 'a')); X printf("Mod date :"); X printf("%2d %3s %02d\n", dy, mon[mo - 1], (yr + 80) % 100); X printf("Crc32 : %d\n",~rec.crc32); X printf("Compressed size : %d\n",rec.compressed_size); X printf("Normal file size: %d\n",rec.uncompressed_size); X printf("File name : %s.%s\n",filename,extra); X printf("Comment size : %d\n",rec.file_comment_length); X printf("Disk start # : %d\n",rec.disk_number_start); X printf("File attributes : %d\n",rec.internal_file_attributes); X printf("Os attributes : %d\n",rec.external_file_attributes); X printf("Offset to header: %d\n",rec.relative_offset_local_header); X printf("Comment : %s\n",comment); X } X X if (list_zip) { X Total_files++; X Total_bytes += rec.uncompressed_size; X Total_length += rec.compressed_size; X X printf("%-12s %8d ", filename,rec.uncompressed_size); X if (verbose) { X printf("%8d ",rec.compressed_size); X if (rec.compressed_size) X printf("%3d%% ",100L - (100L * rec.compressed_size)/ X rec.uncompressed_size); X else X printf("--- "); X } X X printf("%2d %3s %02d", dy, mon[mo - 1], (yr + 80) % 100); X X if (verbose) X printf(" %2d:%02d%cm", X (hh > 12 ? hh - 12 : hh), mm, (hh > 11 ? 'p' : 'a')); X printf("\n"); X } X X} X X X/* ---------------------------------------------------------- */ X Xvoid process_end_central_dir() X{ X end_central_dir_record rec; X X rec.number_this_disk = get_word(); X rec.number_disk_with_start_central_directory = get_word(); X rec.total_entries_central_dir_on_this_disk = get_word(); X rec.total_entries_central_dir = get_word(); X rec.size_central_directory = get_long(); X rec.offset_start_central_directory = get_long(); X rec.zipfile_comment_length = get_word(); X X comment = (byte *) (realloc(comment, rec.zipfile_comment_length)); X get_string(rec.zipfile_comment_length,comment); X X if (debugging) { X printf("\n\nProcess END_CENTRAL directory header.\n"); X printf("This disk : %d\n",rec.number_this_disk); X printf("Starting disk : %d\n", X rec.number_disk_with_start_central_directory); X printf("Total this disk : %d\n", X rec.total_entries_central_dir_on_this_disk); X printf("Total entries : %d\n",rec.total_entries_central_dir); X printf("Central dir size: %d\n",rec.size_central_directory); X printf("Offset to dir : %d\n",rec.offset_start_central_directory); X printf("Comment size : %d\n",rec.zipfile_comment_length); X printf("Comment : %s\n",comment); X } X} X X X/* ---------------------------------------------------------- */ X Xvoid process_headers() X{ X int i; X char sig[4]; X X if (list_zip) { X if (verbose) { X printf("\nName Length Size now SF Date Time"); X printf("\n============ ======== ======== ==== ========= ========\n"); X } else { X printf("\nName Length Date"); X printf("\n============ ======== =========\n"); X } X } X X while (1) X { X for (i=0; i<4; i++) /* Read the ZIP file sig */ X sig[i] = get_byte(); X X if (strncmp(sig,local_file_header_signature,4) == 0) X process_local_file_header(); X else X if (strncmp(sig,central_file_header_signature,4) == 0) X process_central_file_header(); X else X if (strncmp(sig,end_central_dir_signature,4) == 0) X { X process_end_central_dir(); X if (test_zip) { X if (numbad < 1) X printf("No errors detected\n"); X else X if (numbad == 1) X printf("One error detected\n"); X else X printf("%d errors detected\n",numbad); X } X if (list_zip) { X if (verbose) { X printf(" ==== ======== ======== ==== \n"); X printf("Total: %4d %8d %8d ", X Total_files,Total_bytes,Total_length); X if (Total_length) X printf("%3d%%\n", 100 - (100 * Total_length)/ X Total_bytes); X else X printf("---\n"); X } else { X printf(" ==== ========\n"); X printf("Total: %4d %8d\n", X Total_files,Total_bytes); X } X } X if (strlen(comment) && dsp_comment) X printf("%s\n",comment); X return; X } X else X { X printf("Invalid Zipfile Header\n"); X return; X } X } X} X X X X/* ---------------------------------------------------------- */ X Xvoid extract_zipfile() X{ X /* X * open the zipfile for reading and in BINARY mode to prevent cr/lf X * translation, which would corrupt the bitstreams X */ X X if (open_input_file()) X exit(1); X X process_headers(); X X close(zipfd); X} X X X/* ---------------------------------------------------------- */ X/* X * main program X * X */ X Xvoid main(argc, argv) Xint argc; Xchar **argv; X{ X X#ifdef USE_GETOPT X int c; /* next option letter */ X int count = 0; /* count of required options seen */ X X extern int optind; /* from getopt: next arg to process */ X extern int opterr; /* used by getopt */ X extern char *optarg; X X opterr = 0; /* so getopt won't print err msg */ X X while ((c = getopt (argc, argv, "cdltuv")) != EOF) X { X switch (c) { X case 'c': dsp_comment =0; break; X case 'd': debugging++;dsp_comment =0; break; X case 'l': list_zip =1;extract =0; break; X case 't': test_zip =1;extract =0; break; X case 'u': unixfy =0; break; X case 'v': verbose++; break; X default: short_help(); X } X } X X if (argv[optind] != NULL) X strcpy(zipfn,argv[optind]); X else X long_help(); X X /* .ZIP default if none provided by user */ X if (STRCHR(zipfn,'.') == NULL) X strcat(zipfn,".zip"); X#else X if (argc != 2) X long_help(); X X /* .ZIP default if none provided by user */ X strcpy(zipfn, argv[1]); X if (STRCHR(zipfn, '.') == NULL) X strcat(zipfn, ".zip"); X#endif X X /* allocate i/o buffers */ X inbuf = (byte *) (malloc(INBUFSIZ)); X outbuf = (byte *) (malloc(OUTBUFSIZ)); X comment = (byte *) (malloc(STRSIZ)); X if ((inbuf == NULL) || (outbuf == NULL) || (comment == NULL)) { X printf("Can't allocate buffers!\n"); X exit(1); X } X X /* do the job... */ X extract_zipfile(); X exit(0); X} X Xlong_help() X{ Xprintf("\nUnZip: Zipfile Extract Version:%s Patchlevel:%d",VERSION,PATCH); Xprintf("; (C) 1989 Samuel H. Smith\n"); Xprintf("Courtesy of: S.H.Smith and The Tool Shop BBS, (602) 279-2673."); Xprintf("\n\n"); Xprintf("UNIX mods by: Michael Enkelis\n\n"); Xprintf("You may copy and distribute this program freely, provided that:\n"); Xprintf(" 1) No fee is charged for such copying and distribution, and\n"); Xprintf(" 2) It is distributed ONLY in its original, unmodified state."); Xprintf("\n\n"); Xprintf("If you wish to distribute a modified version of this program, you MUST\n"); Xprintf("include the source code.\n\n"); Xprintf("If you modify this program, I would appreciate a copy of the new source\n"); Xprintf("code. I am holding the copyright on the source code, so please don't\n"); Xprintf("delete my name from the program files or from the documentation.\n\n"); Xprintf("IN NO EVENT WILL I BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING ANY LOST\n"); Xprintf("PROFITS, LOST SAVINGS OR OTHER INCIDENTAL OR CONSEQUENTIAL DAMAGES\n"); Xprintf("ARISING OUT OF YOUR USE OR INABILITY TO USE THE PROGRAM, OR FOR ANY\n"); Xprintf("CLAIM BY ANY OTHER PARTY.\n\n"); Xshort_help(); Xexit(1); X} X Xshort_help() X{ X printf("Usage: UnZip -chltuv FILE[.zip]\n\n"); X printf(" -c Don't display coments.\n"); X printf(" -h This help listing.\n"); X printf(" -l List zip archive.\n"); X printf(" -t Test zip archive.\n"); X printf(" -u Don't convert filenames to lowercase.\n"); X printf(" -v Verbose output.\n\n"); X exit(1); X} SHAR_EOF if test 43256 -ne "`wc -c < 'unzipbsd.c'`" then echo shar: error transmitting "'unzipbsd.c'" '(should have been 43256 characters)' fi fi # end of overwriting check echo shar: extracting "'crc32.c'" '(7120 characters)' if test -f 'crc32.c' then echo shar: will not over-write existing file "'crc32.c'" else sed 's/^ X//' << \SHAR_EOF > 'crc32.c' X X /* ============================================================= */ X /* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or */ X /* code or tables extracted from it, as desired without restriction. */ X /* */ X /* First, the polynomial itself and its table of feedback terms. The */ X /* polynomial is */ X /* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ X /* */ X /* Note that we take it "backwards" and put the highest-order term in */ X /* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ X /* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ X /* the MSB being 1. */ X /* */ X /* Note that the usual hardware shift register implementation, which */ X /* is what we're using (we're merely optimizing it by doing eight-bit */ X /* chunks at a time) shifts bits into the lowest-order term. In our */ X /* implementation, that means shifting towards the right. Why do we */ X /* do it this way? Because the calculated CRC must be transmitted in */ X /* order from highest-order term to lowest-order term. UARTs transmit */ X /* characters in order from LSB to MSB. By storing the CRC this way, */ X /* we hand it to the UART in the order low-byte to high-byte; the UART */ X /* sends each low-bit to hight-bit; and the result is transmission bit */ X /* by bit from highest- to lowest-order term without requiring any bit */ X /* shuffling on our part. Reception works similarly. */ X /* */ X /* The feedback terms table consists of 256, 32-bit entries. Notes: */ X /* */ X /* The table can be generated at runtime if desired; code to do so */ X /* is shown later. It might not be obvious, but the feedback */ X /* terms simply represent the results of eight shift/xor opera- */ X /* tions for all combinations of data and CRC register values. */ X /* */ X /* The values must be right-shifted by eight bits by the "updcrc" */ X /* logic; the shift must be unsigned (bring in zeroes). On some */ X /* hardware you could probably optimize the shift in assembler by */ X /* using byte-swap instructions. */ X /* polynomial $edb88320 */ X /* */ X /* -------------------------------------------------------------------- */ X Xlong crc_32_tab[] = { X 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, X 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, X 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, X 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, X 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, X 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, X 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, X 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, X 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, X 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, X 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, X 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, X 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, X 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, X 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, X 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, X 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, X 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, X 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, X 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, X 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, X 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, X 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, X 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, X 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, X 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, X 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, X 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, X 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, X 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, X 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, X 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, X 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, X 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, X 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, X 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, X 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, X 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, X 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, X 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, X 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, X 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, X 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, X 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, X 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, X 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, X 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, X 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, X 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, X 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, X 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, X 0x2d02ef8dL X }; X X/* ------------------------------------------------------------- */ X Xextern long crc32val; X Xvoid UpdateCRC(s, len) Xregister char *s; Xregister int len; X /* update running CRC calculation with contents of a buffer */ X{ X int i; X for (i = 0; i < len; i ++) { X crc32val = crc_32_tab[(int) ((crc32val) ^ (s[i])) & 0xff] ^ X (((crc32val) >> 8) & 0x00FFFFFFL); X } X} SHAR_EOF if test 7120 -ne "`wc -c < 'crc32.c'`" then echo shar: error transmitting "'crc32.c'" '(should have been 7120 characters)' fi fi # end of overwriting check echo shar: extracting "'patchlevel.h'" '(16 characters)' if test -f 'patchlevel.h' then echo shar: will not over-write existing file "'patchlevel.h'" else sed 's/^ X//' << \SHAR_EOF > 'patchlevel.h' X#define PATCH 3 SHAR_EOF if test 16 -ne "`wc -c < 'patchlevel.h'`" then echo shar: error transmitting "'patchlevel.h'" '(should have been 16 characters)' fi fi # end of overwriting check echo shar: extracting "'unzip.doc'" '(3086 characters)' if test -f 'unzip.doc' then echo shar: will not over-write existing file "'unzip.doc'" else sed 's/^ X//' << \SHAR_EOF > 'unzip.doc' X X UnZip X X Version 2.0.1, 09-16-89 X X Zipfile Extract Utility X X Copyright (C) 1989 Samuel H. Smith; ALL RIGHTS RESERVED X X X'UnZip' is a small Zipfile extract utility. It is written to be as Xsmall and portable as possible -- ideal as a starting point for handling X.ZIP files in non-IBM environments. X XSource code is provided in C and Turbo Pascal. If you port this program Xto a non-IBM system, I would appreciate a copy of the ported source and Xexec files. X X XUsage X----- X unz filename[.zip] ;pascal language version X unzip filename[.zip] ;C language version X X XRevision history X---------------- X X3-3-89 X Initial alpha test release. X X3-5-89 X First fully operational release. Does not implement CRC verification, X but should correctly unzip all compression methods. X X3-6-89 X Corrected end-of-file detection in both shrink and reduce expanders. X Resulting files should now always have the correct size. Added ".ZIP" X default to unzip.c to match calling conventions of unz.pas. X X3-8-89 X Moved machine and operating-system specific code to a block starting X around line 180. Added code to swap bytes on host machines that X store the high order bytes in lower address locations than the low X order bytes. X X3-15-89 X Added CRC checking in UNZIP.C. Speeded operation by about 150%. X X I'm spending my time on the C version now and don't plan to do any X further work on the pascal. If you're using the pascal version X please contact me. X X9-9-89 X Addition of new "un-implode" logic to handle new compression format X included with PKZ101. X X X XLICENSE X======= X XYou may copy and distribute this program freely, provided that: X 1) No fee is charged for such copying and distribution, and X 2) It is distributed ONLY in its original, unmodified state. X XIf you wish to distribute a modified version of this program, you MUST Xinclude the source code. X XIf you modify this program, I would appreciate a copy of the new source Xcode. I am holding the copyright on the source code, so please don't Xdelete my name from the program files or from the documentation. X X XSUPPORT X======= X XI work very hard to produce a software package of the highest quality Xand functionality. I try to look into all reported bugs, and will Xgenerally fix reported problems within a few days. X XIN NO EVENT WILL I BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING ANY LOST XPROFITS, LOST SAVINGS OR OTHER INCIDENTAL OR CONSEQUENTIAL DAMAGES XARISING OUT OF YOUR USE OR INABILITY TO USE THE PROGRAM, OR FOR ANY XCLAIM BY ANY OTHER PARTY. X XIf you have any questions, bugs, or suggestions, please contact me at: X X The Tool Shop BBS X (602) 279-2673 (FREE LINE, USR 2400) X (602) 264-3969 (HST 9600) X (602) 270-0239 (HAYES 9600) X XThe latest version is always available for downloading. (Except Xpossibly this portable version.) X XEnjoy! Samuel H. Smith X Author and Sysop of The Tool Shop. X SHAR_EOF if test 3086 -ne "`wc -c < 'unzip.doc'`" then echo shar: error transmitting "'unzip.doc'" '(should have been 3086 characters)' fi fi # end of overwriting check # End of shell archive exit 0 -- _ _ _ __ ' ) ) ) / /) / ` / /) Michael Enkelis / / / o _. /_ __. _ // /-- __ /_ _ // o _ tektronix!vice!michaele / ' (_(_(__/ /_(_(_(<_(/_ (___, /) )_/ <_(<_(/_(_/_)_ (503) 627-4099 From aubrey at rpp386.cactus.org Wed Jan 3 17:03:06 1990 From: aubrey at rpp386.cactus.org (Aubrey McIntosh) Date: 3 Jan 90 06:03:06 GMT Subject: Floppy Format Program for XT Message-ID: <17537@rpp386.cactus.org> This program works in MS-DOS under Logitech 3.x. It is hard coded to format a 3.5" drive in drive A: (/dev/fd0) to 720kb. The user must provide FAT and empty Directory (mkfs must also be run). There is no I/O, so there is no concern with different calling conventions between systems: this talks directly with DMA and the NEC765. NO SYSTEM CALLS are made. The ROM bios is used, but is intact during the Minix bootup menu period. I am looking for someone to correspond with as I translate it into C. I know Zilch about C, and am still trying to get 1.1 --> 1.2 upgrades from NoDak. Actually, I'm looking for help there too. If no one comes forth, I may cheat and post format.a in hand translation. ------------------------format.mod--------------------- (* * NOTICES * Aubrey McIntosh * December 4, 1989 * Austin, Texas * * world!cs.utexas.edu![ rpp386.Cactus.ORG | val.COM ]!aubrey * * Contract Programming Services available. * * Copyright 1989 by Aubrey McIntosh. * Permission granted to make derivative work, and to distribute * for any reasons, provided that this comment remains intact, * derivations are identified by author(s), and original works * can be identified. * * BACKGROUND * This file contains a study for a floppy disk format program * running under Minix. Unfortunately I haven't written C. However, * 'we' can translate a working Modula-2 program into C or .asm * with some confidence. Actually (12/28/89) this draft just * talks with the NEC765, with little regard for Minix. * * Minimal guidance for identifier names and structure taken from * the floppy.c driver under Minix 1.1 * * This program (shall) run(s) under MS-DOS with the Logitech 3.x * environment. * * USAGE * In MS-DOS, type * c:> format0 * Drive 0 will be formatted as a 720kB 3.5" floppy. (hard coded const) * use Norton to write dir stock and virgin fat. * --- This works. --- * * In Minix: * Not yet ported. See future work section. * * FUTURE WORK NEEDED * * Write a Modula-2 compiler for Minix. :-) * anyone who has worked on *nix .DEF files ~please~ drop me a line, * If I do it, everyone will cuss at ~me.~~ * * Add command line switches for: * 1) Drive type. * 2) Which Drive. * 3) Reformatting with data intact. * 4) Robustness, e.g. write protected drive * * January 2, 1990. * * Overview of future work and program environment. * * This program will need to be included by build with fsck and init. * I have not looked at that code to see what needs to be done. * My current idea is to compile this 'by hand' or else to obtain * the newly announced Modula-3 compiler which produces C output, * and end up with the format0.s and executable Minix files. * I further understand that the ROM bios interrupt tables and * hardware initialisation is still in the default state when the * boot menu is active. * * An option, d Diskette format, should be added to the startup menu. * mkfs will be called by the user from the same startup menu. * * A decode file, roughly compatible to 'format0.asm,' is available * for the intrepid. * * REFERENCES * IBM Technical Reference Manual, pn 6025008. * Minix 1.1 sources, floppy.c, Prentice Hall. * NEC uPD765 Data Sheet. * Logitech users manual. *) MODULE Format0; IMPORT DebugPMD, RTSMain, SYSTEM; MODULE NEC765; IMPORT SYSTEM, RTSMain, panic, Relinquish, seekStatus, STATUSport, DATAport, RATE; EXPORT DoRecalibrate, DoSeek, DoSenseInterruptStatus, DoFormatATrack, (* *) SR0Bits, HD; (* Page 6-4 of 1984 NEC data book. * Primitive I/O support for the 765. * * This module should support anything that the NEC765 will do, * and could be made into a separate module and submitted to a * library. *) TYPE MainStatus = ( D0B, D1B, D2B, D3B, CB, EXM, DIO, RQM ); SR0 = ( US0, US1, HD, NR, EC, SE, D6, D7 ); SR1 = ( MA, NW, ND, res13, or, DE, res16, EN ); SR2 = ( MD, BC, SN, SH, WC, DD, CM, res27); SR3 = ( US03, US13, HD3, TS, T0, RY, WP, FT); MainStatusBits = SET OF MainStatus; SR0Bits = SET OF SR0; SR1Bits = SET OF SR1; SR2Bits = SET OF SR2; SR3Bits = SET OF SR3; PROCEDURE DoRecalibrate( (* fdn : CARDINAL *) ); VAR results : SR0Bits; PCN : CARDINAL; BEGIN WriteDataRegisterFile( Recalibrate ); WriteDataRegisterFile( SR0Bits { } (* Drive 0 *) ); REPEAT UNTIL 7 IN seekStatus; EXCL( seekStatus, 7 ); DoSenseInterruptStatus( results, PCN ) END DoRecalibrate; PROCEDURE DoSeek( Head, NCN : CARDINAL ); VAR results : SR0Bits; PCN : CARDINAL; BEGIN WriteDataRegisterFile( Seek ); IF Head = 0 THEN WriteDataRegisterFile( SR0Bits { } (* Head 0 *) ) ELSE WriteDataRegisterFile( SR0Bits { HD } (* Head 1 *) ) END; WriteDataRegisterFile( NCN ); END DoSeek; PROCEDURE DoSenseInterruptStatus( VAR st0 : SR0Bits; VAR PCN : CARDINAL); BEGIN WriteDataRegisterFile( SenseInterruptStatus ); ReadDataRegisterFile( st0 ); ReadDataRegisterFile( PCN ) END DoSenseInterruptStatus; PROCEDURE DoFormatATrack( Head : CARDINAL; Bytes, Sectors : CARDINAL ); VAR aux : CARDINAL; (*The DMA should be armed before this is called.*) BEGIN WriteDataRegisterFile( MFM + FormatATrack ); IF Head = 0 THEN WriteDataRegisterFile( SR0Bits { } (* Head 0 *) ) ELSE WriteDataRegisterFile( SR0Bits { HD } (* Head 1 *) ) END; WriteDataRegisterFile( Bytes ); WriteDataRegisterFile( Sectors ); IF (Bytes = 3) AND (Sectors = 5) THEN (* 3.5" p. 6-11 in Nec Book for Sony drive *) WriteDataRegisterFile( 74H ) ELSE WriteDataRegisterFile( 54H ) END; WriteDataRegisterFile( 0H ); REPEAT (*relinquish*) UNTIL 7 IN seekStatus; EXCL( seekStatus, 7 ); ReadDataRegisterFile( aux ); ReadDataRegisterFile( aux ); ReadDataRegisterFile( aux ); (*Manditory read of meaningless (sic) results...*) ReadDataRegisterFile( aux ); ReadDataRegisterFile( aux ); ReadDataRegisterFile( aux ); ReadDataRegisterFile( aux ); END DoFormatATrack; PROCEDURE ReadMainStatus(): MainStatusBits; (* Wait 12 usec or longer for the chip to know what it did and update * the registers, then read the port. As I read the data sheets, * it will not do to loop poll the chip -- although that is what * Minix 1.1 floppy.c in fact does do. *) VAR result : MainStatusBits; BEGIN Relinquish( 12 ); SYSTEM.INBYTE ( STATUSport, result ); RETURN result END ReadMainStatus; PROCEDURE ReadDataRegisterFile( VAR file : ARRAY OF SYSTEM.WORD ); VAR count : CARDINAL; BEGIN REPEAT (* This should always conclude. *) (* Jan 2, 1990. * To be safe, I should actually do more testing on the * status bits to be sure I'm not here while the NEC765 is * waiting for the last byte of a command. But this works * if the next higher level is correct, and I'm gonna release it. *) UNTIL (ReadMainStatus () * MainStatusBits{ RQM, DIO }) = MainStatusBits{ RQM, DIO }; count := 0; WHILE (ReadMainStatus () * MainStatusBits{ RQM, DIO} = MainStatusBits { RQM, DIO }) AND ( count <= HIGH(file) ) DO SYSTEM.INBYTE( DATAport, file[ count ] ); INC( count ) END (* Jan 2, 1990 * This procedure was designed to be called with a packet parameter. * Then I broke the higher level up during debugging. * I stripped out all the packet data definitions. * After I put them back, I would * assert( count = HIGH(file)); *) END ReadDataRegisterFile; PROCEDURE WriteDataRegisterFile( file : ARRAY OF SYSTEM.WORD ); VAR count : CARDINAL; BEGIN REPEAT (*wait. This should always conclude. *) UNTIL (ReadMainStatus () * MainStatusBits{ RQM, DIO }) = MainStatusBits{ RQM }; count := 0; WHILE (ReadMainStatus () * MainStatusBits{ RQM, DIO} = MainStatusBits { RQM }) AND ( count <= HIGH(file) ) DO SYSTEM.OUTBYTE( DATAport, file[ count ] ); INC( count ) END END WriteDataRegisterFile; CONST MT = 80H; (* The multi track bit command (PD7265 only) *) MFM = 40H; SK = 20H; (* Skip Deleted sector, read next *) (*These are listed here in the order that they are introduced *on page 6-6 in the NEC literature. I don't see the pattern. *) ReadData = 06H; (* 00110 *) ReadDeleted = 0CH; (* 01100 *) WriteData = 05H; (* 00101 *) WriteDeleted = 09H; (* 01001 *) ReadATrack = 02H; (* 00010 *) ReadId = 0AH; (* 01010 *) FormatATrack = 0DH; (* 01101 *) ScanEqual = 11H; (* 10001 *) ScanLowerEqual = 19H; (* 11001 *) ScanHighEqual = 1DH; (* 11101 *) Recalibrate = 07H; (* 00111 *) SenseInterruptStatus = 08H; (* 01000 *) Specify = 03H; (* 00011 *) SenseDriveStatus = 04H; (* 00100 *) Seek = 0FH; (* 01111 *) END NEC765; (* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *) MODULE DiskAdapter; (* * This is board designer stuff, and the nec765 module (should be| * is purely) applicable to the NEC765 and has no board designer * modifications in it. * * I read the schematics in the IBM Technical Reference, * pn 6025008, Revised Edition, July 1982. The various values * agree with that schematic, the NEC 765 Data sheet, and floppy.c * * This is not intended to be complete enough for a separate * module in a library, but just 'nuf to get the code out the door. * *) IMPORT SYSTEM; EXPORT STATUSport, DATAport, RATE, seekStatus, MotorOn, MotorOff; CONST (* IBM-PC magic I/O addresses. * Resolved with floppy.c, BIOS, and schematic. *) DOR = 03F2H; STATUSport= 03F4H; DATAport = 03F5H; RATE = 03F7H; (* not on XT *) ENABLEINT = 0CH; MOTORMASK = 0F0H; TYPE ControlDOR = ( DriveSelect0, DriveSelect1, RST765, DMA2Enable, Motor1, Motor2, Motor3, Motor4 , res0, res1, res2, res3, (*A packed byte*) res4, res5, res6, res7 ); DORBits = SET OF ControlDOR; VAR (*ROM bios accomodation*) seekStatus [ 0040H:003EH ] : BITSET; status [ 0040H:003FH ] : DORBits; BitImage [ 0040H:003FH ] : SYSTEM.BYTE; PROCEDURE MotorOn; BEGIN status := status + DORBits { Motor1 } - DORBits { Motor2, Motor3, Motor4} (*Hard coded for drive 0*) - DORBits { DriveSelect0, DriveSelect1 } (*Set watchdog timer count at 40:40*) + DORBits { res0..res7 }; SYSTEM.OUTBYTE( DOR, BitImage ) END MotorOn; PROCEDURE MotorOff; BEGIN status := status - DORBits { DriveSelect0, DriveSelect1 } - DORBits { Motor1 .. Motor4 }; SYSTEM.OUTBYTE( DOR, status ) END MotorOff; BEGIN (* (*Hmm, if the machine booted, the controller has been *initialized ok! *) status := DORBits{ DMA2Enable }; SYSTEM.OUTBYTE( DOR, status ) INCL( status, RST765 ); *) status := DORBits{ RST765 , DMA2Enable }; SYSTEM.OUTBYTE( DOR, status ); END DiskAdapter; (* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *) MODULE OtherSysStuff; (*These are suggestions for other goodies in the library. *) IMPORT SYSTEM; EXPORT panic, Relinquish, SetupDMA; PROCEDURE panic( msg : ARRAY OF CHAR); BEGIN (* I set a breakpoint in the RTD. * Again, this is prototype activity. *) END panic; PROCEDURE Relinquish( time : CARDINAL ); (* On a blindingly fast machine, this would do a call * into the scheduler or message system, and let other * work be done while 12 micro seconds crawled by. *) CONST usec = 5; (* I don't know a correct value. *) overhead = 0 * usec; (* This'un either *) VAR ix : CARDINAL; BEGIN FOR ix := overhead TO time * usec DO (*nothing*) (*Can You say optimizer interference?*) END; END Relinquish; PROCEDURE SetupDMA( dmaout : BOOLEAN; VAR buffer : ARRAY OF SYSTEM.WORD); (*nb ************************************************** * * WARNING: ESCAPED HACKER IN YOUR VICINITY. * RESIDENTS ARE URGED TO ADOPT EXTREEM CAUTION. * HE IS REPORTED TO EXHIBIT CUTE CODE WITHOUT PROVOCATION. * ARTIFACTS MAY BECOME DANGEROUS WHEN MOVED TO NEW ENVIRONMENTS. * ************************************************** * Not Portable. Uses knowledge of compiler output. * Be wary of optimizers. * PROC is almost guaranteed to be the wrong size. * Be careful if you move variables, * or even change compiler switches. :-) ************************************************** * I guess folks do this all the time in C without warnings, and * call it 'close to the machine' huh? *) TYPE ParamStackPtr = POINTER TO ParamStack; ParamStack = RECORD itself : ParamStackPtr; BP : CARDINAL; return : PROC; Offset : CARDINAL; Segment: CARDINAL; Size : CARDINAL END; VAR top : CARDINAL; aux : CARDINAL; count: CARDINAL; hook : ParamStackPtr; CONST DMAWRITE = 04AH; DMAREAD = 046H; DMAStatus = 00BH; DMATOP = 081H; DMAADDR = 004H; DMACOUNT = 005H; DMAINIT = 00AH; BEGIN hook := SYSTEM.ADR( hook ); WITH hook^ DO IF Size # HIGH( buffer ) THEN panic( 'Stack structure error in SetupDMA.' ) END; aux := (Offset DIV 16) + Segment; top := aux DIV 1000H; Offset := (Offset MOD 16) + 16 * (aux MOD 1000H); IF 0FFFFH - SYSTEM.SIZE(buffer) <= Offset THEN panic ( "Can't set up DMA." ) END; IF dmaout (*For some reason Minix sends the status command to *two DMA channels. So does the ROM bios listing. *I don't comprehend why. I don't do it. The code works. * *What if I'm using DMA for some other device also? *) THEN SYSTEM.OUTBYTE( DMAStatus, DMAWRITE ) ELSE SYSTEM.OUTBYTE( DMAStatus, DMAREAD ) END; SYSTEM.OUTBYTE( DMAADDR, Offset MOD 256 ); SYSTEM.OUTBYTE( DMAADDR, Offset DIV 256 ); SYSTEM.OUTBYTE( DMATOP, top ); count := ((1 + HIGH( buffer )) * 2) - 1; (* Byte Count - 1 *) SYSTEM.OUTBYTE( DMACOUNT, count MOD 256 ); SYSTEM.OUTBYTE( DMACOUNT, count DIV 256 ); SYSTEM.OUTBYTE( DMAINIT, 2 ) END END SetupDMA; END OtherSysStuff; (* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *) CONST (* Sectors = 5; Bytes = 3 (* 512 -- Note: this is ln2(size)-7 NOT size/128*); *) Sectors = 9; Bytes = 2 (* 512 -- Note: this is ln2(size)-7 NOT size/128*); Tracks = 80; Sides = 2; Out = TRUE; VAR track : ARRAY [ 0 .. 9 * 512-1 ] OF CARDINAL; continue : BOOLEAN; tracks : CARDINAL; sectors : CARDINAL; sides : CARDINAL; CHRN : (*This is byte packed -- 4 bytes long*) ARRAY [ 0..Sectors-1 ] OF RECORD CH, RN : CARDINAL END; hackTrack : PROCEDURE( BOOLEAN, VAR ARRAY OF SYSTEM.WORD ); results : SR0Bits; PCN : CARDINAL; BEGIN hackTrack := SetupDMA; (* ... defeat a compiler optimisation...*) WITH CHRN[0] DO CH := 0; RN := Bytes * 100H END; FOR sectors := 0 TO Sectors - 1 DO CHRN[ sectors ] := CHRN [0]; CHRN[ sectors ].RN := (sectors + 1) + 100H * Bytes END; continue := TRUE; (* I've got an RTD, 'continue' changes by magic; this is prototyping! *) WHILE continue DO MotorOn; DoRecalibrate; FOR tracks := 0 TO Tracks - 1 DO MotorOn; FOR sides := 0 TO Sides - 1 DO DoSeek( sides, tracks ); FOR sectors := 0 TO Sectors - 1 DO CHRN[ sectors ].CH := tracks + 100H * sides END; REPEAT (*wait*) UNTIL 7 IN seekStatus; EXCL( seekStatus, 7 ); DoSenseInterruptStatus( results, PCN ); SetupDMA( Out, CHRN ); DoFormatATrack( sides, Bytes, Sectors ) END END; continue := FALSE (*A breakpoint hook.*) END; MotorOff END Format0. -- Aubrey McIntosh Freelance using Modula-2 Real time, embedded, instruments. Austin, TX 78723 Enquiries welcome 1-(512)-452-1540 aubrey%rpp386.Cactus.org at cs.utexas.edu From davidsen at sixhub.UUCP Fri Jan 5 02:01:04 1990 From: davidsen at sixhub.UUCP (Wm E. Davidsen Jr) Date: 4 Jan 90 15:01:04 GMT Subject: ksh macros for use with SCCS Message-ID: <378@sixhub.UUCP> This package is useful for working with SCCS on machines without the sccs command (and I use it there too, but hacked). It add "s." where needed and understands the SCCS directory. #!/bin/sh # shar: Shell Archiver (v1.24) # # Run the following text with /bin/sh to create: # SCCS.ksh # SCCS.ksh.doc # echo "x - extracting SCCS.ksh (Text)" sed 's/^X//' << 'SHAR_EOF' > SCCS.ksh && X# define SCCS macros for ksh X# Copyright (c) 1987,88,90 Bill Davidsen, all rights reserved. X# This package may be freely used and distributed by anyone. X X# allow use of SCCS commands without typing s. on everything. X# "sccs get -e foo.c" generates "get -e s.foo.c" and so forth X Xsccs() X{ # anything not starting with '-' is assumed to be a filename X typeset an=2 cmd="$1" X echotype=$(echo -- xx | wc -w) X X while [ $an -le $# ] X do X # this works for old echo (no options) as well X if [ $echotype -eq 1 ] X then arg=`eval echo -- "\\$$an"` X else arg=`eval echo "\\$$an"` X fi X X case "$arg" in X -*) # any argument X cmd="$cmd $arg";; X s.*)# already in filename format X if [ -r "$arg" ] X then X cmd="$cmd $arg" X else X if [ -r "SCCS/$arg" ] X then X cmd="$cmd SCCS/$arg" X else X echo "Missing file $arg" X return X fi X fi X ;; X *) # assume filename X if [ -d "SCCS" ] X then # use the SCCS directory X cmd="$cmd SCCS/s.$arg" X else X cmd="$cmd s.$arg" X fi X ;; X esac X let an=an+1 X done X X # now execute the command X $cmd X} X# X# do a diff between the last saved versions and the current version X XSdiff() X{ X typeset sfile=s.$1 X X if [ $# -lt 1 ] X then X echo "$0: file [diff opts]" X echo " ex: $0 foo.c" X echo " $0 foo.c -e" X return 1 X fi X X if [ ! -r $sfile ] X then X sfile=SCCS/$sfile X if [ ! -r $sfile ] X then X echo "No sccs file for $1" X return 1 X fi X fi X get -p -k -s $sfile | diff $2 - $1 X} X X# do a diff between the 1st saved versions and the current X# mainly useful when hacking code you got elsewhere, when sending X# back fixes and stuff X XSdiff1() X{ X typeset sfile=s.$1 X X if [ $# -lt 1 ] X then X echo "$0: file [diff opts]" X echo " ex: $0 foo.c" X echo " $0 foo.c -e" X return 1 X fi X X if [ ! -r $sfile ] X then X sfile=SCCS/$sfile X if [ ! -r $sfile ] X then X echo "No sccs file for $1" X return 1 X fi X fi X get -p -k -s -r1.1 $sfile | diff $2 - $1 X} X SHAR_EOF chmod 0644 SCCS.ksh || echo "restore of SCCS.ksh fails" echo "x - extracting SCCS.ksh.doc (Text)" sed 's/^X//' << 'SHAR_EOF' > SCCS.ksh.doc && X SCCS macros for Korn shell X Bill Davidsen (davidsen at crdos1.crd.ge.com) X Jan 3, 1990 X X X These are the macros I have been using for several years to ease use Xof SCCS with Korn shell. This version has recently been updated to work Xwith ksh.88 as well as the several older versions. It has NOT been Xtested with bash. X X Although the object of this was to overcome my tendancy to forget to Xtype "s." when needed, this package provides several other things. It Xsupports an SCCS directory, such that if a command is issued and there Xis (a) no sccs file in the current directory, and (b) there is a Xdirectory called SCCS, and (c) there is a file of the correct name in Xthe SCCS directory, then the filename will be changed before the raw XSCCS command is invoked. X X The two diff commands are useful to me in day to day operation. The XSdiff produces a diff between the current version of the file and the Xlast saved version in the SCCS file. I use this just before doing a Xdelta so that I don't forget something in the comments. X X The Sdiff1 command produces the diff between the current version and Xthe earliest version in the SCCS file. I use this when I get software Xfrom someone else, and modify it extensively, and then want to produce a Xcomplete list of all the changes I've made. X X Copyright (c) 1990 by Bill Davidsen, all rights reserved. This Xpackage may be freely used and distributed by anyone. X X SHAR_EOF chmod 0644 SCCS.ksh.doc || echo "restore of SCCS.ksh.doc fails" exit 0 -- bill davidsen - sysop *IX BBS and Public Access UNIX davidsen at sixhub.uucp ...!uunet!crdgw1!sixhub!davidsen "Getting old is bad, but it beats the hell out of the alternative" -anon From bob at MorningStar.Com Thu Jan 18 04:30:08 1990 From: bob at MorningStar.Com (Bob Sutterfield) Date: 17 Jan 90 17:30:08 GMT Subject: Getting the time over the phone from NBS In-Reply-To: wht@tridom.uucp's message of 17 Jan 90 06:58:58 GMT References: <1043@khijol.UUCP> <899@tridom.uucp> Message-ID: <BOB.90Jan17123008@volitans.MorningStar.Com> In article <899 at tridom.uucp> wht at tridom.uucp (Warren Tucker) writes: v03i079 contains a GREAT program utc.c which allows your system to mimic NBS and provide esentially the same service via a local call. Only the most ultimate time freaks who've replaced their PC's crystal with an atomic clock can tell the difference (I'm pretty bad, but not that bad) :-). I'd hope that only folks either running a local radio clock, or a low- stratum NTP peer, would offer their system's time as a community standard. However, this would be a really nice service for Internet- connected folks to offer to their UUCP-only neighbors. From LC.YRS at forsythe.stanford.edu Thu Jan 11 18:33:46 1990 From: LC.YRS at forsythe.stanford.edu (Richard Stanton) Date: 11 Jan 90 07:33:46 GMT Subject: Wanted: 1990 'sc' 1040 forms Message-ID: <7075@lindy.Stanford.EDU> In article <MDF0.90Jan9121142 at shemesh.gte.com>, mdf0 at shemesh.gte.com (Mark Feblowitz) writes: >For a while, someone was distributing 1040 and related forms for the >"sc" public domain spreadsheet calculator. Is anyone revising these >forms for 1990? > I'm impressed to see someone ready to do his 1990 tax return already. Where can one get hold of the "sc" public domain spreadsheet calculator? Thanks Richard Stanton From dan at hrc.UUCP Fri Jan 19 15:49:10 1990 From: dan at hrc.UUCP (Dan Troxel) Date: 19 Jan 90 04:49:10 GMT Subject: hrc archive site help file Message-ID: <201451@hrc.UUCP> UPDATED 01/18/90 This message comes to you from the archive server at hrc, archives at hrc.UUCP. It received a message from you asking for help. The archive server is a mail-response program. That means that you mail it a request, and it mails back the response. The archive server is a very dumb program and does not have much error checking. VERY IMPORTANT! This archive server is set up mainly for the southwest region of the United States. If you are outside this area, please contact an archive site closer to you. This site batches the requests to be run once-a-week. This is due to the archives being so large, and the requests have to be pulled from tape. The archive server has several commands. Each command must be the first word on a line. The archive server reads your entire message before it does anything, so you can have several different commands in a single message. The archive server DOES NOT recognize the "Subject:" header line. "help" command: The "send help" causes the server to send you the help file. You already know this, of course, because you are reading the help file. The archives are organized into a series of directories and subdirectories. Each subdirectory has an index. The index will also give you the last date of entry. This will help you to know when more files were entered into the archive. To get a general list of where the indexes are, send the following message containing the line send index.main When you get the index back, it will give you the names of all of the indexes and where to locate them. Example: >index.x.v00 current as of Mon May 15 13:02:22 MST 1989 To retrieve the above index, send the following line send index.x.v00 You will get: > ********hrc archives/x/v00 index as of 01/15/90******** > > > Note: For additional information on receiving this index in a > variety of different formats, use the command 'send help'. > > >filename : date installed in archives > size of file : description > >archives/x/v00/awm/part01.Z : 11/15/89 > 61K : v00i002: Ardent Window Manager(X11), Part01/13 > >archives/x/v00/awm/part02.Z : 11/15/89 > 55K : v00i003: Ardent Window Manager(X11), Part02/13 > >archives/x/v00/awm/part03.Z : 11/15/89 > 53K : v00i004: Ardent Window Manager(X11), Part03/13 > >[rest of file deleted] To retrieve part01.Z above: send archives/x/v00/awm/part01.Z The .Z extension in a compressed file, and the archiver will uncompress the file, and send it to you in ascii form. You would save it to disk as: ansiawm/part01 You may send for several indexes. Example: send index.unix.v01 send index.misc.v04 send index.x.v00 send index.games.v06 send index.games.v07 Each index will be mailed seperatly to you. To send for a ls -lR listing of the archives: send index.ls To send for all indexes: send index.all You may put as many "send" commands as you like into one message to the server, but the more you ask for, the longer it will take to receive. See "FAIRNESS", below, for an explanation. "send path" command: The "send path" command exists to help in case you do not get responses from the server when you mail to it. You must include the full path to your site from my box. I have had many of the archives mailed, only to come back becuase of a bad path. IT MUST BE ON THE FIRST LINE IN THE MESSAGE BEFORE ANY OTHER SEND COMMAND! Sometimes the server is unable to return mail over the incoming path. There are dozens of reasons why this might happen, and if you are a true wizard, you already know what those reasons are. If you are an apprentice wizard, you might not know all the reasons but you might know a way to circumvent them. If you put in a "send path" command, then everything that the server mails to you will be mailed to that address, rather than to the return address on your mail. For example, if you say send path pyramid!rutgers!zakkaroo!jj then all mail sent by the server will be sent to that address. If you would like the server to determine a uucp path for you, using the most recent pathalias data, then put in a "send path" command with yoursite!sitename send path yoursite!sitename As you probably know, the pathalias data is sometimes wrong, and lately, quite a bit. So due to the many errors in the past from the maps, please send a full path from my site to yours. "uucppath" command: The "uucppath" command exists to allow users who are connected directly to me, to have the files uucp'ed over. Almost all of the files are in compressed format, and thus will make the transfer faster, and take less disk space. You will also need to use the "uucpname" command to get notified of the transfer. The uucppath command requires a full path to place the file. Generally this will be in your uucppublic directory. Example: uucppath your_site_name!~/your_login_name uucpname your_login_name send archives/unix/v19/file_name This will uucp the file to your machine in directory: /usr/spool/uucppublic/your_login_name/archives/unix/v19/file_name The uucppublic directory may be different on your machine, but most sites keep it as '/usr/spool/uucppublic'. The reason for such a long directory path, is that there are many files that have the same name. If you request files with the same name, without removing them from your uucppublic directory, you would lose your first requested file, to be replaced with the latest transfer. Also, this will seperate file transfers between users, who may be asking for archives, who reside on the same box. EXAMPLES: 1) Find out the list of catagories that are in the archive. Send this message: To: hrc!archives Subject: hi there send index.main 2) Get the ansi file from the archive (you have learned the file name from the list that was sent to you in step 1). To: hrc!archives Subject: a send on the subject line will do you no good! send archives/unix/v01/ansi.c.Z 3) Get the ansi file, and send them over the exact path to my site: To: asuvax!hrc!archives send path mcdphx!sun!nud!yourmachine!yourname send archives/unix/v01/ansi.c.Z NOTES: The archive server acknowledges every request by return mail. If you don't get a message back in a week, you should assume that something is going wrong, and perhaps try a "send path" command. If you aren't getting anywhere and you don't know a wizard to help you, try putting send path yoursite!yourname in your message, where "yourname" is your mailbox name and "youyrsite" is the uucp name of your machine. The delays in sending out large items from the archives are intentional, to make it difficult to get copies of everything in the archives. If you are new to the network and would like to get all back issues of everything, you should post a request to a regional newsgroup asking whether someone who is geographically near you can provide them. We will send tapes to those who request it. If you wish to get the indexes automatically when there is an update, please send mail to hrc!dan, and ask to be put on the list. FAIRNESS: The archive server contains many safeguards to ensure that it is not monopolized by people asking for large amounts of data. The mailer is set up so that it will send no more than a fixed amount of data each week. If the work queue contains more requests than the week's quota, then the unsent files will not be processed until the next week. Whenever the mailer is run to send its week's quota, it sends the requests out shortest-first. If you have a request waiting in the work queue and you send in another request, the new request is added to the old one (thereby increasing its size) rather than being filed anew. This prevents you from being able to send in a large number of small requests as a way of beating the system. If you request 10 items together, you will get substantially higher priority than if you make 10 requests for 1 item each. The reason for all of these quotas and limitations is that the delivery resources are finite, and there are many tens of thousands of people who would like to make use of the archive. -- Dan Troxel @ Handwriting Research Corporation WK 1-602-957-8870 Camelback Corporate Center 2821 E. Camelback Road Suite 600 Phoenix, AZ 85016 ncar!noao!asuvax!hrc!dan zardoz!hrc!dan hrc!dan at asuvax.asu.edu -- Dan Troxel @ Handwriting Research Corporation WK 1-602-957-8870 Camelback Corporate Center 2821 E. Camelback Road Suite 600 Phoenix, AZ 85016 ncar!noao!asuvax!hrc!dan zardoz!hrc!dan hrc!dan at asuvax.asu.edu From cpcahil at virtech.uucp Tue Jan 30 15:47:54 1990 From: cpcahil at virtech.uucp (Conor P. Cahill) Date: 30 Jan 90 04:47:54 GMT Subject: Debugging library for programs that use malloc Message-ID: <1990Jan30.044754.2898@virtech.uucp> The following is a "beta" release of a debugging library I have put together. The purpose of the library is to catch many of the errors made when using malloc'd memory. See the README for more information. I have compiled the code on System V, Ultrix, and HP-UX. Check the Makefile for any system dependent changes that need to be made. If you use this on your system, I would like some feedback as to it's usefullness, suggested additions, fixes, complaints, etc. After a short beta period I will be submitting the package to comp.sources.unix, so I would appreciate feedback as soon as you can get it to me. Good luck and enjoy. Conor P. Cahill # This is a shell archive. # Remove everything above and including the cut line. # Then run the rest of the file through sh. #----cut here-----cut here-----cut here-----cut here----# #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # Makefile # README # calloc.c # debug.h # design # dump.c # free.c # func.hdr # malloc.c # malloc.h # malloc_chk.c # memory.c # pgm.c # realloc.c # string.c # testmalloc.c # testmem.c # toascii.c # toascii.h # This archive created: Tue Jan 30 04:28:37 1990 cat << \SHAR_EOF > Makefile CC=cc # for System V systems use this CFLAGS CFLAGS=-g -DSYS5 # else for BSD use: CFLAGS=-g LIB=libmalloc.a OBJS= malloc.o \ free.o \ realloc.o \ calloc.o \ string.o \ malloc_chk.o \ memory.o \ toascii.o \ dump.o TESTS=testmalloc testmem all: $(LIB) pgm $(TESTS) clean: rm -f $(TESTS) pgm $(LIB) *.o pgm: $(LIB) pgm.o $(CC) -o $@ pgm.o $(LIB) $(LIB): $(OBJS) ar ru $(LIB) $(OBJS) -if test -s /bin/ranlib; then /bin/ranlib $(LIB); else exit 0; fi -if test -s /usr/bin/ranlib; then /usr/bin/ranlib $(LIB); else exit 0; fi testmalloc: $(LIB) testmalloc.o $(CC) -o $@ testmalloc.o $(LIB) testmem: $(LIB) testmem.o $(CC) -o $@ testmem.o $(LIB) $(OBJS): malloc.h toascii.o malloc.o dump.o: toascii.h SHAR_EOF cat << \SHAR_EOF > README This package is a collection of routines which are a drop-in replacement for the malloc(3), memory(3), string(3), and bstring(3) library functions. The purpose of these programs is to aid the development and/or debugging of programs using these functions by providing a high level of consistancy checking whenever a malloc pointer is used. Due to this increased level of consistancy checking, these functions have a considerably larger overhead than the standard functions, but the extra checking should be well worth it in a development environment. To use these functions all you need to do is compile the library and include it on your loader command line. You do not need to recompile your code, only a relink is necessary. Features of this library: 1. The malloced area returned from each call to malloc is filled with non-null bytes. This should catch any use of uninitialized malloc area. The fill pattern for malloced area is 0x01. 2. When free is called numerous validity checks are made on the pointer it is passed. In addition, the data in the malloc block beyound the size requested on the initial malloc is checked to verify that it is still filled with the original fill characters. This is usefull for catching things like: ptr = malloc(5); ptr[5] = '\0'; /* * You should not that this will be caught when it is * freed not when it is done */ And finally, the freed block is filled with a different fill pattern so that you can easily determine if you are still using free'd space. The fill pattern for free'd areas is 0x02. This is usefull for catching things like: ptr = malloc(20); bptr = ptr+10; /* do something usefule with bptr */ free(ptr); /* * now try to do something useful with bptr, it should * be trashed enough that it would cause real problems * and when you went to debug the problem it would be * filled with 0x02's and you would then know to look * for something free'ing what bptr points to. */ 3. Whenever a bstring(3)/string(3)/memory(3) function is called, it's parameters are checked as follows: If they point somewhere in the malloc arena If the operation goes beyond requested malloc space call malloc_warning() This is usefull for catching things like: ptr = malloc(5); strcpy(ptr,"abcde"); 4. Malloc_warning() and malloc_fatal() are used when an error condition is detected. If the error is severe, malloc_fatal is called. Malloc_warning is used otherwise. The decision about what is fatal and what is a warning was made somewhat arbitrarily. Warning messages include: Calling free with a bad pointer Calling a bstring/string/memory (3) function which will go beyond the end of a malloc block (Note that the library function is not modified to refuse the operation. If malloc warnings are in the default IGNORE case, the operation will continue and at some point cause a real problem). Fatal errors are: Detectable corruption to the malloc chain. 5. The operations to perform when an error is detected are specified at run time by the use of environment variables. MALLOC_WARN - specifies the warning error message handling MALLOC_FATAL - specifies the fatal error handling When one of these error conditions occur you will get an error message and the handler will execute based upon what setting is in the environment variables. Currently understood settings are as follows: 0 - continue operations 1 - drop core and exit 2 - just exit 3 - drop core, but continue executing. Core files will be placed into core.[PID].[counter] i.e: core.00123.001 128 - dump malloc chain and continue 129 - dump malloc chain, dump core, and exit 130 - dump malloc chain, exit 131 - dump malloc chain, dump core, continue processing There is an additional environment variable MALLOC_ERRFILE which is used to indicate the name of the file for error message output. For example, to set up the session to generate a core file for every malloc warning, to drop core and exit on a malloc fatal, and to log all messages to the file "malloc_log" do the following: MALLOC_WARN=131 MALLOC_FATAL=1 MALLOC_ERRFILE=malloc_log export MALLOC_WARN MALLOC_FATAL MALLOC_ERRFILE 6. The function malloc_dump() is available to dump the malloc chain whenever you might want. It's only argument is a file descriptor to use to write the data. Review the code if you need to know what data is printed. SHAR_EOF cat << \SHAR_EOF > calloc.c #include <stdio.h> char * calloc(nelem,elsize) unsigned int nelem; unsigned int elsize; { char * malloc(); char * ptr; unsigned int size; size = elsize * nelem; if( (ptr = malloc(size)) != NULL) { memset(ptr,'\0',size); } return(ptr); } SHAR_EOF cat << \SHAR_EOF > debug.h /* static char SCCSID[] = "%W% %E%"; */ /************************************************************************/ /* */ /* this include sets up some macro functions which can be used while */ /* debugging the program, and then left in the code, but turned of by */ /* just not defining "DEBUG". This way your production version of */ /* the program will not be filled with bunches of debugging junk */ /* */ /************************************************************************/ #ifdef DEBUG #if DEBUG == 1 /* if default level */ #undef DEBUG #define DEBUG 100 /* use level 100 */ #endif #include <stdio.h> #define DEBUG0(val,str)\ {\ if( DEBUG > val ) \ fprintf(stderr,"%s(%d): %s\n",\ __FILE__,__LINE__,str);\ } #define DEBUG1(val,str,a1)\ {\ char _debugbuf[100];\ if( DEBUG > val )\ {\ sprintf(_debugbuf,str,a1);\ fprintf(stderr,"%s(%d): %s\n",\ __FILE__,__LINE__,_debugbuf);\ }\ } #define DEBUG2(val,str,a1,a2)\ {\ char _debugbuf[100];\ if( DEBUG > val )\ {\ sprintf(_debugbuf,str,a1,a2);\ fprintf(stderr,"%s(%d): %s\n",\ __FILE__,__LINE__,_debugbuf);\ }\ } #define DEBUG3(val,str,a1,a2,a3)\ {\ char _debugbuf[100];\ if( DEBUG > val )\ {\ sprintf(_debugbuf,str,a1,a2,a3);\ fprintf(stderr,"%s(%d): %s\n",\ __FILE__,__LINE__,_debugbuf);\ }\ } #define DEBUG4(val,str,a1,a2,a3,a4)\ {\ char _debugbuf[100];\ if( DEBUG > val )\ {\ sprintf(_debugbuf,str,a1,a2,a3,a4);\ fprintf(stderr,"%s(%d): %s\n",\ __FILE__,__LINE__,_debugbuf);\ }\ } #define DEBUG5(val,str,a1,a2,a3,a4,a5)\ {\ char _debugbuf[100];\ if( DEBUG > val )\ {\ sprintf(_debugbuf,str,a1,a2,a3,a4,a5);\ fprintf(stderr,"%s(%d): %s\n",\ __FILE__,__LINE__,_debugbuf);\ }\ } #else #define DEBUG0(val,s) #define DEBUG1(val,s,a1) #define DEBUG2(val,s,a1,a2) #define DEBUG3(val,s,a1,a2,a3) #define DEBUG4(val,s,a1,a2,a3,a4) #define DEBUG5(val,s,a1,a2,a3,a4,a5) #endif /* DEBUG */ SHAR_EOF cat << \SHAR_EOF > design This malloc library will emulate the standard malloc libraries but in addition it will include special versions of the following routines which perform checking of the arguments passed to verify that they do not extend outside of a malloced area. These modified routines include: bcopy, bzero, bcmp memcpy, memset, memcmp, memccpy, memchr strcpy, strncpy, strcat, strncat, strdup, strcmp, strncmp, strchr, strrchr, strpbrk, strspn, strcspn, strtok These functions will only be different from the standard functions in that they will call routines in the malloc library to verify that the data accessed by these routines does not overflow a malloc block. If an error is detected, the default action is to display a warning and continue with the function. In other words, it should match the functionality of the library function with the exception that the error message is printed. SHAR_EOF cat << \SHAR_EOF > dump.c #include <stdio.h> #include "malloc.h" #include "toascii.h" /* * Function: malloc_dump() * * Purpose: to dump a printed copy of the malloc chain and * associated data elements * * Arguments: fd - file descriptor to write data to * * Returns: nothing of any use * * Narrative: Just print out all the junk * * Notes: This function is implemented using low level calls because * of the likelyhood that the malloc tree is damaged when it * is called. (Lots of things in the c library use malloc and * we don't want to get into a catch-22). * * Mod History: * 90/01/24 cpcahil Initial revision. */ #define ERRSTR "I/O Error on malloc dump file descriptor\n" #define WRITEOUT(fd,str,len) if( write(fd,str,len) != len ) \ { \ (void) write(2,ERRSTR,strlen(ERRSTR));\ exit(120); \ } malloc_dump(fd) FILE * fd; { char buffer[512]; int i; extern char * malloc_data_end; extern char * malloc_data_start; extern struct mlist * malloc_end; extern struct mlist malloc_start; struct mlist * ptr; WRITEOUT(fd,"MALLOC CHAIN:\n",14); WRITEOUT(fd,"-------------------- START ----------------\n",44); for(i=0; i < 80; i++) { buffer[i] = ' '; } for(ptr = &malloc_start; ptr; ptr = ptr->next) { (void) toascii(buffer, ptr, 8, B_HEX, '0'); (void) toascii(buffer+9, ptr->next, 8, B_HEX, '0'); (void) toascii(buffer+18,ptr->prev, 8, B_HEX, '0'); (void) toascii(buffer+27,ptr->flag, 10, B_HEX, '0'); (void) toascii(buffer+38,ptr->s.size, 8, B_DEC, ' '); (void) toascii(buffer+47,ptr->s.size, 8, B_HEX, '0'); (void) toascii(buffer+57,ptr->data, 8, B_HEX, '0'); buffer[46] = '('; buffer[55] = ')'; buffer[65] = '\n'; WRITEOUT(fd,buffer,66); } WRITEOUT(fd,"-------------------- DONE -----------------\n",44); WRITEOUT(fd,"Malloc start: ",19); (void) toascii(buffer, &malloc_start, 8, B_HEX, '0'); buffer[8] = '\n'; WRITEOUT(fd,buffer,9); WRITEOUT(fd,"Malloc end: ", 19); (void) toascii(buffer, malloc_end, 8, B_HEX, '0'); buffer[8] = '\n'; WRITEOUT(fd,buffer,9); WRITEOUT(fd,"Malloc data start: ", 19); (void) toascii(buffer, malloc_data_start, 8, B_HEX, '0'); buffer[8] = '\n'; WRITEOUT(fd,buffer,9); WRITEOUT(fd,"Malloc data end: ", 19); (void) toascii(buffer, malloc_data_end, 8, B_HEX, '0'); buffer[8] = '\n'; WRITEOUT(fd,buffer,9); } /* malloc_dump(... */ SHAR_EOF cat << \SHAR_EOF > free.c #include <stdio.h> #include "malloc.h" #include "debug.h" void free(cptr) char * cptr; { int i; extern struct mlist * malloc_end; extern char * malloc_data_end; extern char * malloc_data_start; struct mlist * oldptr; struct mlist * ptr; /* * First verify that cptr is within the malloc region... */ if( cptr < malloc_data_start || cptr > malloc_data_end ) { malloc_warning("Free called with invalid address..."); return; } /* * convert pointer to mlist struct pointer. To do this we must * move the pointer backwards the correct number of bytes... */ ptr = (struct mlist *) (cptr - M_SIZE); if( (ptr->flag != (M_MAGIC|M_INUSE)) || (ptr->prev && (ptr->prev->next != ptr) ) || (ptr->next && (ptr->next->prev != ptr) ) || ((ptr->next == NULL) && (ptr->prev == NULL)) ) { malloc_warning( "Free: called with invalid pointer or corrupted chain"); return; } ptr->flag &= ~M_INUSE; /* * verify that the user did not overrun the requested number of bytes. */ for(i=ptr->r_size; i < ptr->s.size; i++) { if( ptr->data[i] != M_FILL ) { malloc_warning( "data overrun in malloced region" ); break; } } DEBUG3(10,"pointers: prev: 0x%.7x, ptr: 0x%.7x, next: 0x%.7x", ptr->prev, ptr, ptr->next); DEBUG3(10,"size: prev: %9d, ptr: %9d, next: %9d", ptr->prev->s.size, ptr->s.size, ptr->next->s.size); DEBUG3(10,"flags: prev: 0x%.7x, ptr: 0x%.7x, next: 0x%.7x", ptr->prev->flag, ptr->flag, ptr->next->flag); /* * check to see if this block can be combined with the next and/or * previous block. Since it may be joined with the previous block * we will save a pointer to the previous block and test to verify * if it is joined (it's next ptr will no longer point to ptr). */ malloc_join(ptr,ptr->next,0,0); oldptr = ptr->prev; malloc_join(ptr->prev, ptr,0,0); if( oldptr->next != ptr ) { DEBUG0(10,"Oldptr was changed"); ptr = oldptr; } /* * fill this block with '\02's to ensure that nobody is using a * pointer to already freed data... */ malloc_memset(ptr->data,M_FREE_FILL,ptr->s.size); } SHAR_EOF cat << \SHAR_EOF > func.hdr /* * Function: malloc_in_arena() * * Purpose: to verify address is within malloc arena. * * Arguments: ptr - pointer to verify * * Returns: TRUE - if pointer is within malloc area * FALSE - otherwise * * Narrative: * IF pointer is >= malloc area start AND <= malloc area end * return TRUE * ELSE * return FALSE * * Mod History: * 90/01/24 cpcahil Initial revision. */ SHAR_EOF cat << \SHAR_EOF > malloc.c #include <stdio.h> #include <fcntl.h> #include "malloc.h" #include "toascii.h" char * malloc_data_start; char * malloc_data_end; struct mlist * malloc_end; int malloc_errfd = 2; int malloc_fatal_level = M_HANDLE_CORE; struct mlist malloc_start; int malloc_warn_level; char * malloc(size) unsigned int size; { char * cptr; char * getenv(); int i; void malloc_split(); unsigned int need; struct mlist * oldptr; struct mlist * ptr; unsigned int rest; char * sbrk(); struct mlist * tptr; /* * If this is the first call to malloc... */ if( malloc_data_start == (char *) 0 ) { malloc_data_start = sbrk(0); malloc_data_end = malloc_data_start; malloc_start.s.size = 0; malloc_end = &malloc_start; if( (cptr=getenv("MALLOC_WARN")) != NULL ) { malloc_warn_level = atoi(cptr); } if( (cptr=getenv("MALLOC_FATAL")) != NULL) { malloc_fatal_level = atoi(cptr); } if( (cptr=getenv("MALLOC_ERRFILE")) != NULL) { i = open(cptr,O_CREAT|O_TRUNC|O_WRONLY,0666); if( i != -1) { malloc_errfd = i; } } } /* * if they ask for zero bytes, give em at least 1... */ if( size == 0 ) { size = 1; } /* * Now look for a free area of memory of size bytes... */ oldptr = NULL; for(ptr = &malloc_start; ; ptr = ptr->next) { /* * Since the malloc chain is a forward only chain, any * pointer that we get should always be positioned in * memory following the previous pointer. If this is not * so, we must have a corrupted chain. */ if( ptr ) { if(ptr < oldptr ) { malloc_fatal("Corrupted malloc chain."); } oldptr = ptr; } else if( oldptr != malloc_end ) { /* * This should never happen. If it does, then * we got a real problem. */ malloc_fatal("Corrupted malloc chain 2."); } /* * if this element is already in use... */ if( ptr && ((ptr->flag & M_INUSE) != 0) ) { continue; } /* * if there isn't room for this block.. */ if( ptr && (ptr->s.size < size) ) { continue; } /* * If ptr is null, we have run out of memory and must sbrk more */ if( ptr == NULL ) { need = (size + M_SIZE) * (size > 100*1024 ? 1:2); if( need < M_BLOCKSIZE ) { need = M_BLOCKSIZE; } else if( need & (M_BLOCKSIZE-1) ) { need &= ~(M_BLOCKSIZE-1); need += M_BLOCKSIZE; } ptr = (struct mlist *) sbrk(need); if( ptr == (struct mlist *) -1 ) { malloc_fatal("Can't allocate any more memory"); } malloc_data_end = sbrk(0); ptr->prev = oldptr; ptr->next = (struct mlist *) 0; ptr->s.size = need - M_SIZE; ptr->flag = M_MAGIC; oldptr->next = ptr; malloc_end = ptr; } /* if( ptr ==... */ /* * Now ptr points to a memory location that can store * this data, so lets go to work. */ ptr->r_size = size; /* save requested size */ ptr->flag |= M_INUSE; /* * split off unneeded data area in this block, if possible... */ malloc_split(ptr); /* * just to make sure that noone is misusing malloced * memory without initializing it, lets set it to * all '\01's. We call local_memset() because memset() * may be checking for malloc'd ptrs and this isn't * a malloc'd ptr yet. */ malloc_memset(ptr->data,M_FILL,ptr->s.size); return( ptr->data); } /* for(... */ } /* malloc(... */ /* * Function: malloc_split() * * Purpose: to split a malloc segment if there is enough room at the * end of the segment that isn't being used * * Arguments: ptr - pointer to segment to split * * Returns: nothing of any use. * * Narrative: * * Mod History: * 90/01/27 cpcahil Initial revision. */ void malloc_split(ptr) struct mlist * ptr; { extern struct mlist * malloc_end; int rest; int size; struct mlist * tptr; void malloc_join(); size = ptr->r_size; /* * roundup size to the appropriate boundry */ M_ROUNDUP(size); /* * figure out how much room is left in the array. * if there is enough room, create a new mlist * structure there. */ if( ptr->s.size > size ) { rest = ptr->s.size - size; } else { rest = 0; } if( rest > (M_SIZE+M_RND) ) { tptr = (struct mlist *) (ptr->data+size); tptr->prev = ptr; tptr->next = ptr->next; tptr->flag = M_MAGIC; tptr->s.size = rest - M_SIZE; /* * If possible, join this segment with the next one */ malloc_join(tptr, tptr->next,0,0); if( tptr->next ) { tptr->next->prev = tptr; } malloc_memset(tptr->data,M_FREE_FILL, tptr->s.size); ptr->next = tptr; ptr->s.size = size; if( malloc_end == ptr ) { malloc_end = tptr; } } } /* malloc_split(... */ /* * Function: malloc_join() * * Purpose: to join two malloc segments together (if possible) * * Arguments: ptr - pointer to segment to join to. * nextptr - pointer to next segment to join to ptr. * * Returns: nothing of any values. * * Narrative: * * Mod History: * 90/01/27 cpcahil Initial revision. */ void malloc_join(ptr,nextptr, inuse_override, fill_flag) struct mlist * ptr; struct mlist * nextptr; int inuse_override; int fill_flag; { unsigned int newsize; if( ptr && ! (inuse_override || (ptr->flag & M_INUSE)) && nextptr && ! (nextptr->flag & M_INUSE) && ((ptr->data+ptr->s.size) == (char *) nextptr) ) { if( malloc_end == nextptr ) { malloc_end = ptr; } ptr->next = nextptr->next; newsize = nextptr->s.size + M_SIZE; /* * if we are to fill and this segment is in use, * fill in with M_FILL newly added space... */ if(fill_flag && (ptr->flag & M_INUSE) ) { malloc_memset(ptr->data+ptr->s.size, M_FILL, nextptr->s.size + M_SIZE); } ptr->s.size += newsize; if( ptr->next ) { ptr->next->prev = ptr; } } } /* malloc_join(... */ /* * The following mess is just to ensure that the versions of these functions in * the current library are included (to make sure that we don't accidentaly get * the libc versions. (This is the lazy man's -u ld directive) */ int free(); int strcmp(); int memcmp(); char * realloc(); int (*malloc_int_funcs[])() = { free, strcmp, memcmp, }; char * (*malloc_char_star_funcs[])() = { realloc, }; /* * This is malloc's own memset which is used without checking the parameters. */ malloc_memset(ptr,byte,len) char * ptr; char byte; int len; { while(len-- > 0) { *ptr++ = byte; } } /* malloc_memset(... */ void malloc_fatal(str) char * str; { char errbuf[128]; int len; extern int malloc_fatal_level; char * s; char * t; s = errbuf; t = "Fatal error: "; while( *s = *t++) { s++; } t = str; while( *s = *t++) { s++; } *(s++) = '\n'; if( write(malloc_errfd,errbuf,(s-errbuf)) != (s-errbuf)) { write(2,"I/O error to error file\n",24); exit(110); } malloc_err_handler(malloc_fatal_level); } /* malloc_fatal(... */ void malloc_warning(str) char * str; { char errbuf[128]; int len; extern int malloc_warn_level; char * s; char * t; s = errbuf; t = "Warning: "; while( *s = *t++) { s++; } t = str; while( *s = *t++) { s++; } *(s++) = '\n'; if( write(malloc_errfd,errbuf,(s-errbuf)) != (s-errbuf)) { write(2,"I/O error to error file\n",24); exit(110); } malloc_err_handler(malloc_warn_level); } /* malloc_warning(... */ malloc_err_handler(level) { if( malloc_warn_level & M_HANDLE_DUMP ) { malloc_dump(malloc_errfd); } switch( malloc_warn_level & ~M_HANDLE_DUMP ) { /* * If we are to drop a core file and exit */ case M_HANDLE_ABORT: abort(); break; /* * If we are to exit.. */ case M_HANDLE_EXIT: exit(200); break; /* * If we are to dump a core, but keep going on our merry way */ case M_HANDLE_CORE: { int pid; int rpid; /* * fork so child can abort (and dump core) */ if( (pid = fork()) == 0 ) { write(2,"Child dumping core\n",19); abort(); } /* * wait for child to finish dumping core */ while( (rpid=wait((int *)0)) != pid) { } /* * Move core file to core.pid.cnt so * multiple cores don't overwrite each * other. */ if( access("core",0) == 0 ) { static int corecnt; char filenam[32]; filenam[0] = 'c'; filenam[1] = 'o'; filenam[2] = 'r'; filenam[3] = 'e'; filenam[4] = '.'; (void)toascii(filenam+5,getpid(), 5, B_DEC, '0'); filenam[10] = '.'; (void)toascii(filenam+11,corecnt++, 3, B_DEC, '0'); filenam[14] = '\0'; (void) unlink(filenam); if( link("core",filenam) == 0) { (void) unlink("core"); } } } /* * If we are to just ignore the error and keep on processing */ case M_HANDLE_IGNORE: break; } /* switch(... */ } /* malloc_err_handler(... */ SHAR_EOF cat << \SHAR_EOF > malloc.h struct mlist { struct mlist * next; /* next entry in chain */ struct mlist * prev; /* prev entry in chain */ int flag; /* inuse flag */ unsigned int r_size; /* requested size */ union { unsigned int size; /* actual size */ double unused_just_for_alignment; } s; char data[4]; }; #define M_SIZE ((int)(char *)((struct mlist *)0)->data) #define M_RND 0x08 #define M_INUSE 0x01 #define M_MAGIC 0x03156100 #define M_BLOCKSIZE (1024*8) #define M_FILL '\01' #define M_FREE_FILL '\02' #define M_ROUNDUP(size) {\ if( size & (M_RND-1) ) \ { \ size &= ~(M_RND-1); \ size += M_RND; \ } \ } /* * Malloc warning/fatal error handler defines... */ #define M_HANDLE_DUMP 0x80 /* 128 */ #define M_HANDLE_IGNORE 0 #define M_HANDLE_ABORT 1 #define M_HANDLE_EXIT 2 #define M_HANDLE_CORE 3 void malloc_warning(); void malloc_fatal(); void malloc_check_data(); void malloc_check_str(); void malloc_verify(); SHAR_EOF cat << \SHAR_EOF > malloc_chk.c #include <stdio.h> #include "malloc.h" #include "debug.h" extern struct mlist malloc_start; extern struct mlist * malloc_end; extern char * malloc_data_start; extern char * malloc_data_end; /* * Function: malloc_in_arena() * * Purpose: to verify address is within malloc arena. * * Arguments: ptr - pointer to verify * * Returns: TRUE - if pointer is within malloc area * FALSE - otherwise * * Narrative: * IF pointer is >= malloc area start AND <= malloc area end * return TRUE * ELSE * return FALSE * * Mod History: * 90/01/24 cpcahil Initial revision. */ int malloc_in_arena(ptr) char * ptr; { extern char * malloc_data_start; extern char * malloc_data_end; int rtn = 0; if( ptr >= malloc_data_start && ptr <= malloc_data_end ) { rtn = 1; } return(rtn); } /* * Function: malloc_check_str() * * Arguments: func - name of function calling this routine * str - pointer to area to check * * Purpose: to verify that if str is within the malloc arena, the data * it points to does not extend beyond the applicable region. * * Returns: Nothing of any use (function is void). * * Narrative: * IF pointer is within malloc arena * determin length of string * call malloc_verify() to verify data is withing applicable region * return * * Mod History: * 90/01/24 cpcahil Initial revision. * 90/01/29 cpcahil Added code to ignore recursive calls. */ void malloc_check_str(func,str) char * func; char * str; { static int layers; register char * s; if( (layers++ == 0) && malloc_in_arena(str) ) { for( s=str; *s; s++) { } malloc_verify(func,str,s-str+1); } layers--; } /* * Function: malloc_check_data() * * Arguments: func - name of function calling this routine * ptr - pointer to area to check * len - length to verify * * Purpose: to verify that if ptr is within the malloc arena, the data * it points to does not extend beyond the applicable region. * * Returns: Nothing of any use (function is void). * * Narrative: * IF pointer is within malloc arena * call malloc_verify() to verify data is withing applicable region * return * * Mod History: * 90/01/24 cpcahil Initial revision. * 90/01/29 cpcahil Added code to ignore recursive calls. */ void malloc_check_data(func,ptr,len) char * func; char * ptr; int len; { static int layers; if( layers++ == 0 ) { DEBUG3(40,"malloc_check_data(%s,0x%x,%d) called...", func,ptr,len); if( malloc_in_arena(ptr) ) { DEBUG0(10,"pointer in malloc arena, verifying..."); malloc_verify(func,ptr,len); } } layers--; } /* * Function: malloc_verify() * * Arguments: func - name of function calling the malloc check routines * ptr - pointer to area to check * len - length to verify * * Purpose: to verify that the data ptr points to does not extend beyond * the applicable malloc region. This function is only called * if it has been determined that ptr points into the malloc arena. * * Returns: Nothing of any use (function is void). * * Narrative: * * Mod History: * 90/01/24 cpcahil Initial revision. */ void malloc_verify(func,ptr,len) char * func; char * ptr; int len; { extern struct mlist malloc_start; extern struct mlist * malloc_end; struct mlist * mptr; DEBUG3(40,"malloc_verify(%s,0x%x,%d) called...", func,ptr,len); /* * Find the malloc block that includes this pointer */ mptr = &malloc_start; while( mptr && ! (((char *)mptr < ptr) && ((mptr->data+mptr->s.size) > ptr) ) ) { mptr = mptr->next; } /* * if ptr was not in a malloc block, it must be part of * some direct sbrk() stuff, so just return. */ if( ! mptr ) { DEBUG1(10,"ptr (0x%x) not found in malloc search", ptr); return; } /* * Now we have a valid malloc block that contains the indicated * pointer. We must verify that it is withing the requested block * size (as opposed to the real block size which is rounded up to * allow for correct alignment). */ DEBUG4(60,"Checking 0x%x-0x%x, 0x%x-0x%x", ptr, ptr+len, mptr->data, mptr->data+mptr->r_size); if( (ptr < mptr->data) || ((ptr+len) > (mptr->data+mptr->r_size)) ) { char errstr[512]; DEBUG4(0,"pointer not within region 0x%x-0x%x, 0x%x-0x%x", ptr, ptr+len, mptr->data, mptr->data+mptr->r_size); sprintf(errstr,"%s %s, %s 0x%x %s '%.2x %.2x %.2x %.2x %.2x'", "Malloced memory overflow detected in function", func, "address:", ptr, "Data: ", *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4)); malloc_fatal(errstr); } return; } SHAR_EOF cat << \SHAR_EOF > memory.c char * memccpy(ptr1, ptr2, ch, len) register char * ptr1; register char * ptr2; int len; int ch; { register int i; char * rtn; /* * I know that the assignment could be done in the following, but * I wanted to perform a check before any assignment, so first I * determine the length, check the pointers and then do the assignment. */ for( i=0; (i < len) && (ptr2[i] != ch); i++) { } malloc_check_data("memccpy", ptr1, i); malloc_check_data("memccpy", ptr2, i); /* * if we found the character... */ if( i < len ) { rtn = ptr1+i+1; } else { rtn = (char *) 0; } while( i-- ) { *(ptr1++) = *(ptr2++); } return(rtn); } char * memchr(ptr1,ch,len) register char * ptr1; register int ch; int len; { int i; for( i=0; (i < len) && (ptr1[i] != ch); i++) { } malloc_check_data("memchr", ptr1, i); if( i < len ) { return( ptr1+i ); } else { return( (char *) 0); } } char * memcpy(ptr1, ptr2, len) register char * ptr1; register char * ptr2; register int len; { char * rtn = ptr1; malloc_check_data("memcpy", ptr1, len); malloc_check_data("memcpy", ptr2, len); while( len-- ) { *(ptr1++) = *(ptr2++); } return(rtn); } int memcmp(ptr1, ptr2, len) register char * ptr1; register char * ptr2; register int len; { malloc_check_data("memcpy", ptr1, len); malloc_check_data("memcpy", ptr2, len); while( --len && (*ptr1 == *ptr2) ) { ptr1++; ptr2++; } return( *ptr1 - *ptr2 ); } char * memset(ptr1, ch, len) register char * ptr1; register int ch; register int len; { char * rtn = ptr1; malloc_check_data("memcpy", ptr1, len); while( len-- ) { *(ptr1++) = ch; } return(rtn); } bcopy(ptr2,ptr1,len) { memcpy(ptr1,ptr2,len); } bzero(ptr1,len) { memset(ptr1,'\0',len); } int bcmp(ptr2, ptr1, len) { return( memcmp(ptr1,ptr2,len) ); } SHAR_EOF cat << \SHAR_EOF > pgm.c #include <stdio.h> main(argc,argv) int argc; char * argv[]; { int i; char * malloc(); char * ptr[10]; char * realloc(); ptr[0] = malloc(2034); printf("malloc() returned 0x%x\n", ptr[0]); ptr[1] = malloc(2034); printf("malloc() returned 0x%x\n", ptr[1]); ptr[2] = malloc(14321); printf("malloc() returned 0x%x\n", ptr[2]); malloc_dump(2); getchar(); memset(ptr[1],' ',2034); ptr[5] = realloc(ptr[1],20300); /* fprintf(stderr,"value at position 200 after realloc: 0x%x\n", ptr[3][200]); */ malloc_dump(2); getchar(); memset(ptr[2],'\0',14321); free(ptr[2]); malloc_dump(2); getchar(); free(ptr[0]); malloc_dump(2); getchar(); ptr[3] = malloc(2034); printf("malloc() returned 0x%x\n", ptr[3]); ptr[4] = malloc(234); printf("malloc() returned 0x%x\n", ptr[4]); malloc_dump(2); getchar(); for(i=0; i < 10; i++) { free(ptr[i]); malloc_dump(2); } } SHAR_EOF cat << \SHAR_EOF > realloc.c #include <stdio.h> #include "malloc.h" char * realloc(cptr,size) char * cptr; unsigned int size; { int i; char * malloc(); extern struct mlist * malloc_end; extern char * malloc_data_end; extern char * malloc_data_start; char * new_cptr; struct mlist * ptr; int r_size; int rest; struct mlist * tptr; /* * First verify that cptr is within the malloc region... */ if( cptr < malloc_data_start || cptr > malloc_data_end ) { malloc_warning("realloc called with invalid address..."); return; } /* * convert pointer to mlist struct pointer. To do this we must * move the pointer backwards the correct number of bytes... */ ptr = (struct mlist *) (cptr - M_SIZE); if( (ptr->flag != (M_MAGIC|M_INUSE)) || (ptr->prev && (ptr->prev->next != ptr) ) || (ptr->next && (ptr->next->prev != ptr) ) || ((ptr->next == NULL) && (ptr->prev == NULL)) ) { malloc_warning( "realloc: called with invalid pointer or corrupted chain"); return(NULL); } r_size = size; M_ROUNDUP(size); if( size > ptr->s.size ) { malloc_join(ptr,ptr->next,1,1); } if( size < ptr->s.size ) { rest = ptr->s.size - size; } else { /* * else we can't combine it, so lets allocate a new chunk, * copy the data and free the old chunk... */ new_cptr = malloc(size); if( new_cptr == (char *) 0) { return(new_cptr); } if( r_size < ptr->r_size ) { i = r_size; } else { i = ptr->r_size; } memcpy(new_cptr,ptr->data,i); free(cptr); return(new_cptr); } /* else... */ /* * save amount of real data in new segment (this will be used in the * memset later) and then save requested size of this segment. */ if( ptr->r_size < r_size ) { i = ptr->r_size; } else { i = r_size; } ptr->r_size = r_size; /* * split off extra free space at end of this segment, if possible... */ malloc_split(ptr); malloc_memset( ptr->data+i, M_FILL, ptr->s.size - i); return(ptr->data); } /* realloc(... */ SHAR_EOF cat << \SHAR_EOF > string.c #include <stdio.h> #include <string.h> #include <sys/types.h> #include "malloc.h" int malloc_checking = 0; char * strcat(str1,str2) register char * str1; register char * str2; { char * rtn; int len; /* * check pointers agains malloc region. The malloc* functions * will properly handle the case where a pointer does not * point into malloc space. */ malloc_checking = 1; len = strlen(str2); malloc_check_str("strcat", str2); len += strlen(str1) + 1; malloc_checking = 0; malloc_check_data("strcat", str1, len); rtn = str1; while( *str1 ) { str1++; } while( (*str1 = *str2) != '\0' ) { str1++; str2++; } return(rtn); } char * strdup(str1) register char * str1; { char * malloc(); char * rtn; register char * str2; malloc_check_str("strdup", str1); rtn = str2 = malloc(strlen(str1)); while( (*str2 = *str1) != '\0' ) { str1++; str2++; } return(rtn); } char * strncat(str1,str2,len) register char * str1; register char * str2; register int len; { int len1; int len2; char * rtn; malloc_checking = 1; len2 = strlen(str2) + 1; len1 = strlen(str1); malloc_checking = 0; malloc_check_data("strncat", str2,len2); if( (len+1) < len2 ) { len1 += len + 1; } else { len1 += len2; } malloc_check_data("strncat", str1, len1); rtn = str1; while( *str1 ) { str1++; } while( len-- && ((*str1++ = *str2++) != '\0') ) { } if( ! len ) { *str1 = '\0'; } return(rtn); } int strcmp(str1,str2) register char * str1; register char * str2; { malloc_check_str("strcmp", str1); malloc_check_str("strcmp", str2); while( *str1 && (*str1 == *str2) ) { str1++; str2++; } return( *str1 - *str2 ); } int strncmp(str1,str2,len) register char * str1; register char * str2; register int len; { malloc_check_str("strncmp", str1); malloc_check_str("strncmp", str2); while( --len && *str1 && (*str1 == *str2) ) { str1++; str2++; } return( *str1 - *str2 ); } char * strcpy(str1,str2) register char * str1; register char * str2; { char * rtn; int len; malloc_checking = 1; len = strlen(str2) + 1; malloc_checking = 0; malloc_check_data("strcpy", str1, len); malloc_check_data("strcpy", str2, len); rtn = str1; while( (*str1++ = *str2++) != '\0') { } return(rtn); } char * strncpy(str1,str2,len) register char * str1; register char * str2; register int len; { int i; extern int malloc_checking; char * rtn; malloc_check_data("strncpy", str1, len); malloc_checking = 1; i = strlen(str2); malloc_checking = 0; if( i > len ) { i = len; } malloc_check_data("strncpy", str2, i); rtn = str1; while(len-- && (*str1++ = *str2++) != '\0') { } while( len-- ) { *str1++ = '\0'; } return(rtn); } int strlen(str1) register char * str1; { register char * s; if(! malloc_checking ) { malloc_check_str("strlen", str1); } for( s = str1; *s; s++) { } return( s - str1 ); } char * strchr(str1,c) register char * str1; register int c; { malloc_check_str("strchr", str1); while( *str1 && (*str1 != (char) c) ) { str1++; } if(! *str1 ) { str1 = (char *) 0; } return(str1); } char * strrchr(str1,c) register char * str1; register int c; { register char * rtn = (char *) 0; malloc_check_str("strrchr", str1); while( *str1 ) { if(*str1 == (char) c ) { rtn = str1; } str1++; } return(rtn); } char * index(str1,c) { return( strchr(str1,c) ); } char * rindex(str1,c) { return( strrchr(str1,c) ); } char * strpbrk(str1,str2) register char * str1; register char * str2; { register char * tmp; malloc_check_str("strpbrk", str1); malloc_check_str("strpbrk", str2); while(*str1) { for( tmp=str2; *tmp && *tmp != *str1; tmp++) { } if( *tmp ) { break; } str1++; } if( ! *str1 ) { str1 = (char *) 0; } return(str1); } int strspn(str1,str2) register char * str1; register char * str2; { register char * tmp; char * orig = str1; malloc_check_str("strspn", str1); malloc_check_str("strspn", str2); while(*str1) { for( tmp=str2; *tmp && *tmp != *str1; tmp++) { } if(! *tmp ) { break; } str1++; } return( (int) (str1 - orig) ); } int strcspn(str1,str2) register char * str1; register char * str2; { register char * tmp; char * orig = str1; malloc_check_str("strcspn", str1); malloc_check_str("strcspn", str2); while(*str1) { for( tmp=str2; *tmp && *tmp != *str1; tmp++) { } if( *tmp ) { break; } str1++; } return( (int) (str1 - orig) ); } /* * strtok() source taken from that posted to comp.lang.c by Chris Torek * in Jan 1990. */ /* * Copyright (c) 1989 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Berkeley. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ /* * Get next token from string s (NULL on 2nd, 3rd, etc. calls), * where tokens are nonempty strings separated by runs of * chars from delim. Writes NULs into s to end tokens. delim need not * remain constant from call to call. * * Modified by cpc: changed variable names to conform with naming * conventions used in rest of code. Added malloc pointer * check calls. */ char * strtok(str1, str2) char * str1; char * str2; { static char * last; char * strtoken(); if( str1 ) { malloc_check_str("strtok", str1); last = str1; } malloc_check_str("strtok", str2); return (strtoken(&last, str2, 1)); } /* * Get next token from string *stringp, where tokens are (possibly empty) * strings separated by characters from delim. Tokens are separated * by exactly one delimiter iff the skip parameter is false; otherwise * they are separated by runs of characters from delim, because we * skip over any initial `delim' characters. * * Writes NULs into the string at *stringp to end tokens. * delim will usually, but need not, remain constant from call to call. * On return, *stringp points past the last NUL written (if there might * be further tokens), or is NULL (if there are definitely no more tokens). * * If *stringp is NULL, strtoken returns NULL. */ char * strtoken(stringp, delim, skip) register char **stringp; register char *delim; int skip; { register char *s; register char *spanp; register int c, sc; char *tok; if ((s = *stringp) == NULL) return (NULL); if (skip) { /* * Skip (span) leading delimiters (s += strspn(s, delim)). */ cont: c = *s; for (spanp = delim; (sc = *spanp++) != 0;) { if (c == sc) { s++; goto cont; } } if (c == 0) { /* no token found */ *stringp = NULL; return (NULL); } } /* * Scan token (scan for delimiters: s += strcspn(s, delim), sort of). * Note that delim must have one NUL; we stop if we see that, too. */ for (tok = s;;) { c = *s++; spanp = delim; do { if ((sc = *spanp++) == c) { if (c == 0) s = NULL; else s[-1] = 0; *stringp = s; return (tok); } } while (sc != 0); } /* NOTREACHED */ } SHAR_EOF cat << \SHAR_EOF > testmalloc.c /* NOT copyright by SoftQuad Inc. -- msb, 1988 */ #ifndef lint static char *SQ_SccsId = "@(#)mtest3.c 1.2 88/08/25"; #endif #include <stdio.h> /* ** looptest.c -- intensive allocator tester ** ** Usage: looptest ** ** History: ** 4-Feb-1987 rtech!daveb */ # ifdef i386 # define SYS5 # endif # ifdef SYS5 # define random rand # else # include <sys/vadvise.h> # endif # include <stdio.h> # include <signal.h> # include <setjmp.h> # define MAXITER 1000000 /* main loop iterations */ # define MAXOBJS 1000 /* objects in pool */ # define BIGOBJ 90000 /* max size of a big object */ # define TINYOBJ 80 /* max size of a small object */ # define BIGMOD 100 /* 1 in BIGMOD is a BIGOBJ */ # define STATMOD 10000 /* interation interval for status */ main( argc, argv ) int argc; char **argv; { register int **objs; /* array of objects */ register int *sizes; /* array of object sizes */ register int n; /* iteration counter */ register int i; /* object index */ register int size; /* object size */ register int r; /* random number */ int objmax; /* max size this iteration */ int cnt; /* number of allocated objects */ int nm = 0; /* number of mallocs */ int nre = 0; /* number of reallocs */ int nal; /* number of allocated objects */ int nfre; /* number of free list objects */ long alm; /* memory in allocated objects */ long frem; /* memory in free list */ long startsize; /* size at loop start */ long endsize; /* size at loop exit */ long maxiter = 0; /* real max # iterations */ extern char end; /* memory before heap */ char *calloc(); char *malloc(); char *sbrk(); long atol(); # ifndef SYS5 /* your milage may vary... */ vadvise( VA_ANOM ); # endif if (argc > 1) maxiter = atol (argv[1]); if (maxiter <= 0) maxiter = MAXITER; printf("MAXITER %d MAXOBJS %d ", maxiter, MAXOBJS ); printf("BIGOBJ %d, TINYOBJ %d, nbig/ntiny 1/%d\n", BIGOBJ, TINYOBJ, BIGMOD ); fflush( stdout ); if( NULL == (objs = (int **)calloc( MAXOBJS, sizeof( *objs ) ) ) ) { fprintf(stderr, "Can't allocate memory for objs array\n"); exit(1); } if( NULL == ( sizes = (int *)calloc( MAXOBJS, sizeof( *sizes ) ) ) ) { fprintf(stderr, "Can't allocate memory for sizes array\n"); exit(1); } /* as per recent discussion on net.lang.c, calloc does not ** necessarily fill in NULL pointers... */ for( i = 0; i < MAXOBJS; i++ ) objs[ i ] = NULL; startsize = sbrk(0) - &end; printf( "Memory use at start: %d bytes\n", startsize ); fflush(stdout); printf("Starting the test...\n"); fflush(stdout); for( n = 0; n < maxiter ; n++ ) { if( !(n % STATMOD) ) { printf("%d iterations\n", n); fflush(stdout); } /* determine object of interst and it's size */ r = random(); objmax = ( r % BIGMOD ) ? TINYOBJ : BIGOBJ; size = r % objmax; i = r % (MAXOBJS - 1); /* either replace the object of get a new one */ if( objs[ i ] == NULL ) { objs[ i ] = (int *)malloc( size ); nm++; } else { /* don't keep bigger objects around */ if( size > sizes[ i ] ) { objs[ i ] = (int *)realloc( objs[ i ], size ); nre++; } else { free( objs[ i ] ); objs[ i ] = (int *)malloc( size ); nm++; } } sizes[ i ] = size; if( objs[ i ] == NULL ) { printf("\nCouldn't allocate %d byte object!\n", size ); break; } } /* for() */ printf( "\n" ); cnt = 0; for( i = 0; i < MAXOBJS; i++ ) if( objs[ i ] ) cnt++; printf( "Did %d iterations, %d objects, %d mallocs, %d reallocs\n", n, cnt, nm, nre ); printf( "Memory use at end: %d bytes\n", sbrk(0) - &end ); fflush( stdout ); /* free all the objects */ for( i = 0; i < MAXOBJS; i++ ) if( objs[ i ] != NULL ) free( objs[ i ] ); endsize = sbrk(0) - &end; printf( "Memory use after free: %d bytes\n", endsize ); fflush( stdout ); if( startsize != endsize ) printf("startsize %d != endsize %d\n", startsize, endsize ); free( objs ); free( sizes ); malloc_dump(); exit( 0 ); } SHAR_EOF cat << \SHAR_EOF > testmem.c #include <stdio.h> /* * These tests test the memory functions... */ main() { char buffer[500]; int exitval = 0; char * memccpy(); char * memchr(); char * ptr1; char * ptr2; fprintf(stdout,"Begining memory(3) tests...\n"); /* * test memccpy()... */ ptr1 = "abcdefghijklmn"; ptr2 = memccpy(buffer,ptr1,'d',3); if( ptr2 != (char *) 0) { fprintf(stdout,"memccpy() failed to use passed length\n"); exitval++; } ptr2 = memccpy(buffer,ptr1,'d',4); if( ptr2 != (buffer+4) ) { fprintf(stdout,"memccpy() failed to find byte in data\n"); exitval++; } /* * Test memchr()... */ ptr1 = "abcdefghijklmn"; ptr2 = memchr(ptr1,'c',10); if( ptr2 != (ptr1+2) ) { fprintf(stdout,"memchr() failed to find byte in data\n"); exitval++; } ptr2 = memchr(ptr1,'j',10); if( ptr2 != (ptr1+9) ) { fprintf(stdout,"memchr() failed to find byte in data\n"); exitval++; } ptr2 = memchr(ptr1,'k',10); if( ptr2 != (char *) 0) { fprintf(stdout,"memchr() failed to obey length argument\n"); exitval++; } fprintf(stdout,"Memory tests complete!\n"); exit(exitval); } SHAR_EOF cat << \SHAR_EOF > toascii.c #include "toascii.h" /* * Function: toascii() * * Purpose: to convert an integer to an ascii display string * * Arguments: buf - place to put the * val - integer to convert * len - length of output field (0 if just enough to hold data) * base - base for number conversion (only works for base <= 16) * fill - fill char when len > # digits * * Returns: length of string * * Narrative: IF fill character is non-blank * Determine base * If base is HEX * add "0x" to begining of string * IF base is OCTAL * add "0" to begining of string * * While value is greater than zero * use val % base as index into xlation str to get cur char * divide val by base * * Determine fill-in length * * Fill in fill chars * * Copy in number * * * Mod History: * 90/01/24 cpcahil Initial revision. */ #define T_LEN 10 int toascii(buf,val,len,base,fill) int base; char * buf; char fill; int len; int val; { char * bufstart = buf; int i = T_LEN; char * xbuf = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; char tbuf[T_LEN]; /* * if we are filling with non-blanks, make sure the * proper start string is added */ if( fill != ' ' ) { switch(base) { case B_HEX: *(buf++) = '0'; *(buf++) = 'x'; if( len ) { len -= 2; } break; case B_OCTAL: *(buf++) = fill; if( len ) { len--; } break; default: break; } } while( val > 0 ) { tbuf[--i] = xbuf[val % base]; val = val / base; } if( len ) { len -= (T_LEN - i); if( len > 0 ) { while(len-- > 0) { *(buf++) = fill; } } else { /* * string is too long so we must truncate * off some characters. We do this the easiest * way by just incrementing i. This means the * most significant digits are lost. */ while( len++ < 0 ) { i++; } } } while( i < T_LEN ) { *(buf++) = tbuf[i++]; } return( (int) (buf - bufstart) ); } /* toascii(... */ SHAR_EOF cat << \SHAR_EOF > toascii.h #define B_BIN 2 #define B_DEC 10 #define B_HEX 16 #define B_OCTAL 8 SHAR_EOF # End of shell archive exit 0 -- +-----------------------------------------------------------------------+ | Conor P. Cahill uunet!virtech!cpcahil 703-430-9247 ! | Virtual Technologies Inc., P. O. Box 876, Sterling, VA 22170 | +-----------------------------------------------------------------------+ From atheybey at lcs.mit.edu Thu Jan 11 02:15:09 1990 From: atheybey at lcs.mit.edu (Andrew Heybey) Date: 10 Jan 90 15:15:09 GMT Subject: crypt.el for GNU Emacs In-Reply-To: kjones@talos.uu.net's message of 9 Jan 90 17:58:37 GMT References: <1990Jan9.175837.25058@talos.uu.net> Message-ID: <ATHEYBEY.90Jan10101509@allspice.lcs.mit.edu> The posting of the latest version of crypt.el reminded me of a bug fix that I had made to the previous version. The "magic number" used to recognize compressed files works only for 16 bit compression. Here is the diff for the previous version. Patch (at least on our system) will apply it to the new version as well. *** /tmp/,RCSt1017910 Wed Jan 10 10:09:46 1990 --- crypt.el Tue Dec 5 13:01:45 1989 *************** *** 68,74 **** "Regexp that matches the magic number at the beginning of files created by the compact(1) command.") ! (defconst compress-magic-regexp "\037\235\220" "Regexp that matches the magic number at the beginning of files created by the compress(1) command.") --- 68,74 ---- "Regexp that matches the magic number at the beginning of files created by the compact(1) command.") ! (defconst compress-magic-regexp "\037\235" "Regexp that matches the magic number at the beginning of files created by the compress(1) command.") -- Andrew Heybey, atheybey at ptt.lcs.mit.edu, uunet!ptt.lcs.mit.edu!atheybey From calvin at hobbes.Sun.COM Fri Jan 19 11:34:31 1990 From: calvin at hobbes.Sun.COM (Christopher Klein - Sun Consulting) Date: 19 Jan 90 00:34:31 GMT Subject: Personal Finance Software wanted Message-ID: <9350@newstop.EBay.Sun.COM> Hi all! This one's gotta be real simple. Anybody have C source to a Personal Finance software, you know, checkbook, etc? How about an address book manager? `Preciate it.. `Chris Christopher Klein calvin at hobbes.east.sun.com Sun Microsystems, NYC (212) 558-9196 From scott at csusac.csus.edu Sun Jan 7 05:38:11 1990 From: scott at csusac.csus.edu (L. Scott Emmons) Date: 6 Jan 90 18:38:11 GMT Subject: 'from' alias in csh UPDATE...READ THIS! Message-ID: <1990Jan6.183811.11397@csusac.csus.edu> I apologize for the error in my last post regarding my csh 'from' script. The correct alias is: --- alias from 'egrep "^From |^Subject:" $MAIL' -- L. Scott Emmons --------------- ...[!ucbvax]!ucdavis!csusac!scott ucdavis!csusac!scott at ucbvax.berkeley.edu From stephand at maestro.htsa.aha.nl Wed Jan 17 01:27:49 1990 From: stephand at maestro.htsa.aha.nl (Stephan Dasia) Date: 16 Jan 90 14:27:49 GMT Subject: WANTED : Ethernet driver ! Message-ID: <1319@maestro.htsa.aha.nl> URGENT : Who can help me ? Recently i got the control over an UNIX machine with an Ethernet controller but no driver. So i'm looking for the sources of a SYSV ETHERNET driver. For an ETHERNET controller with an : AM 7990 LAN Controller for Ethernet ( LANCE ) AM 7992 Serial Interface Adapter ( SIA ) I would appreciate your help with this. Stephan D. -- ============================================================================== = Stephan Dasia | stephand at maestro.htsa.aha.nl = = Algemene Hogeschool Amsterdam | stephand at htsa.UUCP = = Technische en Maritieme Faculteit | ...!hp4nl!htsa!stephand = ============================================================================== From clewis at eci386.uucp Sat Jan 20 09:48:07 1990 From: clewis at eci386.uucp (Chris Lewis) Date: 19 Jan 90 22:48:07 GMT Subject: Oversight in Psroff patch 5 through 7. (Suns particularly) Message-ID: <1990Jan19.224807.7490@eci386.uucp> If you are running psroff patch 5 through 7 on a system who's troff doesn't support the "-T" option (certain Suns in particular), psroff will generate drastically truncated output. troff is aborting with an error message, but the error message is swallowed by the drivers in troff2ps (stderr is used for communicating special directives (eg: font changes) to the backend) Edit psroff.sh and search for the lines that have the "-T$type" option being passed to troff, as in: $troff -t -T$type Change the "-T$type" to "-F/usr/lib/font/$type". [But NOT in the arguments to troff2ps!] make and reinstall. This will be a configuration option in patch 8 - real soon now. Patch 8 should also include better support for Jetroff. -- Chris Lewis, Elegant Communications Inc, {uunet!attcan,utzoo}!lsuc!eci386!clewis Ferret mailing list: eci386!ferret-list, psroff mailing list: eci386!psroff-list From buck at siswat.UUCP Mon Jan 15 07:58:03 1990 From: buck at siswat.UUCP (A. Lester Buck) Date: 14 Jan 90 20:58:03 GMT Subject: Tape retensioning References: <1990Jan6.063506.8670@actrix.co.nz> <6412@turnkey.gryphon.COM> <246@comcon.UUCP> Message-ID: <492@siswat.UUCP> It certainly isn't very hard to do a tape manipulating program. Here is what I wrote several years ago to follow the man page for "mt", the SVR2 tape manipulating command. This was for use with some tape drivers I was moving around from system to system, so I had to be able to move the IOCTL manipulator with me. I left out code for checking the environment variable TAPE and using that before the default device - feel free to add it. And the commands much match exactly, not just in the first unique prefix. I added a few synonyms for some commands, and most drivers do not support backspace file and backspace record, so pick and choose your commands. Mt returns 0 exit status on success, 1 if command unrecognized, and 2 if an operation failed. This program requires the sys/mtio.h (or whatever) header which defines the IOCTL's for your specific driver, but that is copyrighted and specific for your drivers and system. Of course, this program won't help much if you don't have such IOCTL information. #include <stdio.h> #include <sys/types.h> #include <fcntl.h> #include <sys/mtio.h> #define DEF_DEVICE "/dev/rmt/0" #define FAIL (-1) struct mtop mtop = {-1, 1}; struct entry { int op; char *name; } table[] = { { MTREW, "rewind"}, { MTREW, "rew"}, { MTOFFL, "offline"}, { MTOFFL, "rewoffl"}, { MTWEOF, "eof"}, { MTWEOF, "weof"}, { MTFSF, "fsf"}, { MTFSR, "fsr"}, { MTRETEN, "reten"}, { MTERASE, "erase"}, { MTBSF, "bsf"}, { MTBSR, "bsr"}, { MTNOP, "nop"} }; void usage() { fprintf(stderr, "usage: mt [-f tapename] command count\n"); exit(1); } main(argc, argv) int argc; char **argv; { int fd, entries, i; char *devpath, *cmdname; if (argc < 2) { usage(); } if (strcmp(*++argv, "-f") == 0) { switch (argc) { case 4: devpath = *++argv; cmdname = *++argv; break; case 5: devpath = *++argv; cmdname = *++argv; mtop.mt_count = atoi(*++argv); break; default: usage(); } } else { devpath = DEF_DEVICE; switch (argc) { case 2: cmdname = *argv; break; case 3: cmdname = *argv; mtop.mt_count = atoi(*++argv); break; default: usage(); } } if ((fd=open(devpath, O_RDONLY)) == FAIL) { fprintf(stderr, "mt: open failed on %s\n", devpath); exit(1); } entries = sizeof(table)/sizeof(struct entry); for ( i=0; i < entries; i++ ) { if (strcmp(table[i].name, cmdname) == 0) { mtop.mt_op = table[i].op; break; } } if (mtop.mt_op == -1) { fprintf(stderr, "mt: invalid command %s\n", cmdname); exit(1); } if (ioctl(fd, (int)MTIOCTOP, (caddr_t)&mtop) == FAIL) { perror("mt: "); exit(2); } exit(0); } -- A. Lester Buck buck at siswat.lonestar.org ...!texbell!moray!siswat!buck From igp at torch.co.uk Fri Jan 12 20:25:33 1990 From: igp at torch.co.uk (Ian Phillipps) Date: 12 Jan 90 09:25:33 GMT Subject: fast which v3.0. A shorter method References: <5051@solo9.cs.vu.nl> Message-ID: <605@torch.co.uk> IMHO, this is just as quick, and a bit shorter. Note the (brackets) in the alias: this executes in a fork of your login shell and prevents the parameters creeping into your environment. You'll want to put in a complete path name instead of which.src. BUGS: you can't do `which foo` cat <<'END_OF_SHAR' >which.src # execute as a "sourced" file # Parameter WhichWhich is set to name list to be scanned # Set up with: # alias which '(set WhichWhich=(\!*); source which.src )' foreach x ( $WhichWhich ) set TempWhich=`alias $x`; if ( $#TempWhich > 0 ) echo alias: $x "'$TempWhich'" # if ( $#TempWhich > 0 ) break # Break here if only foreach f ($path) if ( -f $f/$x ) then echo $f/$x # break # Break here if only one filename wanted endif end end END_OF_SHAR exit From maart at cs.vu.nl Thu Jan 11 14:44:46 1990 From: maart at cs.vu.nl (Maarten Litmaath) Date: 11 Jan 90 03:44:46 GMT Subject: rn cancel macro update Message-ID: <5080@solo9.cs.vu.nl> Now the `Distribution:' field is set correctly (= limited!). ----------8<----------8<----------8<----------8<----------8<---------- #!/bin/sh # @(#)cancel 1.1 89/12/30 Maarten Litmaath # cancel <path-to-article> INEWS=/usr/lib/news/inews # figure out if echo is BSD or SYSV test "x`echo -n x`" = xx && n=-n c= || n= c=\\c test $# = 1 || { echo "Usage: `basename $0` <path-to-article>" >&2 exit 1 } NEWSGROUPS=`sed -n -e '/^Newsgroups: /{' -e 's///' -e p -e q -e '}' "$1"` IDENT=`sed -n -e '/^Message-ID: /{' -e 's///' -e p -e q -e '}' "$1"` DISTRIBUTION=` sed -n -e '/^$/q' -e '/^Distribution: /{' -e s/// -e p -e q -e '}' "$1" ` test x"$DISTRIBUTION" = x && DISTRIBUTION=world echo "Confirm cancel of article $IDENT in" echo $n "$NEWSGROUPS: [ny] $c" read ans test x"$ans" = xy && $INEWS -c "cancel $IDENT" -n "$NEWSGROUPS" -d "$DISTRIBUTION" \ < /dev/null ----------8<----------8<----------8<----------8<----------8<---------- -- 1755 EST, Dec 14, 1992: Henry Spencer is put on a one-way mission to the moon.| Maarten Litmaath @ VU Amsterdam: maart at cs.vu.nl, uunet!mcsun!botter!maart From paul at devon.lns.pa.us Wed Jan 17 18:57:37 1990 From: paul at devon.lns.pa.us (Paul Sutcliffe Jr.) Date: 17 Jan 90 07:57:37 GMT Subject: Enhanced SYSV Getty, v1.1, part 2 of 4 Message-ID: <1990Jan17.075737.701@devon.lns.pa.us> #! /bin/sh # Make a new directory for the getty sources, cd to it, and run kits 1 # thru 4 through sh. When all 4 kits have been run, read README. echo "This is getty 1.1 kit 2 (of 4). If kit 2 is complete, the line" echo '"'"End of kit 2 (of 4)"'" will echo at the end.' echo "" export PATH || (echo "You didn't use sh, you clunch." ; kill $$) mkdir 2>/dev/null echo Extracting Configure sed >Configure <<'!STUFFY!FUNK!' -e 's/X//' X#! /bin/sh X# X# If these # comments don't work, trim them. Don't worry about any other X# shell scripts, Configure will trim # comments from them for you. X# X# (If you are trying to port this package to a machine without sh, I would X# suggest you cut out the prototypical config.h from the end of Configure X# and edit it to reflect your system. Some packages may include samples X# of config.h for certain machines, so you might look for one of those.) X# X# $Id: Configure,v 1.1 90/01/16 16:09:23 paul Exp Locker: paul $ X# X# $Log: Configure,v $ X# Revision 1.1 90/01/16 16:09:23 paul X# Initial revision X# X# X X: sanity checks XPATH='.:/bin:/usr/bin:/usr/local/bin:/usr/ucb:/usr/local:/usr/lbin:/etc:/usr/new:/usr/new/bin:/usr/nbin' Xexport PATH || (echo "OOPS, this isn't sh. Desperation time. I will feed myself to sh."; sh $0; kill $$) X Xif test ! -t 0; then X echo "Say 'sh Configure', not 'sh <Configure'" X exit 1 Xfi X X(alias) >/dev/null 2>&1 && \ X echo "(I see you are using the Korn shell. Some ksh's blow up on Configure," && \ X echo "especially on exotic machines. If yours does, try the Bourne shell instead.)" X Xif test ! -d ../UU; then X if test ! -d UU; then X mkdir UU X fi X cd UU Xfi X Xcase "$1" in X-d) shift; fastread='yes';; Xesac X Xpackage='' Xdefine='' Xundef='' Xd_eunice='' Xeunicefix='' Xcontains='' Xn='' Xc='' Xspitshell='' Xshsharp='' Xsharpbang='' Xstartsh='' Xloclist='' Xexpr='' Xsed='' Xsort='' Xuniq='' Xecho='' Xcat='' Xrm='' Xmv='' Xcp='' Xtr='' Xgrep='' Xcc='' Xcpp='' Xtrylist='' Xtest='' Xegrep='' XMcc='' Xsendmail='' Xmailx='' Xmail='' Xlibc='' XLog='' XId='' Xxenix='' Xd_getutent='' Xd_strdup='' Xd_putenv='' Xtermlib='' Xllib_termlib='' Xd_ttytype='' Xttytype='' Xgettytab='' Xutmp='' Xwtmp='' Xhostname='' Xphostname='' Xd_douname='' Xd_phostname='' Xd_portable='' Xbin='' Xstdchar='' Xdefvoidused='' Xvoidflags='' Xd_voidsig='' Xmodels='' Xsmall='' Xmedium='' Xlarge='' Xhuge='' Xunsplit='' Xsplit='' Xccflags='' Xldflags='' Xcppstdin='' Xcppminus='' Xregisters='' Xreg1='' Xreg2='' Xreg3='' Xreg4='' Xreg5='' Xreg6='' Xreg7='' Xreg8='' Xreg9='' Xreg10='' Xreg11='' Xreg12='' Xreg13='' Xreg14='' Xreg15='' Xreg16='' Xuidtype='' Xgidtype='' Xuucpid='' Xlock='' Xd_asciipid='' Xmailer='' XCONFIG='' X: set package name Xpackage=getty X Xecho " " Xecho "Beginning of configuration questions for $package kit." X: Eunice requires " " instead of "", can you believe it Xecho " " X Xdefine='define' Xundef='undef' Xlibpth='/usr/lib /usr/local/lib /lib' Xsmallmach='pdp11 i8086 z8000 i80286 iAPX286' Xrmlist='kit[1-9]isdone kit[1-9][0-9]isdone' Xtrap 'echo " "; rm -f $rmlist; exit 1' 1 2 3 X X: We must find out about Eunice early Xeunicefix=':' Xif test -f /etc/unixtovms; then X eunicefix=/etc/unixtovms Xfi Xif test -f /etc/unixtovms.exe; then X eunicefix=/etc/unixtovms.exe Xfi X X: Now test for existence of everything in MANIFEST X Xecho "First let's make sure your kit is complete. Checking..." X(cd ..; cat `awk 'NR>4{print $1}' MANIFEST` >/dev/null || kill $$) Xecho " " X Xattrlist="mc68000 sun gcos unix ibm gimpel interdata tss os mert pyr" Xattrlist="$attrlist vax pdp11 i8086 z8000 u3b2 u3b5 u3b20 u3b200" Xattrlist="$attrlist hpux hp9000s300 hp9000s500 hp9000s800" Xattrlist="$attrlist ns32000 ns16000 iAPX286 mc300 mc500 mc700 sparc" Xattrlist="$attrlist nsc32000 sinix xenix venix posix ansi M_XENIX" Xattrlist="$attrlist $mc68k __STDC__ UTS M_I8086 M_I186 M_I286 M_I386" Xpth="/usr/ucb /bin /usr/bin /usr/local /usr/local/bin /usr/lbin /etc /usr/lib /lib /usr/local/lib" Xdefvoidused=7 X X: some greps do not return status, grrr. Xecho "grimblepritz" >grimble Xif grep blurfldyick grimble >/dev/null 2>&1 ; then X contains=contains Xelif grep grimblepritz grimble >/dev/null 2>&1 ; then X contains=grep Xelse X contains=contains Xfi Xrm -f grimble X: the following should work in any shell Xcase "$contains" in Xcontains*) X echo " " X echo "AGH! Grep doesn't return a status. Attempting remedial action." X cat >contains <<'EOSS' Xgrep "$1" "$2" >.greptmp && cat .greptmp && test -s .greptmp XEOSS Xchmod +x contains Xesac X X: first determine how to suppress newline on echo command Xecho "Checking echo to see how to suppress newlines..." X(echo "hi there\c" ; echo " ") >.echotmp Xif $contains c .echotmp >/dev/null 2>&1 ; then X echo "...using -n." X n='-n' X c='' Xelse X cat <<'EOM' X...using \c XEOM X n='' X c='\c' Xfi Xecho $n "Type carriage return to continue. Your cursor should be here-->$c" Xread ans Xrm -f .echotmp X X: now set up to do reads with possible shell escape and default assignment Xcat <<EOSC >myread Xcase "\$fastread" in Xyes) ans=''; echo " " ;; X*) ans='!';; Xesac Xwhile expr "X\$ans" : "X!" >/dev/null; do X read ans X case "\$ans" in X !) X sh X echo " " X echo $n "\$rp $c" X ;; X !*) X set \`expr "X\$ans" : "X!\(.*\)\$"\` X sh -c "\$*" X echo " " X echo $n "\$rp $c" X ;; X esac Xdone Xrp='Your answer:' Xcase "\$ans" in X'') ans="\$dflt";; Xesac XEOSC X X: general instructions Xcat <<EOH X XThis installation shell script will examine your system and ask you questions Xto determine how the $package package should be installed. If you get stuck Xon a question, you may use a ! shell escape to start a subshell or execute Xa command. Many of the questions will have default answers in square Xbrackets--typing carriage return will give you the default. X XOn some of the questions which ask for file or directory names you are Xallowed to use the ~name construct to specify the login directory belonging Xto "name", even if you don't have a shell which knows about that. Questions Xwhere this is allowed will be marked "(~name ok)". X XEOH Xrp="[Type carriage return to continue]" Xecho $n "$rp $c" X. myread Xcat <<EOH X XMuch effort has been expended to ensure that this shell script will run Xon any Unix system. If despite that it blows up on you, your best bet is Xto edit Configure and run it again. Also, let me (paul at devon.lns.pa.us) Xknow how I blew it. If you can't run Configure for some reason, you'll have Xto generate a config.sh file by hand. X XThis installation script affects things in two ways: 1) it may do direct Xvariable substitutions on some of the files included in this kit, and X2) it builds a config.h file for inclusion in C programs. You may edit Xany of these files as the need arises after running this script. X XIf you make a mistake on a question, there is no easy way to back up to it Xcurrently. The easiest thing to do is to edit config.sh and rerun all the XSH files. Configure will offer to let you do this before it runs the SH files. X XEOH Xrp="[Type carriage return to continue]" Xecho $n "$rp $c" X. myread X X: get old answers, if there is a config file out there Xif test -f ../config.sh; then X echo " " X dflt=y X rp="I see a config.sh file. Did Configure make it on THIS system? [$dflt]" X echo $n "$rp $c" X . myread X case "$ans" in X n*) echo "OK, I'll ignore it.";; X *) echo "Fetching default answers from your old config.sh file..." X tmp="$n" X ans="$c" X . ../config.sh X n="$tmp" X c="$ans" X ;; X esac Xfi X X: see if sh knows # comments Xecho " " Xecho "Checking your sh to see if it knows about # comments..." Xif sh -c '#' >/dev/null 2>&1 ; then X echo "Your sh handles # comments correctly." X shsharp=true X spitshell=cat X echo " " X echo "Okay, let's see if #! works on this system..." X echo "#!/bin/echo hi" > try X $eunicefix try X chmod +x try X try > today X if $contains hi today >/dev/null 2>&1; then X echo "It does." X sharpbang='#!' X else X echo "#! /bin/echo hi" > try X $eunicefix try X chmod +x try X try > today X if test -s today; then X echo "It does." X sharpbang='#! ' X else X echo "It doesn't." X sharpbang=': use ' X fi X fi Xelse X echo "Your sh doesn't grok # comments--I will strip them later on." X shsharp=false X echo "exec grep -v '^#'" >spitshell X chmod +x spitshell X $eunicefix spitshell X spitshell=`pwd`/spitshell X echo "I presume that if # doesn't work, #! won't work either!" X sharpbang=': use ' Xfi X X: figure out how to guarantee sh startup Xecho " " Xecho "Checking out how to guarantee sh startup..." Xstartsh=$sharpbang'/bin/sh' Xecho "Let's see if '$startsh' works..." Xcat >try <<EOSS X$startsh Xset abc Xtest "$?abc" != 1 XEOSS X Xchmod +x try X$eunicefix try Xif try; then X echo "Yup, it does." Xelse X echo "Nope. You may have to fix up the shell scripts to make sure sh runs them." Xfi Xrm -f try today X X: find out where common programs are Xecho " " Xecho "Locating common programs..." Xcat <<EOSC >loc X$startsh Xcase \$# in X0) exit 1;; Xesac Xthing=\$1 Xshift Xdflt=\$1 Xshift Xfor dir in \$*; do X case "\$thing" in X .) X if test -d \$dir/\$thing; then X echo \$dir X exit 0 X fi X ;; X *) X if test -f \$dir/\$thing; then X echo \$dir/\$thing X exit 0 X elif test -f \$dir/\$thing.exe; then X : on Eunice apparently X echo \$dir/\$thing X exit 0 X fi X ;; X esac Xdone Xecho \$dflt Xexit 1 XEOSC Xchmod +x loc X$eunicefix loc Xloclist=" Xexpr Xsed Xsort Xuniq Xecho Xcat Xrm Xmv Xcp Xtr Xgrep Xcc Xcpp X" Xtrylist=" Xtest Xegrep XMcc Xsendmail Xmailx Xmail X" Xfor file in $loclist; do X xxx=`loc $file $file $pth` X eval $file=$xxx X eval _$file=$xxx X case "$xxx" in X /*) X echo $file is in $xxx. X ;; X *) X echo "I don't know where $file is. I hope it's in everyone's PATH." X ;; X esac Xdone Xecho " " Xecho "Don't worry if any of the following aren't found..." Xans=offhand Xfor file in $trylist; do X xxx=`loc $file $file $pth` X eval $file=$xxx X eval _$file=$xxx X case "$xxx" in X /*) X echo $file is in $xxx. X ;; X *) X echo "I don't see $file out there, $ans." X ans=either X ;; X esac Xdone Xcase "$egrep" in Xegrep) X echo "Substituting grep for egrep." X egrep=$grep X ;; Xesac Xcase "$test" in Xtest) X echo "Hopefully test is built into your sh." X ;; X/bin/test) X if sh -c "PATH= test true" >/dev/null 2>&1; then X echo "Using the test built into your sh." X test=test X fi X ;; X*) X test=test X ;; Xesac Xcase "$echo" in Xecho) X echo "Hopefully echo is built into your sh." X ;; X/bin/echo) X echo " " X echo "Checking compatibility between /bin/echo and builtin echo (if any)..." X $echo $n "hi there$c" >foo1 X echo $n "hi there$c" >foo2 X if cmp foo1 foo2 >/dev/null 2>&1; then X echo "They are compatible. In fact, they may be identical." X else X case "$n" in X '-n') n='' c='\c' ans='\c' ;; X *) n='-n' c='' ans='-n' ;; X esac X cat <<FOO XThey are not compatible! You are probably running ksh on a non-USG system. XI'll have to use /bin/echo instead of the builtin, since Bourne shell doesn't Xhave echo built in and we may have to run some Bourne shell scripts. That Xmeans I'll have to use $ans to suppress newlines now. Life is ridiculous. X XFOO X rp="Your cursor should be here-->" X $echo $n "$rp$c" X . myread X fi X $rm -f foo1 foo2 X ;; X*) X : cross your fingers X echo=echo X ;; Xesac Xrmlist="$rmlist loc" X X: get list of predefined functions in a handy place Xecho " " Xif test -f /lib/libc.a; then X echo "Your C library is in /lib/libc.a. You're normal." X libc=/lib/libc.a Xelse X ans=`loc libc.a blurfl/dyick $libpth` X if test ! -f $ans; then X ans=`loc clib blurfl/dyick $libpth` X fi X if test ! -f $ans; then X ans=`loc libc blurfl/dyick $libpth` X fi X if test -f $ans; then X echo "Your C library is in $ans, of all places." X libc=$ans X else X if test -f "$libc"; then X echo "Your C library is in $libc, like you said before." X else X cat <<EOM X XI can't seem to find your C library. I've looked in the following places: X X $libpth X XNone of these seems to contain your C library. What is the full name XEOM X dflt=None X $echo $n "of your C library? $c" X rp='C library full name?' X . myread X libc="$ans" X fi X fi Xfi Xecho " " X$echo $n "Extracting names from $libc for later perusal...$c" Xnm $libc 2>/dev/null >libc.tmp Xsed -n -e 's/^.* [AT] _//p' -e 's/^.* [AT] //p' <libc.tmp >libc.list Xif $contains '^printf$' libc.list >/dev/null 2>&1; then X echo "done" Xelse X sed -n -e 's/^.* D _//p' -e 's/^.* D //p' <libc.tmp >libc.list X $contains '^printf$' libc.list >/dev/null 2>&1 || \ X sed -n -e 's/^_//' \ X -e 's/^\([a-zA-Z_0-9]*\).*xtern.*text.*/\1/p' <libc.tmp >libc.list X if $contains '^printf$' libc.list >/dev/null 2>&1; then X echo "done" X else X echo " " X echo "nm didn't seem to work right." X echo "Trying ar instead..." X if ar t $libc > libc.tmp; then X sed -e 's/\.o$//' < libc.tmp > libc.list X echo "Ok." X else X echo "ar didn't seem to work right." X echo "Maybe this is a Cray...trying bld instead..." X if bld t $libc | sed -e 's/.*\///' -e 's/\.o:.*$//' > libc.list; then X echo "Ok." X else X echo "That didn't work either. Giving up." X exit 1 X fi X fi X fi Xfi Xrmlist="$rmlist libc.tmp libc.list" X X: make some quick guesses about what we are up against Xecho " " X$echo $n "Hmm... $c" Xif $contains SIGTSTP /usr/include/signal.h >/dev/null 2>&1 ; then X echo "Looks kind of like a BSD system, but we'll see..." X echo exit 0 >bsd X echo exit 1 >usg X echo exit 1 >v7 Xelif $contains '^fcntl$' libc.list >/dev/null 2>&1 ; then X echo "Looks kind of like a USG system, but we'll see..." X echo exit 1 >bsd X echo exit 0 >usg X echo exit 1 >v7 Xelse X echo "Looks kind of like a version 7 system, but we'll see..." X echo exit 1 >bsd X echo exit 1 >usg X echo exit 0 >v7 Xfi Xif $contains '^vmssystem$' libc.list >/dev/null 2>&1 ; then X cat <<'EOI' XThere is, however, a strange, musty smell in the air that reminds me of Xsomething...hmm...yes...I've got it...there's a VMS nearby, or I'm a Blit. XEOI X echo "exit 0" >eunice X eunicefix=unixtovms X d_eunice="$define" X: it so happens the Eunice I know will not run shell scripts in Unix format Xelse X echo " " X echo "Congratulations. You aren't running Eunice." X eunicefix=':' X d_eunice="$undef" X echo "exit 1" >eunice Xfi Xif test -f /xenix; then X echo "Actually, this looks more like a XENIX system..." X echo "exit 0" >xenix X xenix="$define" Xelse X echo " " X echo "It's not Xenix..." X echo "exit 1" >xenix X xenix="$undef" Xfi Xchmod +x xenix X$eunicefix xenix Xif test -f /venix; then X echo "Actually, this looks more like a VENIX system..." X echo "exit 0" >venix Xelse X echo " " X if xenix; then X : null X else X echo "Nor is it Venix..." X fi X echo "exit 1" >venix Xfi Xchmod +x bsd usg v7 eunice venix X$eunicefix bsd usg v7 eunice venix Xrmlist="$rmlist bsd usg v7 eunice venix xenix" X X: Warnings Xif v7; then X cat <<'EOM' X XNOTE: many V7 systems do not have a way to do a non-blocking read. If you Xdon't have any of FIONREAD, O_NDELAY, or rdchk(), the $package package Xmay not work as well as it might. It might not work at all. XEOM Xfi X X: preserve RCS keywords in files with variable substitution, grrr XLog='$Log' XId='$Id' X X: set up shell script to do ~ expansion Xcat >filexp <<EOSS X$startsh X: expand filename Xcase "\$1" in X ~/*|~) X echo \$1 | $sed "s|~|\${HOME-\$LOGDIR}|" X ;; X ~*) X if $test -f /bin/csh; then X /bin/csh -f -c "glob \$1" X echo "" X else X name=\`$expr x\$1 : '..\([^/]*\)'\` X dir=\`$sed -n -e "/^\${name}:/{s/^[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:\([^:]*\).*"'\$'"/\1/" -e p -e q -e '}' </etc/passwd\` X if $test ! -d "\$dir"; then X me=\`basename \$0\` X echo "\$me: can't locate home directory for: \$name" >&2 X exit 1 X fi X case "\$1" in X */*) X echo \$dir/\`$expr x\$1 : '..[^/]*/\(.*\)'\` X ;; X *) X echo \$dir X ;; X esac X fi X ;; X*) X echo \$1 X ;; Xesac XEOSS Xchmod +x filexp X$eunicefix filexp X X: now get the host name Xecho "Figuring out host name..." Xecho 'Maybe "hostname" will work...' Xif ans=`sh -c hostname 2>&1` ; then X hostname=$ans X phostname=hostname Xelse X echo 'Oh, dear. Maybe "/etc/systemid" is the key...' X if ans=`cat /etc/systemid 2>&1` ; then X hostname=$ans X phostname='cat /etc/systemid' X if xenix; then X echo "Whadyaknow. Xenix always was a bit strange..." X else X echo "What is a non-Xenix system doing with /etc/systemid?" X fi X else X echo 'No, maybe "uuname -l" will work...' X if ans=`sh -c 'uuname -l' 2>&1` ; then X hostname=$ans X phostname='uuname -l' X else X echo 'Strange. Maybe "uname -n" will work...' X if ans=`sh -c 'uname -n' 2>&1` ; then X hostname=$ans X phostname='uname -n' X else X echo 'Oh well, maybe I can mine it out of whoami.h...' X if ans=`sh -c $contains' sysname /usr/include/whoami.h' 2>&1` ; then X hostname=`echo "$ans" | $sed 's/^.*"\(.*\)"/\1/'` X phostname="sed -n -e '"'/sysname/s/^.*\"\\(.*\\)\"/\1/{'"' -e p -e q -e '}' </usr/include/whoami.h" X else X case "$hostname" in X '') echo "Does this machine have an identity crisis or something?" X phostname='' X ;; X *) echo "Well, you said $hostname before...";; X esac X fi X fi X fi X fi Xfi X: you do not want to know about this Xset $hostname Xhostname=$1 X X: translate upper to lower if necessary Xcase "$hostname" in X *[A-Z]*) X hostname=`echo $hostname | $tr '[A-Z]' '[a-z]'` X echo "(Normalizing case in your host name)" X ;; Xesac X X: verify guess Xif $test "$hostname" ; then X dflt=y X echo 'Your host name appears to be "'$hostname'".' X $echo $n "Is this correct? [$dflt] $c" X rp="Sitename is $hostname? [$dflt]" X . myread X case "$ans" in X y*) ;; X *) hostname='' ;; X esac Xfi X X: bad guess or no guess Xwhile $test "X$hostname" = X ; do X dflt='' X rp="Please type the (one word) name of your host:" X $echo $n "$rp $c" X . myread X hostname="$ans" Xdone X X: a little sanity check here Xcase "$phostname" in X'') ;; X*) case `$phostname` in X $hostname) ;; X *) X case "$phostname" in X sed*) X echo "(That doesn't agree with your whoami.h file, by the way.)" X ;; X *) X echo "(That doesn't agree with your $phostname command, by the way.)" X ;; X esac X phostname='' X ;; X esac X ;; Xesac X X: see if there is the getut family Xecho " " Xif $contains '^getut' libc.list >/dev/null 2>&1 ; then X echo "getutent() found." X d_getutent="$define" Xelse X echo "No getutent() found--will use my own." X d_getutent="$undef" Xfi X X: see if there is a strdup Xif $contains '^strdup$' libc.list >/dev/null 2>&1 ; then X echo "strdup() found." X d_strdup="$define" Xelse X echo "No strdup() found--will use my own." X d_strdup="$undef" Xfi X X: see if there is a putenv Xif $contains '^putenv$' libc.list >/dev/null 2>&1 ; then X echo "putenv() found." X d_putenv="$define" Xelse X echo "No putenv() found--will use my own." X d_putenv="$undef" Xfi X X: see how we will look up host name Xd_douname="$undef" Xd_phostname="$undef" X X# if xenix; then X# echo " " X# echo "(Assuming Xenix uname() is broken.)" X# el Xif $contains '^uname$' libc.list >/dev/null 2>&1 ; then X echo "uname() found." X d_douname="$define" X ans=uname Xfi X Xcase "$d_douname" in X*define*) X dflt=n X cat <<EOM X XEvery now and then someone has a $ans() that lies about the hostname Xbut can't be fixed for political or economic reasons. Would you like to XEOM X rp="pretend $ans() isn't there and maybe compile in the hostname? [$dflt]" X $echo $n "$rp $c" X . myread X case "$ans" in X y*) d_douname="$undef" X $echo $n "Okay... $c" X ;; X esac X ;; Xesac X Xcase "$d_douname" in X*define*) ;; X*) X case "$phostname" in X '') ;; X *) X $cat <<EOT X XThere is no uname() on this system. You have two possibilities at this point: X X1) You can have your host name ($hostname) compiled into $package, which X lets $package start up faster, but makes your binaries non-portable, or X2) you can have $package use a X X popen("$phostname","r") X X which will start slower but be more portable. X XOption 1 will give you the option of using whoami.h if you have one. If you Xwant option 2 but with a different command, you can edit config.sh at the Xend of this shell script. X XEOT X case "$d_phostname" in X "$define") dflt=n;; X "$undef") dflt=y;; X '') X case "$d_portable" in X "$define") dflt=n ;; X *) dflt=y ;; X esac X ;; X esac X rp="Do you want your host name compiled in? [$dflt]" X $echo $n "$rp $c" X . myread X case "$ans" in X n*) d_phostname="$define" ;; X *) phostname='' X d_phostname="$undef" X ;; X esac X ;; X esac X case "$phostname" in X '') X case "$d_whoami" in X "$define") X dflt=y X $cat <<EOM X XNo hostname function--you can either use the whoami.h file, which has this line: X X `grep sysname /usr/include/whoami.h` X Xor you can have the name we came up with earlier ($hostname) hardwired in. XEOM X rp="Use whoami.h to get hostname? [$dflt]" X $echo $n "$rp $c" X . myread X case "$ans" in X n*) d_whoami="$undef";; X esac X ;; X "$undef") X echo 'No hostname function and no whoami.h--hardwiring "'$hostname'".' X ;; X esac X ;; X esac X ;; Xesac X X: where do we get termlib routines from Xecho " " Xans=`loc libcurses.a x $libpth` Xcase "$ans" in X/*) X ar t $ans >grimble X if $contains tputs.o grimble >/dev/null 2>&1; then X termlib='-lcurses' X echo "Terminfo library found." X else X ans=x X fi X rm -f grimble X ;; Xesac Xcase "$ans" in Xx) X ans=`loc libtermlib.a x $libpth` X case "$ans" in X /usr/lib*|/lib*) X termlib='-ltermlib' X echo "Termlib library found." X ;; X /*) X termlib="$ans" X echo "Termlib library found." X ;; X *) X ans=`loc libtermcap.a x $libpth` X case "$ans" in X /usr/lib*|/lib*) X termlib='-ltermcap' X echo "Termcap library found." X ;; X /*) X termlib="$ans" X echo "Termcap library found." X ;; X *) X case "$termlib" in X '') X dflt=y X rp="Your system appears to NOT have termlib-style routines. Is this true? [$dflt]" X $echo $n "$rp $c" X . myread X case "$ans" in X n*|f*) X echo "Then where are the termlib-style routines kept (specify either -llibname" X $echo $n " or full pathname (~name ok))? $c" X rp='Specify termlib:' X . myread X termlib=`filexp $ans` X ;; X *) termlib='' X echo "You will have to play around with main.c then." X ;; X esac X echo " " X ;; X *) echo "You said termlib was $termlib before." X ;; X esac X ;; X esac X ;; X esac X ;; Xesac Xans=`loc llib${termlib}.ln x $libpth` Xcase "$ans" in X/usr/lib*|/lib*) X llib_termlib='-ltermlib' X echo "Termlib lint library found." X ;; Xesac X X: see if there is a ttytype file Xecho " " Xif ttytype=`loc ttytype x /etc`; then X echo "Found $ttytype." X d_ttytype="$define" Xelse X d_ttytype="$undef" Xfi X X: see if there is a gettydefs file Xif gettytab=`loc gettydefs x /etc`; then X echo "Found $gettytab." Xelse X dflt=/etc/gettydefs X echo " " X $echo "No /etc/gettydefs found. I'll let you create your own." X $echo $n "What do you want to call your gettytab file? [$dflt] $c" X rp='Specify gettytab:' X . myread X gettytab=$ans X echo " " Xfi X X: find the utmp file Xif utmp=`loc utmp utmp /etc /usr/adm`; then X echo "Found $utmp." Xelse X dflt=/etc/utmp X echo " " X $echo $n "Where is your utmp file? [$dflt] $c" X rp="Utmp filename? [$dflt]" X . myread X utmp="$ans" X echo " " Xfi X X: find the wtmp file Xif wtmp=`loc wtmp wtmp /etc /usr/adm`; then X echo "Found $wtmp." Xelse X dflt=/etc/wtmp X echo " " X $echo $n "Where is your wtmp file? [$dflt] $c" X rp="Wtmp filename? [$dflt]" X . myread X wtmp="$ans" X echo " " Xfi X X: decide how portable to be Xcase "$d_portable" in X"$define") dflt=y;; X*) dflt=n;; Xesac X$cat <<EOH X XI can set things up so that your $package binaries are more portable, Xat what may be a noticable cost in performance. In particular, if you Xask to be portable, the system name will be determined at run time, Xif at all possible. X XEOH Xrp="Do you expect to run the $package binaries on multiple machines? [$dflt]" X$echo $n "$rp $c" X. myread Xcase "$ans" in X y*) d_portable="$define" ;; X *) d_portable="$undef" ;; Xesac X X: determine where public executables go Xcase "$bin" in X'') X dflt=`loc . /bin /etc /usr/local/bin /usr/lbin /usr/local /usr/bin` X ;; X*) dflt="$bin" X ;; Xesac Xcont=true Xwhile $test "$cont" ; do X echo " " X rp="Where do you want to put the $package executables? [$dflt]" X $echo $n "$rp $c" X . myread X bin="$ans" X bin=`filexp $bin` X if test -d $bin; then X cont='' X else X dflt=n X rp="Directory $bin doesn't exist. Use that name anyway? [$dflt]" X $echo $n "$rp $c" X . myread X dflt='' X case "$ans" in X y*) cont='';; X esac X fi Xdone X X: see what type of char stdio uses. Xecho " " Xif $contains 'unsigned.*char.*_ptr;' /usr/include/stdio.h >/dev/null 2>&1 ; then X echo "Your stdio uses unsigned chars." X stdchar="unsigned char" Xelse X echo "Your stdio uses signed chars." X stdchar="char" Xfi X X: check for void type Xecho " " X$cat <<EOM XChecking to see how well your C compiler groks the void type... X X Support flag bits are: X 1: basic void declarations. X 2: arrays of pointers to functions returning void. X 4: operations between pointers to and addresses of void functions. X XEOM Xcase "$voidflags" in X'') X $cat >try.c <<'EOCP' X#if TRY & 1 Xvoid main() { X#else Xmain() { X#endif X extern void moo(); /* function returning void */ X void (*goo)(); /* ptr to func returning void */ X#if TRY & 2 X void (*foo[10])(); X#endif X X#if TRY & 4 X if(goo == moo) { X exit(0); X } X#endif X exit(0); X} XEOCP X if $cc -S -DTRY=$defvoidused try.c >.out 2>&1 ; then X voidflags=$defvoidused X echo "It appears to support void." X if $contains warning .out >/dev/null 2>&1; then X echo "However, you might get some warnings that look like this:" X $cat .out X fi X else X echo "Hmm, your compiler has some difficulty with void. Checking further..." X if $cc -S -DTRY=1 try.c >/dev/null 2>&1 ; then X echo "It supports 1..." X if $cc -S -DTRY=3 try.c >/dev/null 2>&1 ; then X voidflags=3 X echo "And it supports 2 but not 4." X else X echo "It doesn't support 2..." X if $cc -S -DTRY=5 try.c >/dev/null 2>&1 ; then X voidflags=5 X echo "But it supports 4." X else X voidflags=1 X echo "And it doesn't support 4." X fi X fi X else X echo "There is no support at all for void." X voidflags=0 X fi X fi Xesac Xdflt="$voidflags"; Xrp="Your void support flags add up to what? [$dflt]" X$echo $n "$rp $c" X. myread Xvoidflags="$ans" X$rm -f try.* .out X X: see if signal is declared as pointer to function returning int or void Xecho " " Xif $contains 'void.*signal' /usr/include/signal.h >/dev/null 2>&1 ; then X echo "You have void (*signal())() instead of int." X d_voidsig="$define" Xelse X echo "You have int (*signal())() instead of void." X d_voidsig="$undef" Xfi X X: see how we invoke the C preprocessor Xecho " " Xecho "Now, how can we feed standard input to your C preprocessor..." Xcat <<'EOT' >testcpp.c X#define ABC abc X#define XYZ xyz XABC.XYZ XEOT Xecho 'Maybe "'"$cc"' -E" will work...' X$cc -E <testcpp.c >testcpp.out 2>&1 Xif $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then X echo "Yup, it does." X cppstdin="$cc -E" X cppminus=''; Xelse X echo 'Nope, maybe "'$cpp'" will work...' X $cpp <testcpp.c >testcpp.out 2>&1 X if $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then X echo "Yup, it does." X cppstdin="$cpp" X cppminus=''; X else X echo 'No such luck...maybe "'$cpp' -" will work...' X $cpp - <testcpp.c >testcpp.out 2>&1 X if $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then X echo "It works!" X cppstdin="$cpp" X cppminus='-'; X else X echo 'Nixed again...maybe "'"$cc"' -E -" will work...' X $cc -E - <testcpp.c >testcpp.out 2>&1 X if $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then X echo "Hooray, it works! I was beginning to wonder." X cppstdin="$cc -E" X cppminus='-'; X else X echo 'Nope...maybe "'"$cc"' -P" will work...' X $cc -P <testcpp.c >testcpp.out 2>&1 X if $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then X echo "Yup, that does." X cppstdin="$cc -P" X cppminus=''; X else X echo 'Nope...maybe "'"$cc"' -P -" will work...' X $cc -P - <testcpp.c >testcpp.out 2>&1 X if $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then X echo "Yup, that does." X cppstdin="$cc -P" X cppminus='-'; X else X echo 'Hmm...perhaps you already told me...' X case "$cppstdin" in X '') ;; X *) $cppstdin $cppminus <testcpp.c >testcpp.out 2>&1;; X esac X if $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then X echo "Hooray, you did! I was beginning to wonder." X else X echo 'Uh-uh. Time to get fancy...' X cd .. X echo 'Trying (cat >/tmp/$$.c; '"$cc"' -E /tmp/$$.c; rm /tmp/$$.c)' X echo 'cat >/tmp/$$.c; '"$cc"' -E /tmp/$$.c; rm /tmp/$$.c' >cppstdin X chmod 755 cppstdin X cppstdin=`pwd`/cppstdin X cppminus=''; X cd UU X $cppstdin <testcpp.c >testcpp.out 2>&1 X if $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then X echo "Eureka!." X else X dflt=blurfl X $echo $n "No dice. I can't find a C preprocessor. Name one: $c" X rp='Name a C preprocessor:' X . myread X cppstdin="$ans" X $cppstdin <testcpp.c >testcpp.out 2>&1 X if $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then X echo "OK, that will do." X else X echo "Sorry, I can't get that to work. Go find one." X exit 1 X fi X fi X fi X fi X fi X fi X fi X fi Xfi Xrm -f testcpp.c testcpp.out X X: get C preprocessor symbols handy Xecho " " Xecho $attrlist | $tr '[ - ]' '[\012-\012]' >Cppsym.know X$cat <<EOSS >Cppsym X$startsh Xcase "\$1" in X-l) list=true X shift X ;; Xesac Xunknown='' Xcase "\$list\$#" in X1|2) X for sym do X if $contains "^\$1$" Cppsym.true >/dev/null 2>&1; then X exit 0 X elif $contains "^\$1$" Cppsym.know >/dev/null 2>&1; then X : X else X unknown="\$unknown \$sym" X fi X done X set X \$unknown X shift X ;; Xesac Xcase \$# in X0) exit 1;; Xesac Xecho \$* | $tr '[ - ]' '[\012-\012]' | $sed -e 's/\(.*\)/\\ X#ifdef \1\\ Xexit 0; _ _ _ _\1\\ \1\\ X#endif\\ X/' >/tmp/Cppsym\$\$ Xecho exit 1 >>/tmp/Cppsym\$\$ X$cppstdin $cppminus </tmp/Cppsym\$\$ >/tmp/Cppsym2\$\$ Xcase "\$list" in Xtrue) awk 'NF > 5 {print substr(\$6,2,100)}' </tmp/Cppsym2\$\$ ;; X*) X sh /tmp/Cppsym2\$\$ X status=\$? X ;; Xesac X$rm -f /tmp/Cppsym\$\$ /tmp/Cppsym2\$\$ Xexit \$status XEOSS Xchmod +x Cppsym X$eunicefix Cppsym Xecho "Your C preprocessor defines the following symbols:" XCppsym -l $attrlist >Cppsym.true Xcat Cppsym.true Xrmlist="$rmlist Cppsym Cppsym.know Cppsym.true" X X: see what memory models we can support Xif Cppsym M_I8086 M_I186 M_I286; then X models='small medium large huge' Xfi Xcase "$models" in X'') X : We may not use Cppsym or we get a circular dependency through cc. X : But this should work regardless of which cc we eventually use. X cat >pdp11.c <<'EOP' Xmain() { X#ifdef pdp11 X exit(0); X#else X exit(1); X#endif X} XEOP X cc -o pdp11 pdp11.c >/dev/null 2>&1 X if pdp11 2>/dev/null; then X dflt='unsplit split' X else X ans=`loc . X /lib/small /lib/large /usr/lib/small /usr/lib/large /lib/medium /usr/lib/medium /lib/huge` X case "$ans" in X X) dflt='none';; X *) if $test -d /lib/small || $test -d /usr/lib/small; then X dflt='small' X else X dflt='' X fi X if $test -d /lib/medium || $test -d /usr/lib/medium; then X dflt="$dflt medium" X fi X if $test -d /lib/large || $test -d /usr/lib/large; then X dflt="$dflt large" X fi X if $test -d /lib/huge || $test -d /usr/lib/huge; then X dflt="$dflt huge" X fi X esac X fi X ;; X*) dflt="$models" ;; Xesac X$cat <<EOM X XSome systems have different model sizes. On most systems they are called Xsmall, medium, large, and huge. On the PDP11 they are called unsplit and Xsplit. If your system doesn't support different memory models, say "none". XIf you wish to force everything to one memory model, say "none" here and Xput the appropriate flags later when it asks you for other cc and ld flags. XVenix systems may wish to put "none" and let the compiler figure things out. X(In the following question multiple model names should be space separated.) X XEOM Xrp="Which models are supported? [$dflt]" X$echo $n "$rp $c" X. myread Xmodels="$ans" X Xcase "$models" in Xnone) X small='' X medium='' X large='' X huge='' X unsplit='' X split='' X ;; X*split) X case "$split" in X '') dflt='none' ;; X *) dflt="$split";; X esac X rp="What flag indicates separate I and D space? [$dflt]" X $echo $n "$rp $c" X . myread X case "$ans" in X none) ans='';; X esac X split="$ans" X unsplit='' X ;; X*large*|*small*|*medium*|*huge*) X case "$model" in X *large*) X case "$large" in X '') dflt='-Ml';; X *) dflt="$large";; X esac X rp="What flag indicates large model? [$dflt]" X $echo $n "$rp $c" X . myread X case "$ans" in X none) ans=''; X esac X large="$ans" X ;; X *) large='';; X esac X case "$model" in X *huge*) X case "$huge" in X '') dflt='-Mh';; X *) dflt="$huge";; X esac X rp="What flag indicates huge model? [$dflt]" X $echo $n "$rp $c" X . myread X case "$ans" in X none) ans=''; X esac X huge="$ans" X ;; X *) huge="$large";; X esac X case "$model" in X *medium*) X case "$medium" in X '') dflt='-Mm';; X *) dflt="$medium";; X esac X rp="What flag indicates medium model? [$dflt]" X $echo $n "$rp $c" X . myread X case "$ans" in X none) ans=''; X esac X medium="$ans" X ;; X *) medium="$large";; X esac X case "$model" in X *small*) X case "$small" in X '') dflt='none';; X *) dflt="$small";; X esac X rp="What flag indicates small model? [$dflt]" X $echo $n "$rp $c" X . myread X case "$ans" in X none) ans=''; X esac X small="$ans" X ;; X *) small='';; X esac X ;; X*) X echo "Unrecognized memory models--you may have to edit Makefile.SH" X ;; Xesac X X: see if we need a special compiler Xif usg; then X case "$cc" in X '') X case "$Mcc" in X /*) dflt='Mcc' X ;; X *) X case "$large" in X -M*) X dflt='cc' X ;; X *) dflt='cc' X ;; X esac X ;; X esac X ;; X *) dflt="$cc";; X esac X $cat <<'EOM' X XOn some systems the default C compiler will not resolve multiple global Xreferences that happen to have the same name. On some such systems the X"Mcc" command may be used to force these to be resolved. On other systems Xa "cc -M" command is required. (Note that the -M flag on other systems Xindicates a memory model to use!) If you have the Gnu C compiler, you Xmight wish to use that instead. What command will force resolution on XEOM X $echo $n "this system? [$dflt] $c" X rp="Command to resolve multiple refs? [$dflt]" X . myread X cc="$ans" Xelse X case "$cc" in X '') dflt=cc;; X *) dflt="$cc";; X esac X rp="Use which C compiler? [$dflt]" X $echo $n "$rp $c" X . myread X cc="$ans" Xfi Xcase "$cc" in Xgcc*) cpp=`loc gcc-cpp $cpp $pth`;; Xesac X Xcase "$ccflags" in X'') dflt='none';; X*) dflt="$ccflags";; Xesac Xecho " " Xrp="Any additional cc flags? [$dflt]" X$echo $n "$rp $c" X. myread Xcase "$ans" in Xnone) ans=''; Xesac Xccflags="$ans" X Xcase "$ldflags" in X'') if venix; then X dflt='-i -z' X else X dflt='-i' X fi X ;; X*) dflt="$ldflags";; Xesac Xecho " " Xrp="Any additional ld flags? [$dflt]" X$echo $n "$rp $c" X. myread Xcase "$ans" in Xnone) ans=''; Xesac Xldflags="$ans" Xrmlist="$rmlist pdp11" X X: see how many register declarations we want to use Xcase "$registers" in X'') X if Cppsym vax; then X dflt=6 X elif Cppsym sun mc68000; then X dflt=10 X elif Cppsym pyr; then X dflt=14 X elif Cppsym ns32000 ns16000; then X dflt=5 X elif Cppsym $smallmach; then X dflt=3 X else X : if you have any other numbers for me, send them in X dflt=6 X fi X ;; X*) dflt=$registers ;; Xesac Xcat <<EOM X XDifferent C compilers on different machines pay attention to different Xnumbers of register declarations. About how many register declarations in XEOM X$echo $n "each routine does your C compiler pay attention to? (OK to guess) [$dflt] $c" Xrp="# register declarations used? [$dflt]" X. myread Xregisters=$ans Xreg1='' Xawk "BEGIN { for (i=1; i<=16; i++) printf \"reg%d=''\n\", i}" </dev/null >.foo X. .foo Xawk "BEGIN { for (i=1; i<=$registers; i++) printf \"reg%d=register\n\", i}" \ X </dev/null >.foo X. .foo Xrm -f .foo X X: see what type uids are declared as in the kernel Xcase "$uidtype" in X'') X if $contains 'uid_t;' /usr/include/sys/types.h >/dev/null 2>&1 ; then X dflt='uid_t'; X else X set `grep '_ruid;' /usr/include/sys/user.h 2>/dev/null` unsigned short X case $1 in X unsigned) dflt="$1 $2" ;; X *) dflt="$1" ;; X esac X fi X ;; X*) dflt="$uidtype" X ;; Xesac Xcont=true Xecho " " Xrp="What type are user ids on this system declared as? [$dflt]" X$echo $n "$rp $c" X. myread Xuidtype="$ans" X X: see what type gids are declared as in the kernel Xcase "$gidtype" in X'') X if $contains 'gid_t;' /usr/include/sys/types.h >/dev/null 2>&1 ; then X dflt='gid_t'; X else X set `grep '_rgid;' /usr/include/sys/user.h 2>/dev/null` unsigned short X case $1 in X unsigned) dflt="$1 $2" ;; X *) dflt="$1" ;; X esac X fi X ;; X*) dflt="$gidtype" X ;; Xesac Xcont=true Xecho " " Xrp="What type are group ids on this system declared as? [$dflt]" X$echo $n "$rp $c" X. myread Xgidtype="$ans" X X: determine uucp id Xecho " " Xuucpid=`$sed -e "/uucp:/{s/^[^:]*:[^:]*:\([^:]*\).*"'$'"/\1/" -e "q" -e "}" -e "d" </etc/passwd` Xcase "$uucpid" in X '') uucpid=0 ;; X *) echo "uucp uid = $uucpid" ;; Xesac X X: determine uucp lock files scheme Xcase "$lock" in X'') X if $test -d /usr/spool/locks; then X dflt=/usr/spool/locks X else X dflt=/usr/spool/uucp X fi X ;; X*) dflt="$lock";; Xesac Xcont=true Xwhile $test "$cont" ; do X echo " " X $echo $n "Directory where UUCP lock files live: [$dflt] $c" X rp="Directory for UUCP lock files: [$dflt]" X . myread X lock="$ans" X if test -d $ans; then X cont='' X else X dflt=n X rp="Directory $ans doesn't exist. Use that name anyway? [$dflt]" X $echo $n "$rp $c" X . myread X dflt='' X case "$ans" in X y*) cont='';; X esac X fi Xdone X Xecho " " Xcase "$d_asciipid" in X"$define") dflt=y;; X*) dflt=n;; Xesac Xecho "The PID of the locking process is kept in the lock file." X$echo $n "Does your UUCP store the PID in ASCII format? [$dflt] $c" Xrp="PID stored in ASCII? [$dflt]" X. myread Xcase "$ans" in Xy*) d_asciipid="$define";; X*) d_asciipid="$undef";; Xesac X X: determine mailer to use Xcase "$mailer" in X'') X if $test -f $sendmail; then X dflt=$sendmail X elif Cppsym M_XENIX; then X dflt=/usr/lib/mail/execmail X elif $test -f $mailx; then X dflt="$mailx" X else X dflt=$mail X fi X ;; X*) dflt="$mailer";; Xesac Xcont=true Xwhile $test "$cont" ; do X echo " " X echo "Give the full path name of the program used to deliver mail on your" X $echo $n "system: [$dflt] $c" X rp="Preferred mailer: [$dflt]" X . myread X mailer="$ans" X if test -f $ans; then X cont='' X else X dflt=n X rp="Directory $ans doesn't exist. Use that name anyway? [$dflt]" X $echo $n "$rp $c" X . myread X dflt='' X case "$ans" in X y*) cont='';; X esac X fi Xdone X Xecho " " Xecho "End of configuration questions." Xecho " " X X: create config.sh file Xecho " " Xif test -d ../UU; then X cd .. Xfi Xecho "Creating config.sh..." X$spitshell <<EOT >config.sh X$startsh X# config.sh X# This file was produced by running the Configure script. X Xpackage='$package' Xdefine='$define' Xundef='$undef' Xd_eunice='$d_eunice' Xeunicefix='$eunicefix' Xcontains='$contains' Xn='$n' Xc='$c' Xspitshell='$spitshell' Xshsharp='$shsharp' Xsharpbang='$sharpbang' Xstartsh='$startsh' Xloclist='$loclist' Xexpr='$expr' Xsed='$sed' Xsort='$sort' Xuniq='$uniq' Xecho='$echo' Xcat='$cat' Xrm='$rm' Xmv='$mv' Xcp='$cp' Xtr='$tr' Xgrep='$grep' Xcc='$cc' Xcpp='$cpp' Xtrylist='$trylist' Xtest='$test' Xegrep='$egrep' XMcc='$Mcc' Xsendmail='$sendmail' Xmailx='$mailx' Xmail='$mail' Xlibc='$libc' XLog='$Log' XId='$Id' Xxenix='$xenix' Xd_getutent='$d_getutent' Xd_strdup='$d_strdup' Xd_putenv='$d_putenv' Xtermlib='$termlib' Xllib_termlib='$llib_termlib' Xd_ttytype='$d_ttytype' Xttytype='$ttytype' Xgettytab='$gettytab' Xutmp='$utmp' Xwtmp='$wtmp' Xhostname='$hostname' Xphostname='$phostname' Xd_douname='$d_douname' Xd_phostname='$d_phostname' Xd_portable='$d_portable' Xbin='$bin' Xstdchar='$stdchar' Xdefvoidused='$defvoidused' Xvoidflags='$voidflags' Xd_voidsig='$d_voidsig' Xmodels='$models' Xsmall='$small' Xmedium='$medium' Xlarge='$large' Xhuge='$huge' Xunsplit='$unsplit' Xsplit='$split' Xccflags='$ccflags' Xldflags='$ldflags' Xcppstdin='$cppstdin' Xcppminus='$cppminus' Xregisters='$registers' Xreg1='$reg1' Xreg2='$reg2' Xreg3='$reg3' Xreg4='$reg4' Xreg5='$reg5' Xreg6='$reg6' Xreg7='$reg7' Xreg8='$reg8' Xreg9='$reg9' Xreg10='$reg10' Xreg11='$reg11' Xreg12='$reg12' Xreg13='$reg13' Xreg14='$reg14' Xreg15='$reg15' Xreg16='$reg16' Xuidtype='$uidtype' Xgidtype='$gidtype' Xuucpid='$uucpid' Xlock='$lock' Xd_asciipid='$d_asciipid' Xmailer='$mailer' XCONFIG=true XEOT X XCONFIG=true X Xecho " " Xdflt='' Xfastread='' Xecho "If you didn't make any mistakes, then just type a carriage return here." Xrp="If you need to edit config.sh, do it as a shell escape here:" X$echo $n "$rp $c" X. UU/myread Xcase "$ans" in X'') ;; X*) : in case they cannot read X eval $ans;; Xesac X. ./config.sh X Xecho " " Xecho "Doing variable substitutions on .SH files..." Xset x `awk '{print $1}' <MANIFEST | $grep '\.SH'` Xshift Xcase $# in X0) set x *.SH; shift;; Xesac Xif test ! -f $1; then X shift Xfi Xfor file in $*; do X case "$file" in X */*) X dir=`$expr X$file : 'X\(.*\)/'` X file=`$expr X$file : 'X.*/\(.*\)'` X (cd $dir && . $file) X ;; X *) X . $file X ;; X esac Xdone Xif test -f config.h.SH; then X if test ! -f config.h; then X : oops, they left it out of MANIFEST, probably, so do it anyway. X . config.h.SH X fi Xfi X Xif $contains '^depend:' Makefile >/dev/null 2>&1; then X dflt=n X $cat <<EOM X XNow you need to generate make dependencies by running "make depend". XYou might prefer to run it in background: "make depend > makedep.out &" XIt can take a while, so you might not want to run it right now. X XEOM X rp="Run make depend now? [$dflt]" X $echo $n "$rp $c" X . UU/myread X case "$ans" in X y*) make depend X echo "Now you must run a make." X ;; X *) echo "You must run 'make depend' then 'make'." X ;; X esac Xelif test -f Makefile; then X echo " " X echo "Now you must run a make." Xelse X echo "Done." Xfi X X$rm -f kit*isdone X: the following is currently useless Xcd UU && $rm -f $rmlist X: since this removes it all anyway Xcd .. && $rm -rf UU X: end of Configure !STUFFY!FUNK! echo Extracting makedep.SH sed >makedep.SH <<'!STUFFY!FUNK!' -e 's/X//' X: X# $Id: makedep.SH,v 1.1 90/01/16 16:16:45 paul Exp Locker: paul $ X# X# $Log: makedep.SH,v $ X# Revision 1.1 90/01/16 16:16:45 paul X# Initial revision X# X# X Xcase $CONFIG in X'') X if test ! -f config.sh; then X ln ../config.sh . || \ X ln ../../config.sh . || \ X ln ../../../config.sh . || \ X (echo "Can't find config.sh."; exit 1) X fi X . ./config.sh X ;; Xesac Xcase "$0" in X*/*) cd `expr X$0 : 'X\(.*\)/'` ;; Xesac Xecho "Extracting makedep (with variable substitutions)" X$spitshell >makedep <<!GROK!THIS! X$startsh X# X# makedep X# X# Creates dependencies for Makefile X# X Xexport PATH || (echo "OOPS, this isn't sh. Desperation time. I will feed myself to sh."; sh \$0; kill \$\$) X Xcat='$cat' Xccflags='$ccflags' Xcp='$cp' Xcpp='$cppstdin' Xecho='$echo' Xegrep='$egrep' Xexpr='$expr' Xmv='$mv' Xrm='$rm' Xsed='$sed' Xsort='$sort' Xtest='$test' Xtr='$tr' Xuniq='$uniq' X!GROK!THIS! X X$spitshell >>makedep <<'!NO!SUBS!' X X: the following weeds options from ccflags that are of no interest to cpp Xcase "$ccflags" in X'');; X*) set X $ccflags X ccflags='' X for flag do X case $flag in X -D*|-I*) ccflags="$ccflags $flag";; X esac X done X ;; Xesac X X$cat /dev/null >.deptmp X$rm -f *.c.c c/*.c.c Xif test -f Makefile; then X mf=Makefile Xelse X mf=makefile Xfi Xif test -f $mf; then X defrule=`<$mf sed -n \ X -e '/^\.c\.o:.*;/{' \ X -e 's/\$\*\.c//' \ X -e 's/^[^;]*;[ ]*//p' \ X -e q \ X -e '}' \ X -e '/^\.c\.o: *$/{' \ X -e N \ X -e 's/\$\*\.c//' \ X -e 's/^.*\n[ ]*//p' \ X -e q \ X -e '}'` Xfi Xcase "$defrule" in X'') defrule='$(CC) -c $(CFLAGS)' ;; Xesac X Xmake clist || ($echo "Searching for .c files..."; \ X $echo *.c | $tr ' ' '\012' | $egrep -v '\*' >.clist) Xfor file in `$cat .clist`; do X# for file in `cat /dev/null`; do X case "$file" in X *.c) filebase=`basename $file .c` ;; X *.y) filebase=`basename $file .c` ;; X esac X $echo "Finding dependencies for $filebase.o." X $sed -n <$file >$file.c \ X -e "/^${filebase}_init(/q" \ X -e '/^#/{' \ X -e 's|/\*.*$||' \ X -e 's|\\$||' \ X -e p \ X -e '}' X $cpp -I. $ccflags $file.c | \ X $sed \ X -e '/^# *[0-9]/!d' \ X -e 's/^.*"\(.*\)".*$/'$filebase'.o: \1/' \ X -e 's|: \./|: |' \ X -e 's|\.c\.c|.c|' | \ X $uniq | $sort | $uniq >> .deptmp Xdone X X$sed <Makefile >Makefile.new -e '1,/^# AUTOMATICALLY/!d' X Xmake shlist || ($echo "Searching for .SH files..."; \ X $echo *.SH | $tr ' ' '\012' | $egrep -v '\*' >.shlist) Xif $test -s .deptmp; then X for file in `cat .shlist`; do X $echo `$expr X$file : 'X\(.*\).SH`: $file config.sh \; \ X /bin/sh $file >> .deptmp X done X $echo "Updating Makefile..." X $echo "# If this runs make out of memory, delete /usr/include lines." \ X >> Makefile.new X $sed 's|^\(.*\.o:\) *\(.*/.*\.c\) *$|\1 \2; '"$defrule \2|" .deptmp \ X >>Makefile.new Xelse X make hlist || ($echo "Searching for .h files..."; \ X $echo *.h | $tr ' ' '\012' | $egrep -v '\*' >.hlist) X $echo "You don't seem to have a proper C preprocessor. Using grep instead." X $egrep '^#include ' `cat .clist` `cat .hlist` >.deptmp X $echo "Updating Makefile..." X <.clist $sed -n \ X -e '/\//{' \ X -e 's|^\(.*\)/\(.*\)\.c|\2.o: \1/\2.c; '"$defrule \1/\2.c|p" \ X -e d \ X -e '}' \ X -e 's|^\(.*\)\.c|\1.o: \1.c|p' >> Makefile.new X <.hlist $sed -n 's|\(.*/\)\(.*\)|s= \2= \1\2=|p' >.hsed X <.deptmp $sed -n 's|c:#include "\(.*\)".*$|o: \1|p' | \ X $sed 's|^[^;]*/||' | \ X $sed -f .hsed >> Makefile.new X <.deptmp $sed -n 's|c:#include <\(.*\)>.*$|o: /usr/include/\1|p' \ X >> Makefile.new X <.deptmp $sed -n 's|h:#include "\(.*\)".*$|h: \1|p' | \ X $sed -f .hsed >> Makefile.new X <.deptmp $sed -n 's|h:#include <\(.*\)>.*$|h: /usr/include/\1|p' \ X >> Makefile.new X for file in `$cat .shlist`; do X $echo `$expr X$file : 'X\(.*\).SH`: $file config.sh \; \ X /bin/sh $file >> Makefile.new X done Xfi X$rm -f Makefile.old X$cp Makefile Makefile.old X$cp Makefile.new Makefile X$rm Makefile.new X$echo "# WARNING: Put nothing here or make depend will gobble it up!" >> Makefile X$rm -f .deptmp `sed 's/\.c/.c.c/' .clist` .shlist .clist .hlist .hsed X X!NO!SUBS! X$eunicefix makedep Xchmod +x makedep Xcase `pwd` in X*SH) X $rm -f ../makedep X ln makedep ../makedep X ;; Xesac !STUFFY!FUNK! echo Extracting patchlevel.h sed >patchlevel.h <<'!STUFFY!FUNK!' -e 's/X//' X/* X** $Id: patchlevel.h,v 1.1 90/01/16 16:17:12 paul Exp Locker: paul $ X** X** Getty release/patchlevel X*/ X X X#define PATCHLEVEL 0 /* patchlevel */ X X/* these are used by the man pages, too X */ X#define RELEASE "1.1" /* release number */ X#define DATE "16-Jan-90" /* release date */ X X X/* end of patchlevel.h */ !STUFFY!FUNK! echo "" echo "End of kit 2 (of 4)" cat /dev/null >kit2isdone run='' config='' for iskit in 1 2 3 4; do if test -f kit${iskit}isdone; then run="$run $iskit" else todo="$todo $iskit" fi done case $todo in '') echo "You have run all your kits. Please read README and then type Configure." chmod 755 Configure ;; *) echo "You have run$run." echo "You still need to run$todo." ;; esac : Someone might mail this, so... exit Subject: Enhanced SYSV Getty, v1.1, part 2 of 4 Newsgroups: alt.sources Keywords: getty source INTERNET: paul at devon.lns.pa.us | If life's a bitch, then UUCP: ...!rutgers!devon!paul | we must be her puppies. From peter at ficc.uu.net Tue Jan 30 09:20:14 1990 From: peter at ficc.uu.net (Peter da Silva) Date: 29 Jan 90 22:20:14 GMT Subject: Patches to "Parseargs" by Eric Allman Message-ID: <NKE1:ODxds13@ficc.uu.net> Archive-name: parseargs/patch.pds Parseargs is a much better design than getopt, and the first REAL advancement in parsing C command line arguments since argv[argc] was changed to NULL. But it needs a little tuning. These patches are not intended to be comprehensive, but they do fill the main gaps in the implementation. In particular, they allow you to have a list of names on the command line. : #! /bin/sh # This is a shell archive, created at Ferranti International Controls Corp. # by peter (peter da silva,2419T 5180 @xds13) on Mon Jan 29 16:11:55 1990 # Remove anything before the "#! /bin/sh" line, then unpack it by saving # it into a file and typing "sh file". If you do not have sh, you need # unshar, a dearchiving program which is widely available. In the absolute # wost case, you can crack the files out by hand. # If the archive is complete, you will see the message "End of archive." # at the end. # This archive contains the following files... # 'README.PDS' # 'patches' # 'strtol.c' # To extract them, run the following through /bin/sh echo x - README.PDS sed 's/^X//' > README.PDS << '//END_OF_FILE' XUpdate to parseargs by Peter da Silva (peter at ficc.uu.net). X XParseargs is a really nifty set of routines, but it doesn't fit too Xwell with standard UNIX semantics. In particular, you can get into a Xlot of trouble using it in a script. To make it work better, I've made Xa couple of changes. X XIt compiled straight out of the box on System III once I'd provided Xbcopy, bcmp, and strtol. The strtol I've provided is almost totally Xuntested, but hopefully you won't need to use it. It's only for folks with Xold UNIX systems. X XFirst change was to disable the interactive prompting for arguments. XI think that's inconsistent with usual UNIX semantics. You can undo Xthis change by #defining INTERACTIVE when compiling parseargs.c. X XThe second change was to allow for a trailing list of arguments. There's Xan extra argument, name, that's used by the usage routine and also flags Xthat trailing arguments are acceptable. parseargs now returns a new argc Xand edits argv to match. X XAlso, the error messages have been made a bit more descriptive. Instead Xof saying "stest: value required for -c flag", it prints "stest: RepCount Xrequired for -c flag". The ad_prompt element should relly be a descriptive Xword that can be used in a sentence... or for non_UNIX systems a multi- Xcharacter or keyword based flag. I plan on doing an Amiga version, for Xexample, that uses keyword syntax. In that version, the usage message would Xread: X XUsage: stest [Name] <Name> [RepCount <RepCount>] [DirName <DirName>] \ X [XFlag] [YFlag] [ZFlag] [<File>]... X XInstead of: X XUsage: stest <Name> [-c <RepCount>] [-d <DirName>] [-x] [-y] [-z] \ X [<File>]... X XThis would solve the old problem of UNIX programs sticking out like a Xsore thumb in other operating systems. //END_OF_FILE echo x - patches sed 's/^X//' > patches << '//END_OF_FILE' XMakefile orig/Makefile differ: char 70, line 3 X*** orig/Makefile X--- Makefile X*************** X*** 1,6 **** X # $Header: Makefile,v 2.1 89/12/30 20:59:01 eric Exp $ X X! TARGET= /usr/local X INCLUDES= -I. X O= -O X X--- 1,6 ---- X # $Header: Makefile,v 2.1 89/12/30 20:59:01 eric Exp $ X X! TARGET= /usr1/local X INCLUDES= -I. X O= -O X X*************** X*** 12,18 **** X openpath.o \ X parseargs.o \ X syserr.o \ X! traceset.o X HFILES= funclist.h \ X parseargs.h \ X useful.h X--- 12,19 ---- X openpath.o \ X parseargs.o \ X syserr.o \ X! traceset.o \ X! strtol.o X HFILES= funclist.h \ X parseargs.h \ X useful.h X*************** X*** 35,41 **** X X OBJS= ${OFILES} X SRCFILES= ${XXFILES} ${HFILES} ${CFILES} ${MANFILES} X! LIBNAME= libgoodies.a X LOCLIBS= ${LIBNAME} X SYSLIBS= -lm X LIBS= ${LOCLIBS} ${SYSLIBS} X--- 36,42 ---- X X OBJS= ${OFILES} X SRCFILES= ${XXFILES} ${HFILES} ${CFILES} ${MANFILES} X! LIBNAME= libparseargs.a X LOCLIBS= ${LIBNAME} X SYSLIBS= -lm X LIBS= ${LOCLIBS} ${SYSLIBS} Xparseargs.c orig/parseargs.c differ: char 317, line 13 X*** orig/parseargs.c X--- parseargs.c X*************** X*** 10,19 **** X ** Parameters: X ** argv -- the argument vector as passed to main(). X ** argd -- the argument descriptor array. X ** X ** Returns: X! ** none. Terminates the process if parameters cannot be X! ** properly matched up. X ** X ** Side Effects: X ** Converts and stores arguments into variables as X--- 10,21 ---- X ** Parameters: X ** argv -- the argument vector as passed to main(). X ** argd -- the argument descriptor array. X+ ** name -- name of extra arguments for usage message, X+ ** or NULL if none allowed. X ** X ** Returns: X! ** Modifies argv to eat arguments, returns new argc. X! ** Exits with return code 2 if error in args. X ** X ** Side Effects: X ** Converts and stores arguments into variables as X*************** X*** 42,48 **** X STATIC ARGDESC _DefaultArgs[] = X { X /* name flags type valp prompt */ X! 'T', ARGOPT, argTrace, ARBNULL, "trace flags", X ENDOFARGS X }; X X--- 44,50 ---- X STATIC ARGDESC _DefaultArgs[] = X { X /* name flags type valp prompt */ X! 'T', ARGOPT, argTrace, ARBNULL, "TRACE", X ENDOFARGS X }; X X*************** X*** 52,76 **** X ENDOFARGS X }; X X VOID X! parseargs(argv, argd) X char **argv; X ARGDESC argd[]; X { X register ARGDESC *ad; X! register char **av = argv; X register char *p; X BOOL noflags; X BOOL error; X BOOL shouldprompt; X extern char *getenv ARGS((char *)); X extern int isatty ARGS((int)); X X /* save the name of this program (for error messages) */ X ProgName = *av; X X /* test to see if we are interactive */ X shouldprompt = (BOOL) isatty(0) && (BOOL) isatty(2); X X /* allow null argument descriptor */ X if (argd == (ARGDESC *) NULL) X--- 54,90 ---- X ENDOFARGS X }; X X+ static char *Extra; X+ X VOID X! parseargs(argv, argd, extra) X char **argv; X ARGDESC argd[]; X+ char *extra; X { X register ARGDESC *ad; X! register char **av; X register char *p; X+ int argc; X BOOL noflags; X BOOL error; X+ #ifdef INTERACTIVE X BOOL shouldprompt; X+ #endif X extern char *getenv ARGS((char *)); X+ #ifdef INTERACTIVE X extern int isatty ARGS((int)); X+ #endif X X+ av = argv++; argc = 1; X /* save the name of this program (for error messages) */ X ProgName = *av; X+ Extra = extra; X X+ #ifdef INTERACTIVE X /* test to see if we are interactive */ X shouldprompt = (BOOL) isatty(0) && (BOOL) isatty(2); X+ #endif X X /* allow null argument descriptor */ X if (argd == (ARGDESC *) NULL) X*************** X*** 147,154 **** X if (p == CHARNULL || *p == '-') X { X av--; X! usrerr("value required for -%c flag", X! ad->ad_name); X error = TRUE; X break; X } X--- 161,168 ---- X if (p == CHARNULL || *p == '-') X { X av--; X! usrerr("%s required for -%c flag", X! ad->ad_prompt, ad->ad_name); X error = TRUE; X break; X } X*************** X*** 173,180 **** X } X if (ad->ad_name == '\0') X { X! usrerr("too many positional parameters"); X! error = TRUE; X continue; X } X X--- 187,202 ---- X } X if (ad->ad_name == '\0') X { X! if(extra==NULL) { X! usrerr("too any arguments"); X! error = 1; X! continue; X! } X! /* Compress extra parms back into av */ X! if(argv != av) X! *argv = *av; X! argv++; X! argc++; X continue; X } X X*************** X*** 186,191 **** X--- 208,215 ---- X } X } X X+ *argv = NULL; X+ X /* now rescan for missing required arguments */ X for (ALL_AD) X { X*************** X*** 191,196 **** X--- 215,221 ---- X { X if (BITSET(ARGREQ, ad->ad_flags) && !BITSET(ARGGIVEN, ad->ad_flags)) X { X+ #ifdef INTERACTIVE X /* can we prompt? */ X while (shouldprompt && !error) X { X*************** X*** 214,219 **** X--- 239,246 ---- X break; X } X } X+ #endif X+ X if (!BITSET(ARGGIVEN, ad->ad_flags)) X { X /* still didn't get a value... sigh */ X*************** X*** 219,231 **** X /* still didn't get a value... sigh */ X if (ad->ad_name == ' ') X { X! usrerr("value required for <%s> parameter", X ad->ad_prompt); X } X else X { X! usrerr("value required for -%c flag", X! ad->ad_name); X } X error = TRUE; X } X--- 246,258 ---- X /* still didn't get a value... sigh */ X if (ad->ad_name == ' ') X { X! usrerr("%s required", X ad->ad_prompt); X } X else X { X! usrerr("%s required for -%c flag", X! ad->ad_prompt, ad->ad_name); X } X error = TRUE; X } X*************** X*** 235,242 **** X if (error) X { X usage(argd); X! exit(1); X } X } X /* X ** USAGE -- print a usage message X--- 262,271 ---- X if (error) X { X usage(argd); X! exit(2); X } X+ X+ return argc; X } X /* X ** USAGE -- print a usage message X*************** X*** 319,325 **** X if (!BITSET(ARGREQ, ad->ad_flags)) X fprintf(stderr, "]"); X } X! fprintf(stderr, "\n"); X } X /* X ** ARGtype -- argument translation routines. X--- 348,362 ---- X if (!BITSET(ARGREQ, ad->ad_flags)) X fprintf(stderr, "]"); X } X! if(Extra) { X! pl = 8 + strlen(Extra); X! if (ll + pl > MaxOutputLine) { X! fprintf(stderr, " \\\n\t"); X! ll = 7; X! } X! fprintf(stderr, " [<%s>]...\n", Extra); X! } else X! fprintf(stderr, "\n"); X } X /* X ** ARGtype -- argument translation routines. Xstest.c orig/stest.c differ: char 267, line 15 X*** orig/stest.c X--- stest.c X*************** X*** 12,27 **** X */ X X int RepCount; X! char *XFlag; X! char *FirstArg; X! BOOL FFlag = FALSE; X X ARGDESC Args[] = X { X! ' ', ARGREQ, argStr, __ &FirstArg, "First Argument", X! 'c', ARGREQ, argInt, __ &RepCount, "Repetition Count", X! 'f', ARGREQ, argBool, __ &FFlag, "F Flag", X! ' ', ARGOPT, argStr, __ &XFlag, "This is a long string, to force wrap", X ENDOFARGS X }; X X--- 12,31 ---- X */ X X int RepCount; X! char *Name; X! char *DirName = "."; X! BOOL XFlag = FALSE; X! BOOL YFlag = FALSE; X! BOOL ZFlag = FALSE; X X ARGDESC Args[] = X { X! ' ', ARGREQ, argStr, __ &Name, "Name", X! 'c', ARGOPT, argInt, __ &RepCount, "RepCount", X! 'd', ARGOPT, argStr, __ &DirName, "DirName", X! 'x', ARGOPT, argBool, __ &XFlag, "XFlag", X! 'y', ARGOPT, argBool, __ &YFlag, "YFlag", X! 'z', ARGOPT, argBool, __ &ZFlag, "ZFlag", X ENDOFARGS X }; X X*************** X*** 29,37 **** X int argc; X char **argv; X { X! parseargs(argv, Args); X! printf("FirstArg = '%s', RepCount = %d, FFlag = %d\n", X! FirstArg, RepCount, FFlag); X TRACE(1, 2, ("hello world\n")); X exit(0); X } X--- 33,56 ---- X int argc; X char **argv; X { X! int newargc; X! X! newargc = parseargs(argv, Args, "File"); X! printf("Name = '%s', DirName = '%s', RepCount = %d\n", X! Name, DirName, RepCount); X! printf("XFlag = %d, YFlag = %d, ZFlag = %d\n", X! XFlag, YFlag, ZFlag); X! if(newargc > 1) { X! printf("%d remaining args: ", newargc-1); X! argv++; X! while(*argv) { X! printf("%s", *argv++); X! if(*argv) X! putchar(' '); X! else X! putchar('\n'); X! } X! } X TRACE(1, 2, ("hello world\n")); X exit(0); X } Xuseful.h orig/useful.h differ: char 1894, line 117 X*** orig/useful.h X--- useful.h X*************** X*** 114,117 **** X--- 114,122 ---- X #define MAXINPUTLINE 200 /* maximum string input line */ X #define MAXWORDLEN 100 /* maximum word (token) length */ X X+ #ifndef BSD X+ #define bcopy(f,t,l) memcpy(t,f,l) X+ #define bcmp(s,t,l) memcmp(s,t,l) X+ #endif X+ X #endif /* _USEFUL_H_ */ //END_OF_FILE echo x - strtol.c sed 's/^X//' > strtol.c << '//END_OF_FILE' X#ifndef BSD X#include <ctype.h> X X#define XX 36 Xstatic char valof[128] = { X XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, X XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, X XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, X 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, XX, XX, XX, XX, XX, XX, X XX, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, X 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, XX, XX, XX, XX, XX, X XX, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, X 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, XX, XX, XX, XX, XX X}; X Xlong strtol(str, ptr, base) Xchar *str; Xchar **ptr; Xint base; X{ X long digit; X char *s; X char *p; X long val, sign; X X s = str; X while(isspace(*s)) X s++; X X if(*s=='-') { X sign = -1L; X s++; X } else X sign = 1L; X X if(base <= 0 || base > 36) { X if(s[0]=='0') { X if(s[1]=='x' || s[1]=='X') X base = 16; X else X base = 8; X } else X base = 10; X } X X if(base==16 && s[0]=='0' && (s[1] == 'X' || s[1] == 'x')) X s += 2; X X val = 0L; X X if(*s > 0 && *s < 128) { X digit = valof[*s]; X if(digit >= base) { X if(ptr) *ptr = str; X return 0L; X } X } else { X if(ptr) *ptr = str; X return 0L; X } X X do { X val = val * base + digit; X s++; X digit = valof[*s]; X if(digit >= base) X break; X } while(*s > 0 && *s < 128); X X if(ptr) *ptr = s; X return val * sign; X} X#endif //END_OF_FILE echo "End of archive." # end of archive. exit 0 -- _--_|\ Peter da Silva. +1 713 274 5180. <peter at ficc.uu.net>. / \ \_.--._/ Xenix Support -- it's not just a job, it's an adventure! v "Have you hugged your wolf today?" `-_-' From erc at khijol.UUCP Sat Jan 13 16:11:54 1990 From: erc at khijol.UUCP (Edwin R. Carp) Date: 13 Jan 90 05:11:54 GMT Subject: looking for frag Message-ID: <991@khijol.UUCP> I'm looking for a program called "frag", which (I think) will unfragment a hard disk running XENIX/UNIX. Could someone mail this to me? I don't have ftp access. Thanks very much! -- Ed Carp N7EKG/5 (28.3-28.5) uunet!cs.utexas.edu!khijol!erc Austin, Texas (512) 832-5884 "Good tea. Nice house." - Worf From jfh at rpp386.cactus.org Thu Jan 11 17:14:43 1990 From: jfh at rpp386.cactus.org (John F. Haugh II) Date: 11 Jan 90 06:14:43 GMT Subject: Wanted: 1990 "sc" 1040 forms References: <MDF0.90Jan9121142@shemesh.gte.com> Message-ID: <17619@rpp386.cactus.org> In article <MDF0.90Jan9121142 at shemesh.gte.com> mdf0 at shemesh.gte.com (Mark Feblowitz) writes: >For a while, someone was distributing 1040 and related forms for the >"sc" public domain spreadsheet calculator. Is anyone revising these >forms for 1990? A man who has never filed income tax before in his entire life ... Sometime next year, when your 1990 taxes are due, someone will no doubt update the spreadsheet. -- John F. Haugh II UUCP: ...!cs.utexas.edu!rpp386!jfh Ma Bell: (512) 832-8832 Domain: jfh at rpp386.cactus.org From paul at devon.lns.pa.us Wed Jan 17 19:08:51 1990 From: paul at devon.lns.pa.us (Paul Sutcliffe Jr.) Date: 17 Jan 90 08:08:51 GMT Subject: Enhanced SYSV Getty, v1.1, part 3 of 4 Message-ID: <1990Jan17.080851.823@devon.lns.pa.us> #! /bin/sh # Make a new directory for the getty sources, cd to it, and run kits 1 # thru 4 through sh. When all 4 kits have been run, read README. echo "This is getty 1.1 kit 3 (of 4). If kit 3 is complete, the line" echo '"'"End of kit 3 (of 4)"'" will echo at the end.' echo "" export PATH || (echo "You didn't use sh, you clunch." ; kill $$) mkdir man 2>/dev/null echo Extracting man/getty.m4 sed >man/getty.m4 <<'!STUFFY!FUNK!' -e 's/X//' X.\" +---------- X.\" | $Id: getty.m4,v 1.1 90/01/16 16:01:43 paul Exp Locker: paul $ X.\" | X.\" | GETTY/UUGETTY man page. X.\" | X.\" | Copyright 1989,1990 by Paul Sutcliffe Jr. X.\" | X.\" | Permission is hereby granted to copy, reproduce, redistribute, X.\" | or otherwise use this software as long as: there is no monetary X.\" | profit gained specifically from the use or reproduction or this X.\" | software, it is not sold, rented, traded or otherwise marketed, X.\" | and this copyright notice is included prominently in any copy X.\" | made. X.\" | X.\" | The author make no claims as to the fitness or correctness of X.\" | this software for any use whatsoever, and it is provided as is. X.\" | Any use of this software is at the user's own risk. X.\" | X.\" X.\" +---------- X.\" | $Log: getty.m4,v $ X.\" | Revision 1.1 90/01/16 16:01:43 paul X.\" | Initial revision X.\" | X.\" | X.\" X.\" +---------- X.\" | M4 configuration X.\" Xinclude(config.m4).\" X.\" X.\" define(`_gtab_file_', _gtab_`_file') X.\" X.\" +---------- X.\" | Manpage source follows: X.\" X.TH GETTY _mcmd_section_ "DATE" "Release RELEASE" X.SH NAME Xgetty \- sets terminal mode, speed, and line discipline X.SH SYNOPSIS X.B /etc/getty X.\" +---------- X.\" | M4_start (trs16) Xifdef(`trs16', X.B speed X.I [defaults_file], X.\" | else (trs16) X[\-d X.I defaults_file] X[\-h] [\-r X.I delay] X[\-t X.I timeout] X.B line X.I [speed [type [lined]]]) X.\" | M4_end (trs16) X.\" +---------- X.br X.B /etc/getty \-c X.I _gtab_file_ X.SH DESCRIPTION X.I Getty Xis the second of the three programs X.I (init(_mcmd_section_), getty(_mcmd_section_), Xand X.I login(_mcmd_section_)), Xused by the X.\" +---------- X.\" | M4_start Xifdef(`M_XENIX', XENIX, .\") Xifdef(`XENIX', XENIX, .\") Xifdef(`UNIX', UNIX, .\") X.\" | M4_end X.\" +---------- Xsystem to allow users to login. X.I Getty Xis invoked by X.I init(_mcmd_section_) Xto: X.br X.TP 3 X1. XOpen tty lines and set their modes. X.TP X2. XPrint the login prompt, and get the user's name. X.TP X3. XInitiate a login process for the user. X.P XThe actual procedure that X.I getty Xfollows is described below: Initially, X.I getty Xparses its command line. If no errors are found, X.I getty Xscans the defaults file (normally X.B _defaults_`/getty\fR)' Xto determine certain runtime values. The values in the defaults file X(whose compiled\-in name can be altered with the optional X.\" +---------- X.\" | M4_start (trs16) Xifdef(`trs16', .\", .B \-d) X.\" | M4_end (trs16) X.\" +---------- X.I defaults_file Xargument) take precedence to those on the command line. X.I Getty Xthen opens the X.I line Xfor reading and writing, and disables stdio buffering. X.\" +---------- X.\" | M4_start (logutmp) Xifdef(`logutmp', XThe X.I utmp(_file_section_) Xand X.I wtmp(_file_section_) Xfiles are updated to indicate a LOGIN_PROCESS., X.\" | else (logutmp) X.\") X.\" | M4_end (logutmp) X.\" +---------- XIf an initialization was specified, it is performed (see LINE XINITIALIZATION). X.PP XNext, X.I getty Xtypes the X.\" +---------- X.\" | M4_start (issue) Xifdef(`_issue_', Xissue `(or login banner,' usually from X.B _issue_`\fR)' Xand, X.\" | else (issue) X.\") X.\" | M4_end (issue) X.\" +---------- Xlogin prompt. Finally, X.I getty Xreads the user's login name and invokes X.I login(_mcmd_section_) Xwith the user's name as an argument. While reading the name, X.I getty Xattempts to adapt the system to the speed of the terminal being used, Xand also sets certain terminal parameters (see X.\" +---------- X.\" | M4_start (trs16) Xifdef(`trs16', X.I tty`('_misc_section_`))', X.\" | else (trs16) X.I termio`('_misc_section_`))') X.\" | M4_end (trs16) X.\" +---------- Xto conform with the user's login procedure. X.PP XThe tty device used by X.I getty Xis determined by X.\" +---------- X.\" | M4_start (trs16) Xifdef(`trs16', Xa call to X.I ttyname(S)`,' Xwhich sets the X.I line Xvalue., X.\" | else (trs16) Xthe X.I line Xargument.) X.\" | M4_end (trs16) X.\" +---------- X.I Getty Xuses the string X.B /dev/\fIline\fR Xas the name of the device to attach itself to. Unless X.I getty Xis invoked with the X.B \-h Xflag (or X.B HANGUP=NO Xis specified in the defaults file), it will force a hangup on the line Xby setting the speed to zero. Giving X.B \-r X.I delay Xon the command line (or using X.B WAITCHAR=YES Xand X.B DELAY=\fIdelay\fR Xin the defaults file) will cause X.I getty Xto wait for a character from the line, and then to wait X.I delay Xseconds before continuing. If no delay is desired, use X.B \-r0\fR. XGiving X.B \-t X.I timeout Xon the command line (or using X.B TIMEOUT=\fItimeout\fR Xin the defaults file) will cause X.I getty Xto exit if no user name is accepted within X.I timeout Xseconds after the login prompt is typed. X.PP XThe X.I speed Xargument is a label to a entry in the X.B _gettytab_ Xfile (see X.I _gtab_`('_file_section_)). XThis entry defines to X.I getty Xthe initial speed (baud rate) and tty settings, the login prompt to be Xused, the final speed and tty settings, and a pointer to another entry Xto try should the user indicate that the speed is not correct. This Xis done by sending a X.I <break> Xcharacter (actually sequence). Under certain conditions, a Xcarriage\-return will perform the same function. This is usually the Xcase when getty is set to a higher speed than the modem or terminal. X.I XGetty Xscans the X_gtab_ Xfile sequentially looking for a matching entry. X.\" +---------- X.\" | M4_start (trs16) Xifdef(`trs16', XIf an entry for the given X.I speed, X.\" | else (trs16) XIf no X.I speed Xwas given or the entry) X.\" | M4_end (trs16) X.\" +---------- Xcannot be found, the first entry in the X.B _gettytab_ Xfile is used as a default. In the event that the X_gtab_ Xfile cannot be Xaccessed`,' there is a compiled\-in default that is used. X.PP X.\" +---------- X.\" | M4_start (trs16) Xifdef(`trs16', XThe terminal type is determined by examining the X.I ttytype Xfile`,' using the value associated with X.I line. X.I Getty Xuses this value to determine how to clear the video display., X.\" | else (trs16) XThe X.I type Xargument is a string which names the type of terminal attached to the Xline. The X.I type Xshould be a valid terminal name listed in the X.\" +---------- X.\" | M4_start (termcap) Xifdef(`termcap', X.B termcap(_misc_section_), X.\" | else (termcap) X.B terminfo(_misc_section_)) X.\" | M4_end (termcap) X.\" +---------- Xdatabase. X.\" +---------- X.\" | M4_start (ttytype) Xifdef(`ttytype', XIf no X.I type Xis given on the command line`,' one is deduced from the X.B ttytype Xfile., X.\" | else (ttytype) X.\") X.\" | M4_end (ttytype) X.\" +---------- X.I Getty Xuses this value to determine how to clear the video display. X.PP XThe X.I lined Xargument is a string describing the line discipline to use on the Xline. The default is X.B LDISC0\fR.) X.\" | M4_end (trs16) X.\" +---------- X.PP XAs mentioned, X.I getty Xtypes the login prompt and then reads the user's login name. If a Xnull character is received, it is assumed to be the result of the user Xpressing the X.I <break> Xkey or the carriage\-return key to indicate the speed is wrong. This Xcauses X.I getty Xto locate the next X.I speed Xin the series (defined in _gettytab_). X.PP XThe user's name is terminated by a new\-line or carriage\-return Xcharacter. A carriage\-return results in the system being set to map Xthose to new\-lines (see X.I ioctl(_system_section_)). X.PP XThe user's name is scanned to see if it contains only upper\-case Xcharacters. If so, X.\" +---------- X.\" | M4_start (warncase) Xifdef(`warncase', Xa warning is issued to the user to retry his login`,' using lower\-case Xif possible. If the second attempt is still all upper\-case`,', X.\" | else (warncase) X.\") X.\" | M4_end (warncase) X.\" +---------- Xthe system is set to map any future upper\-case characters into Xlower\-case. X.PP XA check option is provided for testing the X_gtab_ Xfile. When X.I getty Xis invoked with the X.B \-c X.I _gtab_ Xoption, it scans the named X.I _gtab_ Xfile and prints out (to the standard output) the values it sees. If Xany parsing errors occur (due to errors in the syntax of the X_gtab_ Xfile), they are reported. X.SH "DEFAULTS FILE" XDuring its startup, X.I getty Xlooks for the file X.B _defaults_`/getty\fI.line\fR,' X(or, if it cannot find that file, then X.B _defaults_`/getty\fR),' Xand if found, reads the contents for lines of the form X X.in +.5i XNAME=\fIvalue\fR X.in -.5i X XThis allows getty to have certain features configurable at runtime, Xwithout recompiling. The recognized NAME strings, and their Xcorresponding values, follows: X.TP 8 XSYSTEM=\fIname\fR XSets the nodename value (displayed by X.B @S X\-\- see PROMPT SUBSTITUTIONS) to X.I name. XThe default is the X.I nodename Xvalue returned by the X.I uname(_library_section_) Xcall. On XENIX systems, if the value of nodename is a zero\-length Xstring, the file X.B /etc/systemid Xis examined to get the nodename. XNote that some sites may have elected to compile the nodename value Xinto X.I getty. X.TP XVERSION=\fIstring\fR XSets the value that is displayed by the X.B @V Xparameter (see PROMPT SUBSTITUTIONS) to X.I string. XThere is no default value. If X.I string Xbegins with a '/' character, it is assumed to be the full pathname of a Xfile, and X.B @V Xis set to the contents of that file. X.TP XLOGIN=\fIname\fR XSets the name of the login program to X.I name. XThe default is X.B _login_ X(see X.I login(_mcmd_section_)). XIf used, X.I name Xmust be the full pathname of the program that X.I getty Xwill execute instead of X.B _login_\fR. XNote that this program is called, as is X.B _login_\fR, Xthe with the user's name as its only argument. X.TP XINIT=\fIstring\fR XIf defined, X.I string Xis a send/expect sequence that is used to initialize the line before X.I getty Xattempts to use it. This string is in a form resembling that used by Xthe X.I L.sys Xor X.I Systems Xfile of X.I uucp(_cmd_section_). XFor more details, see LINE INITIALIZATION. By default, no Xinitialization is done. X.\" +---------- X.\" | M4_start (issue) Xifdef(`_issue_', X.TP XISSUE=\fIstring\fR XDuring startup`,' X.I getty Xdefaults to displaying`,' as an issue or login banner`,' the contents of Xthe X.B _issue_ Xfile. If ISSUE is defined to a X.I string`,' Xthat string is typed instead. If X.I string Xbegins with a '/' character`,' it is assumed to be the full pathname of Xa file`,' and that file is used instead of X.B _issue_\fR., X.\" | else (issue) X.\") X.\" | M4_end (issue) X.\" +---------- X.TP XCLEAR=\fIvalue\fR XIf X.I value Xis X.B NO\fR, Xthen X.I getty Xwill not attempt to clear the video screen before typing the X.\" +---------- X.\" < M4_start (issue) Xifdef(`_issue_', Xissue or login prompts., X.\" | else (issue) Xlogin prompt.) X.\" | M4_end (issue) X.\" +---------- X.TP XHANGUP=\fIvalue\fR XIf X.I value Xis X.B NO\fR, Xthen X.I getty Xwill NOT hangup the line during its startup. This is analogus to Xgiving the X.B \-h Xargument on the command line. X.TP XWAITCHAR=\fIvalue\fR XIf X.I value Xis X.B YES\fR, Xthen X.I getty Xwill wait for a single character from it's line before continuing. XThis is useful for modem connections where the modem has CD forced Xhigh at all times, to keep getty from endlessly chatting with the Xmodem. X.TP XDELAY=\fIseconds\fR XUsed in conjunction with X.B WAITCHAR\fR, Xthis adds a time delay of X.I seconds Xafter the character is accepted before allowing X.I getty Xto continue. Both X.B WAITCHAR Xand X.B DELAY Xhave the same effect as specifying X.B \-r X.I delay Xon the command line. XIf X.B WAITCHAR Xis given without a X.B DELAY, Xthe result is equal to having said X.B \-r0 Xon the command line. X.TP XTIMEOUT=\fInumber\fR XAs with the X.B \-t X.I timeout Xcommand line argument, tells X.I getty Xto exit if no user name is accepted before the X.I number Xof seconds elapse after the login prompt is typed. X.TP XALTLOCK=\fIline\fR X.I Uugetty Xuses this parameter to lock an alternate device, in addition to the Xone it is attached to. This is for those systems that have two Xdifferent device names that refer to the same physical port; e.g. X/dev/tty1A vs. /dev/tty1a, where one uses modem control and the Xother doesn't. See the section on UUGETTY for more details. X.P XThe name of the defaults file can be changed by specifying X.\" +---------- X.\" | M4_start (trs16) Xifdef(`trs16', X.\" Nothing, X.\" | else (trs16) X.B \-d) X.\" | M4_end (trs16) X.\" +---------- X.I defaults_file Xon the command line. If X.I defaults_file Xbegins with a slash, it is assumed to be a complete pathname of the Xdefaults file to be used. Otherwise, it is assumed to be a regular Xfilename, causing X.I getty Xto use the pathname X.B _defaults_`/\fIdefaults_file\fR.' X.SH "PROMPT SUBSTITUTIONS" XWhen X.I getty Xis typing X.\" +---------- X.\" | M4_start (issue) Xifdef(`_issue_', Xthe issue or login banner (ususally X.B _issue_\fR)`,' Xor, X.\" | else (issue) X.\") X.\" | M4_end (issue) X.\" +---------- Xthe X.I login\-prompt, Xit recognizes several escape (quoted) characters. When one of these Xquoted characters is found, its value is substituted in the output Xproduced by X.I getty. XRecognized escape characters are: X.nf X X\\\\ Backslash (\\). X X\\b Backspace (^H). X X\\c Placed at the end of a string, this prevents X a new\-line from being typed after the string. X X\\f Formfeed (^L). X X\\n New\-line (^J). X X\\r Carriage\-return (^M). X X\\s A single space (' '). X X\\t Horizontal tab (^I). X X\\\fInnn\fR Outputs the ASCII character whose octal value X is \fInnn\fR. X X.fi XIn addition, a single backslash at the end of a line causes the Ximmediately following new\-line to be ignored, allowing continuation Xlines. X.PP XAlso, certain X.B @\fIchar\fR Xparameters are recognized. Those parameters, and the value that is Xsubstituted for them are: X.TP 5 X at B XThe current (evaluated at the time the X.B @B Xis seen) baud rate. X.TP X at D XThe current date, in MM/DD/YY format. X.TP X at L XThe X.I line Xto which X.I getty Xis attached. X.TP X at S XThe system node name. X.TP X at T XThe current time, in HH:MM:SS (24-hour) format. X.TP X at U XThe number of currently signed\-on users. This is a count of the Xnumber of entries in the X.I _utmp_ Xfile X.\" +---------- X.\" | M4_start (logutmp) Xifdef(`logutmp', Xwhose ut_type field is LOGIN_PROCESS., X.\" | else (logutmp) Xthat have a non\-null ut_name field.) X.\" | M4_end (logutmp) X.\" +---------- X.TP X at V XThe value of X.B VERSION\fR, Xas given in the defaults file. X.P XTo display a single '@' character, use either '\\@' or '@@'. X.SH "LINE INITIALIZATION" XOne of the greatest benefits (in the author's opinion, at least) is Xthe ability of X.I getty Xto initialize its line before use. This will most likely be done on Xlines with modems, not terminals, although initializing terminals is Xnot out of the question. X.PP XLine initialization is accomplished by placing an X X.in +.5i XINIT=\fIstring\fR X.in -.5i X Xline in the defaults file. X.I String Xis a series of one or more fields in the form X X.in +.5i Xsend [ expect [ send [ expect ] ] ... ] X.in -.5i X XThis format resembles the expect/send sequences used in the UUCP X.I L.sys Xor X.I Systems Xfile, with the following exceptions: X.TP 3 X1. XThe expect/send pairs are reversed. That is, the first sequence Xgiven is 'sent', not 'expected'. X.TP X2. XA carriage return is NOT appended automatically to sequences that Xare 'sent'. If you want a carriage\-return sent, you must explicitly Xshow it, with '\\r'. X.P X.I Getty Xsupports subfields in the expect field of the form X X.in +.5i Xexpect[\-send\-expect]... X.in -.5i X Xas with UUCP. All the escape characters (those beginning with a '\\' Xcharacter) listed in the PROMPT SUBSTITUTIONS section are valid in Xthe send and expect fields. XIn addition, the following two escape characters are recognized: X.nf X X\\p Inserts a 1\-second delay. X X\\d Inserts a 2\-second delay. X X.fi XNote that for these two escape characters, no actual character is sent. X.SH UUGETTY X.I Uugetty Xhas identical behavior to X.I getty, Xexcept that X.I uugetty Xis designed to create and use the lock files maintained by the UUCP Xfamily X.I (uucp(_cmd_section_), cu(_cmd_section_) Xand others). This prevents two or more processes from having conficting Xuse of a tty line. X.PP XWhen X.I uugetty Xstarts up, if it sees a lock file on the line it intends to use, Xit will use the pid in the lock file to see if there is an active Xprocess holding the lock. If not, X.I uugetty Xwill remove the lock file and continue. If a valid process is found, X.I uugetty Xwill sleep until that process releases the lock and then it will exit, Xforcing X.I init(_mcmd_section_) Xto spawn a new X.I uugetty. XOnce no conflicting process is found, X.I uugetty Xgrabs the X.I line Xby creating the lock file itself before issuing the login prompt. XThis prevents other processes from using the line. Judicious use Xof the X.B \-r\fIdelay\fR Xargument (or with X.B WAITCHAR=YES Xand X.B DELAY=\fIdelay\fR) Xwill prevent X.I uugetty Xfrom locking the line until a user attempts to login. X.PP X.I Uugetty Xwill normally only lock the name of the line it is running on. On Xsystems where there are two device names referring to the same port X(as is the case where one device uses modem control while the other Xdoesn't), place a line of the form X X.in +.5i XALTLOCK=\fIline\fR X.in -.5i X Xline in the defaults file. For instance, if X.I uugetty Xis on X.I /dev/tty1a, Xand you want to have it lock X.I /dev/tty1A Xalso, use the line X.B ALTLOCK=tty1A Xin the defaults file. X.SH FILES X.TP 16 X_console_ XThe device to which errors are reported. X.\" +---------- X.\" | M4_start (trymail) Xifdef(`trymail', XIf the device is for some reason unavailable (cannot be written to)`,' Xa mail message containing the error is sent to the user X.B _notify_\fR., X.\" | else (trymail) X.\") X.\" | M4_end (trymail) X.\" +---------- X.TP X_defaults_`/getty' XContains the runtime configuration. Note that X.I uugetty Xuses _defaults_`/uugetty\fR.' X.TP X_gettytab_ XContains speed and tty settings to be used by X.I getty. X.\" +---------- X.\" | M4_start (issue) Xifdef(`_issue_', X.TP X_issue_ XThe default issue (or login banner). X.\" | else (issue) X.\") X.\" | M4_end (issue) X.\" +---------- X.TP X_login_ XThe default login program called after the user's name is entered. X.\" +---------- X.\" | M4_start (ttytype) Xifdef(`ttytype', X.TP X_ttytype_ XContains the terminal types for each line in the system., X.\" | else (ttytype) X.\") X.\" | M4_end (ttytype) X.\" +---------- X.P X.SH "SEE ALSO" Xinit(_mcmd_section_), Xlogin(_mcmd_section_), Xuucp(_cmd_section_), Xioctl(_system_section_), Xuname(_library_section_), X.\" +---------- X.\" | M4_start (issue) Xifdef(`issue', Xissue`('_file_section_`)', X.\" | else (issue) X.\") X.\" | M4_end (issue) X.\" +---------- X_gtab_`('_file_section_), Xutmp(_file_section_), X.\" +---------- X.\" | M4_start (trs16) Xifdef(`trs16', Xtty`('_misc_section_`)', X.\" | else (trs16) Xtermio`('_misc_section_`)') X.\" | M4_end (trs16) X.\" +---------- X.SH AUTHOR X.nf XPaul Sutcliffe, Jr. <paul at devon.lns.pa.us> XUUCP: ...!rutgers!devon!paul !STUFFY!FUNK! echo Extracting table.c sed >table.c <<'!STUFFY!FUNK!' -e 's/X//' X/* X** $Id: table.c,v 1.1 90/01/16 16:18:56 paul Exp Locker: paul $ X** X** Routines to process the gettytab file. X*/ X X/* X** Copyright 1989,1990 by Paul Sutcliffe Jr. X** X** Permission is hereby granted to copy, reproduce, redistribute, X** or otherwise use this software as long as: there is no monetary X** profit gained specifically from the use or reproduction or this X** software, it is not sold, rented, traded or otherwise marketed, X** and this copyright notice is included prominently in any copy X** made. X** X** The author make no claims as to the fitness or correctness of X** this software for any use whatsoever, and it is provided as is. X** Any use of this software is at the user's own risk. X*/ X X/* X** $Log: table.c,v $ X** Revision 1.1 90/01/16 16:18:56 paul X** Initial revision X** X*/ X X X#include "getty.h" X#include "table.h" X X#if defined(RCSID) && !defined(lint) Xstatic char *RcsId = X"@(#)$Id: table.c,v 1.1 90/01/16 16:18:56 paul Exp Locker: paul $"; X#endif X X X/* Sane conditions. X */ X#define ISANE ( BRKINT | IGNPAR | ISTRIP | ICRNL | IXON | IXANY ) X#define OSANE ( OPOST | ONLCR ) X#define CSANE ( DEF_CFL | CREAD | HUPCL ) X#define LSANE ( ISIG | ICANON | ECHO | ECHOE | ECHOK ) X X#define CC_SANE { CINTR, CQUIT, CERASE, CKILL, CEOF, CNUL, CNUL, CNUL } X X X/* States for gtabvalue() X */ X#define ENTRY 0 /* looking for an entry line */ X#define QUIT 1 /* error occurred */ X X X#define NULLPTR (char *) NULL X X X/* All possible mode flags. X */ X XSYMTAB imodes[] = { X { "IGNBRK", IGNBRK }, X { "BRKINT", BRKINT }, X { "IGNPAR", IGNPAR }, X { "PARMRK", PARMRK }, X { "INPCK", INPCK }, X { "ISTRIP", ISTRIP }, X { "INLCR", INLCR }, X { "IGNCR", IGNCR }, X { "ICRNL", ICRNL }, X { "IUCLC", IUCLC }, X { "IXON", IXON }, X { "IXANY", IXANY }, X { "IXOFF", IXOFF }, X { NULLPTR, 0 } X}; X XSYMTAB omodes[] = { X { "OPOST", OPOST }, X { "OLCUC", OLCUC }, X { "ONLCR", ONLCR }, X { "OCRNL", OCRNL }, X { "ONOCR", ONOCR }, X { "ONLRET", ONLRET }, X { "OFILL", OFILL }, X { "OFDEL", OFDEL }, X { "NLDLY", NLDLY }, X { "NL0", NL0 }, X { "NL1", NL1 }, X { "CRDLY", CRDLY }, X { "CR0", CR0 }, X { "CR1", CR1 }, X { "CR2", CR2 }, X { "CR3", CR3 }, X { "TABDLY", TABDLY }, X { "TAB0", TAB0 }, X { "TAB1", TAB1 }, X { "TAB2", TAB2 }, X { "TAB3", TAB3 }, X { "BSDLY", BSDLY }, X { "BS0", BS0 }, X { "BS1", BS1 }, X { "VTDLY", VTDLY }, X { "VT0", VT0 }, X { "VT1", VT1 }, X { "FFDLY", FFDLY }, X { "FF0", FF0 }, X { "FF1", FF1 }, X { NULLPTR, 0 } X}; X XSYMTAB cmodes[] = { X { "B0", B0 }, X { "B50", B50 }, X { "B75", B75 }, X { "B110", B110 }, X { "B134", B134 }, X { "B150", B150 }, X { "B200", B200 }, X { "B300", B300 }, X { "B600", B600 }, X { "B1200", B1200 }, X { "B1800", B1800 }, X { "B2400", B2400 }, X { "B4800", B4800 }, X { "B9600", B9600 }, X#ifdef B19200 X { "B19200", B19200 }, X#endif /* B19200 */ X { "EXTA", EXTA }, X { "EXTB", EXTB }, X { "CS5", CS5 }, X { "CS6", CS6 }, X { "CS7", CS7 }, X { "CS8", CS8 }, X { "CSTOPB", CSTOPB }, X { "CREAD", CREAD }, X { "PARENB", PARENB }, X { "PARODD", PARODD }, X { "HUPCL", HUPCL }, X { "CLOCAL", CLOCAL }, X#ifdef LOBLK X { "LOBLK", LOBLK }, X#endif /* LOBLK */ X { NULLPTR, 0 }, X}; X XSYMTAB lmodes[] = { X { "ISIG", ISIG }, X { "ICANON", ICANON }, X { "XCASE", XCASE }, X { "ECHO", ECHO }, X { "ECHOE", ECHOE }, X { "ECHOK", ECHOK }, X { "ECHONL", ECHONL }, X { "NOFLSH", NOFLSH }, X#ifdef XCLUDE X { "XCLUDE", XCLUDE }, X#endif /* XCLUDE */ X { NULLPTR, 0 } X}; X XSYMTAB ldiscs[] = { X { "LDISC0", LDISC0 }, X { NULLPTR, 0 } X}; X X/* X * Gettytab entry to use if no other can be determined X */ XGTAB Default = { X "default", X { 0, 0, ( SSPEED | CSANE ), 0, 0, CC_SANE, }, X { ISANE, OSANE, ( SSPEED | CSANE ), LSANE, LDISC0, CC_SANE, }, X "login: ", X "default" X}; X X#define VALUE(cptr) ((cptr == (char *) NULL) ? "NULL" : cptr) X Xint errors = 0; X Xint nextentry(), parseGtab(), findsym(); Xchar *nextword(); Xvoid addfield(), chkerr(); X X X/* X** gtabvalue() - find a gettytab entry that matches "id." X** X** Returns (GTAB *)NULL if not found or an error occurs. X*/ X XGTAB * Xgtabvalue(id) XReg1 char *id; X{ X Reg2 int state; X Reg3 char *p; X Reg4 char *gettytab; /* gettytab file to use */ X STDCHAR buf[MAXLINE+1]; /* buffer for Gtab entries */ X char buf_id[MAXID+1]; /* buffer to compare initial label */ X char *this = "First"; /* First or Next entry */ X static GTAB gtab; /* structure to be returned */ X FILE *fp; X X debug3(D_GTAB, "gtabvalue(%s) called\n", VALUE(id)); X X gettytab = (Check) ? CheckFile : GETTYTAB; X debug3(D_GTAB, "gettytab=%s\n", gettytab); X X /* open the gettytab file X */ X if ((fp = fopen(gettytab, "r")) == (FILE *) NULL) { X (void) sprintf(MsgBuf, "cannot open %s", gettytab); X logerr(MsgBuf); X return(&Default); X } X X /* search through the file for "id", unless X * id is NULL, in which case we drop down X * to get the 'default' entry. X */ X state = (!Check && (id == (char *) NULL)) ? QUIT : ENTRY; X X while (state != QUIT && nextentry(buf, sizeof(buf), fp) == SUCCESS) { X if (buf[0] == '#' || buf[0] == '\n') X continue; /* keep looking */ X if (Check) { X (void) printf("*** %s Entry ***\n", this); X (void) printf("%s\n", buf); X this = "Next"; X } X if (buf[strlen(buf)-1] != '\n') { X /* last char not \n, line is too long */ X chkerr("line too long", FAIL); X state = QUIT; X continue; X } X /* get the first (label) field X */ X (void) strncpy(buf_id, buf, MAXID); X if ((p = strtok(buf_id, "# \t")) != (char *) NULL) X *(--p) = '\0'; X /* if Check is set, parse all entries; X * otherwise, parse only a matching entry X */ X if (Check || strequal(id, buf_id)) { X if (parseGtab(>ab, buf) == FAIL) { X chkerr("*** Invalid Entry ***", FAIL); X state = QUIT; X continue; X } X if (!Check) { X (void) fclose(fp); X return(>ab); X } X } X } X X if (Check) { X if (errors) X (void) printf("*** %d errors found ***\n", errors); X (void) printf("*** Check Complete ***\n"); X (void) fclose(fp); X return((GTAB *) NULL); X } X X /* matching entry not found or defective; X * use the first line of the file X */ X if (id != (char *) NULL) { X (void) sprintf(MsgBuf, "%s entry for \"%s\" not found", X gettytab, id); X logerr(MsgBuf); X } X rewind(fp); X (void) nextentry(buf, sizeof(buf), fp); X (void) fclose(fp); X if (parseGtab(>ab, buf) == FAIL) X return(&Default); /* punt: first line defective */ X X debug2(D_GTAB, "gtabvalue() successful\n"); X return(>ab); X} X X X/* X** nextentry() - retrieve next entry from gettytab file X** X** Returns FAIL if an error occurs. X*/ X Xint Xnextentry(buf, len, stream) XReg1 char *buf; XReg2 int len; XFILE *stream; X{ X Reg3 int count = 0; X STDCHAR line[MAXLINE+1]; X X *buf = '\0'; /* erase buffer */ X X while (fgets(line, sizeof(line), stream) != (char *) NULL) { X debug2(D_GTAB, "line read = ("); X debug1(D_GTAB, line); X debug2(D_GTAB, ")\n"); X if (count) X buf[strlen(buf)-1] = '\0'; X if ((count += strlen(line)) >= len) X return(FAIL); /* entry too long */ X (void) strcat(buf, line); X if (line[0] == '\n') X return(SUCCESS); /* blank line */ X } X X return(QUIT); X} X X X/* X** parseGtab() - fill in GTAB structure from buffer X** X** Returns FAIL if an error occurs. X*/ X Xint XparseGtab(gtab, line) XGTAB *gtab; XReg1 char *line; X{ X Reg2 int field; X Reg3 char *p; X static int count; X static char p_cur[MAXID+1], p_next[MAXID+1]; X static char p_login[MAXLOGIN+1]; X X debug2(D_GTAB, "parseGtab() called\n"); X X /* initialize gtab to empty X */ X gtab->cur_id = (char *) NULL; X gtab->itermio.c_iflag = 0; X gtab->itermio.c_oflag = 0; X gtab->itermio.c_cflag = 0; X gtab->itermio.c_lflag = 0; X gtab->itermio.c_line = 0; X gtab->ftermio.c_iflag = 0; X gtab->ftermio.c_oflag = 0; X gtab->ftermio.c_cflag = 0; X gtab->ftermio.c_lflag = 0; X gtab->ftermio.c_line = 0; X gtab->login = (char *) NULL; X gtab->next_id = (char *) NULL; X X if (LineD != (char *) NULL) { /* line disc given on command line */ X addfield(&(gtab->itermio), LineD); X addfield(&(gtab->ftermio), LineD); X } X X /* parse the line X */ X debug2(D_GTAB, "parsing line:\n"); X field = 1; X while (field != FAIL && field != SUCCESS) { X if ((p = nextword(line, &count)) == (char *) NULL) { X field = FAIL; X continue; X } X debug4(D_GTAB, "field=%d, nextword=(%s)\n", field, p); X switch (field) { X case 1: X /* cur_id label X */ X (void) strncpy(p_cur, p, MAXID); X gtab->cur_id = p_cur; X field++; X break; X case 2: X /* '#' field separator X */ X if (*p != '#') { X field = FAIL; X continue; X } X field++; X break; X case 3: X /* initial termio flags X */ X if (*p == '#') X field++; X else X addfield(&(gtab->itermio), p); X break; X case 4: X /* final termio flags X */ X if (*p == '#') X field++; X else X addfield(&(gtab->ftermio), p); X break; X case 5: X /* login message -- X * nextword won't be the whole message; look X * ahead to the next '#' and terminate string there X */ X if ((p = strchr(line, '#')) == (char *) NULL) { X field = FAIL; X continue; X } X *p = '\0'; X p = line; /* point p to line again */ X count = strlen(p)+1; /* adjust count accordingly */ X debug3(D_GTAB, "login=(%s)\n", p); X (void) strncpy(p_login, p, MAXLOGIN); X gtab->login = p_login; X field++; X break; X case 6: X /* next_id label X */ X (void) strncpy(p_next, p, MAXID); X gtab->next_id = p_next; X field = SUCCESS; X continue; X } X /* skip over word just processed X */ X line += count; X } X X if (Check) { X (void) printf("id: \"%s\"\n", gtab->cur_id); X (void) printf("initial termio flags:\n"); X (void) printf(" iflag: %o, oflag: %o, cflag: %o, lflag: %o\n", X gtab->itermio.c_iflag, gtab->itermio.c_oflag, X gtab->itermio.c_cflag, gtab->itermio.c_lflag); X (void) printf(" line disc: %o\n", gtab->itermio.c_line); X (void) printf("final termio flags:\n"); X (void) printf(" iflag: %o, oflag: %o, cflag: %o, lflag: %o\n", X gtab->ftermio.c_iflag, gtab->ftermio.c_oflag, X gtab->ftermio.c_cflag, gtab->ftermio.c_lflag); X (void) printf(" line disc: %o\n", gtab->ftermio.c_line); X (void) printf("login prompt: \"%s\"\n", gtab->login); X (void) printf("next id: \"%s\"\n\n", gtab->next_id); X } X X return(field); X} X X X/* X** nextword() - get next "word" from buffer X*/ X Xchar * Xnextword(buf, count) XReg1 char *buf; XReg4 int *count; X{ X Reg2 int num = 0; X Reg3 char *p; X static char word[MAXLINE+1]; X X while (*buf == ' ' || *buf == '\t' || *buf == '\\' || X *buf == '\n') { /* skip leading whitespace */ X buf++; num++; X } X p = word; X if (*buf == '#') { /* first char is '#' ? */ X *p++ = *buf; X num++; X } else { X while (*buf != ' ' && *buf != '\t' && *buf != '\\' && X *buf != '#' && *buf != '\n') { X *p++ = *buf++; X num++; X } X } X *p = '\0'; X *count = num; X return(word); X} X X X/* X** addfield() - add symbol to termio structure X*/ X Xvoid Xaddfield(termio, field) XReg2 TERMIO *termio; XReg3 char *field; X{ X Reg1 int val; X X if (strequal(field, "SANE")) { X termio->c_iflag |= ISANE; X termio->c_oflag |= OSANE; X termio->c_cflag |= CSANE; X termio->c_lflag |= LSANE; X } else { X if ((val = findsym(field, imodes)) != FAIL) X termio->c_iflag |= (ushort) val; X else if ((val = findsym(field, omodes)) != FAIL) X termio->c_oflag |= (ushort) val; X else if ((val = findsym(field, cmodes)) != FAIL) X termio->c_cflag |= (ushort) val; X else if ((val = findsym(field, lmodes)) != FAIL) X termio->c_lflag |= (ushort) val; X else if ((val = findsym(field, ldiscs)) != FAIL) X termio->c_line |= (ushort) val; X else if (Check) { X (void) sprintf(MsgBuf, "undefined symbol: %s", field); X chkerr(MsgBuf, OK); X } X } X} X X X/* X** findsym() - look for field in SYMTAB list X*/ X Xint Xfindsym(field, symtab) XReg1 char *field; XReg2 SYMTAB *symtab; X{ X for (; symtab->symbol != (char *) NULL; symtab++) X if (strequal(symtab->symbol, field)) X return((int) symtab->value); X X return(FAIL); X} X X X/* X** chkerr() - display error message from check routines X*/ X Xvoid Xchkerr(msg, status) Xchar *msg; Xint status; X{ X (void) printf("*** parsing error: %s ***\n", msg); X if (status) X (void) printf("*** checking halted ***\n"); X else X (void) printf("*** checking continued ***\n"); X X errors++; X} X X X/* end of table.c */ !STUFFY!FUNK! echo Extracting defaults.c sed >defaults.c <<'!STUFFY!FUNK!' -e 's/X//' X/* X** $Id: defaults.c,v 1.1 90/01/16 16:13:23 paul Exp Locker: paul $ X** X** Routines to access runtime defaults file. X** This is to allow program features to be configured X** without the need to recompile. X** X** XENIX has defopen(S) and defread(S), but I think this is better, X** since it reads the file only once, storing the values in core. X** It is certainly more portable. X*/ X X/* X** Copyright 1989,1990 by Paul Sutcliffe Jr. X** X** Permission is hereby granted to copy, reproduce, redistribute, X** or otherwise use this software as long as: there is no monetary X** profit gained specifically from the use or reproduction or this X** software, it is not sold, rented, traded or otherwise marketed, X** and this copyright notice is included prominently in any copy X** made. X** X** The author make no claims as to the fitness or correctness of X** this software for any use whatsoever, and it is provided as is. X** Any use of this software is at the user's own risk. X*/ X X/* X** $Log: defaults.c,v $ X** Revision 1.1 90/01/16 16:13:23 paul X** Initial revision X** X*/ X X X#include "getty.h" X#include "defaults.h" X#include <sys/stat.h> X#include <errno.h> X X#if defined(RCSID) && !defined(lint) Xstatic char *RcsId = X"@(#)$Id: defaults.c,v 1.1 90/01/16 16:13:23 paul Exp Locker: paul $"; X#endif X X#ifndef DEFAULTS X#define DEFAULTS "/etc/default/%s" /* location of defaults file */ X#endif /* DEFAULTS */ X X#ifndef MAXLINE X#define MAXLINE 256 /* maximum # chars in a line */ X#endif /* MAXLINE */ X X#ifndef MAXDEF X#define MAXDEF 100 /* maximum # of lines in defaults file */ X#endif /* MAXDEF */ X X X/* X** defbuild() - create in-core list of defaults X** X** Returns (DEF**)NULL if no defaults file found or an error occurs. X*/ X XDEF ** Xdefbuild(filename) Xchar *filename; X{ X Reg1 int i; X Reg2 DEF *dp; X Reg3 DEF *next; X FILE *fp; X char *fname, defname[MAXLINE+1], buf[MAXLINE+1]; X static DEF *deflist[MAXDEF+1]; /* in-core list */ X struct stat st; X extern int errno; X X debug3(D_DEF, "defbuild(%s) called\n", X ((filename == (char *) NULL) ? "NULL" : filename)); X X /* look to see if there's a DEFAULTS/MyName.Device file X */ X (void) sprintf(buf, "%s", DEFAULTS); X (void) strcat(buf, ".%s"); X (void) sprintf(defname, buf, MyName, Device); X debug3(D_DEF, "looking for %s\n", defname); X if ((stat(defname, &st) == FAIL) && errno == ENOENT) { /* Nope */ X debug2(D_DEF, "stat failed, no file\n"); X (void) sprintf(defname, DEFAULTS, MyName); X } X X fname = (filename != (char *) NULL) ? filename : defname; X X /* if fname doesn't begin with a '/', assume it's a X * filename to be made "DEFAULTS/fname" X */ X if (*fname != '/') { X (void) sprintf(defname, DEFAULTS, fname); X fname = defname; X } X X debug3(D_DEF, "fname = (%s)\n", fname); X X if ((fp = defopen(fname)) == (FILE *) NULL) { X debug2(D_DEF, "defopen() failed\n"); X return((DEF **) NULL); /* couldn't open file */ X } X X for (i=0; i < MAXDEF; i++) { X if ((dp = defread(fp)) == (DEF *) NULL) X break; X if ((next = (DEF *) malloc((unsigned) sizeof(DEF))) == X (DEF *) NULL) { X logerr("malloc() failed: defaults list truncated"); X break; X } X next->name = dp->name; X next->value = dp->value; X deflist[i] = next; X debug5(D_DEF, "deflist[%d]: name=(%s), value=(%s)\n", X i, deflist[i]->name, deflist[i]->value); X } X deflist[i] = (DEF *) NULL; /* terminate list */ X (void) defclose(fp); X debug2(D_DEF, "defbuild() successful\n"); X return(deflist); X} X X X/* X** defvalue() - locate the value in "deflist" that matches "name" X** X** Returns (char*)NULL if no match is made. X*/ X Xchar * Xdefvalue(deflist, name) XReg1 DEF **deflist; XReg2 char *name; X{ X debug3(D_DEF, "defvalue(%s) called\n", name); X X if (deflist != (DEF **) NULL) X for (; *deflist != (DEF *) NULL; *deflist++) X if (strequal(name, (*deflist)->name)) { X debug3(D_DEF, "defvalue returns (%s)\n", X (*deflist)->value); X return((*deflist)->value); /* normal exit */ X } X X debug2(D_DEF, "defvalue returns NULL\n"); X return((char *) NULL); X} X X X/* X** defopen() - open the defaults file X** X** Returns (FILE*)NULL if file not found or an error occurs. X*/ X XFILE * Xdefopen(filename) XReg1 char *filename; X{ X if (filename != (char *) NULL) X return(fopen(filename, "r")); X X return((FILE *) NULL); X} X X X/* X** defread() - read a line from the defaults file X** X** Returns (DEF*)NULL if an error occurs. X*/ X XDEF * Xdefread(fp) XReg2 FILE *fp; X{ X Reg1 char *p; X STDCHAR buf[MAXLINE+1]; /* buffer large enough for 1 line */ X static DEF def; X X do { X if (fgets(buf, sizeof(buf), fp) == (char *) NULL) X return((DEF *) NULL); /* no more lines */ X X } while (buf[0] == '#'); /* ignore comment lines */ X X buf[strlen(buf)-1] = '\0'; /* rm trailing \n */ X X /* lines should be in the form "NAME=value" X */ X if ((p = strchr(buf, '=')) == (char *) NULL) { X (void) sprintf(MsgBuf, "bad defaults line: %s", buf); X logerr(MsgBuf); X return((DEF *) NULL); X } X *p++ = '\0'; /* split into two fields, name and value */ X def.name = strdup(buf); X def.value = strdup(p); X X return(&def); X} X X X/* X** defclose() - closes the defaults file X** X** Returns EOF if an error occurs. X*/ X Xint Xdefclose(fp) XReg1 FILE *fp; X{ X return(fclose(fp)); X} X X X/* end of defaults.c */ !STUFFY!FUNK! echo Extracting man/gettytab.m4 sed >man/gettytab.m4 <<'!STUFFY!FUNK!' -e 's/X//' X.\" +---------- X.\" | $Id: gettytab.m4,v 1.1 90/01/16 16:02:17 paul Exp Locker: paul $ X.\" | X.\" | GETTYTAB man page. X.\" | X.\" | Copyright 1989,1990 by Paul Sutcliffe Jr. X.\" | X.\" | Permission is hereby granted to copy, reproduce, redistribute, X.\" | or otherwise use this software as long as: there is no monetary X.\" | profit gained specifically from the use or reproduction or this X.\" | software, it is not sold, rented, traded or otherwise marketed, X.\" | and this copyright notice is included prominently in any copy X.\" | made. X.\" | X.\" | The author make no claims as to the fitness or correctness of X.\" | this software for any use whatsoever, and it is provided as is. X.\" | Any use of this software is at the user's own risk. X.\" | X.\" X.\" +---------- X.\" | $Log: gettytab.m4,v $ X.\" | Revision 1.1 90/01/16 16:02:17 paul X.\" | Initial revision X.\" | X.\" | X.\" X.\" +---------- X.\" | M4 configuration X.\" Xinclude(config.m4).\" X.\" X.\" define(`_temp_', maketemp(m4bXXXXX)) X.\" syscmd(echo _gtab_ | tr "[a-z]" "[A-Z]" | tr -d "\012" > _temp_) X.\" define(`_GTAB_', include(_temp_)) X.\" syscmd(rm -f _temp_) X.\" X.\" +---------- X.\" | Manpage source follows: X.\" X.TH _GTAB_ _file_section_ X.SH NAME X_gtab_ \- speed and tty settings used by getty X.SH DESCRIPTION XThe file X.B _gettytab_ Xcontains information used by X.I getty(_mcmd_section_) Xto set up the speed and tty settings for a line. It supplies Xinformation on what the X.I login-prompt Xshould look like. It also supplies the speed to try next if Xthe user indicates the current speed is not correct by typing a X.I <break> Xcharacter. X.PP XEach entry in X.B _gettytab_ Xhas the following format: X X.in +.2i X.ll 7.5i Xlabel# initial-flags # final-flags # login-prompt #next-label X.ll X.in -.2i X XEach entry is followed by a blank line. Lines that begin with X.B \# Xare ignored and may be used to comment the file. The various Xfields can contain quoted characters of the form X.B \\\\b\fR, \fB\\\\n\fR, \fB\\\\c\fR, Xetc., as well as X.B \\\\\fInnn\fR, Xwhere X.I nnn Xis the octal value of the desired character. The various fields are: X.TP 16 X.I label XThis is the string against which X.I getty Xtries to match its second argument. It is often the speed, such as X.B 1200\fR, Xat which the terminal is supposed to run, but it needn't be (see below). X.TP X.I initial-flags XThese flags are the initial X.I ioctl(_system_section_) Xsettings to which the terminal is to be set if a terminal type is Xnot specified to X.I getty\fR. X.I Getty Xunderstands the symbolic names specified in X.B /usr/`include'/termio.h X(see X.\" +---------- X.\" | M4_start (trs16) Xifdef(`trs16', X.I tty`('_misc_section_`)).', X.\" | else (trs16) X.I termio`('_misc_section_`)).') X.\" | M4_end (trs16) X.\" +---------- XNormally only the speed flag is required in the X.I initial-flags Xfield. X.I Getty Xautomatically sets the terminal to raw input mode and takes care of Xmost of the other flags. The X.I initial-flag Xsettings remain in effect until X.I getty Xexecutes X.I login(_mcmd_section_). X.TP X.I final-flags XThese flags take the same values as the X.I initial-flags Xand are set just prior to X.I getty Xexecutes X.B _login_\fR. XThe speed flag is again required. The composite flag X.B SANE Xtakes care of most of the other flags that need to be set so that Xthe processor and terminal are communicating in a rational fashion. XThe other two commonly specified X.I final-flags Xare X.B TAB3\fR, Xso that tabs are sent to the terminal as spaces, and X.B HUPCL\fR, Xso that the line is hung up on the final close. X.TP X.I login-prompt XThis entire field is printed as the X.I login-prompt\fR. XUnlike the above fields where white space is ignored (a space, Xtab or new-line), they are included in the X.I login-prompt Xfield. X XThe X.I login-prompt Xmay contain various X.B @\fIchar\fR Xand X.B \\\\\fIchar\fR Xparameters. These are described in full in the X.I getty(_mcmd_section_) Xsection PROMPT SUBSTITUTIONS. X.TP X.I next-label XThis indicates the next X.I label Xof the entry in the table that X.I getty Xshould use if the user types a X.I <break> Xor the input cannot be read. Usually, a series of speeds are linked Xtogether in this fashion, into a closed set. For instance, X.B 2400 Xlinked to X.B 1200\fR, Xwhich in turn is linked to X.B 300\fR, Xwhich finally is linked back to X.B 2400\fR. X.P XIf X.I getty Xis called without a X.I speed Xargument, then the first entry of X.B _gettytab_ Xis used, thus making the first entry of X.B _gettytab_ Xthe default entry. It is also used if X.I getty Xcan't find the specified X.I label. XIf X.B _gettytab_ Xitself is missing, there is one entry built into X.I getty Xwhich will bring up a terminal at X.B 9600 Xbaud. X.P XIt is strongly recommended that after making or modifying X.B _gettytab_`,' Xit be run through X.I getty Xwith the check (\fB-c\fR) option to be sure there are no errors. X.SH FILES X_gettytab_ X.SH "SEE ALSO" Xlogin(_mcmd_section_), Xgetty(_mcmd_section_), Xioctl(_system_section_), X.\" +---------- X.\" | M4_start (trs16) Xifdef(`trs16', Xtty`('_misc_section_`)', X.\" | else (trs16) Xtermio`('_misc_section_`)') X.\" | M4_end (trs16) X.\" +---------- !STUFFY!FUNK! echo Extracting config.h.SH sed >config.h.SH <<'!STUFFY!FUNK!' -e 's/X//' X: X# $Id: config.h.SH,v 1.1 90/01/16 16:13:03 paul Exp Locker: paul $ X# X# Creates config.h file for getty distribution X# X# $Log: config.h.SH,v $ X# Revision 1.1 90/01/16 16:13:03 paul X# Initial revision X# X# X Xcase $CONFIG in X'') X if test ! -f config.sh; then X ln ../config.sh . || \ X ln ../../config.sh . || \ X ln ../../../config.sh . || \ X (echo "Can't find config.sh."; exit 1) X fi X . config.sh X ;; Xesac Xcase "$0" in X*/*) cd `expr X$0 : 'X\(.*\)/'` ;; Xesac Xecho "Extracting config.h (with variable substitutions)" X$spitshell >config.h <<!GROK!THIS! X/* X** config.h X** X** Getty configuration. X*/ X X/* X** Copyright 1989,1990 by Paul Sutcliffe Jr. X** X** Permission is hereby granted to copy, reproduce, redistribute, X** or otherwise use this software as long as: there is no monetary X** profit gained specifically from the use or reproduction or this X** software, it is not sold, rented, traded or otherwise marketed, X** and this copyright notice is included prominently in any copy X** made. X** X** The author make no claims as to the fitness or correctness of X** this software for any use whatsoever, and it is provided as is. X** Any use of this software is at the user's own risk. X*/ X X X#include "tune.h" /* defs needed below */ X X X/* These are set by config.sh. X * If you change them here, they will be reset X * the next time you run Configure. X */ X X#$define Reg1 $reg1 /* register declarations */ X#$define Reg2 $reg2 X#$define Reg3 $reg3 X#$define Reg4 $reg4 X#$define Reg5 $reg5 X#$define Reg6 $reg6 X#$define Reg7 $reg7 X#$define Reg8 $reg8 X#$define Reg9 $reg9 X#$define Reg10 $reg10 X#$define Reg11 $reg11 X#$define Reg12 $reg12 X#$define Reg13 $reg13 X#$define Reg14 $reg14 X#$define Reg15 $reg15 X#$define Reg16 $reg16 X X#$d_portable PORTABLE /* compile for more than one site */ X#$d_getutent GETUTENT /* we have getutent() and friends */ X#$d_strdup STRDUP /* we have strdup() */ X#$d_putenv PUTENV /* we have putenv() */ X X#$d_ttytype TTYTYPE "$ttytype" /* file used to identify terminals */ X#$define GETTYTAB "$gettytab" /* file used for speed/termio table */ X X#$define STDCHAR $stdchar /* signed or unsigned chars in stdio */ X#$define UIDTYPE $uidtype /* storage type of UID's */ X#$define GIDTYPE $gidtype /* storage type of GID's */ X X#$d_voidsig VOIDSIG /* you have 'void (*signal)()' */ X X#ifdef VOIDSIG /* define sig_t appropriately */ Xtypedef void sig_t; X#else /* VOIDSIG */ Xtypedef int sig_t; X#endif /* VOIDSIG */ X X#ifndef VOIDUSED X#$define VOIDUSED $defvoidused X#endif X#$define VOIDFLAGS $voidflags X#if (VOIDFLAGS & VOIDUSED) != VOIDUSED X#$define void int /* is void to be avoided? */ X#$define M_VOID /* Xenix strikes again */ X#endif X X#ifndef PORTABLE X#$define HOSTNAME "$hostname" /* compile node name in */ X#else X#$d_douname DOUNAME /* use uname() to get node name */ X#$d_phostname PHOSTNAME "$phostname" /* get node name from this command */ X#endif X X#ifndef UTMP_FILE X#$define UTMP_FILE "$utmp" /* name of the utmp file */ X#endif X X#ifdef LOGUTMP X#ifndef WTMP_FILE X#$define WTMP_FILE "$wtmp" /* name of the wtmp file */ X#endif /* WTMP_FILE */ X#endif /* LOGUTMP */ X X#ifdef TRYMAIL X#$define MAILER "$mailer" /* mail agent */ X#endif X X#ifdef UUGETTY X#$d_asciipid ASCIIPID /* PID stored in ASCII in lock file */ X#$define LOCK "$lock/LCK..%s" /* lock file name */ X#$define UUCPID $uucpid /* uid of UUCP account */ X#endif X X X/* end of config.h */ X!GROK!THIS! Xchmod 644 config.h X$eunicefix config.h !STUFFY!FUNK! echo Extracting putenv.c sed >putenv.c <<'!STUFFY!FUNK!' -e 's/X//' X/* X** $Id: putenv.c,v 1.1 90/01/16 16:17:33 paul Exp Locker: paul $ X** X** Implements putenv(3c). X*/ X X/* X** Copyright 1989,1990 by Paul Sutcliffe Jr. X** X** Permission is hereby granted to copy, reproduce, redistribute, X** or otherwise use this software as long as: there is no monetary X** profit gained specifically from the use or reproduction or this X** software, it is not sold, rented, traded or otherwise marketed, X** and this copyright notice is included prominently in any copy X** made. X** X** The author make no claims as to the fitness or correctness of X** this software for any use whatsoever, and it is provided as is. X** Any use of this software is at the user's own risk. X*/ X X/* X** $Log: putenv.c,v $ X** Revision 1.1 90/01/16 16:17:33 paul X** Initial revision X** X*/ X X X#include "getty.h" X X#if defined(RCSID) && !defined(lint) Xstatic char *RcsId = X"@(#)$Id: putenv.c,v 1.1 90/01/16 16:17:33 paul Exp Locker: paul $"; X#endif X X#ifndef MAXENV X#define MAXENV 64 /* max # lines in envorinment */ X#endif /* MAXENV */ X X X/* X** putenv() - change or add value to environment X** X** Returns non-zero if an error occurrs, zero otherwise. X*/ X Xextern char **environ; X Xint Xputenv(s) Xchar *s; X{ X Reg1 int i; X Reg2 char *p; X char *q, **envp, *env[MAXENV]; X boolean match = FALSE; X X if (s == (char *) NULL) X return(FAIL); /* can't add NULL to the environment */ X X if ((p = malloc((unsigned) strlen(s)+1)) == (char *) NULL) X return(FAIL); /* malloc failed */ X X (void) strcpy(p, s); X if ((q = strchr(p, '=')) == (char *) NULL) { X free(p); X return(FAIL); /* not in the form ``name=value'' */ X } X X *q = '\0'; /* split into two fields, name & value */ X X /* copy the environ list, replacing `s' if a match is found X */ X for (i=0, envp=environ; *envp != (char *) NULL; i++, envp++) { X if (strnequal(*envp, p, strlen(p))) { X match = TRUE; X env[i] = s; X } else X env[i] = *envp; X } X X if (!match) { X *q = '='; /* put back the equal sign */ X env[i++] = p; /* add p to env list */ X } else X free(p); /* not needed, s replaced old value */ X X env[i++] = (char *) NULL; X X /* now dup env to make new environment X */ X if ((envp = (char **) malloc((unsigned) (i*sizeof(char *)))) == X (char **) NULL) { X return(FAIL); X } X environ = envp; /* point to new area */ X for (i=0; env[i] != (char *) NULL; i++) X *envp++ = env[i]; X *envp = (char *) NULL; X X return(SUCCESS); X} X X X/* end of putenv.c */ !STUFFY!FUNK! echo "" echo "End of kit 3 (of 4)" cat /dev/null >kit3isdone run='' config='' for iskit in 1 2 3 4; do if test -f kit${iskit}isdone; then run="$run $iskit" else todo="$todo $iskit" fi done case $todo in '') echo "You have run all your kits. Please read README and then type Configure." chmod 755 Configure ;; *) echo "You have run$run." echo "You still need to run$todo." ;; esac : Someone might mail this, so... exit INTERNET: paul at devon.lns.pa.us | If life's a bitch, then UUCP: ...!rutgers!devon!paul | we must be her puppies. From barton at holston.UUCP Sat Jan 20 05:37:14 1990 From: barton at holston.UUCP (Barton A. Fisk) Date: 19 Jan 90 18:37:14 GMT Subject: Getting the time over the phone from NBS References: <1043@khijol.UUCP> <899@tridom.uucp> <BOB.90Jan17123008@volitans.MorningStar.Com> Message-ID: <5667@holston.UUCP> Hey, this program is really spiffy, but what exactly is NBS? I am assuming it's a standard time sort of system, could some- one expound a bit for me and others who don't know? Thanks for the program... -- Barton A. Fisk | UUCP: {attctc,texbell}vector!holston!barton PO Box 1781 | (PSEUDO) DOMAIN: barton at holston.UUCP Lake Charles, La. 70602 | ---------------------------------------- 318-439-5984 | "Let him who is without sin cast the first stone"-JC From LC.YRS at forsythe.stanford.edu Thu Jan 11 18:34:52 1990 From: LC.YRS at forsythe.stanford.edu (Richard Stanton) Date: 11 Jan 90 07:34:52 GMT Subject: Wanted: 1990 'sc' 1040 forms Message-ID: <7076@lindy.Stanford.EDU> In article <MDF0.90Jan9121142 at shemesh.gte.com>, mdf0 at shemesh.gte.com (Mark Feblowitz) writes: >For a while, someone was distributing 1040 and related forms for the >"sc" public domain spreadsheet calculator. Is anyone revising these >forms for 1990? > I'm impressed to see someone ready to do his 1990 tax return already. Where can one get hold of the "sc" public domain spreadsheet calculator? Thanks Richard Stanton From tneff at bfmny0.UU.NET Wed Jan 10 08:17:10 1990 From: tneff at bfmny0.UU.NET (Tom Neff) Date: 9 Jan 90 21:17:10 GMT Subject: laston.c - determine last time user has logged on References: <1540@lakesys.lakesys.com> Message-ID: <15082@bfmny0.UU.NET> In article <1540 at lakesys.lakesys.com> davek at lakesys.lakesys.com (Dave Kraft) writes: >Here's a little something I wrote to help me determine when I've last logged >on... Perhaps a bit overdone? How about #! /bin/sh lof=$HOME/.laston test -f $lof && echo "Last on: "`cat $lof` date > $lof -- 'We have luck only with women -- not spacecraft!' \\ Tom Neff -- R. Kremnev, builder of failed Soviet FOBOS probes // tneff at bfmny0.UU.NET From jms at close.cs.columbia.edu Thu Jan 18 06:10:25 1990 From: jms at close.cs.columbia.edu (Jonathan M. Smith) Date: 17 Jan 90 19:10:25 GMT Subject: Another "Rapid Location of Mount Points" Message-ID: <6705@columbia.edu> # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by Jonathan M. Smith <jms at close> on Wed Jan 17 14:07:08 1990 # # This archive contains: # README Script defs.h dev_tab.c # direct.c getmnt.c makefile namelist.c # ngetmnt.c print.c tree.c util.c # xgetmnt.c # LANG=""; export LANG PATH=/bin:/usr/bin:$PATH; export PATH echo x - README cat >README <<'@EOF' These are the various versions of "getmnt" described in the article "Rapid Location of Mount Points", by me, in the September 1989 issue of Software - Practice and Experience. getmnt.c is the source for getmnt1 of the article ngetmnt.c is the source for getmnt2 of the article and the remaining source is for getmnt3 of the article. Script was used for running the tests, and makefile makes the various executables. Since the programs were developed for high performance in a production environment (System V UNIX on VAXen), there are various non-portabilities. My current address is (for questions, comments, et cetera): Jonathan M. Smith Asst. Prof., Dept. CIS Univ. of Penn., 200 South 33rd St., Phila., PA 19104-6389 (215) 898-9509 jms at dsl.cis.upenn.edu @EOF chmod 666 README echo x - Script cat >Script <<'@EOF' # # location of executables # DIR=/pkg/bcrcc/tst_spe.d # # initial setup work # cd ${DIR} /bin/make -f makefile clean /bin/make -f makefile getmnt ngetmnt xgetmnt # # begin by initializing namelist data for [nx]getmnt # ${DIR}/ngetmnt >/dev/null ${DIR}/xgetmnt >/dev/null # # create the output file, which will contain the timings. # /bin/uname -a >/tmp/output # # now flush buffers, so that buffer cache does not # interfere with timing. # ulimit 300000 /bin/dd if=/dev/mem of=/tmp/file bs=128k count=20 /bin/sync /bin/rm -f /tmp/file /usr/bin/timex ${DIR}/getmnt >/dev/null 2>>/tmp/output /bin/dd if=/dev/mem of=/tmp/file bs=128k count=20 /bin/sync /bin/rm -f /tmp/file /usr/bin/timex ${DIR}/ngetmnt >/dev/null 2>>/tmp/output /bin/dd if=/dev/mem of=/tmp/file bs=128k count=20 /bin/sync /bin/rm -f /tmp/file /usr/bin/timex ${DIR}/xgetmnt >/dev/null 2>>/tmp/output /bin/sync /bin/make -f makefile clean /bin/mail pyuxe!smith </tmp/output @EOF chmod 666 Script echo x - defs.h cat >defs.h <<'@EOF' # include <stdio.h> # include <fcntl.h> # include <sys/var.h> # include <sys/types.h> # include <sys/stat.h> # include <sys/dir.h> # include <sys/inode.h> # include <sys/buf.h> # include <sys/mount.h> # include <sys/sysmacros.h> #define EOS '\0' /* End of String */ #define SLASH '/' /* separates directory components */ #define ROOT_DIR "/" #define DEV_DIR "/dev/dsk" /* /dev/dsk saves search of /dev, less general */ #define DEV "/dev" #define DEV_LEN (4) /* strlen("/dev") */ #define UNIX "/unix" #define KMEM "/dev/kmem" #define NL_FILE "/letc/xgetmnt_nlist" #define VMASK 0x3fffffff /* VAX address mask */ #define HASHSIZE 128 /* size, table for directory structures */ #define MAX_DIRS (128) /* maximum *printable* number of directories */ /* in a path */ #ifndef brdev # ifdef u3b2 # define brdev(x) ((int)(x)&0xFF) # else # define brdev(x) ((int)(x)&0x7F) # endif #endif struct node { dev_t n_dev; char *n_name; struct node *n_next; struct node *n_prev; struct node *n_parent; }; struct device { dev_t d_number; /* device number */ short d_flags; /* mainly to indicate DELETED */ #define NO_FLAGS (0) #define IN_TREE (1) #define DELETED (2) char *d_name; /* device pathname */ struct device *d_parent;/* parent device in tree */ struct device *d_next; /* used for hashlist maintenance */ struct device *d_children; /* children of this device in tree */ struct device *d_next_child; /* siblings of this device in tree */ }; struct device *lookup(); extern char *strsave(), *emalloc(), *malloc(); #include <a.out.h> /* deal with stupidity in sym.h */ #ifdef n_name # undef n_name #endif /* indices for elements of Namelist structure in namelist.c */ #define MOUNT 0 #define V 1 /* stuff for directory management routines */ typedef struct _dirdesc { int dd_fd; long dd_loc; long dd_size; long dd_bbase; long dd_entno; long dd_bsize; char *dd_buf; } DIR; extern DIR *opendir(); extern struct direct *readdir(); extern long telldir(); extern void seekdir(); #define rewinddir(dirp) seekdir( (dirp), (long) 0) extern void closedir(); #define TRUE 1 #define FALSE 0 @EOF chmod 666 defs.h echo x - dev_tab.c cat >dev_tab.c <<'@EOF' #include "defs.h" /* Devnames should contain regular expressions * which characterize block * special files containing file systems. * The last entry should be a null string. */ char *Devnames[] = { "/dev/dsk/*", "" }; struct device *new_device(), *Hashtab[HASHSIZE]; struct device * lookup( device ) dev_t device; { register struct device *ptr; register int index; index = hash( (int)device ); for( ptr = Hashtab[ index ]; ptr != (struct device *)NULL; ptr = ptr->d_next ) { if( ptr->d_number == device ) break; } return( ptr ); } int hash( j ) int j; { return( ( 7*j ) % HASHSIZE ); } insert( dev_name ) char *dev_name; { struct stat stat_buf; int index, hash(); struct device *ptr, *lookup(); if( !valid_name( dev_name ) ) return; stat( dev_name, &stat_buf ); if( lookup( brdev(stat_buf.st_rdev) ) == (struct device *) NULL ) { index = hash( (int)brdev(stat_buf.st_rdev) ); ptr = new_device( (int)brdev(stat_buf.st_rdev), dev_name ); ptr->d_next = Hashtab[ index ]; Hashtab[ index ] = ptr; } return; } struct device * new_device( dev, name ) int dev; char *name; { struct device *ptr; ptr = (struct device *) emalloc( sizeof(struct device) ); ptr->d_number = dev; ptr->d_flags = NO_FLAGS; ptr->d_name = strsave( name ); ptr->d_next = ptr->d_children = ptr->d_next_child = ptr->d_parent = (struct device *) NULL; return( ptr ); } #ifdef HDEBUG hash_stats() { int i, count; struct device *np; fprintf( stderr, "%s\n", "getmnt device name hash table performance report" ); fprintf( stderr, "Hash table size: %d\n", HASHSIZE ); for( i = 0; i < HASHSIZE; i += 1 ) { for( count = 0, np = Hashtab[i]; np != (struct device *) NULL; np = np->d_next ) count = count + 1; fprintf( stderr, "Bucket Number: %d, List Length: %d\n", i, count ); } } #endif do_devs( dir ) char *dir; { struct stat stat_buf; register struct direct *d_ptr; DIR *dir_fd; #define NAMELEN 128 /* longest possible device name */ char name_buf[ NAMELEN ]; dir_fd = opendir( dir ); if( dir_fd == (DIR *) NULL ) panic( "opendir() failed in do_devs()" ); if( chdir( dir ) < 0 ) panic( "chdir( dir ) failed in do_devs()" ); while( (d_ptr = readdir( dir_fd )) != (struct direct *) NULL ) { /* crude but fast code to boogie thru ino==0, "." and ".." */ if( (d_ptr->d_ino == 0) || (d_ptr->d_name[0] == '.' && ((d_ptr->d_name[1] == EOS) || (d_ptr->d_name[1] == '.' && d_ptr->d_name[2] == EOS)))) continue; strcpy( name_buf, dir ); strcat( name_buf, "/" ); strncat( name_buf, d_ptr->d_name, DIRSIZ ); stat( name_buf, &stat_buf ); if( (stat_buf.st_mode & S_IFMT) == S_IFBLK ) { insert( name_buf ); } else if( (stat_buf.st_mode & S_IFMT) == S_IFDIR ) { do_devs( name_buf ); } } if( chdir( ".." ) < 0 ) panic( "chdir(..) failed in do_devs()" ); closedir( dir_fd ); return; } int valid_name( dev_name ) register char *dev_name; { register int index; int match(); for( index = 0; *Devnames[ index ] != EOS ; index += 1 ) if( match( Devnames[ index ], dev_name ) ) return( 1 ); return( 0 ); } #ifdef EBUG dump_devs() { struct device *device; int index; for( index = 0; index < HASHSIZE; index += 1 ) for( device = Hashtab[index]; device != (struct device *) NULL; device = device->d_next ) print_dev( device ); return; } print_dev( device ) struct device *device; { printf( "device: 0x%x\n", device ); printf( "device->d_number: 0x%x\n", device->d_number ); printf( "device->d_name: %s\n", device->d_name ); printf( "device->d_parent: 0x%x\n", device->d_parent ); printf( "device->d_children: 0x%x\n", device->d_children ); printf( "device->d_next_child: 0x%x\n", device->d_next_child ); printf( "device->d_next: 0x%x\n", device->d_next ); return; } #endif @EOF chmod 666 dev_tab.c echo x - direct.c cat >direct.c <<'@EOF' /* * this file contains routines which deal with directories * and pathnames. * */ #include "defs.h" int matched_dirs( path1, path2 ) register char *path1, *path2; { int count; for( count = 0; *path1 == *path2; ++path1, ++path2 ) { if( *path1 == EOS ) return( count+1 ); if( *path1 == SLASH ) count += 1; } return( count ); } int count_dirs( path ) register char *path; { int count; for( count = 1; *path != EOS; ++path ) if( *path == SLASH ) count += 1; return( count ); } char * next_dir( path ) register char *path; { while( *path != EOS ) { if( *path == SLASH ) { ++path; break; } ++path; } return( path ); } int cheap_cd( current, destination ) char *current, *destination; { int cl, dl, ml, strip_dirs, prefix_dd; char buf[BUFSIZ]; register char *ptr; cl = count_dirs( current ); dl = count_dirs( destination ); ml = matched_dirs( current, destination ); #ifdef EBUG fprintf( stderr, "current: %s, destination: %s, cl: %d, dl: %d, ml: %d\n", current,destination, cl, dl, ml ); #endif if( cl == dl && cl == ml ) return( 0 ); /* already there, no work */ strip_dirs = ml; while( strip_dirs-- > 0 ) destination = next_dir( destination ); prefix_dd = cl-ml; ptr = buf; while( prefix_dd-- > 0 ) { *ptr++ = '.'; /* effect of strcat( foo, "../" ) */ *ptr++ = '.'; /* but a lot */ *ptr++ = SLASH; /* faster */ } while( *ptr++ = *destination++ ) ; #ifdef EBUG fprintf( stderr, "chdir( %s )\n", buf ); #endif return( chdir( buf ) ); } #ifndef BSD /* * C routines to implement Berkeley style directory * manipulation stuff. */ DIR * opendir( filename ) char *filename; { char *malloc(); DIR *dirp; dirp = (DIR *) malloc( (unsigned) sizeof( DIR ) ); if( dirp != (DIR *) NULL ) { struct stat sb; int nbytes; dirp->dd_fd = open( filename, 0 ); if( dirp->dd_fd < 0 ) { free( dirp ); return( (DIR *) NULL ); } fstat( dirp->dd_fd, &sb ); dirp->dd_size = dirp->dd_bsize = sb.st_size; dirp->dd_buf = malloc( (unsigned) dirp->dd_bsize ); if( dirp->dd_buf == (char *) NULL ) { close( dirp->dd_fd ); free( dirp ); return( (DIR *) NULL ); } /* * Read in the entire directory. * ?should this be in readdir()? */ nbytes = read( dirp->dd_fd, dirp->dd_buf, dirp->dd_bsize ); if( nbytes < dirp->dd_bsize ) { close( dirp->dd_fd ); free( dirp->dd_buf ); free( dirp ); return( (DIR *) NULL ); } /* should this be in closedir()? * It's not needed after that big read... */ close( dirp->dd_fd ); dirp->dd_loc = 0L; dirp->dd_entno = 0L; } return( dirp ); } struct direct * readdir( dirp ) DIR *dirp; { struct direct *dp; if( dirp->dd_loc >= dirp->dd_size ) return( (struct direct *) NULL ); dp = (struct direct *) &(dirp->dd_buf[ dirp->dd_loc ]); dirp->dd_entno += 1; dirp->dd_loc = dirp->dd_entno * sizeof( struct direct ); /* Sys V */ return( dp ); } long telldir( dirp ) DIR *dirp; { return( dirp->dd_loc ); } void seekdir( dirp, loc ) DIR *dirp; long loc; { dirp->dd_loc = loc; dirp->dd_entno = loc / (sizeof (struct direct) ); /* Sys V */ return; } /* * rewinddir() is implemented as a macro. */ void closedir( dirp ) DIR *dirp; { /* deallocate buffer */ free( dirp->dd_buf ); /* deallocate "dirp" */ free( dirp ); return; } #endif @EOF chmod 666 direct.c echo x - getmnt.c cat >getmnt.c <<'@EOF' /* * Algorithm: * 1.)Build a hash table containing all block devices, * (satisfying naming constraints: see Devnames table) * indexed by hash( dev_id ), where dev_id is the * device id alluded to in the "stat(2)" documentation. * This table also contains the path name of the special file. * 2.)Peruse the directory structure, limited by MAXDEPTH, to * look for mount points. Mount points are found by comparing the * device id of the parent to the device id of the child. * When they differ, we have a mount point. Then we can * hash to the appropriate device name and dump the data. * * Possible Problems: * a.)It's slow. * b.)Non-unique names ( "/dev/ra0" and "/dev/ra00" for example ) * c.)The program is not guaranteed to perform correctly * if either the user is not root **or** mount points are * found more than MAXDEPTH-1 deep. * * Notes: * a.)Assumes devices found under /dev * b.)get_mnt_pts() uses both a full path name and a relative * path name to save time on "stat()" system calls, which * use namei(). * */ static char *SCCS_ID_STR = "@(#) /STD/pkg/bcrcc/getmnt.d/s.getmnt.c REL LEVEL=1.2 LAST DELTA ON 5/2/85 "; # include <stdio.h> # include <fcntl.h> # include <sys/types.h> # include <sys/stat.h> # include <sys/dir.h> #define ROOT_DIR "/" #define DEV_DIR "/dev" #define SPECIAL 070000 /* mode val., all special files */ #define BLOCK_SPECIAL 060000 /* mode val. for block special file */ #define DIR_MODE 040000 /* mode val. for dir. returned by stat() */ #define TABSIZE 32 /* size, table for directory structures */ #define HASHSIZE 128 #define MAXDEPTH 4 /* how deep to go */ #define NAMELEN ( (MAXDEPTH+1) * (DIRSIZ+1) + 1 ) struct stat S_buf; int Cur_Depth = 1; struct node { dev_t dev_id; char *name; struct node *next; }; /* Devnames should contain regular expressions * which characterize block * special files containing file systems. * The last entry should be a null string. */ char *Devnames[] = { "*/dsk*", "*/rp*", "*/ra*", "" }; /* * Flag to indicate short output format. */ int Short_Flag; struct node *Hashtab[HASHSIZE]; main( argc, argv ) int argc; char *argv[]; { struct stat stat_buf; if( argc > 2 ) { usage(); } else if( argc == 2 ) { if( strcmp( argv[1], "-s" ) == 0 ) Short_Flag = 1; else usage(); } else { Short_Flag = 0; } close( 0 ); /* not used, nothing read. */ setup( DEV_DIR ); print_data( ROOT_DIR ); if( stat( ROOT_DIR, &stat_buf ) < 0 ) { panic("can\'t stat /"); } get_mnt_pts( ROOT_DIR, ROOT_DIR, stat_buf.st_dev ); exit( 0 ); } get_mnt_pts( full_name, rel_name, P_dev ) register char *full_name, *rel_name; dev_t P_dev; { int file; struct direct dir_tab[TABSIZE]; register struct direct *d_ptr; int entries; char name_buf[ NAMELEN ]; char dir_name_buf[ DIRSIZ+1 ]; dev_t device; if( Cur_Depth > MAXDEPTH ) return; if( stat( rel_name, &S_buf ) < 0 ) { fprintf( stderr, "can\'t stat " ); panic( full_name ); } if( !(S_buf.st_mode & SPECIAL )) /* e.g. regular */ { return; } else if( (S_buf.st_mode & SPECIAL) == DIR_MODE ) { if( S_buf.st_dev != P_dev ) { print_data( full_name ); } device = S_buf.st_dev; file = open( rel_name , O_RDONLY ); if( file < 0 ) { fprintf(stderr, "can\'t open " ); panic( full_name ); } /* seek past "." and ".." */ lseek( file, 2L * sizeof( struct direct ) , 0 ); /* deal with rest of directory */ if( chdir( rel_name ) < 0 ) /* can't get there */ { fprintf(stderr, "can\'t cd to "); panic( full_name ); } ++Cur_Depth; while( (entries = read(file, dir_tab, sizeof(dir_tab))) >= sizeof( struct direct) ) { d_ptr = dir_tab; entries = entries / sizeof( struct direct ); for( d_ptr = dir_tab; entries>0; --entries, ++d_ptr ) { if( d_ptr->d_ino != 0 ) { strcpy( name_buf, full_name ); if( strcmp( full_name, "/" ) !=0 ) { strcat( name_buf, "/" ); } /* following code protects against * names of length DIRSIZ. */ strncpy( dir_name_buf, d_ptr->d_name, DIRSIZ ); dir_name_buf[ DIRSIZ ] = '\0'; strcat( name_buf, dir_name_buf ); get_mnt_pts( name_buf, dir_name_buf, device ); } } } close( file ); if( chdir( ".." ) < 0 ) { panic("can\'t cd to .."); } --Cur_Depth; return; } else { return; } } print_data( path_name ) register char *path_name; { struct stat stat_buf; struct node *device; struct node *lookup(); /* no need to check ret. value; already stat'd */ stat( path_name, &stat_buf ); device = lookup( stat_buf.st_dev ); if( device == NULL ) { panic("error in dumping data."); } if( Short_Flag ) printf("%s %s\n", &device->name[ strlen(DEV_DIR)+1 ], path_name ); else printf("%s %s\n", device->name, path_name ); return; } panic( str ) char *str; { write( 2, str, strlen( str ) ); write( 2, "\n", strlen( "\n" ) ); exit( 1 ); } usage() { panic( "usage: getmnt [-s]" ); } struct node * lookup( device ) dev_t device; { register struct node *ptr; register int index; index = hash( (int)device ); for( ptr = Hashtab[ index ]; ptr != NULL; ptr = ptr->next ) { if( ptr->dev_id == device ) break; } return( ptr ); } int hash( j ) int j; { return( ( 7*j ) % HASHSIZE ); } insert( dev_name ) char *dev_name; { struct stat stat_buf; int index; struct node *ptr; char *malloc(), *strsave(); int hash(); struct node *lookup(); if( !valid_name( dev_name ) ) return; stat( dev_name, &stat_buf ); if( lookup( stat_buf.st_rdev ) == NULL ) { index = hash( (int)stat_buf.st_rdev ); ptr = (struct node *) malloc( sizeof(struct node) ); if( ptr == NULL ) panic("no space"); ptr->dev_id = stat_buf.st_rdev; ptr->name = strsave( dev_name ); if( ptr->name == NULL ) panic("no space"); ptr->next = Hashtab[ index ]; Hashtab[ index ] = ptr; } return; } setup( dir ) char *dir; { struct stat stat_buf; struct direct dirent; char name_buf[ NAMELEN ]; int file; if( chdir( dir ) < 0 ) { panic("Can\'t get to device directory."); } file = open( ".", O_RDONLY ); if( file < 0 ) { panic("Can\'t read device directory."); } lseek( file, 2L * sizeof (struct direct), 0 ); /* skip . and .. */ while( read( file, &dirent, sizeof dirent ) == sizeof dirent ) { if( dirent.d_ino == 0 ) continue; stat( dirent.d_name, &stat_buf ); if( (stat_buf.st_mode & BLOCK_SPECIAL) == BLOCK_SPECIAL ) { strcpy( name_buf, dir ); strcat( name_buf, "/" ); strcat( name_buf, dirent.d_name ); insert( name_buf ); } else if( stat_buf.st_mode & DIR_MODE ) { strcpy( name_buf, dir ); strcat( name_buf, "/" ); strcat( name_buf, dirent.d_name ); setup( name_buf ); } } close( file ); chdir( ".." ); return; } char * strsave( str ) char *str; { char *ptr, *malloc(); int strlen(); if( (ptr = malloc( (unsigned) strlen(str)+1 )) != NULL ) strcpy(ptr, str); return( ptr ); /* NULL if malloc() NULL */ } /* * Pattern matching function: * returns 1 on a match, 0 otherwise. * The meta-characters '*' and '?' * behave as with the shell when * found in string "a". */ int match(a,b) char *a, *b; { if( *b == '\0' ) { if( *a == '\0' ) return(1); else if( *a == '*' && *(a+1) == '\0' ) return(1); else return(0); } else if ( *a == *b || *a == '?' ) return( match(a+1,b+1) ); else if( *a == '*' ) return( match(a,b+1) || match(a+1,b+1) || match(a+1,b) ); else return(0); } int valid_name( dev_name ) register char *dev_name; { register int index; int match(); for( index = 0; *Devnames[ index ] != '\0' ; index += 1 ) if( match( Devnames[ index ], dev_name ) ) return( 1 ); return( 0 ); } @EOF chmod 666 getmnt.c echo x - makefile cat >makefile <<'@EOF' CFLAGS = -O CC = /bin/cc OBJS = xgetmnt.o direct.o namelist.o util.o print.o dev_tab.o tree.o getmnt: $(CC) $(CFLAGS) getmnt.c -o getmnt ngetmnt: $(CC) $(CFLAGS) ngetmnt.c -o ngetmnt xgetmnt: $(OBJS) $(CC) $(CFLAGS) -o xgetmnt $(OBJS) direct.o: defs.h direct.c $(CC) -c $(CFLAGS) direct.c xgetmnt.o: defs.h xgetmnt.c $(CC) -c $(CFLAGS) xgetmnt.c namelist.o: defs.h namelist.c $(CC) -c $(CFLAGS) namelist.c util.o: defs.h util.c $(CC) -c $(CFLAGS) util.c print.o: defs.h print.c $(CC) -c $(CFLAGS) print.c dev_tab.o: defs.h dev_tab.c $(CC) -c $(CFLAGS) dev_tab.c tree.o: defs.h tree.c $(CC) -c $(CFLAGS) tree.c clean: rm -f *~ *.o xgetmnt ngetmnt getmnt @EOF chmod 666 makefile echo x - namelist.c cat >namelist.c <<'@EOF' #include "defs.h" /* * Entries to look for in system name list. */ struct nlist NameList[] = { #ifdef u3b2 { "mount" }, { "v" }, #else { "_mount" }, { "_v" }, #endif { NULL }, }; /* routine to get nlist data * it's isolated here because the call to nlist is * possible to circumvent, as we do here, * but this should not be * known to the calling routine. * * Implementation Notes: * The algorithm is pretty straightforward: * we look for a file containing the results of * a previous nlist call. Its name is passed in * fyle, and the nlist values come in via "list". * If the file is there, and is valid ( see below ) * we use data from the file. If any of this fails , * we do an nlist, and write the data values to fyle * for next time. * * File validity checking: * 1.)Check existence ( "stat()" call ) * 2.)Check if up to date ( against time of /unix ) * 3.)Check if readable by us. * 4.)For each nlist entry in list: * a.)Read in an nlist structure from the file. * b.)Verify the name and position in the list. * */ get_nl(fyle, list ) char *fyle; struct nlist *list; { int fd, ret; struct stat s_buf; time_t sys_mtime; struct nlist *n_ptr; char save_name[256]; /* for flexinames */ FILE *filep; ret = stat( UNIX, &s_buf ); sys_mtime = s_buf.st_mtime; /* modification time of system */ ret = stat(fyle, &s_buf ); if( ret != -1 && s_buf.st_mtime > sys_mtime && ( s_buf.st_mode & 0400 )) { filep = fopen( fyle, "r" ); if( filep == NULL ) { /* this shouldn't happen if we got here */ goto do_nl; } for( n_ptr=list; n_ptr->n_name != (char *) NULL; ++n_ptr ) { strcpy( save_name, n_ptr->n_name ); if( !n_read(filep, n_ptr) ) { fclose( filep ); goto do_nl; } if( strcmp( n_ptr->n_name, save_name ) != 0 ) { strcpy( n_ptr->n_name, save_name ); fclose( filep ); goto do_nl; } } fclose( filep ); return; } do_nl: /* do an actual nlist call; this can be time-consuming!!!! */ ret = nlist("/unix", list); if( ret == -1 ) panic("nlist system call failed"); #ifndef u3b2 /* implying VAX .... */ for ( n_ptr=list; n_ptr->n_name != (char *)NULL; ++n_ptr ) n_ptr->n_value &= VMASK; #endif fd = creat(fyle, 0400); if( fd < 0 ) { return; } filep = fdopen( fd, "a" ); if( filep == (FILE *) NULL ) { return; /* can't write to it */ } for( n_ptr=list; n_ptr->n_name != (char *)NULL; ++n_ptr ) n_write(filep, n_ptr ); fclose( filep ); close( fd ); return; } int n_write( filep, n_ptr ) FILE *filep; struct nlist *n_ptr; { fprintf( filep, "%d:%ld:%s\n", n_ptr->n_type, n_ptr->n_value, n_ptr->n_name ); return; } int n_read( filep, n_ptr ) FILE *filep; struct nlist *n_ptr; { char buf[BUFSIZ]; char *strsave(); int type; long value; char *name; fscanf( filep, "%d:%ld:%s\n", &type, &value, buf ); n_ptr->n_value = value; n_ptr->n_type = type; name = strsave( buf ); if( name == (char *) NULL ) { return( 0 ); } else { n_ptr->n_name = name; return( 1 ); } } @EOF chmod 666 namelist.c echo x - ngetmnt.c cat >ngetmnt.c <<'@EOF' /* * Algorithm: * 1.)Build a hash table containing all block devices, * (satisfying naming constraints: see Devnames table) * indexed by hash( dev_id ), where dev_id is the * device id alluded to in the "stat(2)" documentation. * This table also contains the path name of the special file. * 2.)Construct a "skeleton" file system tree by reading * /dev/kmem and obtaining information about the relations * between mount points. This information can then be used * to decide if we are on a "leaf" file system (where no other * file systems are mounted) or on a file system which contains * other mount points ("internal"). * 3.)Peruse the directory structure, limited by MAXDEPTH, to * look for mount points. Mount points are found by comparing the * device id of the parent to the device id of the child. * When they differ, we have a mount point. Then we can * hash to the appropriate device name and dump the data. * * Possible Problems: * a.)It's potentially quite slow. * b.)Non-unique names ( "/dev/ra0" and "/dev/ra00" for example ) * can have the same device number and confuse the program; * the specification of naming conventions with Devnames[] * alleviates this to some degree. * c.)The program is not guaranteed to perform correctly * if the user is not root. It should probably do a getuid() * and print an informational message. * * Notes: * a.)Assumes devices found under DEV_DIR. * b.)get_mnt_pts() uses both a full path name (for * robustness) and a relative path name (to save time * on "stat()" and "chdir()" system calls, which use namei().) * */ static char *SCCS_ID_STR = "@(#) /STD/pkg/bcrcc/getmnt.d/s.getmnt.c REL LEVEL=1.2 LAST DELTA ON 5/2/85 "; # include <stdio.h> # include <fcntl.h> # include <sys/var.h> # include <sys/types.h> # include <sys/stat.h> # include <sys/dir.h> # include <sys/inode.h> # include <sys/buf.h> # include <sys/mount.h> # include <sys/sysmacros.h> # include <a.out.h> /* deal with stupidity in sym.h */ #ifdef n_name # undef n_name #endif #define EOS '\0' /* End of String */ #define ROOT_DIR "/" #define DEV_DIR "/dev" #define UNIX "/unix" #define KMEM "/dev/kmem" #define NL_FILE "/letc/getmnt_nlist" /* mode val., special files */ #define SPECIAL (S_IFBLK | S_IFCHR) /* mode val. for block special file */ #define BLOCK_SPECIAL S_IFBLK /* mode val. for dir. returned by stat() */ #define DIR_MODE S_IFDIR /* VAX address mask */ #define VMASK 0x3fffffff /* size, table for directory structures */ #define TABSIZE (BUFSIZ/sizeof(struct direct)) #define HASHSIZE 128 #define MAXDEPTH 4 /* how deep to go */ #define NAMELEN ( (MAXDEPTH+1) * (DIRSIZ+1) + 1 ) struct stat S_buf; int Cur_Depth = 1; struct node { dev_t dev_id; char *name; struct node *next; int status; #define UNREFERENCED 0 #define INTERNAL 1 #define LEAF 2 }; struct node *lookup(); char *strsave(), *emalloc(), *malloc(); /* Devnames should contain regular expressions * which characterize block * special files containing file systems. * The last entry should be a null string. */ char *Devnames[] = { "*/dsk*", "" }; /* * Entries to look for in system name list. */ struct nlist NameList[] = { #define MOUNT 0 { "_mount" }, #define V 1 { "_v" }, { NULL }, }; /* * Flag to indicate short output format. */ int Short_Flag; struct node *Hashtab[HASHSIZE]; main( argc, argv ) int argc; char *argv[]; { struct stat stat_buf; if( argc > 2 ) { usage(); } else if( argc == 2 ) { if( strcmp( argv[1], "-s" ) == 0 ) Short_Flag = 1; else usage(); } else { Short_Flag = 0; } setup(); print_data( ROOT_DIR ); if( stat( ROOT_DIR, &stat_buf ) < 0 ) { panic("can't stat /"); } get_mnt_pts( ROOT_DIR, ROOT_DIR, stat_buf.st_dev ); #ifdef HDEBUG hash_stats(); #endif exit( 0 ); } get_mnt_pts( full_name, rel_name, P_dev ) register char *full_name, *rel_name; dev_t P_dev; { struct direct dir_tab[TABSIZE]; register struct direct *d_ptr; char name_buf[ NAMELEN ], dir_name_buf[ DIRSIZ+1 ]; int entries, file, new_dir = 1; dev_t device; struct node *node_p; if( stat( rel_name, &S_buf ) < 0 ) { fprintf( stderr, "can't stat " ); warn( full_name ); return; /* check this */ } if( !(S_buf.st_mode & SPECIAL )) /* e.g. regular */ { return; } else if( (S_buf.st_mode & SPECIAL) == DIR_MODE ) { if( S_buf.st_dev != P_dev ) { print_data( full_name ); node_p = lookup( S_buf.st_dev ); /* safe; chked alrdy */ if( node_p->status == LEAF ) return; } if( Cur_Depth >= MAXDEPTH ) return; device = S_buf.st_dev; file = open( rel_name , O_RDONLY ); if( file < 0 ) { fprintf(stderr, "can't open " ); warn( full_name ); return; /* check this */ } /* deal with rest of directory */ if( chdir( rel_name ) < 0 ) /* can't get there */ { fprintf(stderr, "can't cd to "); warn( full_name ); close( file ); return; /* check this */ } ++Cur_Depth; while( (entries = read(file, dir_tab, sizeof(dir_tab))) >= sizeof( struct direct) ) { d_ptr = dir_tab; entries = entries / sizeof( struct direct ); if( new_dir == 1 ) { ++d_ptr; ++d_ptr; entries = entries - 2; new_dir = 0; } for( ; entries > 0; --entries, ++d_ptr ) { if( d_ptr->d_ino != 0 ) { strcpy( name_buf, full_name ); if( strcmp( full_name, "/" ) !=0 ) { strcat( name_buf, "/" ); } /* following code protects against * names of length DIRSIZ. */ strncpy( dir_name_buf, d_ptr->d_name, DIRSIZ ); dir_name_buf[ DIRSIZ ] = EOS; strcat( name_buf, dir_name_buf ); get_mnt_pts( name_buf, dir_name_buf, device ); } } } close( file ); if( chdir( ".." ) < 0 ) { char *p1, *p2, *strrchr(); warn("can't cd to .."); p1 = strsave( full_name ); p2 = strrchr( p1 , '/' ); if( p1 != p2 && p2 != (char *)NULL ) *p2 = EOS; if( chdir( p2 ) < 0 ) { fprintf( stderr, "%s", "Can't escape " ); panic( p2 ); } } --Cur_Depth; return; } else { return; } } print_data( path_name ) register char *path_name; { struct stat stat_buf; struct node *device; struct node *lookup(); /* no need to check ret. value; already stat'd */ stat( path_name, &stat_buf ); device = lookup( stat_buf.st_dev ); if( device == NULL ) { panic("error in dumping data."); } if( Short_Flag ) printf("%s %s\n", &device->name[ strlen(DEV_DIR)+1 ], path_name ); else printf("%s %s\n", device->name, path_name ); return; } panic( str ) char *str; { fprintf( stderr, "%s\n", str ); exit( 1 ); } warn( str ) char *str; { fprintf( stderr, "%s\n", str ); return; } usage() { panic( "usage: getmnt [-s]" ); } struct node * lookup( device ) dev_t device; { register struct node *ptr; register int index; index = hash( (int)device ); for( ptr = Hashtab[ index ]; ptr != NULL; ptr = ptr->next ) { if( ptr->dev_id == device ) break; } return( ptr ); } int hash( j ) int j; { return( ( 7*j ) % HASHSIZE ); } insert( dev_name ) char *dev_name; { struct stat stat_buf; int index, hash(); struct node *ptr, *lookup(); if( !valid_name( dev_name ) ) return; stat( dev_name, &stat_buf ); if( lookup( stat_buf.st_rdev ) == NULL ) { index = hash( (int)stat_buf.st_rdev ); ptr = (struct node *) emalloc( sizeof(struct node) ); ptr->dev_id = stat_buf.st_rdev; ptr->name = strsave( dev_name ); ptr->next = Hashtab[ index ]; ptr->status = UNREFERENCED; Hashtab[ index ] = ptr; } return; } setup() { do_devs( DEV_DIR ); analyze_tree(); return; } do_devs( dir ) char *dir; { struct stat stat_buf; struct direct dir_tab[TABSIZE]; register struct direct *d_ptr; char name_buf[ NAMELEN ]; int file, entries, new_dir = 1; if( chdir( dir ) < 0 ) { panic("Can't get to device directory."); } file = open( ".", O_RDONLY ); if( file < 0 ) { panic("Can't read device directory."); } while( (entries = read(file, dir_tab, sizeof(dir_tab))) >= sizeof(struct direct)) { d_ptr = dir_tab; entries = entries / sizeof(struct direct); if( new_dir == 1 ) /* deal with "." and ".." */ { ++d_ptr; ++d_ptr; entries = entries - 2; new_dir = 0; } for( ; entries > 0 ; --entries, ++d_ptr ) { if( d_ptr->d_ino == 0 ) continue; stat( d_ptr->d_name, &stat_buf ); if( (stat_buf.st_mode & BLOCK_SPECIAL) == BLOCK_SPECIAL ) { strcpy( name_buf, dir ); strcat( name_buf, "/" ); strncat( name_buf, d_ptr->d_name, DIRSIZ ); insert( name_buf ); } else if( stat_buf.st_mode & DIR_MODE ) { strcpy( name_buf, dir ); strcat( name_buf, "/" ); strncat( name_buf, d_ptr->d_name, DIRSIZ ); do_devs( name_buf ); } } } close( file ); chdir( ".." ); return; } char * strsave( str ) char *str; { char *ptr; int strlen(); ptr = emalloc( (unsigned) strlen(str)+1 ); strcpy(ptr, str); return( ptr ); } char *emalloc( size ) unsigned size; { char *ptr; ptr = malloc( size ); if( ptr == (char *) NULL ) panic( "no space" ); else return( ptr ); } /* * Pattern matching function: * returns 1 on a match, 0 otherwise. * The meta-characters '*' and '?' * behave as with the shell when * found in string "a". */ int match(a,b) char *a, *b; { if( *b == EOS ) { if( *a == EOS ) return(1); else if( *a == '*' && *(a+1) == EOS ) return(1); else return(0); } else if ( *a == *b || *a == '?' ) return( match(a+1,b+1) ); else if( *a == '*' ) return( match(a,b+1) || match(a+1,b+1) || match(a+1,b) ); else return(0); } int valid_name( dev_name ) register char *dev_name; { register int index; int match(); for( index = 0; *Devnames[ index ] != EOS ; index += 1 ) if( match( Devnames[ index ], dev_name ) ) return( 1 ); return( 0 ); } analyze_tree() { int index, kmem_fd; struct var v; struct mount mtab_entry; struct inode itab_entry; struct node *device, *lookup(); get_nl( NL_FILE, NameList ); for( index = 0; NameList[index].n_name != (char *) NULL; index += 1 ) { if( NameList[index].n_value == 0 ) panic( "bad nlist data" ); } kmem_fd = open( KMEM, O_RDONLY ); if( kmem_fd < 0 ) { panic( "can't open KMEM" ); } eseek( kmem_fd, (long) NameList[V].n_value, 0 ); eread( kmem_fd, &v, sizeof(v) ); /* we look at each mount table entry, in turn */ for( index = 0; index < v.v_mount; index += 1 ) { eseek( kmem_fd, (long ) (NameList[MOUNT].n_value + index * sizeof( mtab_entry )), 0 ); eread( kmem_fd, &mtab_entry, sizeof( mtab_entry ) ); if( mtab_entry.m_flags != MINUSE ) continue; device = lookup( brdev(mtab_entry.m_dev) ); if( device == (struct node *) NULL ) panic( "error in lookup() for device" ); if( device->status == UNREFERENCED ) device->status = LEAF; eseek( kmem_fd, (long ) ( (unsigned) mtab_entry.m_inodp & VMASK), 0 ); eread( kmem_fd, &itab_entry, sizeof( itab_entry ) ); device = lookup( brdev(itab_entry.i_dev) ); if( device == (struct node *) NULL ) panic( "error in lookup() for device" ); device->status = INTERNAL; } return; } #ifdef HDEBUG hash_stats() { int i, count; struct node *np; fprintf( stderr, "%s\n", "getmnt device name hash table performance report" ); fprintf( stderr, "Hash table size: %d\n", HASHSIZE ); for( i = 0; i < HASHSIZE; i += 1 ) { for( count = 0, np = Hashtab[i]; np != (struct node *) NULL; np = np->next ) count = count + 1; fprintf( stderr, "Bucket Number: %d, List Length: %d\n", i, count ); } } #endif /* routine to get nlist data * it's isolated here because the call to nlist is * possible to circumvent, as we do here, * but this should not be * known to the calling routine. * * Implementation Notes: * The algorithm is pretty straightforward: * we look for a file containing the results of * a previous nlist call. Its name is passed in * fyle, and the nlist values come in via "list". * If the file is there, and is valid ( see below ) * we use data from the file. If any of this fails , * we do an nlist, and write the data values to fyle * for next time. * * File validity checking: * 1.)Check existence ( "stat()" call ) * 2.)Check if up to date ( against time of /unix ) * 3.)Check if readable by us. * 4.)For each nlist entry in list: * a.)Read in an nlist structure from the file. * b.)Verify the name and position in the list. * */ get_nl(fyle, list ) char *fyle; struct nlist *list; { int fd, ret; struct stat s_buf; time_t sys_mtime; struct nlist *n_ptr; char save_name[256]; /* for flexinames */ FILE *filep; ret = stat( UNIX, &s_buf ); sys_mtime = s_buf.st_mtime; /* modification time of system */ ret = stat(fyle, &s_buf ); if( ret != -1 && s_buf.st_mtime > sys_mtime && ( s_buf.st_mode & 0400 )) { filep = fopen( fyle, "r" ); if( filep == NULL ) { /* this shouldn't happen if we got here */ goto do_nl; } for( n_ptr=list; n_ptr->n_name != (char *) NULL; ++n_ptr ) { strcpy( save_name, n_ptr->n_name ); if( !n_read(filep, n_ptr) ) { fclose( filep ); goto do_nl; } if( strcmp( n_ptr->n_name, save_name ) != 0 ) { strcpy( n_ptr->n_name, save_name ); fclose( filep ); goto do_nl; } } fclose( filep ); return; } do_nl: /* do an actual nlist call; this can be time-consuming!!!! */ ret = nlist("/unix", list); if( ret == -1 ) panic("nlist system call failed"); for ( n_ptr=list; n_ptr->n_name != (char *)NULL; ++n_ptr ) n_ptr->n_value &= VMASK; fd = creat(fyle, 0400); if( fd < 0 ) { return; } filep = fdopen( fd, "a" ); if( filep == (FILE *) NULL ) { return; /* can't write to it */ } for( n_ptr=list; n_ptr->n_name != (char *)NULL; ++n_ptr ) n_write(filep, n_ptr ); fclose( filep ); close( fd ); return; } int n_write( filep, n_ptr ) FILE *filep; struct nlist *n_ptr; { fprintf( filep, "%d:%ld:%s\n", n_ptr->n_type, n_ptr->n_value, n_ptr->n_name ); return; } int n_read( filep, n_ptr ) FILE *filep; struct nlist *n_ptr; { char buf[BUFSIZ]; char *strsave(); int type; long value; char *name; fscanf( filep, "%d:%ld:%s\n", &type, &value, buf ); n_ptr->n_value = value; n_ptr->n_type = type; name = strsave( buf ); if( name == (char *) NULL ) { return( 0 ); } else { n_ptr->n_name = name; return( 1 ); } } int eseek( fd, addr, whence ) int fd, whence; long addr; { long l; l = lseek( fd, addr, whence ); if( l < 0L ) panic( "can't seek" ); return( l ); } int eread( fd, buf, count ) int fd, count; char *buf; { int n; n = read( fd, buf, count ); if( n < 0 ) panic( "can't read" ); return( n ); } @EOF chmod 666 ngetmnt.c echo x - print.c cat >print.c <<'@EOF' #include "defs.h" extern int Short_Flag; panic( str ) char *str; { fprintf( stderr, "%s\n", str ); exit( 1 ); } warn( str ) char *str; { fprintf( stderr, "%s\n", str ); return; } usage() { panic( "usage: getmnt [-s]" ); } /* * given some information, we print the mount point * data in a format usable by setmnt or whatever, * modified by the flag ShortFlag. */ void prt_mnt_pt( node, name, sb ) struct node *node; char *name; struct stat *sb; { struct device *device, *lookup(); char buf[BUFSIZ]; int len; device = lookup( brdev(sb->st_dev) ); if( device == NULL ) { panic("error in dumping data."); } if( Short_Flag ) printf("%s", &device->d_name[ DEV_LEN+1 ] ); else printf("%s", device->d_name ); putchar( ' ' ); sprt_path_from_node( buf, node ); len = strlen( buf ); if( len>0 && buf[len-1] != '/' ) buf[len] = '/', buf[len+1] = EOS; printf( "%s%s\n", buf, name ); return; } sprt_path_from_node( str, node ) char *str; struct node *node; { char *nn[MAX_DIRS]; register char *name; register int index; int stack; struct node *np; /* we use nn[] as a stack of character strings; * this loop pushes them onto the stack. */ for( np = node, stack = 0, nn[0] = node->n_name; np != np->n_parent; /* i.e., root */ np = np->n_parent ) { if( stack >= MAX_DIRS ) panic( "sprt_path_from_node: stack > MAX_DIRS" ); nn[stack] = np->n_name; stack += 1; } /* this loop sucks stuff back off of the nn[] "stack". */ for( stack -= 1, index = 0, str[0] = '/'; stack >= 0; stack -= 1 ) { for( name = nn[stack]; *name != EOS; ++name ) str[++index] = *name; if( stack > 0 ) str[++index] = '/'; } str[++index] = EOS; return; } @EOF chmod 666 print.c echo x - tree.c cat >tree.c <<'@EOF' #include "defs.h" extern struct nlist NameList[]; analyze_tree() { int index, kmem_fd; struct var v; struct mount mtab_entry; struct inode itab_entry; struct device *device, *parent, *lookup(); get_nl( NL_FILE, NameList ); for( index = 0; NameList[index].n_name != (char *) NULL; index += 1 ) { if( NameList[index].n_value == 0 ) panic( "bad nlist data" ); } kmem_fd = open( KMEM, O_RDONLY ); if( kmem_fd < 0 ) { panic( "can't open KMEM" ); } eseek( kmem_fd, (long) NameList[V].n_value, 0 ); eread( kmem_fd, &v, sizeof(v) ); /* we look at each mount table entry, in turn */ for( index = 0; index < v.v_mount; index += 1 ) { eseek( kmem_fd, (long ) (NameList[MOUNT].n_value + index * sizeof( mtab_entry )), 0 ); eread( kmem_fd, &mtab_entry, sizeof( mtab_entry ) ); if( mtab_entry.m_flags != MINUSE ) continue; device = lookup( brdev(mtab_entry.m_dev) ); if( device == (struct device *) NULL ) panic( "error in lookup() for device" ); #ifndef u3b2 eseek( kmem_fd, (long ) ( (unsigned) mtab_entry.m_inodp & VMASK), 0 ); eread( kmem_fd, &itab_entry, sizeof( itab_entry ) ); #else if( mtab_entry.m_inodp == 0 ) /* root */ itab_entry.i_dev = 0; else { eseek( kmem_fd, (long) mtab_entry.m_inodp, 0 ); eread( kmem_fd, &itab_entry, sizeof( itab_entry ) ); } #endif parent = lookup( brdev(itab_entry.i_dev) ); if( parent == (struct device *) NULL ) panic( "error in lookup() for device" ); device->d_parent = parent; device->d_flags |= IN_TREE; parent->d_flags |= IN_TREE; add_child( parent, device ); } return; } int leaf( dev_num ) dev_t dev_num; { struct device *dev_ptr; dev_ptr = lookup( brdev(dev_num) ); if( dev_ptr == (struct device *) NULL ) panic( "leaf(): device not found." ); return( ((dev_ptr->d_children == (struct device *) NULL ) && (dev_ptr->d_parent != (struct device *) NULL )) ? TRUE : FALSE ); } int all_found() { struct device *root; extern struct node *ListHead; root = lookup( brdev(ListHead->n_dev) ); /* should be root */ return( (root->d_children == (struct device *) NULL ) ? TRUE : FALSE ); } add_child( parent, new_child ) struct device *parent, *new_child; { struct device *tmp; if( new_child == parent ) return; /* put in for idiot 3b2 */ #ifdef EBUG fprintf( stderr, "Adding child 0x%x to parent 0x%x\n", new_child->d_number, parent->d_number ); #endif tmp = parent->d_children; parent->d_children = new_child; new_child->d_next_child = tmp; return; } remove_child( parent, old_child ) struct device *parent, *old_child; { struct device *ptr, *old; /* dispense with bad args. parent == NULL may be root */ if( (parent == (struct device *) NULL) || (old_child == (struct device *) NULL ) ) return; for( old = ptr = parent->d_children; ptr != (struct device *) NULL; old = ptr, ptr = ptr->d_next_child ) { if( ptr == old_child ) /* i.e., found on chain */ { if( ptr->d_children == (struct device *) NULL ) { #ifdef EBUG fprintf(stderr, "deleting 0x%x from 0x%x\n", ptr->d_number, parent->d_number ); #endif if( ptr == parent->d_children ) /* was old == */ parent->d_children = ptr->d_next_child; else old->d_next_child = ptr->d_next_child; /* check for pending removal */ if( (parent->d_flags & DELETED ) == DELETED ) remove_child( parent->d_parent, parent ); } else { #ifdef EBUG fprintf( stderr, "marking 0x%x as DELETED\n", ptr->d_number ); #endif ptr->d_flags |= DELETED; } break; } } #ifdef EBUG if( ptr == (struct device *) NULL ) fprintf( stderr, "device 0x%x not found under 0x%x\n", old_child->d_number, parent->d_number ); #endif return; } update_tree( dev ) dev_t dev; { struct device *device, *lookup(); device = lookup( brdev(dev) ); if( device == (struct device *) NULL ) panic( "bad device passed to update_tree()" ); remove_child( device->d_parent, device ); return; } @EOF chmod 666 tree.c echo x - util.c cat >util.c <<'@EOF' #include "defs.h" char * strsave( str ) char *str; { char *ptr; int strlen(); ptr = emalloc( (unsigned) strlen(str)+1 ); strcpy(ptr, str); return( ptr ); } char *emalloc( size ) unsigned size; { char *ptr; ptr = malloc( size ); if( ptr == (char *) NULL ) panic( "no space" ); else return( ptr ); } /* * Pattern matching function: * returns 1 on a match, 0 otherwise. * The meta-characters '*' and '?' * behave as with the shell when * found in string "a". */ int match(a,b) char *a, *b; { if( *b == EOS ) { if( *a == EOS ) return(1); else if( *a == '*' && *(a+1) == EOS ) return(1); else return(0); } else if ( *a == *b || *a == '?' ) return( match(a+1,b+1) ); else if( *a == '*' ) return( match(a,b+1) || match(a+1,b+1) || match(a+1,b) ); else return(0); } int eseek( fd, addr, whence ) int fd, whence; long addr; { long l; l = lseek( fd, addr, whence ); if( l < 0L ) panic( "can't seek" ); return( l ); } int eread( fd, buf, count ) int fd, count; char *buf; { int n; n = read( fd, buf, count ); if( n < 0 ) panic( "can't read" ); return( n ); } @EOF chmod 666 util.c echo x - xgetmnt.c cat >xgetmnt.c <<'@EOF' /* * Algorithm: * 1.)Build a hash table containing all block devices, * (satisfying naming constraints: see Devnames table) * indexed by hash( dev_id ), where dev_id is the * device id alluded to in the "stat(2)" documentation. * This table also contains the path name of the special file. * 2.)Construct a "skeleton" file system tree by reading * /dev/kmem and obtaining information about the relations * between mount points. This information can then be used * to decide if we are on a "leaf" file system (where no other * file systems are mounted) or on a file system which contains * other mount points ("internal"). * 3.)Peruse the directory structure breadth-first, * looking for mount points. Mount points are found by comparing the * device id of the parent to the device id of the child. * When they differ, we have a mount point. Then we can * hash to the appropriate device name and dump the data. * * Possible Problems: * a.)It's potentially quite slow. * b.)Memory utilization is potentially tremendous. * c.)The program is not guaranteed to perform correctly * if the user is not root. It should probably do a getuid() * and print an informational message. * d.)Non-unique device names; currently defaults to * those prefixed with DEV_DIR, e.g., for DEV_DIR "/dev/dsk", * /dev/dsk/c0d0s6 is preferred to /dev/diskette. * * Notes: * a.)Assumes devices found under DEV_DIR. * */ #include "defs.h" struct node *new_node(), *ListHead, *ListTail; char *strsave(), *emalloc(), *malloc(), *Current_Dir, /* our idea of the current directory */ *New_Dir; /* destination when changing dirs */ /* * Flag to indicate short output format. */ int Short_Flag; char *StartBrk; /* starting break value */ main( argc, argv ) int argc; char *argv[]; { char *sbrk(); if( argc > 2 ) { usage(); } else if( argc == 2 ) { if( strcmp( argv[1], "-s" ) == 0 ) Short_Flag = 1; else usage(); } else { Short_Flag = 0; } setup(); search(); #ifdef HDEBUG hash_stats(); #endif #ifdef MEM printf( "Used %d characters of allocated memory.\n", sbrk(0) - StartBrk ); #endif exit( 0 ); } setup() { char *sbrk(); struct stat sb; struct node *nd; static char path_buf1[BUFSIZ], path_buf2[BUFSIZ]; StartBrk = sbrk(0); nd = new_node(); stat( ROOT_DIR, &sb ); nd->n_name = strsave( ROOT_DIR ); nd->n_parent = nd; nd->n_next = nd; nd->n_dev = sb.st_dev; ListHead = ListTail = nd; do_devs( DEV_DIR ); analyze_tree(); if( chdir( ROOT_DIR ) < 0 ) panic( "can't cd to root directory" ); prt_mnt_pt( nd, "", &sb ); sprintf( path_buf1, "%s", ROOT_DIR ); Current_Dir = path_buf1; New_Dir = path_buf2; return; } search() { int all_found(); struct node *ptr; ptr = ListHead; while( !all_found() ) { get_mnt_pts( ptr ); ptr = ptr->n_next; } return; } get_mnt_pts( dir ) struct node *dir; { DIR *dir_fd; void append_List(); struct direct *dir_ent; struct stat sb; char *tmp; /* test this code if( leaf( dir->n_dev ) ) return; */ sprt_path_from_node( New_Dir, dir ); /* cheap hack; buys a lot on big systems; * If there's a possibility of finding mount points * under DEV, some code should be added to * do_devs() so that stat()'s aren't done twice. */ if( strcmp( New_Dir, DEV ) == 0 ) return; if( cheap_cd( Current_Dir, New_Dir ) < 0 ) panic( "chdir() failed" ); tmp = Current_Dir; Current_Dir = New_Dir; New_Dir = tmp; dir_fd = opendir( "." ); if( dir_fd == (DIR *) NULL ) { fprintf( stderr, "Current_Dir was: %s\n", Current_Dir ); panic( "opendir(\".\") failed; exiting" ); } while( (dir_ent = readdir( dir_fd )) != (struct direct *) NULL ) { /* crude but fast code to boogie thru ino==0, "." and ".." */ if( (dir_ent->d_ino == 0) || (dir_ent->d_name[0] == '.' && ((dir_ent->d_name[1] == EOS) || (dir_ent->d_name[1] == '.' && dir_ent->d_name[2] == EOS)))) continue; stat( dir_ent->d_name, &sb ); if( ((sb.st_mode & S_IFMT) == S_IFDIR )) { if( sb.st_dev != dir->n_dev ) { prt_mnt_pt( dir, dir_ent->d_name, &sb ); if( !leaf( sb.st_dev ) ) append_List( dir, dir_ent->d_name, sb.st_dev ); update_tree( sb.st_dev ); } else { append_List( dir, dir_ent->d_name, sb.st_dev ); } } } closedir( dir_fd ); return; } void append_List( dir, name, dev ) struct node *dir; char *name; dev_t dev; { struct node *nd; nd = new_node(); nd->n_name = strsave( name ); nd->n_parent = dir; nd->n_dev = dev; /* append to list, at tail */ ListTail->n_next = nd; nd->n_prev = ListTail; nd->n_next = (struct node *) NULL; ListTail = nd; return; } struct node * new_node() { return( (struct node *) emalloc( sizeof( struct node ) ) ); } @EOF chmod 666 xgetmnt.c exit 0 From pat at rwing.UUCP Sun Jan 14 07:36:17 1990 From: pat at rwing.UUCP (Pat Myrto) Date: 13 Jan 90 20:36:17 GMT Subject: Menu software... version 1.35 upgrade to "lush" part 1/1 References: <3888@yunccn.UUCP> <3890@yunccn.UUCP> Message-ID: <1033@rwing.UUCP> In article <3890 at yunccn.UUCP>, shields at yunccn.UUCP (Paul Shields) writes: > Note: I haven't compiled lush for MS-DOS in at least a year. You may > have to work on it. When the Version 1.35 sources are combined with the rest of the package posted earlier as Version 1.34, I discovered it wouldn't compile under Sys V, stopping at edit.c with 'grp' being undefined. The problem is the order in which lush.h includes defs.h and config.h. The present order of including defs.h before config.h prevents defs.h from seeing if MULTIUSER is defined in config.h, preventing the struct group *grp from being defined. The fix is to simply reverse the order of the includes in lush.h from #include "defs.h" /* old directives */ #include "config.h" to #include "config.h" /* fixed directives */ #include "defs.h" The package will now compile under Sys V the same as Version 1.34. Hopefully this will save someone the time of figuring out why the structure wasn't defined in this version when it was OK in the the previous one. -- pat at rwing (Pat Myrto), Seattle, WA ...!uunet!gtenmc!pilchuck!rwing!pat ...!uw-beaver!uw-entropy!dataio!/ WISDOM: "Travelling unarmed is like boating without a life jacket" From wht at tridom.uucp Wed Jan 17 17:58:58 1990 From: wht at tridom.uucp (Warren Tucker) Date: 17 Jan 90 06:58:58 GMT Subject: Getting the time over the phone from NBS References: <1043@khijol.UUCP> Message-ID: <899@tridom.uucp> I just posted to alt.sources cmostime3, a two-part shar, which was an expansion on my previous program, nbs_time.c. The whole business was inspired by comp.sources.misc v03i079. The original author did all the hard work. For nbs_time.c, I just put a bunch of async junk around it to autodial and otherwise make it a standalone program. cmostime built on this to avoid using the inexact /etc/setclock and a few other goodies. v03i079 contains a GREAT program utc.c which allows your system to mimic NBS and provide esentially the same service via a local call. Only the most ultimate time freaks who've replaced their PC's crystal with an atomic clock can tell the difference (I'm pretty bad, but not that bad) :-). -- ------------------------------------------------------------------ Warren Tucker, Tridom Corporation ...!gatech!emory!tridom!wht home address: ...!gatech!kd4nc!n4hgf!wht From clewis at eci386.uucp Wed Jan 10 07:36:00 1990 From: clewis at eci386.uucp (Chris Lewis) Date: 9 Jan 90 20:36:00 GMT Subject: Official Patch 6 for psroff. Message-ID: <1990Jan9.203600.5919@eci386.uucp> Patch 06 for psroff, please install it. To install the patch, please: cd to your psroff source directory restore the original defs.h and Makefile unshar this patch execute the file 'prepatch', by executing 'sh ./prepatch' patch -p < Patch06 Please read README for patch 06 and see if any of the the changes affect your installation. Reconfigure the new defs.h and Makefile to match your system make su root make install #! /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 archive 1 (of 1)." # Contents: ./Intro.06 ./Patch06 ./macros ./macros/common.post # ./macros/common.pre ./macros/tmac.an ./macros/tmac.m # ./macros/tmac.s ./prepatch ./tmac.t2.sh # Wrapped by clewis at eci386 on Mon Jan 8 16:40:21 1990 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f './Intro.06' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./Intro.06'\" else echo shar: Extracting \"'./Intro.06'\" \(435 characters\) sed "s/^X//" >'./Intro.06' <<'END_OF_FILE' X Patch 06 for psroff, please install it. X X To install the patch, please: X X cd to your psroff source directory X restore the original defs.h and Makefile X unshar this patch X execute the file 'prepatch', by executing 'sh ./prepatch' X patch -p < Patch06 X Please read README for patch 06 and see if any of the X the changes affect your installation. X Reconfigure the new defs.h and Makefile to match your system X make X su root X make install END_OF_FILE if test 435 -ne `wc -c <'./Intro.06'`; then echo shar: \"'./Intro.06'\" unpacked with wrong size! fi # end of './Intro.06' fi if test -f './Patch06' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./Patch06'\" else echo shar: Extracting \"'./Patch06'\" \(27263 characters\) sed "s/^X//" >'./Patch06' <<'END_OF_FILE' X*** /usr4/public/src/t2current/./lj.c Mon Jan 8 16:37:54 1990 X--- ./lj.c Mon Jan 8 16:38:58 1990 X*************** X*** 52,61 **** X X #ifndef SVR3 X #ifndef lint X! static char SCCSid[] = "@(#)lj.c: 1.10 Copyright 89/12/05 14:03:51 Chris Lewis"; X #endif X #else X! #ident "@(#)lj.c: 1.10 Copyright 89/12/05 14:03:51 Chris Lewis" /*(SVR3)*/ X #endif X X #define USED 1 X--- 52,61 ---- X X #ifndef SVR3 X #ifndef lint X! static char SCCSid[] = "@(#)lj.c: 1.11 Copyright 89/12/22 11:02:10 Chris Lewis"; X #endif X #else X! #ident "@(#)lj.c: 1.11 Copyright 89/12/22 11:02:10 Chris Lewis" /*(SVR3)*/ X #endif X X #define USED 1 X*************** X*** 190,195 **** X--- 190,196 ---- X xad = points * rp->t2b_xc; X yad = points * rp->t2b_yc; X ljSetFont(font, points); X+ DEBUGPRINTF("sequence: %s, x, y = %f,%f\n", sequence, nx+xad, ny+yad); X X /* We won't output fractions */ X #define XYS "\033&a%.0fh%.0fV%s" X*** /usr4/public/src/t2current/./dt.h Mon Jan 8 16:38:29 1990 X--- ./dt.h Mon Jan 8 16:39:00 1990 X*************** X*** 14,23 **** X X #ifndef SVR3 X #ifndef lint X! static char dtID[] = "@(#)dt.h: 1.2 Copyright 89/12/08 15:35:07 Chris Lewis"; X #endif X #else X! #ident "@(#)dt.h: 1.2 Copyright 89/12/08 15:35:07 Chris Lewis" X #endif X X /* This is actually done in the back-end */ X--- 14,23 ---- X X #ifndef SVR3 X #ifndef lint X! static char dtID[] = "@(#)dt.h: 1.3 Copyright 90/01/08 16:31:05 Chris Lewis"; X #endif X #else X! #ident "@(#)dt.h: 1.3 Copyright 90/01/08 16:31:05 Chris Lewis" X #endif X X /* This is actually done in the back-end */ X*************** X*** 24,33 **** X #define DTRESOLUTION 300 X /* Length scaling factor */ X #define DTSCALEFACTOR ((double) dtresolution / TROFFRESOLUTION) X! /* Troff assumes 7.5" paper width, most macro packages print in X! 6.5" area within that. Sooo, we'll center the paperwidth on the X! physical page - implying .5" inch physical margins.*/ X! #define TROFF2DTX(x) ((x) * DTSCALEFACTOR + dtresolution / 2) X /* 11" paper length */ X #define TROFF2DTY(y) ((y) * DTSCALEFACTOR) X X--- 24,30 ---- X #define DTRESOLUTION 300 X /* Length scaling factor */ X #define DTSCALEFACTOR ((double) dtresolution / TROFFRESOLUTION) X! #define TROFF2DTX(x) ((x) * DTSCALEFACTOR) X /* 11" paper length */ X #define TROFF2DTY(y) ((y) * DTSCALEFACTOR) X X*** /usr4/public/src/t2current/./psroff.sh Mon Jan 8 16:38:30 1990 X--- ./psroff.sh Mon Jan 8 16:39:00 1990 X*************** X*** 11,25 **** X # Author: Chris Lewis X # Specs: troff driver X # X! #ident "@(#)psroff.sh: 1.22 Copyright 89/12/12 15:55:55 Chris Lewis" X troff=troff X! #troff=/usr2/clewis/src/spxroff/tnroff/troff X term=false X type=`basename $0 | sed -e 's/^\(..\).*/\1/'` X copies=1 X for i in $* X do X case $i in X -X) X set -x X ;; X--- 11,29 ---- X # Author: Chris Lewis X # Specs: troff driver X # X! #ident "@(#)psroff.sh: 1.24 Copyright 90/01/03 11:48:55 Chris Lewis" X troff=troff X! #troff=/usr2/clewis/src/spx/tnroff/troff X term=false X+ fail=false X type=`basename $0 | sed -e 's/^\(..\).*/\1/'` X copies=1 X for i in $* X do X case $i in X+ -F) X+ fail=true X+ ;; X -X) X set -x X ;; X*************** X*** 43,48 **** X--- 47,56 ---- X file="%%TMACDIR%%/mac.$type/tmac.$mac" X if [ ! -r $file ] X then X+ file="%%TMACDIR%%/tmac.$mac" X+ fi X+ if [ ! -r $file ] X+ then X file="%%RTMACDIR%%/tmac.$mac" X fi X if [ ! -r $file ] X*************** X*** 106,112 **** X exit 1 X ;; X esac X! if $term X then X ( $troff -t -T$type $args $files 2>&1 ) | $t2 $length -T$type $debug X exit $? X--- 114,123 ---- X exit 1 X ;; X esac X! if $fail X! then X! $troff -t -T$type $args $files > /dev/null X! elif $term X then X ( $troff -t -T$type $args $files 2>&1 ) | $t2 $length -T$type $debug X exit $? X*** /usr4/public/src/t2current/./ps.h Mon Jan 8 16:37:56 1990 X--- ./ps.h Mon Jan 8 16:39:01 1990 X*************** X*** 13,22 **** X X #ifndef SVR3 X #ifndef lint X! static char psID[] = "@(#)ps.h: 1.16 Copyright 89/12/06 15:28:45 Chris Lewis"; X #endif X #else X! #ident "@(#)ps.h: 1.16 Copyright 89/12/06 15:28:45 Chris Lewis" X #endif X X /* Points per inch (default PostScript resolution) */ X--- 13,22 ---- X X #ifndef SVR3 X #ifndef lint X! static char psID[] = "@(#)ps.h: 1.17 Copyright 90/01/08 16:31:08 Chris Lewis"; X #endif X #else X! #ident "@(#)ps.h: 1.17 Copyright 90/01/08 16:31:08 Chris Lewis" X #endif X X /* Points per inch (default PostScript resolution) */ X*************** X*** 23,32 **** X #define PSRESOLUTION 72 X /* Length scaling factor */ X #define PSSCALEFACTOR ((double) PSRESOLUTION / TROFFRESOLUTION) X! /* Troff assumes 7.5" paper width, most macro packages print in X! 6.5" area within that. Sooo, we'll center the paperwidth on the X! physical page - implying .5" inch physical margins.*/ X! #define TROFF2PSX(x) ((x) * PSSCALEFACTOR + PSRESOLUTION / 2) X /* 11" paper length (note the reversed sign!) */ X #define TROFF2PSY(y) ((pagelength - (y)) * PSSCALEFACTOR) X X--- 23,29 ---- X #define PSRESOLUTION 72 X /* Length scaling factor */ X #define PSSCALEFACTOR ((double) PSRESOLUTION / TROFFRESOLUTION) X! #define TROFF2PSX(x) ((x) * PSSCALEFACTOR) X /* 11" paper length (note the reversed sign!) */ X #define TROFF2PSY(y) ((pagelength - (y)) * PSSCALEFACTOR) X X*** /usr4/public/src/t2current/./dt.c Mon Jan 8 16:38:31 1990 X--- ./dt.c Mon Jan 8 16:39:03 1990 X*************** X*** 19,28 **** X X #ifndef SVR3 X #ifndef lint X! static char SCCSid[] = "@(#)dt.c: 1.9 Copyright 89/12/13 11:28:39 Chris Lewis"; X #endif X #else X! #ident "@(#)dt.c: 1.9 Copyright 89/12/13 11:28:39 Chris Lewis" /*(SVR3)*/ X #endif X X #define MAXFONT 50 X--- 19,28 ---- X X #ifndef SVR3 X #ifndef lint X! static char SCCSid[] = "@(#)dt.c: 1.10 Copyright 89/12/21 17:26:07 Chris Lewis"; X #endif X #else X! #ident "@(#)dt.c: 1.10 Copyright 89/12/21 17:26:07 Chris Lewis" /*(SVR3)*/ X #endif X X #define MAXFONT 50 X*************** X*** 334,344 **** X long x, y; X int font, points, troffChar; { X static double lasty = (-1); X register double nx = TROFF2DTX(x), ny = TROFF2DTY(y); X register struct troff2befont *rp; X register char *sequence = "a"; X if (pagePending) { X! lasty = lastFont = lastPoints = (-1); X doPageStart(); X } X X--- 334,345 ---- X long x, y; X int font, points, troffChar; { X static double lasty = (-1); X+ static double lastx = (-1); X register double nx = TROFF2DTX(x), ny = TROFF2DTY(y); X register struct troff2befont *rp; X register char *sequence = "a"; X if (pagePending) { X! lastx = lasty = lastFont = lastPoints = (-1); X doPageStart(); X } X X*************** X*** 394,408 **** X printf("H%d\nV%d\nc%s\n", (int) nx, (int) ny, sequence); X else { X #endif X! printf("H%d\n", (int) nx); X! if (lasty != ny) { X! printf("V%d\n", (int) ny); X! lasty = ny; X } X- if (sequence[1]) X- printf("C%s\n", sequence); X- else X- printf("c%s\n", sequence); X #ifdef NOTYET X } X #endif X--- 395,423 ---- X printf("H%d\nV%d\nc%s\n", (int) nx, (int) ny, sequence); X else { X #endif X! /* print an nnc sequence if we can...may even be able to avoid X! the newline. */ X! X! if (lasty == ny && X! sequence[1] == 0 && X! lastx != -1 && X! (nx - lastx) > 0 && (nx - lastx) < 100) { X! X! printf("%02d%c\n",(int)(nx - lastx), sequence[0]); X! X! } else { X! X! printf("H%d\n", (int) nx); X! X! if (lasty != ny) { X! printf("V%d\n", (int) ny); X! lasty = ny; X! } X! if (sequence[1]) X! printf("C%s\n", sequence); X! else X! printf("c%s\n", sequence); X } X #ifdef NOTYET X } X #endif X*** /usr4/public/src/t2current/./lj.h Mon Jan 8 16:38:34 1990 X--- ./lj.h Mon Jan 8 16:39:05 1990 X*************** X*** 16,25 **** X X #ifndef SVR3 X #ifndef lint X! static char ljID[] = "@(#)lj.h: 1.7 Copyright 89/12/14 11:29:36 Chris Lewis"; X #endif X #else X! #ident "@(#)lj.h: 1.7 Copyright 89/12/14 11:29:36 Chris Lewis" X #endif X X /* We're using decipoints */ X--- 16,25 ---- X X #ifndef SVR3 X #ifndef lint X! static char ljID[] = "@(#)lj.h: 1.8 Copyright 90/01/08 16:31:10 Chris Lewis"; X #endif X #else X! #ident "@(#)lj.h: 1.8 Copyright 90/01/08 16:31:10 Chris Lewis" X #endif X X /* We're using decipoints */ X*************** X*** 27,50 **** X /* Length scaling factor */ X #define LJSCALEFACTOR ((double) LJRESOLUTION / TROFFRESOLUTION) X X! /* Troff assumes 7.5" paper width, most macro packages print in X! 6.5" area within that. Sooo, we'll center the paperwidth on the X! physical page - implying .5" inch physical margins.*/ X! #define TROFF2LJX(x) ((x) * LJSCALEFACTOR + LJRESOLUTION / 2) X X /* 11" paper length */ X #define TROFF2LJY(y) ((y) * LJSCALEFACTOR) X X- /* These won't work (ron at mlfarm, */ X- /* 10.22.89) -- the offset of 1/2 inch */ X- /* spoils it, and the length scaling */ X- /* won't fit on a page. I'll only */ X /* change the DJ */ X- #ifdef BROKEN_XENIX X- #define TROFF2DJX(x) ((x) * LJSCALEFACTOR) X- #else X #define TROFF2DJX(x) TROFF2LJX(x) X- #endif X /* for length, we want .25 inch */ X /* margins top and bottom, so we'll */ X /* scale the requests and add .25 inch */ X--- 27,39 ---- X /* Length scaling factor */ X #define LJSCALEFACTOR ((double) LJRESOLUTION / TROFFRESOLUTION) X X! #define TROFF2LJX(x) ((x) * LJSCALEFACTOR) X X /* 11" paper length */ X #define TROFF2LJY(y) ((y) * LJSCALEFACTOR) X X /* change the DJ */ X #define TROFF2DJX(x) TROFF2LJX(x) X /* for length, we want .25 inch */ X /* margins top and bottom, so we'll */ X /* scale the requests and add .25 inch */ X*** /usr4/public/src/t2current/./defs.h Mon Jan 8 16:38:36 1990 X--- ./defs.h Mon Jan 8 16:39:09 1990 X*************** X*** 17,23 **** X #define LIBDIR "/usr/lib/troff2" X #endif X X! #define T2VERSION "Release 1 Patchlevel 5 89/12/14" X X /* Configuration parameters: X */ X--- 17,23 ---- X #define LIBDIR "/usr/lib/troff2" X #endif X X! #define T2VERSION "Release 1 Patchlevel 6 89/12/29" X X /* Configuration parameters: X */ X*************** X*** 118,127 **** X X #ifndef SVR3 X #ifndef lint X! static char defid[] = "@(#)defs.h: 1.23 Copyright 89/12/14 11:29:44 Chris Lewis"; X #endif X #else X! #ident "@(#)defs.h: 1.23 Copyright 89/12/14 11:29:44 Chris Lewis" X #endif X X #include <stdio.h> X--- 118,127 ---- X X #ifndef SVR3 X #ifndef lint X! static char defid[] = "@(#)defs.h: 1.24 Copyright 89/12/29 15:24:49 Chris Lewis"; X #endif X #else X! #ident "@(#)defs.h: 1.24 Copyright 89/12/29 15:24:49 Chris Lewis" X #endif X X #include <stdio.h> X*** /usr4/public/src/t2current/./ps.c Mon Jan 8 16:38:37 1990 X--- ./ps.c Mon Jan 8 16:39:12 1990 X*************** X*** 18,27 **** X X #ifndef SVR3 X #ifndef lint X! static char SCCSid[] = "@(#)ps.c: 1.32 Copyright 89/12/14 11:29:57 Chris Lewis"; X #endif X #else X! #ident "@(#)ps.c: 1.32 Copyright 89/12/14 11:29:57 Chris Lewis" /*(SVR3)*/ X #endif X X /* ps.c will generate some additional "print" commands to cause X--- 18,27 ---- X X #ifndef SVR3 X #ifndef lint X! static char SCCSid[] = "@(#)ps.c: 1.33 Copyright 90/01/05 20:16:44 Chris Lewis"; X #endif X #else X! #ident "@(#)ps.c: 1.33 Copyright 90/01/05 20:16:44 Chris Lewis" /*(SVR3)*/ X #endif X X /* ps.c will generate some additional "print" commands to cause X*************** X*** 318,328 **** X }; X X psPage() { X! EMITPS("hits misses\n"); X! EMITPS("PageSave restore\n"); X! EMITPS("/misses exch def /hits exch def\n"); X! EMITPS("ShowPage\n"); X! pagePending = 1; X } X X static X--- 318,330 ---- X }; X X psPage() { X! if (!currentPage) X! return; X! EMITPS("hits misses\n"); X! EMITPS("PageSave restore\n"); X! EMITPS("/misses exch def /hits exch def\n"); X! EMITPS("ShowPage\n"); X! pagePending = 1; X } X X static X*** /usr4/public/src/t2current/./psroff.1 Mon Jan 8 16:38:38 1990 X--- ./psroff.1 Mon Jan 8 16:39:15 1990 X*************** X*** 1,14 **** X! .\"Copyright 1988 by Chris Lewis 1.7 89/12/12 X .TH PSROFF 1 local X .SH NAME X psroff,ljroff,xxroff \- troff replacement for PostScript or other printers X .SH SYNOPSIS X .IB xx roff X! [-D] [-X] [-M] X! [-Rnn] X .RI "[-T" xx "]" X .RI "[-rL" length "]" X! .RI [ troffopts ] files ... X .SH DESCRIPTION X .I Psroff X is functionally equivalent for X--- 1,15 ---- X! .\"Copyright 1988 by Chris Lewis 1.8 89/12/29 X .TH PSROFF 1 local X .SH NAME X psroff,ljroff,xxroff \- troff replacement for PostScript or other printers X .SH SYNOPSIS X .IB xx roff X! [-D] [-X] [-M] [-F] X! .RI "[-R" nn "]" X .RI "[-T" xx "]" X .RI "[-rL" length "]" X! .RI [ troffopts ] X! files ... X .SH DESCRIPTION X .I Psroff X is functionally equivalent for X*************** X*** 20,30 **** X arguments, in particular -m directives for specifying macro package. X Note that the semantics of "-t" are changed - it means send the Postscript X (or HP Laserjet) output to stdout. X! The "-X" option does a "set -x" for debugging. X! The "-D" option passes the "-D" option through to troff2ps. X! The "-M" option turns on printer metrics (if supported by the driver). X! The "-Rnn" option is passed to troff2ps and will set the resolution of X the generated output (ditroff output only). X .P X Note that -m directives are parsed by psroff itself, not troff, and X must be invoked *after* -T if -T is used. X--- 21,34 ---- X arguments, in particular -m directives for specifying macro package. X Note that the semantics of "-t" are changed - it means send the Postscript X (or HP Laserjet) output to stdout. X! The ``-X'' option does a ``set -x'' for debugging. X! The ``D'' option passes the ``-D'' option through to troff2ps. X! The ``-M'' option turns on printer metrics (if supported by the driver). X! The ``-Rnn'' option is passed to troff2ps and will set the resolution of X the generated output (ditroff output only). X+ The ``-F'' option runs troff without X+ .RI troff2 xx X+ so that you can see troff's error messages. X .P X Note that -m directives are parsed by psroff itself, not troff, and X must be invoked *after* -T if -T is used. X*************** X*** 58,63 **** X--- 62,136 ---- X used (see the documentation for MM and X .I troff2ps X for more details). X+ .SH MACROS X+ Included with the X+ .I psroff X+ package is a set of macros called X+ .IR tmac.t2 . X+ This is a set of extensions to and definitions for MM that we find useful. X+ .P X+ .I psroff X+ comes with a series of macro adapters designed to make it work X+ with the least amount of grief with various macro packages. X+ In order for this to work, whenever you specify the X+ .RI -m macro X+ option, X+ .I psroff X+ attempts to find a set of adapters for the specified macro package. X+ The search path is as follows: X+ .BI /usr/lib/troff2/macros/mac. type /tmac. macro , X+ .BI /usr/lib/troff2/macros/tmac. macro , X+ and finally X+ .BI /usr/lib/tmac/tmac. macro . X+ Where X+ .I type X+ is the printer type (eg: ``ps'') and X+ .I macro X+ is the macros you requested (eg: ``m'' for a request of ``-mm''). X+ Only the first X+ .BR tmac. macro X+ file found is used. X+ .P X+ The first two directories can contain files with something of the following X+ form: X+ .nf X+ \&.so /usr/lib/troff2/macros/common.pre X+ macro specific prolog customization if necessary X+ \&.so <real macro package> X+ macro specific epilog customization if necessary X+ \&.so /usr/lib/troff2/macros/common.post X+ .fi X+ .P X+ The intent is for X+ .BI macros/mac. type /tmac. macro X+ files to be adapters where the modifications have to be based on X+ printer type, X+ and X+ .BI macros/tmac. macro X+ where the modifications are independent of the printer type. X+ .P X+ .IR Psroff, X+ as shipped comes with only printer independent adapters which have X+ the following customizations in X+ .BR common.pre : X+ turn off ligatures, X+ reload R, I, B, S font width tables, X+ define ``.sR'' macro, X+ and redefine ``.fp" directive to call both the built-in troff function ``.fp'' X+ and ``.sR''. X+ .B common.post X+ merely contains a disabling of ligatures (again). X+ The macro-specific customization (as present) is simply the removal of X+ cut marks. X+ .SH FILES X+ .if t .ta 2.5i X+ .if n .ta 3.5i X+ /usr/lib/troff2 Troff2ps library directory X+ .br X+ /usr/lib/troff2/macros/mac.* printer specific macro adapter directories X+ .br X+ /usr/lib/troff2/macros/tmac.* non-specific macro adapters X+ etc. X .SH BUGS X Old-fashioned CAT troff doesn't have a mechanism for passing arbitrary X commands to the CAT - eg: overlays, and physical font mounting etc. X*************** X*** 75,82 **** X errors except possibly as "illegal flash" errors from troff2ps, or varying X degrees of extreme garbage on the printer. X If you encounter mangled output, try running X! troff instead of psroff, with the ``-t'' option, and direct stdout X! to /dev/null. X Then you will see troff's stderr. X .SH "SEE ALSO" X troff(1), troff2ps(1L), mm(5?) X--- 148,154 ---- X errors except possibly as "illegal flash" errors from troff2ps, or varying X degrees of extreme garbage on the printer. X If you encounter mangled output, try running X! psroff, with the ``-F'' option. X Then you will see troff's stderr. X .SH "SEE ALSO" X troff(1), troff2ps(1L), mm(5?) X*** /usr4/public/src/t2current/./Makefile Mon Jan 8 16:38:39 1990 X--- ./Makefile Mon Jan 8 16:39:16 1990 X*************** X*** 12,18 **** X # Note: This is a System V Makefile, so you may X # have some problems making a few of the items. X # X! #ident "@(#)Makefile: 1.42 Copyright 89/12/13 14:19:41 Chris Lewis" X X # Set to where you want the user-interfaces to go X BINDIR = /usr/lbin X--- 12,18 ---- X # Note: This is a System V Makefile, so you may X # have some problems making a few of the items. X # X! #ident "@(#)Makefile: 1.44 Copyright 90/01/08 16:31:17 Chris Lewis" X X # Set to where you want the user-interfaces to go X BINDIR = /usr/lbin X*************** X*** 33,39 **** X DTOUTPUT = | /usr/lib/troff/tpscript | rlp -dgate!AppleLaser -n$$copies X # Testing type: X TTYPE = ps X! TFLAGS = -mt2 X X # Libraries for Troff2 internals, created if it doesn't exist. X # This *must* be a directory all by itself with no other stuff X--- 33,39 ---- X DTOUTPUT = | /usr/lib/troff/tpscript | rlp -dgate!AppleLaser -n$$copies X # Testing type: X TTYPE = ps X! TFLAGS = -mm X X # Libraries for Troff2 internals, created if it doesn't exist. X # This *must* be a directory all by itself with no other stuff X*************** X*** 57,62 **** X--- 57,66 ---- X MAIN = troff2.o utils.o t2conf.o X BACKENDS = lj.o ps.o lj.o ljtables.o dt.o X PLIBDIR = $(LIBDIR)/lib X+ X+ MACROS = $(TMACDIR)/common.post $(TMACDIR)/common.pre \ X+ $(TMACDIR)/tmac.an $(TMACDIR)/tmac.m $(TMACDIR)/tmac.s X+ X INSTALL = $(LIBDIR)/troff2ps $(BINDIR)/psroff $(LIBDIR)/psxlate \ X $(T2DIR)/tmac.t2 \ X $(MANDIR)/psroff.1 \ X*************** X*** 67,72 **** X--- 71,85 ---- X $(PLIBDIR)/lib.ps $(PLIBDIR)/fonts.ps \ X $(PLIBDIR)/confid.ps $(PLIBDIR)/lethead.ps X X+ SEDSCRIPT = sed -e 's;%%LJOUTPUT%%;$(LJOUTPUT);g' \ X+ -e 's;%%LKOUTPUT%%;$(LKOUTPUT);g' \ X+ -e 's;%%DJOUTPUT%%;$(DJOUTPUT);g' \ X+ -e 's;%%PSOUTPUT%%;$(PSOUTPUT);g' \ X+ -e 's;%%DTOUTPUT%%;$(DTOUTPUT);g' \ X+ -e 's;%%LIBDIR%%;$(LIBDIR);g' \ X+ -e 's;%%TMACDIR%%;$(TMACDIR);g' \ X+ -e 's;%%RTMACDIR%%;$(RTMACDIR);g' X+ X DEFINES = '-DLIBDIR="$(PLIBDIR)"' X CFLAGS = $(DEFINES) X X*************** X*** 105,110 **** X--- 118,125 ---- X X all: $(UTILLIST) fonts X X+ macros: $(MACROS) X+ X chartab.tst ltest.tst: troff2ps X chartab.prt ltest.prt: troff2ps X X*************** X*** 120,125 **** X--- 135,142 ---- X dit2catwid: dit2catwid.o X $(CC) $(CFLAGS) -o dit2catwid dit2catwid.o $(LIBFLAGS) X X+ dit2catwid.o:: defs.h X+ X # The following is commented out because make has a bug in that X # even if you don't want to make lint, it insists on making X # the .c's from the SCCS files. X*************** X*** 132,138 **** X ps.o: defs.h ps.h X lj.o ljtables.o: defs.h lj.h X dt.o: defs.h dt.h X- dit2catwid.o: defs.h X X # Testing software: X testps.o: defs.h ps.h X--- 149,154 ---- X*************** X*** 140,146 **** X troff2.o utils.o: defs.h X X install: $(LIBDIR) $(T2DIR) $(TMACDIR) $(RTMACDIR) $(PLIBDIR) \ X! $(INSTALL) installfonts X X fonts: dit2catwid gfnttab X for i in font?? ; \ X--- 156,162 ---- X troff2.o utils.o: defs.h X X install: $(LIBDIR) $(T2DIR) $(TMACDIR) $(RTMACDIR) $(PLIBDIR) \ X! $(INSTALL) $(MACROS) installfonts X X fonts: dit2catwid gfnttab X for i in font?? ; \ X*************** X*** 164,181 **** X $(LIBDIR) $(T2DIR) $(TMACDIR) $(PLIBDIR): X su root -c "mkdir $@" X X! psroff: psroff.sh Makefile X! sed -e 's;%%LJOUTPUT%%;$(LJOUTPUT);g' \ X! -e 's;%%LKOUTPUT%%;$(LKOUTPUT);g' \ X! -e 's;%%DJOUTPUT%%;$(DJOUTPUT);g' \ X! -e 's;%%PSOUTPUT%%;$(PSOUTPUT);g' \ X! -e 's;%%DTOUTPUT%%;$(DTOUTPUT);g' \ X! -e 's;%%LIBDIR%%;$(LIBDIR);g' \ X! -e 's;%%TMACDIR%%;$(TMACDIR);g' \ X! -e 's;%%RTMACDIR%%;$(RTMACDIR);g' \ X! psroff.sh > T X chmod 755 T X! mv T psroff X X deinstall: X su root -c "rm -f $(INSTALL); rmdir $(LIBDIR)" X--- 180,193 ---- X $(LIBDIR) $(T2DIR) $(TMACDIR) $(PLIBDIR): X su root -c "mkdir $@" X X! psroff upload showfont tmac.t2: $$(@).sh Makefile X! $(SEDSCRIPT) $@.sh > T X chmod 755 T X! mv T $@ X! X! $(MACROS): macros/$$(@F) X! $(SEDSCRIPT) macros/$(@F) > T X! su root -c "mv T $@" X X deinstall: X su root -c "rm -f $(INSTALL); rmdir $(LIBDIR)" X*** /usr4/public/src/t2current/./showfont.sh Mon Jan 8 16:36:27 1990 X--- ./showfont.sh Mon Jan 8 16:39:18 1990 X*************** X*** 1,7 **** X : X! #@(#)showfont 1.3 89/08/25 X # Shell script to dump postscript fonts with widths into a pretty table X X ( X cat << !END! X %! PS-Adobe 1.0 X--- 1,8 ---- X : X! #@(#)showfont 1.4 90/01/08 X # Shell script to dump postscript fonts with widths into a pretty table X X+ copies=1 X ( X cat << !END! X %! PS-Adobe 1.0 X*************** X*** 173,176 **** X %%Pages: 1 X !END! X echo '\004' X! ) | rlp -dgate!AppleLaser X--- 174,177 ---- X %%Pages: 1 X !END! X echo '\004' X! ) %%PSOUTPUT%% X*** /usr4/public/src/t2current/./upload.sh Mon Jan 8 16:35:51 1990 X--- ./upload.sh Mon Jan 8 16:39:19 1990 X*************** X*** 1,6 **** X : X! #@(#)upload 1.1 89/05/18 X! rlp -dgate!AppleLaser << 'END' X X /savearea save def X X--- 1,7 ---- X : X! #@(#)upload 1.2 90/01/08 X! copies=1 X! (cat %%PSOUTPUT%%) << 'END' X X /savearea save def X X*** /usr4/public/src/t2current/./README Mon Jan 8 16:38:42 1990 X--- ./README Mon Jan 8 16:39:26 1990 X*************** X*** 1,4 **** X! README 1.20 89/12/14 X See defs.h for the patchlevel X X Please read this document, especially any new patches near the end before X--- 1,4 ---- X! README 1.23 90/01/08 X See defs.h for the patchlevel X X Please read this document, especially any new patches near the end before X*************** X*** 28,35 **** X Or, generate ditroff and use tpscript. Output is X indistinguishable unless you know what you're looking for X (and I forgot ;-) X! - If you have ditroff backends, then use ditroff and throw X! psroff in the trash bucket. X X This is an formal release. There are rough edges however. I encourage X people to fiddle with it (particularly the mapping tables) and PLEASE X--- 28,35 ---- X Or, generate ditroff and use tpscript. Output is X indistinguishable unless you know what you're looking for X (and I forgot ;-) X! - If you have ditroff, then use ditroff and throw psroff X! in the trash bucket. X X This is an formal release. There are rough edges however. I encourage X people to fiddle with it (particularly the mapping tables) and PLEASE X*************** X*** 106,114 **** X tpscript by the way - great minds think alike) X X - The ditroff driver is fully complete, but not extremely X! well tested with backends other than tpscript. I've heard rumors X! of problems with jettroff, but haven't had them fully tracked down X! yet. X X - Regarding font width tables, there are several ways to go with X Postscript: X--- 106,114 ---- X tpscript by the way - great minds think alike) X X - The ditroff driver is fully complete, but not extremely X! well tested with backends other than tpscript. Nor have I X! personal experience with using it with jetroff, but I understand X! it works okay. X X - Regarding font width tables, there are several ways to go with X Postscript: X*************** X*** 175,180 **** X--- 175,182 ---- X .fp 2 I X .fp 3 B X .fp 4 S X+ X+ This is now done automatically by the macro adapter libraries. X X - There is some code to allow the sending of arbitrary commands to X the driver - see the .sR macro in tmac.t2, and troff2's X*************** X*** 405,416 **** X page offsets. X - NOCONTROLD for postscript printers that don't like ^D. X X Coming features (watch this space!) X - automatic macro/pre/post-processor determination (ala Doug X Gwyn's doctype function) X - More complete listings of Postscript font widths. X - Automatic generation of the fonts.?? file by gfnttab. X! (it already does, but not completely) X X PLEASE PLEASE PLEASE! If you have any problems with it, or would like X to make some suggestions for changing it, or have implemented a new driver X--- 407,444 ---- X page offsets. X - NOCONTROLD for postscript printers that don't like ^D. X X+ Patch 6: Dec 29 1989: macros/installability X+ 1) dt.c optimization from Dan Mick (uunet!charyb!dan) X+ 2) finished off adapter library stuff and documented it in psroff.1. X+ If you've made psroff-specific changes to your macro packages, X+ *please* take a look at what's going on in macros/common.* X+ and macros/tmac.*. Please note that this now automatically X+ reloads the width tables (for versions of troff that X+ have compiled-in default widths for R, I, B and S) and has X+ redefined ".fp" to call both troff's built-in ".fp" and X+ ".sR", so that font changes should now be psroff-independent. X+ Further, MM default width and offset has been changed to X+ 6.5 and .963 inches respectively. MAN and MS is .963inch offset. X+ MAN should centre properly, but MS may not. X+ 3) I removed the 1/2" rightshift in all versions of psroff, X+ and move the calculations to the macro packages. If you (or X+ your macro package) doesn't emit any ".po"'s, it will start X+ at the extreme left edge of the page (eg: in the unprintable X+ region of laser engines!) X+ 4) Added -F option to psroff. X+ 5) Added the SED script stuff to fix some things in other files X+ (eg: upload, showfont, tmac.t2). X+ 6) tmac.t2 is no longer a source file - it's now tmac.t2.sh. X+ X Coming features (watch this space!) X+ - Patch 7 will contain Ron Florence's SFP download improvements. X+ (but this will be superceded by SFP/PK downloading whenever X+ I get around to it). X - automatic macro/pre/post-processor determination (ala Doug X Gwyn's doctype function) X - More complete listings of Postscript font widths. X - Automatic generation of the fonts.?? file by gfnttab. X! (it already does, but not yet completely) X X PLEASE PLEASE PLEASE! If you have any problems with it, or would like X to make some suggestions for changing it, or have implemented a new driver END_OF_FILE if test 27263 -ne `wc -c <'./Patch06'`; then echo shar: \"'./Patch06'\" unpacked with wrong size! fi # end of './Patch06' fi if test ! -d './macros' ; then echo shar: Creating directory \"'./macros'\" mkdir './macros' fi if test -f './macros/common.post' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./macros/common.post'\" else echo shar: Extracting \"'./macros/common.post'\" \(69 characters\) sed "s/^X//" >'./macros/common.post' <<'END_OF_FILE' X.\"@(#)ident common.post %I% %E% X.\"Turn ligatures off (again) X'lg 0 END_OF_FILE if test 69 -ne `wc -c <'./macros/common.post'`; then echo shar: \"'./macros/common.post'\" unpacked with wrong size! fi # end of './macros/common.post' fi if test -f './macros/common.pre' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./macros/common.pre'\" else echo shar: Extracting \"'./macros/common.pre'\" \(588 characters\) sed "s/^X//" >'./macros/common.pre' <<'END_OF_FILE' X.\"@(#)ident common.pre %I% %E% X.\"Turn ligatures off X'lg 0 X.desR X.\"Output request sequence - thru .tm - caught by backend X.if t \{\ X.\"M is illegal C/A/T opcode - triggers troff2 to start collecting. X.\"newline is terminator X'tm M\\$1 X\} X.. X.\" Some troffs have built-in width tables for the base fonts. X.\" This forces troff to reload them from /usr/lib/font... X.fp 1 R X.fp 2 I X.fp 3 B X.fp 4 S X.\" Fix CAT Troff's ".fp" request to both load the font width X.\" table, plus issue the special request to the back end to switch X.\" fonts. X.rn fp fP X.de fp X.fP \\$1 \\$2 X.sR "F\\$1\\$2" X.. END_OF_FILE if test 588 -ne `wc -c <'./macros/common.pre'`; then echo shar: \"'./macros/common.pre'\" unpacked with wrong size! fi # end of './macros/common.pre' fi if test -f './macros/tmac.an' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./macros/tmac.an'\" else echo shar: Extracting \"'./macros/tmac.an'\" \(290 characters\) sed "s/^X//" >'./macros/tmac.an' <<'END_OF_FILE' X.\"@(#)ident tmac.an %I% %E% X.so %%TMACDIR%%/common.pre X.so %%RTMACDIR%%/tmac.an X.\"Default offset (my version of the man macros uses it). X.nr )O .963i X.\"See if someone's using the -rO option (ala MM) X.if \nO .nr )O \nOu X.po \n()Ou X.\"Clobber cut marks. X.rm }C X.so %%TMACDIR%%/common.post END_OF_FILE if test 290 -ne `wc -c <'./macros/tmac.an'`; then echo shar: \"'./macros/tmac.an'\" unpacked with wrong size! fi # end of './macros/tmac.an' fi if test -f './macros/tmac.m' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./macros/tmac.m'\" else echo shar: Extracting \"'./macros/tmac.m'\" \(239 characters\) sed "s/^X//" >'./macros/tmac.m' <<'END_OF_FILE' X.\"@(#)ident tmac.m %I% %E% X.so %%TMACDIR%%/common.pre X.\"Default linewidth 6.5 inches & page offset .963 inches. X.if !\nW .nr W 6.5i X.if !\nO .nr O .963i X.so %%RTMACDIR%%/tmac.m X.\"Clobber MM cut marks. X.rm )k X.so %%TMACDIR%%/common.post END_OF_FILE if test 239 -ne `wc -c <'./macros/tmac.m'`; then echo shar: \"'./macros/tmac.m'\" unpacked with wrong size! fi # end of './macros/tmac.m' fi if test -f './macros/tmac.s' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./macros/tmac.s'\" else echo shar: Extracting \"'./macros/tmac.s'\" \(136 characters\) sed "s/^X//" >'./macros/tmac.s' <<'END_OF_FILE' X.\"@(#)ident tmac.s %I% %E% X.so %%TMACDIR%%/common.pre X.so %%RTMACDIR%%/tmac.s X.\"Clobber cut marks. X.rm CM X.so %%TMACDIR%%/common.post END_OF_FILE if test 136 -ne `wc -c <'./macros/tmac.s'`; then echo shar: \"'./macros/tmac.s'\" unpacked with wrong size! fi # end of './macros/tmac.s' fi if test -f './prepatch' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./prepatch'\" else echo shar: Extracting \"'./prepatch'\" \(136 characters\) sed "s/^X//" >'./prepatch' <<'END_OF_FILE' Xif [ -r tmac.t2 -a ! -r tmac.t2.old ] Xthen X mv tmac.t2 tmac.t2.old X echo "Saving your old tmac.t2 just in case" Xfi Xrm -f prepatch END_OF_FILE if test 136 -ne `wc -c <'./prepatch'`; then echo shar: \"'./prepatch'\" unpacked with wrong size! fi # end of './prepatch' fi if test -f './tmac.t2.sh' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./tmac.t2.sh'\" else echo shar: Extracting \"'./tmac.t2.sh'\" \(1838 characters\) sed "s/^X//" >'./tmac.t2.sh' <<'END_OF_FILE' X.\" Copyright 1985, 1986, 1987, 1988 Chris Lewis X.\" All Rights Reserved X.\" X.\" Permission to copy and further distribute is freely given provided X.\" this copyright notice remains intact and that this software is not X.\" sold for profit. X.\" X.\" Project: Generic Troff drivers X.\" Module: tmac.eci.sh X.\" Author: Chris Lewis X.\" Specs: MM Prolog X.\"ident "@(#)tmac.eci.sh: 1.28 Copyright 90/01/08 16:31:03 Chris Lewis" X.\"endif X.so %%TMACDIR%%/tmac.m X.tr \(bs X.ds}2 Elegant Communications Inc. X.dsIn \*(}2 X.dsBU \s+2\(bu\s0 X.de eX X.ie \\w'\\$1'=0 .ds ee X.el .ds ee "\\$1 X.DS \\$2 \\$3 X\!.fp 1 C X.\"\!.lg 0 X\!.cs 1 24 X.ss 24 X\!.br X.. X.de eE X\!.fp 1 R X\!.cs 1 X.ss 12 X\!.br X\.if \\w'\\*(ee'>0 .FG "\\*(ee" X.DE X.. X.ds HP +4 +2 X.ds HF 3 3 2 2 X.OH "'''Elegant Communications Inc.'" X.EH "'''Elegant Communications Inc.'" X.PH "''''" X.if t .PF "''\s8481 University Avenue, Suite 602, Toronto, Canada, M5G 2E9 (416)-595-5425, FAX (416) 595-5439\s0''" X.if n .PF "''481 University Avenue, Suite 602, Toronto, Canada''" X.\".OF "'Page \\\\nP''\\\\*(DT'" X.OF "'\\\\*(DT''Page \\\\nP'" X.EF "'\\\\*(DT''Page \\\\nP'" X.de nH X.OF "''''" X.EF "''''" X.PF "''''" X.OH "''''" X.EH "''''" X.PH "''''" X.. X.de aD X.SP 3 X.DS XElegant Communications Inc. X481 University Avenue, XSuite 602 XToronto, Ontario XM5G 2E9 X XPhone: (416) 595-5425 XFax: (416) 595-5439 X.DE X.. X.\" Appendix Macros X.de AH X.if \\n(aH=0\{ X.nr aH 1 X.nr h1 0\} X.nr;1 0\\$1 X.if!\\n(;1 .)D "aH:bad arg:\\$1" X.if2-\\n(;1 .nr h2 0 1 X.if3-\\n(;1 .nr h3 0 1 X.if4-\\n(;1 .nr h4 0 1 X.if5-\\n(;1 .nr h5 0 1 X.if6-\\n(;1 .nr h6 0 1 X.if7-\\n(;1 .nr h7 0 1 X.nr h\\n(;1 +1 X.afh1 A X.ds}0 \\n(h1. X.if0\\$1-1 .as }0 \\n(h2 X.if0\\$1-2 .as }0 .\\n(h3 X.if0\\$1-3 .as }0 .\\n(h4 X.if0\\$1-4 .as }0 .\\n(h5 X.if0\\$1-5 .as }0 .\\n(h6 X.if0\\$1-6 .as }0 .\\n(h7 X.nr Hu \\n(;1 X.HU "Appendix \\*(}0\\ \\ \\$2" X.. END_OF_FILE if test 1838 -ne `wc -c <'./tmac.t2.sh'`; then echo shar: \"'./tmac.t2.sh'\" unpacked with wrong size! fi # end of './tmac.t2.sh' fi echo shar: End of archive 1 \(of 1\). cp /dev/null ark1isdone MISSING="" for I in 1 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have the archive. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 -- Chris Lewis, Elegant Communications Inc, {uunet!attcan,utzoo}!lsuc!eci386!clewis Ferret mailing list: eci386!ferret-list, psroff mailing list: eci386!psroff-list From maart at cs.vu.nl Thu Jan 11 14:32:13 1990 From: maart at cs.vu.nl (Maarten Litmaath) Date: 11 Jan 90 03:32:13 GMT Subject: rn macro to decrypt & save (was: Rot 13 Postings) References: <1990Jan7.204009.10925@watcsc.waterloo.edu> Message-ID: <5079@solo9.cs.vu.nl> In article <1990Jan7.204009.10925 at watcsc.waterloo.edu> mkuch at watcsc.waterloo.edu (Murray Kucherawy) writes: \Can anyone tell me how to store a posting that was posted in \ROT 13 in its decrypted form? I tried reading it, then reading \it with CTRL/X (decrypted), and then saving it, but it saves \it to a file in ROT 13. Please help. Between the following `cut-here' lines is a macro definition for `*'. I've split the macro into 2 lines, because there appear to be mailers which don't like lines much longer than 80 chars. :-( When you put the macro into a file called `.rnmac' in the directory in which your `.newsrc' resides, you must join the 2 lines and delete the `\' at the end of the first line; `rn' doesn't know about continuation lines. :-( ----------8<----------8<----------8<----------8<----------8<---------- * %(%m=[ap]?|rot13 >> \ %(%"Decrypt to: [%p/Decrypted] "=^\(..*\)$?%1:%p/Decrypted)^J:*) ----------8<----------8<----------8<----------8<----------8<---------- The `rot13' program is the following shell script, to be put in your PATH. On a System-V UNIX variant you might want to change the first line to a single `:'. ----------8<----------8<----------8<----------8<----------8<---------- #!/bin/sh exec tr '[A-M][N-Z][a-m][n-z]' '[N-Z][A-M][n-z][a-m]' ----------8<----------8<----------8<----------8<----------8<---------- -- 1755 EST, Dec 14, 1992: Henry Spencer is put on a one-way mission to the moon.| Maarten Litmaath @ VU Amsterdam: maart at cs.vu.nl, uunet!mcsun!botter!maart From davek at lakesys.lakesys.com Tue Jan 9 11:29:21 1990 From: davek at lakesys.lakesys.com (Dave Kraft) Date: 9 Jan 90 00:29:21 GMT Subject: laston.c - determine last time user has logged on Message-ID: <1540@lakesys.lakesys.com> Here's a little something I wrote to help me determine when I've last logged on. It gets the current time/date from /dev/clock. If you aren't familiar on how /dev/clock is broken down, here it is: 0108182790 Positions Meaning 1-2 month 3-4 day 5-6 hour (24-hour format) 7-8 minute 9-10 year It gets the last time on from a file in the same format as /dev/clock in your home directory. If you have any questions, improvements, etc., please leave email. Dave ---- cut here -- #include <stdio.h> main() { struct { char month[3]; char day[3]; char hour[3]; char minute[3]; char year[3]; } now, last; int flag = 0; char *fn; FILE *f1, *fopen(); fn = getenv("HOME"); strcat(fn,"/.laston"); putchar('\n'); f1 = fopen("/dev/clock","r"); fread(now.month,2,1,f1); fread(now.day,2,1,f1); fread(now.hour,2,1,f1); fread(now.minute,2,1,f1); fread(now.year,2,1,f1); fclose(f1); add_null(now.month,2); add_null(now.day,2); add_null(now.hour,2); add_null(now.minute,2); add_null(now.year,2); f1 = fopen(fn,"r"); if(f1 == NULL){ flag = 1; printf("Could not determine last time on.\n"); } if(flag == 0){ fread(last.month,2,1,f1); fread(last.day,2,1,f1); fread(last.hour,2,1,f1); fread(last.minute,2,1,f1); fread(last.year,2,1,f1); add_null(last.month,2); add_null(last.day,2); add_null(last.hour,2); add_null(last.minute,2); add_null(last.year,2); } fclose(f1); printf("Last on: "); if(flag == 0) printf("%s:%s\t%s/%s/%s\n",last.hour,last.minute,last.month, last.day,last.year); else printf("%s:%s\t%s/%s/%s\n",now.hour,now.minute,now.month, now.day,now.year); f1 = fopen(fn,"w"); fwrite(now.month,2,1,f1); fwrite(now.day,2,1,f1); fwrite(now.hour,2,1,f1); fwrite(now.minute,2,1,f1); fwrite(now.year,2,1,f1); fclose(f1); putchar('\n'); } add_null(s,pos) char s[]; int pos; { s[pos] = '\0'; } -- davek at lakesys.lakesys.com <OR> uunet!marque!lakesys!davek ------------------------------------------------------------------------------- "Empathy is sort of like telepathy's kid brother" -- taken from "Stardance" by Spider and Jeanne Robinson From jeff at tc.fluke.COM Sun Jan 7 12:59:16 1990 From: jeff at tc.fluke.COM (Jeff Stearns) Date: 7 Jan 90 01:59:16 GMT Subject: [comp.sys.mac.programmer] Convert among Apple file formats Message-ID: <10560@stag.math.lsa.umich.edu> Archive-name: macbinconvert/release Original-posting-by: jeff at tc.fluke.COM (Jeff Stearns) Original-subject: Re: need Apple-Double format help Reposted-by: emv at math.lsa.umich.edu (Edward Vielmetti) [This is an experimental alt.sources re-posting from the newsgroup(s) comp.sys.mac.programmer. Comments on this service to emv at math.lsa.umich.edu (Edward Vielmetti).] In article <SCOTTH.90Jan3150218 at harlie.corp.sgi.com> scotth at sgi.com (Scott Henry) writes: > ... Where can I get the structure of the resource fork of Apple-Double > format? I have been able to reverse engineer parts of it ... AppleSingle and AppleDouble specs are available from Apple or Cayman. I'll dig them up and post them myself in a few days if they don't show up in somebody else's posting by then. Creating the resource fork isn't totally sufficient to make a double-clickable file, since the GatorBox stores some needed information in the .DESKTOP file. Creating a file behind the GatorBox's back won't result in a document that's directly launchable until the GatorBox knows what you've done. I don't know the exact details of what's necessary to make it work. Certainly rebuilding the desktop is sufficient; maybe unmounting and remounting the volume. Maybe just closing and reopening the folder. To the fellow who wants to write a program to convert zmodem <-> AppleDouble <-> macbinary, here's a start I hacked out recently: :::::::::::::: macbintogator :::::::::::::: #! /bin/sh # # Convert a MacBinary three-pronged file into an AppleDouble file suitable # for a GatorBox. The .info file is retained in case a subsequent # reconversion is attempted. # # The pathnames should be in "basename" form, without any trailing .info or # .rsrc or .data extension. # # Jeff Stearns jeff at tc.fluke.COM # John Fluke Mfg. Co, Inc. (206) 356-5064 for file do ( : do nothing with $file.info && mv $file.rsrc `dirname $file`/%`basename $file` && mv $file.data $file ) || exit 1 done exit 0 :::::::::::::: macbintoz :::::::::::::: #! /bin/sh # # Convert three UNIX files representing the 3 MacBinary forks # into one Zmodem file. # # The three forks are concatenated as info, data, rsrc. # # Each fork begins on a 128-byte boundary. Holes are padded # with zeros. # # Jeff Stearns jeff at tc.fluke.COM # John Fluke Mfg. Co, Inc. (206) 356-5064 ( dd if=$1.info bs=128 conv=sync dd if=$1.data bs=128 conv=sync dd if=$1.rsrc bs=128 conv=sync ) :::::::::::::: ztomacbin :::::::::::::: #! /bin/sh # # Convert one Zmodem file into three UNIX files representing its 3 MacBinary # forks # # The three forks produced are info, data, rsrc. # # Within the info "fork" is encoded the length of the data and # rsrc forks: # # bytes 53-56 = data length # bytes 57-60 = rsrc length # # Each fork begins on a 128-byte boundary; that leaves some # padding after the data and rsrc forks. # # N.B. Our use of adb presumes that this host uses Macintosh byte order; # that's true for a Sun. # # Byte positions are numbered BETWEEN bytes; byte 0 lies just to the left # of the first byte in the file. Thus we call byte N what you'd get if you # did seek(N, ...); read( ...) # # Jeff Stearns jeff at tc.fluke.COM # John Fluke Mfg. Co, Inc. (206) 356-5064 dd if=$1 bs=128 count=1 of=$1.info DataStart=128 DataLength=`echo '53?D' | adb $1.info | awk '{print $2}'` RsrcStart=`expr 128 + '(' '(' $DataLength + 127 ')' / 128 '*' 128 ')'` RsrcLength=`echo '57?D' | adb $1.info | awk '{print $2}'` echo 1>&2 "DataLength=$DataLength RsrcLength=$RsrcLength" dd if=$1 ibs=1 skip=$DataStart count=$DataLength of=$1.data dd if=$1 ibs=1 skip=$RsrcStart count=$RsrcLength of=$1.rsrc :::::::::::::: ztogator :::::::::::::: #! /bin/sh # # Convert one Zmodem file into two UNIX files representing its rsrc and data # forks. # # Within the zmodem info "fork" is encoded the length of the data and # rsrc forks: # # bytes 53-56 = data length # bytes 57-60 = rsrc length # # Each fork begins on a 128-byte boundary; that leaves some # padding after the data and rsrc forks. # # N.B. Our use of adb presumes that this host uses Macintosh byte order; # that's true for a Sun. # # Byte positions are numbered BETWEEN bytes; byte 0 lies just to the left # of the first byte in the file. Thus we call byte N what you'd get if you # did seek(N, ...); read( ...) # # Jeff Stearns jeff at tc.fluke.COM # John Fluke Mfg. Co, Inc. (206) 356-5064 Backup=$1.original echo "To avoid overwriting your file $1, a backup copy is made at $Backup" cp $1 $Backup dd if=$Backup bs=128 count=1 of=$1.info 2>&- DataStart=128 DataLength=`echo '53?D' | adb $1.info | awk '{print $2}'` RsrcStart=`expr 128 + '(' '(' $DataLength + 127 ')' / 128 '*' 128 ')'` RsrcLength=`echo '57?D' | adb $1.info | awk '{print $2}'` rm $1.info echo 1>&2 "DataLength=$DataLength RsrcLength=$RsrcLength" dd if=$Backup ibs=1 skip=$RsrcStart count=$RsrcLength of=`dirname $1`/%`basename $1` dd if=$Backup ibs=1 skip=$DataStart count=$DataLength of=$1 :::::::::::::: gatortoz :::::::::::::: #! /bin/sh # # gatortoz - Convert an AppleDouble file (actually a file and %file pair) # to a file in zmodem format. # # Within the zmodem info "fork" is encoded the length of the data and # rsrc forks: # # bytes 53-56 = data length # bytes 57-60 = rsrc length # # Each fork begins on a 128-byte boundary. # # N.B. Our use of adb presumes that this host uses Macintosh byte order; # that's true for a Sun. # # Byte positions are numbered BETWEEN bytes; byte 0 lies just to the left # of the first byte in the file. Thus we call byte N what you'd get if you # did seek(N, ...); read( ...) # # Jeff Stearns jeff at tc.fluke.COM # John Fluke Mfg. Co, Inc. (206) 356-5064 for file do # # The data fork is found in file. # The resource fork is found in %file. # A temporary info fork is synthesized in /tmp/file.info. # Data="$1" Rsrc="`dirname $1`/%`basename $1`" TempInfo="/tmp/`basename $1`.info" MacFileName="$Data" MacFileNameLength=`echo -n "$MacFileName" | wc -c` DataLength=`ls -l $Data | awk '{print $4}'` RsrcLength=`ls -l $Rsrc | awk '{print $4}'` echo 1>&2 "$file: Data length = $DataLength Resource length = $RsrcLength" # # Create the info fork as size 128 bytes. # Insert the Macintosh filename at byte 2. # In a minute, we'll use adb to patch in the byte count that # must precede the filename (these are Pascal-type strings). # echo -n "XX$MacFileName" | dd bs=128 conv=sync of=$TempInfo 2>&- ( echo "0?w $MacFileNameLength" echo "53?W $DataLength" echo "57?W $RsrcLength" ) | adb -w $TempInfo 1>&- # # Each fork begins on a 128-byte boundary. Gaps are NULL-padded: # dd if=$TempInfo bs=128 conv=sync 2>&- dd if=$Data bs=128 conv=sync 2>&- dd if=$Rsrc bs=128 conv=sync 2>&- rm $TempInfo done -- Jeff Stearns John Fluke Mfg. Co, Inc. (206) 356-5064 jeff at tc.fluke.COM {uw-beaver,microsoft,sun}!fluke!jeff From kjones at talos.uu.net Wed Jan 10 04:58:37 1990 From: kjones at talos.uu.net (Kyle Jones) Date: 9 Jan 90 17:58:37 GMT Subject: crypt.el for GNU Emacs Message-ID: <1990Jan9.175837.25058@talos.uu.net> ;;; Compaction, compression and encryption for GNU Emacs ;;; Copyright (C) 1988, 1989, 1990 Kyle E. Jones ;;; ;;; 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 1, 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. ;;; ;;; A copy of the GNU General Public License can be obtained from this ;;; program's author (send electronic mail to kyle at cs.odu.edu) or from ;;; the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA ;;; 02139, USA. ;;; ;;; Send bug reports to kyle at cs.odu.edu. ;; To use this package, put it in a file called "crypt.el" in a Lisp ;; directory that Emacs knows about, byte-compile it, and put the line: ;; (require 'crypt) ;; in your .emacs file or in the file default.el in the "lisp" directory ;; of the Emacs distribution. Don't bother trying to autoload this file; ;; this package uses a find-file hook and thus should be loaded the ;; first time you visit any sort of file. ;; ;; The basic purpose of this package of Lisp functions is to automatically ;; recognize encrypted, compacted or compressed files when they are first ;; visited and decode the file's BUFFER before it is presented to the user. ;; The file itself is unchanged. When the buffer is subsequently saved to ;; disk, a hook function re-encodes the buffer before the actual disk write ;; takes place. ;; ;; This package recognizes compacted and compressed files by a magic number at ;; the beginning of these files, but a heuristic is used to detect encrypted ;; files. If you are asked for an encryption key for a file that is in fact ;; not encrypted, just hit RET and the file will be accepted as is, and the ;; crypt minor mode will not be entered. (provide 'crypt) (defvar auto-decode-buffer t "*Non-nil value means that the buffers associated with encoded files will be decoded automatically, without requesting confirmation from the user. Nil means to ask before doing the decoding.") (defvar buffer-save-encrypted nil "*Non-nil means that when this buffer is saved it will be written out encrypted, as with the UNIX crypt(1) command. Automatically local to all buffers.") (make-variable-buffer-local 'buffer-save-encrypted) (defvar buffer-save-compacted nil "*Non-nil means that when this buffer is saved it will be written out compacted, as with the UNIX compact(1) command. Automatically local to all buffers.") (make-variable-buffer-local 'buffer-save-compacted) (defvar buffer-save-compressed nil "*Non-nil means that when this buffer is saved it will be written out compressed, as with the UNIX compress(1) command. Automatically local to all buffers.") (make-variable-buffer-local 'buffer-save-compressed) (defvar buffer-encryption-key nil "*Key to use when encrypting the current buffer, prior to saving it. Automatically local to all buffers.") (make-variable-buffer-local 'buffer-encryption-key) (defconst compact-magic-regexp "\377\037" "Regexp that matches the magic number at the beginning of files created by the compact(1) command.") (defconst compress-magic-regexp "\037\235\220" "Regexp that matches the magic number at the beginning of files created by the compress(1) command.") ;; Encrypted files have no magic number, so we have to hack a way of ;; determining which new buffers start in crypt mode. The current setup is ;; that we use only buffers that have a non-ASCII character very close to ;; beginning of buffer and that do NOT match crypt-magic-regexp-inverse. ;; Currently crypt-magic-regexp-inverse will match Sun OS, 4.x BSD, and ;; Ultrix executable magic numbers, so binaries can still be edited (heh) ;; without headaches. (defconst crypt-magic-regexp-inverse "\\(..\\)?\\([\007\010\013]\001\\|\001[\007\010\013]\\)" "Regexp that must NOT match the beginning of an encrypted buffer.") (defmacro save-point (&rest body) "Save value of point, evalutes FORMS and restore value of point. If the saved value of point is no longer valid go to (point-max). This macro exists because, save-excursion loses track of point during some types of deletions." (let ((var (make-symbol "saved-point"))) (list 'let (list (list var '(point))) (list 'unwind-protect (cons 'progn body) (list 'goto-char var))))) (defun find-crypt-file-hook () (save-point (save-restriction (widen) (goto-char (point-min)) (let ((buffer-file-name buffer-file-name) (old-buffer-file-name buffer-file-name) (old-buffer-modified-p (buffer-modified-p)) encrypted compressed compacted case-fold-search buffer-read-only) ;; We can reasonably assume that either compaction or compression will ;; be used, or neither, but not both. (cond ((and (looking-at compact-magic-regexp) (or auto-decode-buffer (y-or-n-p (format "Uncompact buffer %s? " (buffer-name))))) (message "Uncompacting %s..." (buffer-name)) (compact-buffer (current-buffer) t) ;; We can't actually go into compact mode yet because the major ;; mode may change later on and blow away all local variables ;; (and thus the minor modes). So we make a note to go into ;; compact mode later. (setq compacted t) ;; here we strip the compacted file's .C extension so that later ;; we can set the buffer's major mode based on this modified ;; name instead of the name with the .C extension. (if (string-match "\\(\\.C\\)$" buffer-file-name) (setq buffer-file-name (substring buffer-file-name 0 (match-beginning 1)))) (if (not (input-pending-p)) (message "Uncompacting %s... done" (buffer-name)))) ((and (looking-at compress-magic-regexp) (or auto-decode-buffer (y-or-n-p (format "Uncompress buffer %s? " (buffer-name))))) (message "Uncompressing %s..." (buffer-name)) (compress-buffer (current-buffer) t) (setq compressed t) (if (string-match "\\(\\.Z\\)$" buffer-file-name) (setq buffer-file-name (substring buffer-file-name 0 (match-beginning 1)))) (if (not (input-pending-p)) (message "Uncompressing %s... done" (buffer-name))))) ;; Now peek at the file and see if it still looks like a binary file. ;; If so, try the crypt-magic-regexp-inverse against it and if it FAILS ;; we assume that this is an encrypted buffer. (cond ((and (not (eobp)) (re-search-forward "[\200-\377]" (min (point-max) 15) t) (goto-char (point-min)) (not (looking-at crypt-magic-regexp-inverse))) (if (not buffer-encryption-key) (call-interactively 'set-encryption-key)) ;; if user did not enter a key, turn off crypt mode. ;; good for binaries that crypt-magic-regexp-inverse ;; doesn't recognize. ;; -- thanx to Paul Dworkin (paul at media-lab.media.mit.edu) (if (equal buffer-encryption-key "") (message "No key given, buffer %s assumed normal." (buffer-name)) (message "Decrypting %s..." (buffer-name)) (crypt-buffer buffer-encryption-key) ;; Tuck the key away for safe keeping since setting the major ;; mode may well blow it away. (setq encrypted buffer-encryption-key) (if (not (input-pending-p)) (message "Decrypting %s... done" (buffer-name)))))) ;; OK, if any changes have been made to the buffer we need to rerun the ;; code the does automatic selection of major mode. (cond ((or compressed compacted encrypted) (set-auto-mode) (hack-local-variables) ;; Now set our minor modes. (if compressed (compress-mode 1)) (if compacted (compact-mode 1)) (if encrypted (progn (crypt-mode 1) (setq buffer-encryption-key encrypted))) ;; Restore buffer file name now, so that lock file entry is ;; removed properly. (setq buffer-file-name old-buffer-file-name) ;; Restore buffer modified flag to its previous value. ;; This will also remove the lock file entry for the buffer ;; if the previous value was nil; this is why buffer-file-name ;; had to be manually restored above. (set-buffer-modified-p old-buffer-modified-p))))))) ;; This function should be called ONLY as a write-file hook. ;; Odd things will happen if it is called elsewhere. (defun write-crypt-file-hook () (cond ((or buffer-save-encrypted buffer-save-compacted buffer-save-compressed) (save-excursion (save-restriction (let ((copy-buffer (get-buffer-create " *crypt copy buffer*")) (selective-display selective-display) (buffer-read-only)) (copy-to-buffer copy-buffer 1 (1+ (buffer-size))) (narrow-to-region (point) (point)) (unwind-protect (progn (insert-buffer-substring copy-buffer) (kill-buffer copy-buffer) ;; selective-display non-nil means we must convert carriage ;; returns to newlines now, and set selective-display ;; temporarily to nil. (cond (selective-display (goto-char (point-min)) (subst-char-in-region (point-min) (point-max) ?\r ?\n) (setq selective-display nil))) (cond (buffer-save-encrypted (if (null buffer-encryption-key) (error "No encryption key set for buffer %s" (buffer-name))) (if (not (stringp buffer-encryption-key)) (error "Encryption key is not a string")) (message "Encrypting %s..." (buffer-name)) (crypt-buffer buffer-encryption-key))) (cond ((and buffer-save-compacted buffer-save-compressed) (error "Cannot compact and compress buffer %s" (buffer-name))) (buffer-save-compacted (message "Compacting %s..." (buffer-name)) (compact-buffer)) (buffer-save-compressed (message "Compressing %s..." (buffer-name)) (compress-buffer))) (write-region (point-min) (point-max) buffer-file-name nil t) (delete-region (point-min) (point-max)) (set-buffer-modified-p nil) ;; return t so that basic-save-buffer will ;; know that the save has already been done. t ) ;; unwind... ;; If the crypted stuff has already been removed ;; then this is a no-op. (delete-region (point-min) (point-max))))))))) (defun crypt-region (start end key) "Encrypt/decrypt the text in the region. >From a program, this function takes three args: START, END and KEY. When called interactively START and END default to point and mark \(START being the lesser of the two), KEY is prompted for." (interactive (progn (barf-if-buffer-read-only) (list (region-beginning) (region-end) (read-string-no-echo "Crypt region using key: ")))) (save-point (let ((opoint-max (point-max))) (call-process-region start end shell-file-name t t nil "-c" (concat "crypt \"" key "\"")) (if (not (= opoint-max (point-max))) (error "crypt command failed!"))))) (defun crypt-buffer (key &optional buffer) "Using KEY, encrypt/decrypt BUFFER. BUFFER defaults to the current buffer." (interactive (progn (barf-if-buffer-read-only) (list (read-string-no-echo "Crypt buffer using key: ")))) (or buffer (setq buffer (current-buffer))) (save-excursion (set-buffer buffer) (crypt-region (point-min) (point-max) key))) (defun compact-region (start end &optional undo) "Compact the text in the region. >From a program, this function takes three args: START, END and UNDO. When called interactively START and END default to point and mark \(START being the lesser of the two). Prefix arg (or optional second arg non-nil) UNDO means uncompact." (interactive "*r\nP") (save-point (call-process-region start end shell-file-name t t nil "-c" (if undo "uncompact" "compact")) (cond ((not undo) (goto-char start) (let (case-fold-search) (if (not (looking-at compact-magic-regexp)) (error "%s failed!" (if undo "Uncompaction" "Compaction")))))))) (defun compact-buffer (&optional buffer undo) "Compact BUFFER. BUFFER defaults to the current buffer. Prefix arg (or second arg non-nil from a program) UNDO means uncompact." (interactive (list (current-buffer) current-prefix-arg)) (or buffer (setq buffer (current-buffer))) (save-excursion (set-buffer buffer) (compact-region (point-min) (point-max) undo))) (defun compress-region (start end &optional undo) "Compress the text in the region. >From a program, this function takes three args: START, END and UNDO. When called interactively START and END default to point and mark \(START being the lesser of the two). Prefix arg (or optional second arg non-nil) UNDO means uncompress." (interactive "*r\nP") (save-point (call-process-region start end shell-file-name t t nil "-c" (if undo "compress -d" "compress")) (cond ((not undo) (goto-char start) (let (case-fold-search) (if (not (looking-at compress-magic-regexp)) (error "%s failed!" (if undo "Uncompression" "Compression")))))))) (defun compress-buffer (&optional buffer undo) "Compress BUFFER. BUFFER defaults to the current buffer. Prefix arg (or second arg non-nil from a program) UNDO means uncompress." (interactive (list (current-buffer) current-prefix-arg)) (or buffer (setq buffer (current-buffer))) (save-excursion (set-buffer buffer) (compress-region (point-min) (point-max) undo))) (defun set-encryption-key (key &optional buffer) "Set the encryption KEY for BUFFER. KEY should be a string. BUFFER should be a buffer or the name of one; it defaults to the current buffer. If BUFFER is in crypt mode, then it is also marked as modified, since it needs to be saved with the new key." (interactive (progn (barf-if-buffer-read-only) (list (read-string-no-echo (format "Set encryption key for buffer %s: " (buffer-name)))))) (or buffer (setq buffer (current-buffer))) (save-excursion (set-buffer buffer) (if (equal key buffer-encryption-key) (message "Key is identical to original, no change.") (setq buffer-encryption-key key) ;; don't touch the modify flag unless we're in crypt-mode. (if buffer-save-encrypted (set-buffer-modified-p t))))) (defun crypt-mode (&optional arg) "Toggle crypt mode. With arg, turn crypt mode on iff arg is positive, otherwise turn it off. In crypt mode, buffers are automatically encrypted before being written. If crypt mode is toggled and a key has been set for the current buffer, then the current buffer is marked modified, since it needs to be rewritten with (or without) encryption. Use \\[set-encryption-key] to set the encryption key for the current buffer. Entering crypt mode causes auto-saving to be turned off in the current buffer, as there is no way (in Emacs Lisp) to force auto save files to be encrypted." (interactive "P") (let ((oldval buffer-save-encrypted)) (setq buffer-save-encrypted (if arg (> arg 0) (not buffer-save-encrypted))) (if buffer-save-encrypted (auto-save-mode 0) (auto-save-mode (if (and auto-save-default buffer-file-name) 1 0))) (if buffer-encryption-key (set-buffer-modified-p (not (eq oldval buffer-save-encrypted)))))) (defun compact-mode (&optional arg) "Toggle compact mode. With arg, turn compact mode on iff arg is positive, otherwise turn it off. In compact mode, buffers are automatically compacted before being written. If compact mode is toggled, the current buffer is marked modified, since it needs to be written with (or without) compaction. Entering compact mode causes auto-saving to be turned off in the current buffer, as there is no way (in Emacs Lisp) to force auto save files to be compacted." (interactive "P") (let ((oldval buffer-save-compacted)) (setq buffer-save-compacted (if arg (> arg 0) (not buffer-save-compacted))) (if buffer-save-compacted (auto-save-mode 0) (auto-save-mode (if (and auto-save-default buffer-file-name) 1 0))) (set-buffer-modified-p (not (eq oldval buffer-save-compacted))))) (defun compress-mode (&optional arg) "Toggle compress mode. With arg, turn compress mode on iff arg is positive, otherwise turn it off. In compress mode, buffers are automatically compressed before being written. If compress mode is toggled, the current buffer is marked modified, since it needs to be written with (or without) compression. Entering compress mode causes auto-saving to be turned off in the current buffer, as there is no way (in Emacs Lisp) to force auto save files to be compressed." (interactive "P") (let ((oldval buffer-save-compressed)) (setq buffer-save-compressed (if arg (> arg 0) (not buffer-save-compressed))) (if buffer-save-compressed (auto-save-mode 0) (auto-save-mode (if (and auto-save-default buffer-file-name) 1 0))) (set-buffer-modified-p (not (eq oldval buffer-save-compressed))))) (defun read-string-no-echo (prompt &optional confirm) "Read a string from the minibuffer, prompting with PROMPT. Optional second argument CONFIRM non-nil means that the user will be asked to type the string a second time for confirmation and if there is a mismatch, the process is repeated. Line editing keys are: C-h, DEL rubout C-u, C-x line kill C-q, C-v literal next" (catch 'return-value (save-excursion (let ((input-buffer (get-buffer-create " *password*")) (cursor-in-echo-area t) (echo-keystrokes 0) char string help-form done kill-ring) (set-buffer input-buffer) (unwind-protect (while t (erase-buffer) (message prompt) (while (not (memq (setq char (read-char)) '(?\C-m ?\C-j))) (if (setq form (cdr (assq char '((?\C-h . (delete-char -1)) (?\C-? . (delete-char -1)) (?\C-u . (delete-region 1 (point))) (?\C-x . (delete-region 1 (point))) (?\C-q . (quoted-insert 1)) (?\C-v . (quoted-insert 1)))))) (condition-case error-data (eval form) (error t)) (insert char)) (message prompt)) (cond ((and confirm string) (cond ((not (string= string (buffer-string))) (message (concat prompt "[Mismatch... try again.]")) (ding) (sit-for 2) (setq string nil)) (t (throw 'return-value string)))) (confirm (setq string (buffer-string)) (message (concat prompt "[Retype to confirm...]")) (sit-for 2)) (t (throw 'return-value (buffer-string))))) (set-buffer-modified-p nil) (kill-buffer input-buffer)))))) ;; Install the hooks, then add the mode indicators to ;; the minor mode alist. (cond ((not (memq 'write-crypt-file-hook write-file-hooks)) ;; make this hook last on purpose (setq write-file-hooks (append write-file-hooks (list 'write-crypt-file-hook)) find-file-hooks (cons 'find-crypt-file-hook find-file-hooks) find-file-not-found-hooks (cons 'find-crypt-file-hook find-file-not-found-hooks) minor-mode-alist (nconc (list '(buffer-save-encrypted " Crypt") '(buffer-save-compacted " Compact") '(buffer-save-compressed " Compress")) minor-mode-alist)))) From dalgic at Neon.Stanford.EDU Sun Jan 7 11:07:40 1990 From: dalgic at Neon.Stanford.EDU (Ismail Dalgic) Date: 7 Jan 90 00:07:40 GMT Subject: 'from' alias in csh References: <1990Jan6.183428.11336@csusac.csus.edu> Message-ID: <1990Jan7.000740.21661@Neon.Stanford.EDU> Since people started sending millions of different versions of "from", let me send my own version that I have been using for some time. This one uses "mail" to do most of the job. It prints the sender, the number of lines/characters in the message, and the subject, all in one line. You can simply add $4,$5,$6 and $7 in the print list of awk to print the date as well. Here it is: alias from 'echo "q" | mail | awk \' {if (NF == 9) print $3,$8,$9}\'' BTW, is alt.sources really the appropriate place to send such one-liners? Have Fun, --Ismail From erc at khijol.UUCP Sat Jan 13 16:55:34 1990 From: erc at khijol.UUCP (Edwin R. Carp) Date: 13 Jan 90 05:55:34 GMT Subject: newsmail - mail news articles to users automagically Message-ID: <992@khijol.UUCP> This is a handy little program I threw together on a boring Saturday evening to send mail from certain selected groups to me at work. It could also be used to "distribute" news groups to users. It, um, parses the Subject and Newsgroups lines from the article, then calls mail to mail it off. This can be put in your sys file to mail stuff - see the source for details. Since it consists of only one file, I didn't go to the trouble of shar'ing it or anything. It uses a standard "cc -s -o newsmail newsmail.c -O" to compile, and shouldn't require anything fancy. If you: like it/don't like it/have suggestions, please let me know. --------------------------------- cut here ----------------------------------- /* * * newsmail - package stdin appropriate for mailing, then mail to args * puts newsgroup(if any), then original subject in -s line. * like: "Subject: newsgroup: Subject" * * Handy for remailing stuff from news to individual users: * * fwd1:sci.space,world::newsmail user (in /usr/lib/news/sys file) * * Should work on just about any system (BSD, Sys V, XENIX) * * Compile like: cc -s -o newsmail newsmail.c -O * * flow: * * read stdin, copying to /tmp file. * strip off Subject, Newsgroups lines along the way. * construct subject line. * call mail to do the dirty work. * */ #include <stdio.h> #define SUBJECT "Subject: " #define NEWSG "Newsgroups: " /* * this should be the only place you have to change anything. */ #ifdef BSD #define MAILER "Mail" #else #define MAILER "mail" #endif main(argc, argv) int argc; char **argv; { char Subject[512]; char Newsgroup[512]; char outfile[20]; char line[512]; FILE *out; int lsub, lnews, i; sprintf(outfile, "/tmp/newsmail.%d", getpid()); if((out=fopen(outfile, "w")) == (FILE *)NULL) { perror(outfile); exit(1); } lsub = strlen(SUBJECT); lnews = strlen(NEWSG); while(gets(line) != (char *)NULL) { if(strncmp(line, SUBJECT, lsub) == 0) strcpy(Subject, line+lsub); if(strncmp(line, NEWSG, lnews) == 0) strcpy(Newsgroup, line+lnews); strcat(line, "\n"); fputs(line, out); } fclose(out); if(*Subject == NULL) strcpy(Subject, "<none>"); if(*Newsgroup == NULL) strcpy(Newsgroup, "<none>"); for(i=1; i<argc; i++) { sprintf(line, "%s -s '%s: %s' %s < %s", MAILER, Newsgroup, Subject, argv[i], outfile); puts(line); system(line); } unlink(outfile); } -- Ed Carp N7EKG/5 (28.3-28.5) uunet!cs.utexas.edu!khijol!erc Austin, Texas (512) 832-5884 "Good tea. Nice house." - Worf From shields at yunccn.UUCP Mon Jan 8 20:51:16 1990 From: shields at yunccn.UUCP (Paul Shields) Date: 8 Jan 90 09:51:16 GMT Subject: Menu software... Here it is: "lush" version 1.34, part 2/2 References: <3888@yunccn.UUCP> Message-ID: <3889@yunccn.UUCP> #--------------------------------CUT HERE------------------------------------- #! /bin/sh # # This is a shell archive. Save this into a file, edit it # and delete all lines above this comment. Then give this # file to sh by executing the command "sh file". The files # will be extracted into the current directory owned by # you with default permissions. # # The files contained herein are: # # -rw-r--r-- 1 bin staff 1054 Jan 8 01:57 config.h # -rw-r--r-- 1 bin staff 1498 Jan 7 15:51 defs.h # -rw-r--r-- 1 bin staff 6473 Jan 5 18:16 edit.c # -rw-r--r-- 1 bin staff 1509 Jan 8 04:11 edit.h # -rw-r--r-- 1 bin staff 8605 Jan 8 04:11 envinit.c # -rw-r--r-- 1 bin staff 809 Mar 11 1988 getin.c # -rw-r--r-- 1 bin staff 537 Jan 8 04:14 login.c # -rw-r--r-- 1 bin staff 1586 Jan 7 22:26 lush.c # -rw-r--r-- 1 bin staff 2156 Jan 7 17:56 lush.h # -rw-r--r-- 1 bin staff 5062 Jan 8 04:11 menu.c # -rw-r--r-- 1 bin staff 1580 Jan 8 02:01 menu.h # -rw-r--r-- 1 bin staff 2411 Jan 8 04:13 mfile.c # -rw-r--r-- 1 bin staff 1056 Jan 8 00:46 mfile.h # -rw-r--r-- 1 bin staff 2111 Jan 8 00:54 mlex.c # -rw-r--r-- 1 bin staff 1082 Jan 8 01:52 mlex.h # -rw-r--r-- 1 bin staff 10005 Jan 8 04:13 mparse.c # -rw-r--r-- 1 bin staff 661 Jan 7 23:14 mparse.h # -rw-r--r-- 1 bin staff 66 Jan 8 03:04 version.h # echo 'x - config.h' if test -f config.h; then echo 'shar: not overwriting config.h'; else sed 's/^X//' << '________This_Is_The_END________' > config.h X/* config.h - some definitions you might want to change. */ X X#define GLOBALFILE "/usr/lib/lush/lushrc" /* global config file */ X#define MENUFILE "/usr/lib/lush/menu" /* menu file */ X#define ROOTMENU "MAIN_MENU" /* the default root menu */ X X#ifdef MSDOS X#define LUSHRC "~/lushrc" /* user config file */ X#else X#define LUSHRC "~/.lushrc" X#endif X X#define ILLEGAL "|<>;&" /* disallowed user-input characters */ X#define TERM "dumb" /* terminal type if none in environment */ X X/* things you probably don't want to change... */ X#define LJ_MAX 20 /* Max size of setjmp() stack. This governs how X many levels down in the menu hierarchy you can go. */ X X#define MAX_OPTIONS 20 /*(menu.h) max options per menu */ X#define MAX_RESP 10 /*(menu.h) max number of responses per option */ X#define NAME_SIZE 20 /*(menu.h) Max size of a menu name or option word */ X X#define MAX_MENUS 50 /*(mparse.c) max number of menus in the system */ X X#define MAX_TOKENS 200 /*(mlex.c) Max number of lexical tokens. */ ________This_Is_The_END________ if test `wc -l < config.h` -ne 26; then echo 'shar: config.h was damaged during transit (should have been 26 lines)' fi fi ; : end of overwriting check echo 'x - defs.h' if test -f defs.h; then echo 'shar: not overwriting defs.h'; else sed 's/^X//' << '________This_Is_The_END________' > defs.h X/* File: defs.h X Author: PAS X Date: Sept 7, 1987 X Purpose: Contains global definitions for lush and other programs. X */ X/* -- standard headers -------------------------------------------------- */ X X#ifdef DEBUG X#include <stdio.h> X#endif X#include <fcntl.h> X X#ifdef MSDOS X#include <stdlib.h> X#include <dos.h> X#include <float.h> X#endif X X#include <string.h> X#include <ctype.h> X#include <time.h> X#include <pwd.h> X#include <grp.h> X#include <signal.h> X#include <setjmp.h> X#include <errno.h> X X#ifndef PROTOTYPE /* function declarations are not done for us. */ Xextern char *malloc(); Xextern int getopt(); Xextern char *getenv(); Xextern int putenv(); Xextern char *ttyname(); Xextern char *getlogin(); X#endif X X/* -- system dependent defs --------------------------------------------- */ X X#define HOMEDIR "/" /* default home directory if none can be found. */ X X#ifdef MSDOS X#define access laccess /* our own access() function. */ X#define GROUP "/etc/group" /* various group access permissions. */ X#define PASSWD "/etc/passwd" /* where to find the passwords. */ X#define TTY "nul" /* default tty name */ X#else X#define TTY "/dev/null" X#endif X X/* -- immutable defs ---------------------------------------------------- */ X X/* function return values... */ X#define OK 0 X#define ERROR -1 X#define FALSE 0 X#define TRUE 1 X X#define MAX_LEN 255 /* maximum line length in a file */ X#define PATH_LEN 64 /* max length of a path. */ ________This_Is_The_END________ if test `wc -l < defs.h` -ne 59; then echo 'shar: defs.h was damaged during transit (should have been 59 lines)' fi fi ; : end of overwriting check echo 'x - edit.c' if test -f edit.c; then echo 'shar: not overwriting edit.c'; else sed 's/^X//' << '________This_Is_The_END________' > edit.c X/* File: edit.c X Author: PAS X Date: May 15, 1987 X Purpose: this is where the real work is done. X */ X X#include "lush.h" X#ifndef DEBUG X#include <stdio.h> X#endif X X#include "edit.h" X#ifdef PROTOTYPE Xextern char *getpass(char *); X#else Xextern char *getpass(); X#endif X X#ifdef PROTOTYPE Xint (*funcs[])(char *) = /* array of pointers to functions taking char* and returning int. */ X#else Xint (*funcs[])() = X#endif X{ ChgDir, /* 00 change directory */ X ChkPort, /* 01 check port access */ X ChkTerm, /* 02 check terminal type */ X Pause, /* 03 pause with "Press enter: " message */ X ChkRdAcc, /* 04 check read access to a file list */ X CallCmd, /* 05 system() to a command with parameters */ X SecurChk, /* 06 perform a security check */ X ChkWrAcc, /* 07 check write access to a file list */ X Expert, /* 08 toggle novice/expert mode */ X P1name, /* 09 write prompt, get parameter. */ X P2name, /* 10 write prompt, get second parameter. */ X ChkAccess, /* 11 check read/write access to a file list */ X SetEnvt, /* 12 set environment variable */ X SaveStr, /* 13 save string in (global) recall-buffer */ X P1Recall, /* 14 put recall-buffer in parameter 1 */ X P2Recall /* 15 put recall-buffer in parameter 2 */ X}; X Xstatic char param1[MAX_LEN]; /* parameter for CallCmd. */ Xstatic char param2[MAX_LEN]; /* parameter for CallCmd. */ Xstatic char recall[MAX_LEN]; /* global recall-buffer. */ X Xint ChgDir(dn) /* change to a directory. */ Xchar *dn; X{ X char *buf, pbuf[MAX_LEN]; X X sprintf(pbuf, dn, param1, param2); /* add the parameter(s) to the command. */ X buf = envsubst(pbuf); /* substitute environment variables if nec. */ X X if(chdir(buf) != 0) { X perror(buf); X return ERROR; X } X return OK; X} X Xint lookupfile(nam, str) /* find a string in a file. */ Xchar *nam, *str; X{ X FILE *fp; X char line[MAX_LEN+1]; X int i = strlen(str); X X line[MAX_LEN] = '\0'; X if((fp = fopen(nam, "r")) != NULL) { X while(fgets(line, MAX_LEN, fp) != NULL) X if(strncmp(str, line, i) == 0) { X fclose(fp); X return OK; X } X fclose(fp); X } else X perror(nam); X X return ERROR; X} X Xint ChkPort(c) /* check for local mode */ Xchar *c; X{ X if(lookupfile(c, tty) == OK) X return OK; X X printf("\nThis command is unavailable from TTY %s\n", tty); X return ERROR; X} X Xint ChkTerm(c) /* check for remote mode */ Xchar *c; X{ X if(lookupfile(c, term) == OK) X return OK; X X printf("\nThis command is unavailable on terminals of type %s\n", term); X return ERROR; X} X Xint Pause(c) /* wait for user */ Xchar *c; X{ X getin("Press enter: "); X return OK; X} X Xint ChkRdAcc(list) /* 04 */ Xchar *list; X{ X printf("\nFile Access Check failed\n"); X return ERROR; X} X Xint ChkWrAcc(list) /* 07 */ Xchar *list; X{ X printf("\nFile Access Check failed\n"); X return ERROR; X} X Xint ChkAccess(list) /* 11 */ Xchar *list; X{ X printf("\nFile Access Check failed\n"); X return ERROR; X} X Xint P1name(prompt) Xchar *prompt; X{ X int i; X char *p; X X p = getin(prompt); X X if(strlen(p) > 0) { X /* none of that funny stuff... */ X i = strcspn(p, ILLEGAL); X } X else i=0; X X strncpy(param1, p, i); X param1[i] = '\0'; X X return OK; /* null is ok. */ X} X Xint P2name(prompt) Xchar *prompt; X{ X int i; X char *p; X X p = getin(prompt); X X if(strlen(p) > 0) { X /* none of that funny stuff... */ X i = strcspn(p, ILLEGAL); X } X else i=0; X X strncpy(param2, p, i); X param2[i] = '\0'; X X return OK; /* null is ok. */ X} X Xint CallCmd(cmd) /* use the system function to execute a command. */ Xchar *cmd; /* name of command to call. */ X{ X int ret; X char *buf, pbuf[MAX_LEN]; X X sprintf(pbuf, cmd, param1, param2); /* add the parameter(s) to the command. */ X buf = envsubst(pbuf); /* substitute environment variables if nec. */ X X#ifdef DEBUG X if(debuglevel & 1) X fprintf(stderr,"CallCmd(%s)= system(\"%s\")\n", cmd, buf); X#endif X if((ret = system(buf)) == 0) X return OK; X X#ifdef DEBUG X fprintf(stderr,"--returned error %d--\n", errno); X perror(buf); X#endif X return ERROR; X} X X/* Return TRUE if user is a member of the group, ow FALSE. X */ Xstatic int member(gr) Xchar *gr; X{ X struct group *grp; X char **n; X X if((grp = getgrnam(gr)) != NULL) { X for(n = grp->gr_mem; *n != NULL && strcmp(user, *n) != 0; n++) X#ifdef DEBUG X if(debuglevel & 1) X fprintf(stderr, "%s ",*n) X#endif X ; X return (*n != NULL); X } X /* else invalid group. */ X printf("\nSystem error verifying group %s. Please consult system administrator\n",gr); X return FALSE; X} X Xint SecurChk(gr) /* check to see that the user is a member of the */ Xchar *gr; /* permitted groups... */ X{ X#ifdef DEBUG X if(debuglevel & 1) X fprintf(stderr,"SecurChk(%s) ",gr); X#endif X if(getuid() == 0) X return OK; X X if(*gr == '!') { /* user must not be member of this group. */ X if(!member(++gr)) return OK; X } else X if(member(gr)) return OK; X X printf("\nYou are not allowed to use this command.\n"); X return ERROR; X} X Xint Expert(w) /* toggle novice/expert mode */ Xchar *w; X{ X novice ^= TRUE; /* xor */ X return OK; X} X Xint SetEnvt(w) /* set environment variable. allocates memory for it, */ Xchar *w; /* and substitutes parameters, etc. */ X{ X char *buf, pbuf[MAX_LEN]; X X sprintf(pbuf, w, param1, param2); /* add the parameter(s) to the command. */ X buf = envsubst(pbuf); /* substitute environment variables if nec. */ X X if((w = malloc(strlen(buf)+1)) == NULL) /* allocate in static storage */ X return ERROR; X strcpy(w, buf); X X if(putenv(w) != 0) { X free(w); X return ERROR; X } X return OK; X} X Xint SaveStr(w) /* save string in global recall buffer. */ Xchar *w; X{ X strncpy(w, recall, MAX_LEN-1); X recall[MAX_LEN] = 0; X return OK; X} X Xint P1Recall(w) /* save string in global recall buffer. */ Xchar *w; X{ X strcpy(recall, param1); X return OK; X} Xint P2Recall(w) /* save string in global recall buffer. */ Xchar *w; X{ X strcpy(recall, param2); X return OK; X} ________This_Is_The_END________ if test `wc -l < edit.c` -ne 279; then echo 'shar: edit.c was damaged during transit (should have been 279 lines)' fi fi ; : end of overwriting check echo 'x - edit.h' if test -f edit.h; then echo 'shar: not overwriting edit.h'; else sed 's/^X//' << '________This_Is_The_END________' > edit.h X/* File: edit.h X Author: PAS X Date: May 19, 1987 X Purpose: private definitions for edit.c. X */ X X/* prototype statements... */ X#ifdef PROTOTYPE Xint ChgDir(char *); /* 00 change directory */ Xint ChkPort(char *); /* 01 check port access */ Xint ChkTerm(char *); /* 02 check terminal access */ Xint Pause(char *); /* 03 pause with "Press enter: " message */ Xint ChkRdAcc(char *); /* 04 check read access to a file list */ Xint CallCmd(char *); /* 05 system() to a command with parameter */ Xint SecurChk(char *); /* 06 perform a security check */ Xint ChkWrAcc(char *); /* 07 check write access to a file list */ Xint Expert(char *); /* 08 toggle expert mode */ Xint P1name(char *); /* 09 write prompt, get parameter 1 */ Xint P2name(char *); /* 10 write prompt, get parameter 2 */ Xint ChkAccess(char *); /* 11 check read/write access to a file list */ Xint SetEnvt(char *); /* 12 set environment variable */ Xint SaveStr(char *); /* 13 save string in global recall buffer */ Xint P1Recall(char *); /* 14 put recall-buffer in parameter 1 */ Xint P2Recall(char *); /* 15 put recall-buffer in parameter 2 */ X XFILE *popen(char *,char *); X#else Xint ChgDir(),ChkPort(),ChkTerm(),Pause(),ChkRdAcc(),CallCmd(),SecurChk(); Xint ChkWrAcc(),Expert(),P1name(),P2name(),ChkAccess(), SetEnvt(); Xint SaveStr(),P1Recall(),P2Recall(); X XFILE *popen(); X#endif ________This_Is_The_END________ if test `wc -l < edit.h` -ne 33; then echo 'shar: edit.h was damaged during transit (should have been 33 lines)' fi fi ; : end of overwriting check echo 'x - envinit.c' if test -f envinit.c; then echo 'shar: not overwriting envinit.c'; else sed 's/^X//' << '________This_Is_The_END________' > envinit.c X/* File: envinit.c X Author: Paul Shields X Date: May 13, 1987 X Purpose: sets up variables for the environment. X */ X X#include "lush.h" X#ifndef DEBUG X#include <stdio.h> X#endif X X/* We logged into the console, a local tty, or a remote tty. Certain things X are unavailable from a remote tty, so we'll need to compare the environment X variable TTY with a list of permitted devices when the need calls for it. X */ Xchar *root_menu = NULL, /* default main menu name. */ X *menufile = NULL, /* name of menu file. */ X *globalrc = NULL, /* name of global rc file. */ X *userrc = NULL, /* name of user rc file. */ X *user, /* name of the user. */ X *tty, /* TTY environment variable. */ X *term = NULL; /* TERM environment variable. */ X Xchar *CL, *SO, *SE; /* termcap Clear-screen, Stand-out, Unstand-out */ Xint LI, CO; /* lines, columns */ X X Xchar * Xgethome(u) /* allocate and return user home dir or null. */ Xchar *u; X{ X struct passwd *pw; X X X /* if u is null, use default of current user. */ X if(u == NULL || strlen(u) == 0) X u = user; X if((pw = getpwnam(u)) == NULL) X return NULL; X X if((u = malloc(strlen(pw->pw_dir)+1)) == NULL) X return NULL; X strcpy(u,pw->pw_dir); X return u; X} X X/* allocate and store an environment variable. */ Xchar *mputenv(var,def) Xchar *var,*def; X{ X char *ut; X if((ut = malloc(strlen(var)+1+strlen(def)+1)) == NULL) X return NULL; X sprintf(ut, "%s=%s",var,def); X putenv(ut); X return ut; X} X X#define trim(s) {char *tl; while(*s && isspace(*s)) s++; \ X for(tl=s; *tl; tl++) ; for(tl--; tl > s; tl--) \ X { if(isspace(*tl)) *tl = '\0'; else break; } } X X/* Process a line in the global rc. X Allow environment definitions. X Do translation of $VAR and ~user strings. X *** Yet to add: System() out to commands enclosed in ``. X X Side-effects: writes junk into the line. X */ Xstatic int proc_global(line) Xchar *line; X{ X char *tl, *var, *def; X X#ifdef DEBUG X if(debuglevel & 1) X fprintf(stderr,"line: |%s|\n",line); X#endif X X/***/ /* this won't do. need to convert to use the scanner in mparse.c */ X if((tl = strpbrk(line,"#")) != NULL) /* strip comments */ X *tl = '\0'; X X /* look for = and break into two: "A=B" => "A","B" */ X if((def = strpbrk(line, "=")) != NULL) { X var = strtok(line, "="); X def++; X trim(var); /* zap leading/trailing white space */ X trim(def); X tl = envsubst(def); /* do $ and ~ substitutions */ X mputenv(var, tl); X } else { X trim(line); X if(strlen(line) > 0) X return ERROR; X } X return OK; X} X X/* Process a line in the user rc. X Only environment definitions allowed. X Restrict to ones already defined. X */ Xstatic int proc_user(line) Xchar *line; X{ X return proc_global(line); /***/ /* for now, do the same. */ X} X X/* Get and process the global rc file */ Xstatic int getrc_global(name) Xchar *name; X{ X FILE *fp; X char line[MAX_LEN+1]; X int ln; X X if((fp=fopen(name, "r")) == NULL) { X perror(name); X return ERROR; X } X for(ln=1; fgets(line, MAX_LEN, fp) != NULL; ln++) X if(proc_global(line) == ERROR) X fprintf(stderr,"%s: syntax error: line %d\n",name,ln); X fclose(fp); X return OK; X} X X/* Get and process the user rc file */ Xstatic int getrc_user(name) Xchar *name; X{ X FILE *fp; X char line[MAX_LEN+1]; X int ln; X X if((fp=fopen(name, "r")) == NULL) { X perror(name); X return ERROR; X } X for(ln=1; fgets(line, MAX_LEN, fp) != NULL; ln++) X if(proc_user(line) == ERROR) X fprintf(stderr,"%s: syntax error: line %d\n",name,ln); X fclose(fp); X return OK; X} X Xint envinit(argc,argv) Xint argc; Xchar *argv[]; X{ X register char *h; X char *ut; /* temporary */ X int err = 0, c; X extern char *optarg; X X#ifndef MSDOS X if(getenv("SHELL") != argv[0]) /* security. */ X mputenv("SHELL",argv[0]); X#endif X X /* find out who we are. */ X if((user = getlogin()) == NULL) { X struct passwd *pw; X if((pw = getpwuid(getuid())) == NULL) { X fprintf(stderr,"Can't find your username anywhere.\n"); X return ERROR; X } X ut = pw->pw_name; X if((user = malloc(strlen(ut)+1)) == NULL) X { perror("envinit()"); return ERROR; } X strcpy(user,ut); X } X mputenv("USER",user); X#ifdef DEBUG X if(debuglevel & 1) X fprintf(stderr,"USER=<%s> ",user); X#endif X X if((ut = getenv("HOME")) == NULL) { X if((ut = gethome(user)) == NULL) X ut = HOMEDIR; X mputenv("HOME",ut); X } X#ifdef DEBUG X if(debuglevel & 1) X fprintf(stderr,"HOME=<%s> ",ut); X#endif X X /* process the command line options... */ X while ((c = getopt(argc, argv, "f:R:M:G:U:")) != EOF) X switch((char)c) { X case 'f': X case 'M': X if((menufile=malloc(strlen(optarg)+1)) == NULL) X { perror("envinit()"); return ERROR; } X strcpy(menufile,optarg); X break; X case 'R': X if((root_menu=malloc(strlen(optarg)+1)) == NULL) X { perror("envinit()"); return ERROR; } X strcpy(root_menu,optarg); X break; X case 'G': X if((globalrc=malloc(strlen(optarg)+1)) == NULL) X { perror("envinit()"); return ERROR; } X strcpy(globalrc,optarg); X break; X case 'U': X if((userrc=malloc(strlen(optarg)+1)) == NULL) X { perror("envinit()"); return ERROR; } X strcpy(userrc,optarg); X break; X case '?': X err = TRUE; X } X if(err) { X fprintf(stderr, "Usage: %s [-G global-config-file] [-M menufile]\n",argv[0]); X fprintf(stderr, " [-R rootmenu] [-U user-config-file]\n"); X return ERROR; X } X X if(globalrc == NULL) /* default global rc file location */ X globalrc = GLOBALFILE; X X#ifdef DEBUG X if(debuglevel & 1) X fprintf(stderr,"global rc=<%s>\n",globalrc); X#endif X /* Now process global rc file... must always exist. */ X getrc_global(globalrc); X X if(menufile == NULL) /* default menu file location */ X if((menufile = getenv("MENUFILE")) == NULL) X menufile = MENUFILE; X X if(root_menu == NULL) /* default root menu name */ X if((root_menu = getenv("ROOTMENU")) == NULL) X root_menu = ROOTMENU; X X if(userrc == NULL) X if((userrc = getenv("LUSHRC")) == NULL) X userrc = LUSHRC; X X#ifdef DEBUG X if(debuglevel & 1) X printf("userrc: <%s>, menufile: <%s>, root_menu: <%s>\n", X userrc, menufile, root_menu); X#endif X /***/ /* note: may need to subst ~ in userrc here. */ X X /* now process the user rc file... */ X getrc_user(userrc); X X if((tty = getenv("TTY")) == NULL) { /* default terminal */ X if((ut = ttyname(fileno(stdin))) == NULL) X tty = TTY; X else { X tty = malloc(strlen(ut)+1); X strcpy(tty, ut); X } X mputenv("TTY",tty); X } X X if((term = getenv("TERM")) == NULL) { /* default to "dumb" terminal */ X term = TERM; X mputenv("TERM",term); X } X X return OK; X} X X/* Initialize the termcap variables. Some of this code is from MicroEMACS X by Daniel M. Lawrence (and others.) */ Xint Xtcapinit() /* important. call envinit() before this. */ X{ X char *tgetstr(); X int tgetnum(); X char tcbuf[1024]; X static char strbuf[128]; X char *str = strbuf; X X if (term == NULL) { X fprintf(stderr,"Environment variable TERM not defined!\n"); X return ERROR; X } X X if ((tgetent(tcbuf, term)) <= 0) { X fprintf(stderr, "Unknown terminal type %s!\n", term); X return ERROR; X } X X LI = tgetnum("li"); /* lines & columns */ X CO = tgetnum("co"); X X if((CL = tgetstr("cl",&str)) == NULL) /* clear screen */ X CL = "\n------------------------------------------------------------------------------\n"; X X if((SO = tgetstr("so",&str)) == NULL) /* stand-out enter */ X SO = ""; X X if((SE = tgetstr("se", &str)) == NULL) /* stand-out end */ X SE = ""; X X /* caution: we lose access to tcbuf now. don't call any more termcap X functions. CL, SO, and SE are in static memory. */ X X return OK; X} X Xstatic char retbuf[BUFSIZ]; X#define scanword(s, var) {char *tmp; \ X tmp = ++(s); while(isalnum(*(s))) (s)++; \ X strncpy(var, tmp, (s)-tmp); \ X (var)[(s)-tmp] = '\0'; } X Xchar * /* substitute environment values in "$VAR" strings for s. */ Xenvsubst(s) /* returns with static data which is overwritten by the next call. */ Xchar *s; X{ X char *r = retbuf, *tmp; X static char var[MAX_LEN]; X X while(*r = *s) { X if(*s == '\\') /* escape with \$ or \~. */ X *++r = *++s; X if(*s == '$') { /* substitute */ X scanword(s, var); X if((tmp = getenv(var)) == NULL) /* look it up.. */ X tmp = ""; /* Nothing there */ X while(*r = *tmp++) /* copy */ X r++; X continue; X } X if(*s == '~') { /* look for ~user */ X scanword(s, var); X X if((tmp = gethome(var)) == NULL) X tmp = ""; /* no translation */ X X while(*r = *tmp++) /* copy */ X r++; X continue; X } X s++; X r++; X } X X return retbuf; X} ________This_Is_The_END________ if test `wc -l < envinit.c` -ne 351; then echo 'shar: envinit.c was damaged during transit (should have been 351 lines)' fi fi ; : end of overwriting check echo 'x - getin.c' if test -f getin.c; then echo 'shar: not overwriting getin.c'; else sed 's/^X//' << '________This_Is_The_END________' > getin.c X/* File: getin.c X Author: PAS X Date: May 13, 1987 X Purpose: Miscellaneous esoteric system-dependent functions X */ X X#include "defs.h" X Xstatic char istr[MAX_LEN+1]; /* for returned strings. */ X X/* p = getin(prompt); X Get a string from stdin with prompting on stderr. X X If it's a terminal, avoids that yucky mess that happens if ^Z is pressed X in gets() or scanf(). X */ Xchar * Xgetin(prompt) Xchar *prompt; X{ X int i; X X write(2, prompt, strlen(prompt)); X X /* Get an input-string. Don't allow ^Z characters to force EOF on X subsequent reads when tty's are used. X */ X i = read(0, istr, MAX_LEN); X istr[i] = '\0'; /* make null-terminated */ X X i = strcspn(istr,"\n\r"); /* span to end of line. */ X istr[i] = '\0'; /* strip off the junk. */ X return istr; X} ________This_Is_The_END________ if test `wc -l < getin.c` -ne 34; then echo 'shar: getin.c was damaged during transit (should have been 34 lines)' fi fi ; : end of overwriting check echo 'x - login.c' if test -f login.c; then echo 'shar: not overwriting login.c'; else sed 's/^X//' << '________This_Is_The_END________' > login.c X/* File: login.c X Author: PAS X Date: May 13, 1987 X Purpose: Miscellaneous esoteric system-dependent functions X */ X X#include "defs.h" X#ifndef NULL X#define NULL (char *)0 X#endif X Xvoid login(p) /* log in operator. */ Xchar *p; /* oper name */ X{ X struct passwd *pwd = getpwuid(getuid()); X X if((char *)pwd != NULL) X strcpy(p,pwd->pw_name); /* set operator name */ X X /***/ /* remember login time. */ X} X X/***/ Xvoid logout(p) /* log out operator */ Xchar *p; /* oper name */ X{ /* log system use */ X} ________This_Is_The_END________ if test `wc -l < login.c` -ne 27; then echo 'shar: login.c was damaged during transit (should have been 27 lines)' fi fi ; : end of overwriting check echo 'x - lush.c' if test -f lush.c; then echo 'shar: not overwriting lush.c'; else sed 's/^X//' << '________This_Is_The_END________' > lush.c X/* File: lush.c X Author: Paul A. Shields X Date: Sept 6, 1987 X Purpose: NCCN luser shell -- main program. X */ X X#include "lush.h" X X#ifndef UNAMELEN X#define UNAMELEN 8 X#endif X Xchar version[] = VERSION; Xint novice = TRUE; /* novice mode */ X#ifdef DEBUG Xint debuglevel = 1; X#else X#include <stdio.h> X#endif X X#ifdef PROTOTYPE Xextern void menu(char *); /* display main menu */ Xextern int menuinit(void); X#else Xextern void menu(); Xextern int menuinit(); X#endif X Xint num_lj = 0; /* stack of (jmp_buf *) for longjmp() */ Xjmp_buf ljstack[LJ_MAX]; /* MAX of 10 levels deep. */ X Xcatch_intr() X{ X (void) signal(SIGINT, catch_intr); X longjmp(ljstack[num_lj-1], SIGINT); X} X Xmain(argc,argv) Xint argc; Xchar *argv[]; X{ X int (*ofun)(); X X /* initialize setjmp stack. */ X if(setjmp(ljstack[num_lj++]) != 0) X exit(1); X ofun = signal(SIGINT, catch_intr); /* ^C trapping */ X#ifdef SIGQUIT X ofun = signal(SIGQUIT, SIG_IGN); X#endif X#ifdef SIGTSTP X ofun = signal(SIGTSTP, SIG_IGN); X#endif X X if(envinit(argc,argv) == ERROR) { /* environment initialization */ X fprintf(stderr, "can't initialize environment\n"); X exit(1); X } X if(tcapinit() == ERROR) { /* retrieve terminal capabilities */ X fprintf(stderr, "can't initialize terminal capabilities\n"); X exit(1); X } X if(menuinit() == ERROR) { /* initialize menu data structures */ X fprintf(stderr, "can't initialize menus\n"); X exit(1); X } X X login(user); /* log in operator. */ X menu(root_menu); /* display & process main menu */ X logout(user); /* log out operator. */ X} ________This_Is_The_END________ if test `wc -l < lush.c` -ne 71; then echo 'shar: lush.c was damaged during transit (should have been 71 lines)' fi fi ; : end of overwriting check echo 'x - lush.h' if test -f lush.h; then echo 'shar: not overwriting lush.h'; else sed 's/^X//' << '________This_Is_The_END________' > lush.h X/* File: lush.h X Author: Paul Shields X Date: Feb 2, 1988 X Purpose: Contains global definitions for lush. X */ X/* -- standard headers -------------------------------------------------- */ X X/* global variables... */ X X#include "version.h" X#include "defs.h" X#include "config.h" X X/* valid function handles begin at 0. here are some special ones... */ X#define QUIT -3 /* PAS - 89/03/01: go back to main menu. */ X#define RETURN -2 /* return to calling menu. */ X#define NONE -1 /* don't change menus. */ X Xextern char *user; /* name of user */ Xextern int novice; /* Boolean: novice mode (lush.c) */ Xextern char *globalrc; /* global run-time configuration */ Xextern char *userrc; /* user run-time configuration */ Xextern char *menufile; /* defines the menus */ Xextern char *root_menu; /* root menu title */ Xextern char *tty; /* the port the user is on. */ Xextern char *term; /* the user's terminal type. */ X#ifdef PROTOTYPE Xextern int (*funcs[])(char *); /* array of pointers to functions taking char* and returning int. */ X#else Xextern int (*funcs[])(); X#endif Xextern int intr; /* TRUE if interrupt caught */ Xextern int num_lj; /* for setjmp()/longjmp() */ Xextern jmp_buf ljstack[]; /* ... */ Xextern char *CL, *SO, *SE; /* variables for termcap */ Xextern int LI, CO; /* ... */ X X#ifdef DEBUG Xextern int debuglevel; X#endif X X/* prototype statements for nccn library: */ X#ifdef PROTOTYPE Xint chkfree(int); /* returns boolean true if enuf space. */ Xint envinit(int, char **); /* initialize global variables. */ Xchar *envsubst(char *); /* substitute in environment variable values */ Xchar *getin(char *); /* read from stdin with prompt. */ Xvoid login(char *); /* log in operator. */ Xvoid logout(char *); /* log out operator */ Xint catch_intr(void); /* interrupt signal catcher */ Xint tcapinit(void); /* termcap initialization. */ X#else Xint chkfree(); Xint envinit(); Xchar *envsubst(),*getin(); Xvoid login(),logout(); Xint catch_intr(); Xint tcapinit(); X#endif ________This_Is_The_END________ if test `wc -l < lush.h` -ne 59; then echo 'shar: lush.h was damaged during transit (should have been 59 lines)' fi fi ; : end of overwriting check echo 'x - menu.c' if test -f menu.c; then echo 'shar: not overwriting menu.c'; else sed 's/^X//' << '________This_Is_The_END________' > menu.c X/* File: menu.c X Author: PAS X Date: May 13, 1987 X Purpose: menu display and selection. X */ X X#include "lush.h" X#include "menu.h" X X#ifndef DEBUG X#include <stdio.h> X#endif X Xstatic int /* match characters, case insensitive. */ Xmatch(inp, word) /* return TRUE if inp is a prefix of word. */ Xchar *inp, *word; X{ X#ifdef SUN X#define toupper(c) (isupper(c) ? (c) : (c) - 'a' + 'A') X#endif X X while(*inp && toupper(*inp) == toupper(*word)) { X inp++; X word++; X } X return (*inp == '\0'); X} X Xstatic int GetMenu(name) /* search for menu and return its handle, or ERROR */ Xchar *name; X{ X int i; X for(i=0; i<NumMenus; i++) { X if(strncmp(MenuTree[i].name, name, NAME_SIZE)==0) X return i; X#ifdef DEBUG X else if(debuglevel & 1) X fprintf(stderr, "node %d=<%s>\n", i, MenuTree[i].name); X#endif X } X return ERROR; X} X Xstatic int /* output function for tputs */ Xoutc(c) Xchar c; X{ X return putchar(c); X} X Xstatic void Display(mh) /* display a menu */ Xint mh; /* menu handle */ X{ X int i; X MENUPTR mp; X X tputs(CL,LI,outc); /* clear terminal screen. */ X printf("%s Commands...\n\n", MenuTree[mh].prompt); /* title. */ X printf("%-20s %s\n", "Command", "Purpose"); X printf("%-20s %s\n", "-------", "-------"); X X for(i=0, mp=MenuTree[mh].m; i< mp->numop; i++) X switch(mp->opt[i].flag) { X case '-': X break; X default: X printf("%-20s %s\n", mp->opt[i].word, mp->opt[i].purpose); X break; X } X} X Xstatic int Select(mh) /* select an option and return the option number */ Xint mh; /* menu handle */ X{ X char *p, X line[MAX_LEN+1], X prompt[MAX_LEN+1]; /* input line */ X int i; X MENUPTR mp; X X (void)setjmp(ljstack[num_lj++]); /* signal-return-stack */ X X while(TRUE) { X sprintf(prompt, "\n%s> ", MenuTree[mh].prompt); X X while(strlen(p = getin(prompt)) == NULL) /* get the line. */ X ; X if((p = strtok(p, "\t ")) == NULL) /* rip off the token. */ X continue; X strncpy(line, p, MAX_LEN); X line[MAX_LEN] = '\0'; X X /* call Display if "?" is pressed. if blank, retype the prompt and X try again. otherwise scan for the option. if option not found, X display a message and try again. */ X#ifdef DEBUG X if(debuglevel & 1) X fprintf(stderr,"selected <%s>\n",line); X#endif X if(strcmp(line, "?") == 0) Display(mh); X else { X int j, n; X X for(i=0, n=0, mp=MenuTree[mh].m; i< mp->numop; i++) X if(match(line, mp->opt[i].word)) { X j = i; X n++; X } X switch(n) { X case 0: /* not found. */ X printf("Unrecognised command. Check spelling or press '?' for command list.\n"); X break; X case 1: X --num_lj; X return j; X default: X printf("Ambiguous command. Use more letters.\n"); X break; X } X } X } X} X Xstatic int Process(mh) /* process menu display & selection by handle */ Xint mh; /* menu handle */ X{ X int n, /* option number */ X i, /* for loop counter */ X err; /* error tag */ X struct option *op; /* */ X X (void)setjmp(ljstack[num_lj++]); /* signal-return-stack */ X X if(novice) Display(mh); X X while((n = Select(mh)) != ERROR) { X op = &MenuTree[mh].m->opt[n]; X X /* Call the functions first. Don't go to the next menu if any of them X returns ERROR, or if the user interrupts. */ X for(i=0, err=0; i < op->numresp && !err; i++) { X#ifdef DEBUG X if(debuglevel & 1) X fprintf(stderr,"calling %d ",i); X#endif X err = (*(op->rsp[i].func))(op->rsp[i].param) == ERROR; X } X X if(err) X getin("Press enter: "); X else if(op->nextmenu == RETURN || op->nextmenu == QUIT) { X --num_lj; X return op->nextmenu; X } X else if(op->nextmenu != NONE) { X switch (Process(op->nextmenu)) { /* QUIT returns to root menu. */ X case QUIT: X if(GetMenu(root_menu) != mh) { X --num_lj; X return QUIT; X } X case NONE: X case RETURN: /* drop thru */ X default: X break; X } X } X if(novice) Display(mh); X } X --num_lj; /* should never reach here. */ X return 0; X} X Xvoid menu(name) /* display menu and select. */ Xchar *name; /* menu name */ X{ X int mh; /* menu handle */ X X if((mh = GetMenu(name)) == ERROR) /* search for the menu */ X fprintf(stderr, "%s: Menu not found\n", name); X else X Process(mh); X} ________This_Is_The_END________ if test `wc -l < menu.c` -ne 183; then echo 'shar: menu.c was damaged during transit (should have been 183 lines)' fi fi ; : end of overwriting check echo 'x - menu.h' if test -f menu.h; then echo 'shar: not overwriting menu.h'; else sed 's/^X//' << '________This_Is_The_END________' > menu.h X/* File: menu.h X * Author: PAS X * Date: May 13, 1987 X * Purpose: defines private data structures for menu.c X */ X X/* resplist -- for building lists of functions to call upon selection of X * an option. X */ Xstruct resplist { X#ifdef PROTOTYPE X int (*func)(char *); /* function to be called */ X#else X int (*func)(); X#endif X char *param; /* parameter to give it */ X}; X X/* option -- contains the option word, its purpose, and a list of pointers X * to procedures to call. The procedure returns a command: X * 0 to return, or 1 to select another option. X */ Xstruct option { X int nextmenu, /* handle of the next menu in the tree */ X numresp; /* number of responses */ X struct resplist X rsp[MAX_RESP]; /* list of routines to activate */ X char flag, /* display flag */ X word[NAME_SIZE+1], X *purpose; X}; X X/* MENU -- an array of options. these will be dynamically allocated, and X * initialized by MenuInit. X */ Xtypedef struct menu { X int numop; X struct option opt[MAX_OPTIONS]; X} *MENUPTR; X X/* X * How to calculate the size of a menu with n options: X */ X#define mnusize(n) (sizeof(int) + (sizeof(struct option))*(n)) X X/* treenode -- holds the menu name and a pointer to it X */ Xstruct treenode { X char name[NAME_SIZE+1], /* menu name */ X *prompt; /* prompt text */ X MENUPTR m; /* point to menu */ X}; X X/* tree -- an array (indexed by menu handle) of treenodes. X */ Xtypedef struct treenode TREE[MAX_MENUS]; X Xextern int NumMenus; Xextern TREE MenuTree; ________This_Is_The_END________ if test `wc -l < menu.h` -ne 59; then echo 'shar: menu.h was damaged during transit (should have been 59 lines)' fi fi ; : end of overwriting check echo 'x - mfile.c' if test -f mfile.c; then echo 'shar: not overwriting mfile.c'; else sed 's/^X//' << '________This_Is_The_END________' > mfile.c X/* File: mfile.c X Author: PAS X Date: Jan 7, 1990 X Purpose: A few file utilities capable of counting line numbers. X This code was part of mparse.c in earlier encarnations and is X needed by the lexical analysis and parsing code. X */ X#include "lush.h" X X#ifndef DEBUG X#include <stdio.h> X#endif X X#include "mfile.h" X X/* ---------------------- Utility Procedures --------------------- */ X XMFILE *Mfopen(name, mode) Xchar *name; Xchar *mode; X{ X MFILE *mfp; X FILE *fp; X X if((fp = fopen(name, mode)) == NULL) X return NULL; X if(((char *)mfp = malloc(sizeof(MFILE))) == NULL) { X fclose(fp); X return NULL; X } X mfp->fp = fp; X mfp->name = name; X mfp->curline = 1; X X#ifdef DEBUG X fprintf(stderr,"Mfopen(%s,%s)\n", name, mode); X#endif X return mfp; X} X Xint Mfclose(mfp) XMFILE *mfp; X{ X FILE *fp = mfp->fp; X free(mfp); X X#ifdef DEBUG X fprintf(stderr,"Mfclose()\n"); X#endif X return fclose(mfp->fp); X} X Xvoid MnextCh(mfp) /* advance file pointer to next char. */ XMFILE *mfp; X{ X mfp->curchar = fgetc(mfp->fp); X if(mfp->curchar == '\n') X mfp->curline++; X#ifdef DEBUG X if(debuglevel & 4) X fprintf(stderr,"MnextCh()=%c ",Mcurchar(mfp)); X#endif X} X Xvoid MwNextCh(mfp) /* get a character. ignore white space & comments. */ XMFILE *mfp; X{ X do { X MnextCh(mfp); X while(isspace(mfp->curchar)) /* skip white space. */ X MnextCh(mfp); X if(mfp->curchar == '#') { /* skip to eoln. */ X MnextCh(mfp); X while((mfp->curchar) != '\n' && mfp->curchar != EOF) X MnextCh(mfp); X } X } while(isspace(mfp->curchar) && mfp->curchar != EOF); X X#ifdef DEBUG X if(debuglevel & 4) X fprintf(stderr,"MwNextCh()=%c ",c); X#endif X} X X/* X Read delimited text, creating buffer space as necessary. The delimiter X is the current character. X */ Xchar *ReadText(mfp) XMFILE *mfp; /* file pointer */ X{ X char buf[MAX_LEN]; /* temporary buffer. */ X char *t = buf; X int i = 1; X char d = Mcurchar(mfp); /* delimiter */ X X#ifdef DEBUG X if(debuglevel & 1) X fprintf(stderr, "ReadText() "); X#endif X MnextCh(mfp); X while((*t = Mcurchar(mfp)) != d && i < MAX_LEN) { X t++; i++; X MnextCh(mfp); X } X *t = '\0'; X X#ifdef DEBUG X if(debuglevel & 1) X fprintf(stderr, "size=%d, value=<%s>\n", i, buf); X#endif X X /* allocate just enough space. */ X if((t = malloc(i)) == NULL) { X perror("ReadText()"); X fprintf(stderr, "%s line %d\n", mfp->name, mfp->curline); X return NULL; X } X strcpy(t, buf); X return t; X} ________This_Is_The_END________ if test `wc -l < mfile.c` -ne 121; then echo 'shar: mfile.c was damaged during transit (should have been 121 lines)' fi fi ; : end of overwriting check echo 'x - mfile.h' if test -f mfile.h; then echo 'shar: not overwriting mfile.h'; else sed 's/^X//' << '________This_Is_The_END________' > mfile.h X/* File: mfile.h X Author: Paul Shields X Date: Jan 7, 1990 X Purpose: defines private data structures for mfile.c X */ X Xtypedef struct mfile { X char curchar; /* the current character. */ X int curline; /* the current line. */ X char *name; /* the file name. */ X FILE *fp; /* UNIX file pointer. */ X} MFILE; X X/* prototype statements... */ X#ifdef PROTOTYPE X Xvoid MwNextCh(MFILE *); /* get a character, remove white space. */ Xvoid MnextCh(MFILE *); /* get a character. */ XMFILE *Mfopen(char *, char *); /* open an MFILE. */ Xint Mfclose(MFILE *); /* close an MFILE. */ Xchar *ReadText(MFILE *); /* read a delimited string of text. */ X X#else X Xvoid MwNextCh(), MnextCh(); XMFILE *Mfopen(); Xint Mfclose(); Xchar *ReadText(); X X#endif X X/* some more defines... */ X X/* the current line number. */ X#define Mcurline(mfp) ((mfp) == NULL ? ERROR : (mfp)->curline) X X/* the current file name. */ X#define Mfilename(mfp) ((mfp) == NULL ? NULL : (mfp)->name) X X/* the current character. */ X#define Mcurchar(mfp) ((mfp) == NULL ? ERROR : (mfp)->curchar) ________This_Is_The_END________ if test `wc -l < mfile.h` -ne 41; then echo 'shar: mfile.h was damaged during transit (should have been 41 lines)' fi fi ; : end of overwriting check echo 'x - mlex.c' if test -f mlex.c; then echo 'shar: not overwriting mlex.c'; else sed 's/^X//' << '________This_Is_The_END________' > mlex.c X/* File: mlex.c X Author: Paul Shields X Date: June 1, 1987 X Purpose: lexical analysis. X */ X X#include "lush.h" X#ifndef DEBUG X#include <stdio.h> X#endif X X#include "mfile.h" X#include "mlex.h" X Xint NumTokens = 0; /* (lexical) number of tokens */ XTOKENS SymTable; /* (lexical) symbol table */ X X/* ----------------------- Lexical Analysis ---------------------- */ X X/* X GetToken: get a token, which must be a word or an integer. X Will allocate space as necessary, and return token "handle" X if successful, o/w ERROR. X */ Xint GetToken(fp) XMFILE *fp; X{ X char s[MAX_LEN], *t; /* string buffers */ X int ttype, /* token type */ X i; /* counter */ X X if(isalpha(Mcurchar(fp))) { /* a word */ X t = s; *t++ = Mcurchar(fp); X MnextCh(fp); X while(isalnum(*t = Mcurchar(fp)) || *t == '_') { X t++; X MnextCh(fp); X } X *t = '\0'; X if(isspace(Mcurchar(fp))) /* gobble white space */ X MwNextCh(fp); X X ttype = (strcmp(s,"RETURN")==0) ? M_RETURN : X ((strcmp(s,"NONE")==0) ? M_NONE : X M_WORD); X } X else if(isdigit(Mcurchar(fp)) || Mcurchar(fp)=='-') /* a number */ X { X t = s; *t++ = Mcurchar(fp); X MnextCh(fp); X while(isdigit(*t = Mcurchar(fp))) { X t++; X MnextCh(fp); X } X *t = '\0'; X if(isspace(Mcurchar(fp))) /* gobble white space */ X MwNextCh(fp); X ttype = M_INTEGER; X } X else return ERROR; X X /* look up token in symbol table. */ X X for(i=0; i<NumTokens; i++) X if(strcmp(SymTable[i].val, s) == 0) return i; X X /* not found. allocate new space. */ X if(NumTokens < MAX_TOKENS) { X if((SymTable[NumTokens].val = malloc(strlen(s)+1)) == NULL) { X perror("GetToken()"); X fprintf(stderr, "%s line %d\n", Mfilename(fp), Mcurline(fp)); X return ERROR; X } X strcpy(SymTable[NumTokens].val, s); X SymTable[NumTokens].typ = ttype; X SymTable[NumTokens].mh = -1; /* set later, if necessary */ X return NumTokens++; X } X fprintf(stderr,"Out of space for Tokens. Recompile with larger MAX_TOKENS (mlex.h)\n"); X return ERROR; X} ________This_Is_The_END________ if test `wc -l < mlex.c` -ne 81; then echo 'shar: mlex.c was damaged during transit (should have been 81 lines)' fi fi ; : end of overwriting check echo 'x - mlex.h' if test -f mlex.h; then echo 'shar: not overwriting mlex.h'; else sed 's/^X//' << '________This_Is_The_END________' > mlex.h X/* File: mlex.h X Author: Paul Shields X Date: June 1, 1987 X Purpose: defines private data structures for mlex.c X */ X X/* lexical elements... */ X#define M_DOT 1 X#define M_COMMA 2 X#define M_SEMI 3 X#define M_COLON 4 X#define M_ARROW 5 X#define M_QUOTE 6 X#define M_NONE 7 X#define M_RETURN 8 X#define M_TEXT 9 X#define M_WORD 10 X#define M_INTEGER 11 X Xstruct tokens { X char *val; /* value */ X int typ, /* symbol type M_whatever. */ X mh; /* menu handle, if menu type. */ X}; X Xtypedef struct tokens TOKENS[MAX_TOKENS]; X Xextern int NumTokens; /* (lexical) number of tokens */ Xextern TOKENS SymTable; /* (lexical) symbol table */ X X#ifdef PROTOTYPE Xint GetToken(MFILE *); /* get next token from input stream. */ X#else Xint GetToken(); X#endif X X#define GetValue(h) ((h) < NumTokens ? SymTable[h].val : NULL) X#define GetType(h) ((h) < NumTokens ? SymTable[h].typ : ERROR) X#define GetMnuH(h) ((h) < NumTokens ? SymTable[h].mh : ERROR) X#define SetMnuH(h,i) {if((h) < NumTokens) \ X SymTable[h].mh = (i); else return ERROR;} ________This_Is_The_END________ if test `wc -l < mlex.h` -ne 41; then echo 'shar: mlex.h was damaged during transit (should have been 41 lines)' fi fi ; : end of overwriting check echo 'x - mparse.c' if test -f mparse.c; then echo 'shar: not overwriting mparse.c'; else sed 's/^X//' << '________This_Is_The_END________' > mparse.c X/* File: mparse.c X Author: Paul Shields X Date: May 13, 1987 X Purpose: parses the menu file to build menu structure during initialization. X */ X X#include "lush.h" X X#ifndef DEBUG X#include <stdio.h> X#endif X X#include "menu.h" X#include "mfile.h" X#include "mlex.h" X#include "mparse.h" X Xint NumMenus = 0; /* number of menus */ XTREE MenuTree; X X/* temporary menu. the syntax is simple enough to allow us to make the X following a single global variable. it is a stack in its general form. X */ Xstatic struct menu tmenu; X X/* note the fields: X tmenu.numop X tmenu.opt[0..MAX_OPTIONS] { X [x].word command word string. X [x].purpose explanitory text. X [x].nextmenu handle of next menu. how do we get this? X assign handles as we add mnu-name to symbol table. X [x].rsp list of functions to call X } X */ X X/* ---------------------- Utility Procedures --------------------- */ X X/* look up the name in the menu list. if new, return a new handle. X */ Xstatic int Lookup(name, mhp) Xchar *name; Xint *mhp; /* returned menu handle */ X{ X int i; X X if((strcmp("NONE", name) == 0 && (*mhp = NONE)) || X (strcmp("RETURN", name) == 0 && (*mhp = RETURN)) || X (strcmp("QUIT", name) == 0 && (*mhp = QUIT)) ) X return OK; X X for(i=0; i<NumMenus; i++) X if(strncmp(MenuTree[i].name, name, NAME_SIZE)==0) { X *mhp = i; X return OK; X } X X /* not found.. */ X X if(NumMenus < MAX_MENUS) { X strncpy(MenuTree[NumMenus].name, name, NAME_SIZE); /* copy the name.. */ X MenuTree[NumMenus].name[NAME_SIZE] = '\0'; /* make sure it's null-terminated */ X X MenuTree[NumMenus].prompt = NULL; /* supplimentary initialization */ X MenuTree[NumMenus].m = NULL; X X *mhp = NumMenus++; X return OK; X } X fprintf(stderr,"Out of space for menus. Recompile with larger MAX_MENUS\n"); X return ERROR; X} X Xstatic int NewMenu(mh,n) /* allocate space for a new menu. */ Xint mh, /* menu handle */ X n; /* number of options */ X{ X MENUPTR p; X X /* kill it if it's already there. */ X if(MenuTree[mh].m != NULL) free((char *)MenuTree[mh].m); X X /* allocate just enuf space.. */ X if (((char *)p = malloc(mnusize(n))) == NULL) X return ERROR; X X /* some initialization... */ X p->numop = n; X MenuTree[mh].m = p; X X return OK; X} X Xstatic int MenuParse(fp) /* parse the file and build the structure. */ XMFILE *fp; X{ X char c; X int rc; /* return code */ X X#ifdef DEBUG X if(debuglevel & 1) X fprintf(stderr,"sizeof(struct menu) = %d\n", mnusize(MAX_OPTIONS)); X#endif X X MwNextCh(fp); /* get the first character. */ X rc = MnuTree(fp); /* menu-tree -> menu-list ".". */ X return rc; X} X Xint menuinit() /* initialize data structures */ X{ X MFILE *fp; X X if((fp = Mfopen(menufile, "r")) == NULL) { X perror(menufile); X return ERROR; X } X X NumMenus = 0; /* initialize the menu structure */ X X if(MenuParse(fp) == ERROR) { X fprintf(stderr, "%s: Syntax error, line %d\n", Mfilename(fp), Mcurline(fp)); X Mfclose(fp); X return ERROR; X } X Mfclose(fp); X return OK; X} X X/* ----------------- Syntax and Semantic Analysis ----------------- */ X X/* X mnu-tree -> mnu-list ".". X */ Xstatic int MnuTree(fp) XMFILE *fp; X{ X#ifdef DEBUG X if(debuglevel & 2) X fprintf(stderr,"MnuTree('%c')\n",Mcurchar(fp)); X#endif X X if(MnuList(fp) == ERROR) return ERROR; X if(Mcurchar(fp) == '.') { X MwNextCh(fp); X return OK; X } X return ERROR; X} X X X/* Xmnu-list -> mnu {NewMenu(mh, opt-count, mnu-name), menuinit(mh, tmenu)} X mnu-seq. X */ Xstatic int MnuList(fp) XMFILE *fp; X{ X int mh; /* menu handle */ X X#ifdef DEBUG X if(debuglevel & 2) X fprintf(stderr,"MnuList('%c')\n",Mcurchar(fp)); X#endif X if((mh=Mnu(fp)) == ERROR) return ERROR; X X NewMenu(mh, tmenu.numop); X memcpy( (char *)(MenuTree[mh].m), (char *)(&tmenu), X mnusize(tmenu.numop)); X X return MnuSeq(fp); X} X X/* mnu-seq -> ";" mnu-list. X mnu-seq -> . X */ Xstatic int MnuSeq(fp) XMFILE *fp; X{ X#ifdef DEBUG X if(debuglevel & 2) X fprintf(stderr,"MnuSeq('%c')\n",Mcurchar(fp)); X#endif X if(Mcurchar(fp) == ';') { X MwNextCh(fp); X return MnuList(fp); X } X return OK; X} X X/* mnu -> mnu-name {mh = Lookup(mnu-name)} ":" X prompt-text {clear temporary menu} X opt-list. X */ Xstatic int Mnu(fp) XMFILE *fp; X{ X int sh, /* symbol handle. */ X mh; /* menu handle */ X X#ifdef DEBUG X if(debuglevel & 2) X fprintf(stderr,"Mnu('%c')\n",Mcurchar(fp)); X#endif X if((sh=MnuName(fp)) == ERROR || X (Lookup(GetValue(sh),&mh)) == ERROR || X Mcurchar(fp) != ':') return ERROR; X X MwNextCh(fp); /* read prompt-text. recall, delimiters are ", ', or / */ X if(Mcurchar(fp) != '"' && Mcurchar(fp) != '\'' && Mcurchar(fp) != '/') return ERROR; X X MenuTree[mh].prompt = ReadText(fp); /* allocate and read text (single line) into a buffer */ X MwNextCh(fp); X X tmenu.numop = 0; /* clear temporary menu */ X if(OptList(fp)==ERROR) return ERROR; /* build option list */ X else SetMnuH(sh, mh); /* store handle for later reference */ X X return mh; X} X X/* opt-list -> opt {tmenu.numop++} opt-seq. X */ Xstatic int OptList(fp) XMFILE *fp; X{ X#ifdef DEBUG X if(debuglevel & 2) X fprintf(stderr,"OptList('%c')\n",Mcurchar(fp)); X#endif X if(Opt(fp) == ERROR) return ERROR; X tmenu.numop++; X return OptSeq(fp); X} X X/* opt-seq -> "," opt-list. X opt-seq -> . X */ Xstatic int OptSeq(fp) XMFILE *fp; X{ X#ifdef DEBUG X if(debuglevel & 2) X fprintf(stderr,"OptSeq('%c')\n",Mcurchar(fp)); X#endif X if(Mcurchar(fp) == ',') { X MwNextCh(fp); X return OptList(fp); X } X return OK; X} X X/* opt -> {op = &tmenu.opt[opt-count]} X cmd {strcpy(op->word, cmd)} X mnu-name {op->nextmenu = Lookup(mnu-name)} X X "(" resp-list {op->rsp = response} ")" X X explanitory-text {op->purpose = explanitory-text)}. X */ Xstatic int Opt(fp) XMFILE *fp; X{ X struct option *op; X int fl, t1, t2; /* token handles */ X X#ifdef DEBUG X if(debuglevel & 2) X fprintf(stderr,"Opt('%c')\n",Mcurchar(fp)); X#endif X op = &tmenu.opt[tmenu.numop]; X if((fl=Flag(fp)) == ERROR || X (t1=Cmd(fp)) == ERROR || X (t2=MnuName(fp)) == ERROR || X Mcurchar(fp) != '(') X return ERROR; X X op->flag = (char)fl; X op->numresp = 0; /* initialize */ X X MwNextCh(fp); /* looking for [resp-list] ")" */ X if(Mcurchar(fp) != ')') X if(RspList(fp,op) == ERROR) X return ERROR; X#ifdef DEBUG X if(debuglevel & 2) X fprintf(stderr,"numresp = %d\n", op->numresp); X#endif X if(Mcurchar(fp) != ')') X return ERROR; X MwNextCh(fp); X X strcpy(op->word, GetValue(t1)); X if(Lookup(GetValue(t2), &(op->nextmenu)) == ERROR) return ERROR; X X#ifdef DEBUG X if(debuglevel & 2) X fprintf(stderr,"Explanitory text...\n"); X#endif X X /* explanitory text */ X if(Mcurchar(fp) != '"' && Mcurchar(fp) != '\'' && Mcurchar(fp) != '/') return ERROR; X op->purpose = ReadText(fp); /* allocate and read text */ X X MwNextCh(fp); X return OK; X} X Xstatic int Flag(fp) /* finds the display-flag. */ XMFILE *fp; X{ X switch(Mcurchar(fp)) { X case '-': X MwNextCh(fp); X return (int)'-'; X default: X break; X } X return (int)' '; X} X Xstatic int Cmd(fp) /* command -> word. Return token handle or ERROR */ XMFILE *fp; X{ X int th; /* token handle */ X X#ifdef DEBUG X if(debuglevel & 2) X fprintf(stderr,"Cmd('%c')\n",Mcurchar(fp)); X#endif X if((th = GetToken(fp)) == ERROR) X return ERROR; X X return (GetType(th) == M_WORD) ? th : ERROR; X} X Xstatic int MnuName(fp) /* menu-name -> word. */ XMFILE *fp; /* menu-name -> "NONE". */ X /* menu-name -> "RETURN". */ X{ X int th, /* token handle */ X tt; /* token type */ X X#ifdef DEBUG X if(debuglevel & 2) X fprintf(stderr,"MnuName('%c')\n",Mcurchar(fp)); X#endif X if((th=GetToken(fp)) == ERROR) return ERROR; X tt = GetType(th); X X return (tt==M_WORD || tt==M_NONE || tt==M_RETURN) ? th : ERROR; X} X X X/* resp-list -> resp {numresp++} resp-seq . X */ Xstatic int RspList(fp,op) XMFILE *fp; Xstruct option *op; X{ X#ifdef DEBUG X if(debuglevel & 2) X fprintf(stderr,"RspList('%c')\n",Mcurchar(fp)); X#endif X if(Rsp(fp,&(op->rsp[op->numresp])) == ERROR) return ERROR; X#ifdef DEBUG X if(debuglevel & 2) X fprintf(stderr,"numresp == %d, ",op->numresp); X#endif X if(op->numresp < MAX_RESP) { /* die if too many responses. */ X (op->numresp)++; X#ifdef DEBUG X if(debuglevel & 2) X fprintf(stderr,"numresp++ "); X#endif X } else { X fprintf(stderr,"Too many menu options. Edit rc to decrease.\n"); X return ERROR; X } X X return RspSeq(fp,op); X} X X/* resp-seq -> ";" resp-list . X resp-seq -> . X */ Xstatic int RspSeq(fp,op) XMFILE *fp; Xstruct option *op; X{ X#ifdef DEBUG X if(debuglevel & 2) X fprintf(stderr,"RspSeq('%c')\n",Mcurchar(fp)); X#endif X if(Mcurchar(fp) != ';') return OK; X X MwNextCh(fp); X return RspList(fp,op); X} X X/* rsp -> X proc-id {op->rsp[op->numresp].func = funcs[proc-id]} X param-text {op->rsp[op->numresp].param = ReadText(fp,d) } X */ Xstatic int Rsp(fp,rp) XMFILE *fp; Xstruct resplist *rp; /* pointer to current response */ X{ X int th, /* token handle */ X fh; /* function handle */ X X#ifdef DEBUG X if(debuglevel & 2) X fprintf(stderr,"Rsp('%c') ",Mcurchar(fp)); X#endif X if((th = ProcId(fp)) == ERROR) X return ERROR; X X sscanf(GetValue(th),"%d",&fh); X rp->func = funcs[fh]; X#ifdef DEBUG X if(debuglevel & 2) X fprintf(stderr,"fh = %d, ",fh); X#endif X X /* parameter text */ X if(Mcurchar(fp) != '"' && Mcurchar(fp) != '\'' && Mcurchar(fp) != '/') return ERROR; X rp->param = ReadText(fp); /* allocate and read text */ X X#ifdef DEBUG X if(debuglevel & 2) X fprintf(stderr,"param = %s, ",rp->param); X#endif X X MwNextCh(fp); X return OK; X} X Xstatic int ProcId(fp) /* routine-ident -> integer. Return token handle or ERROR */ XMFILE *fp; X{ X int th; /* token handle */ X X#ifdef DEBUG X if(debuglevel & 2) X fprintf(stderr,"ProcId('%c')\n",Mcurchar(fp)); X#endif X if((th=GetToken(fp)) == ERROR) return ERROR; X X return (GetType(th) == M_INTEGER) ? th : ERROR; X} ________This_Is_The_END________ if test `wc -l < mparse.c` -ne 451; then echo 'shar: mparse.c was damaged during transit (should have been 451 lines)' fi fi ; : end of overwriting check echo 'x - mparse.h' if test -f mparse.h; then echo 'shar: not overwriting mparse.h'; else sed 's/^X//' << '________This_Is_The_END________' > mparse.h X/* File: mparse.h X Author: PAS X Date: June 1, 1987 X Purpose: defines private data structures for mparse.c X */ X X/* prototype statements for parser... */ X#ifdef PROTOTYPE X Xint MnuTree(MFILE *); Xint MnuList(MFILE *); Xint MnuSeq(MFILE *); Xint Mnu(MFILE *); Xint OptList(MFILE *); Xint OptSeq(MFILE *); Xint Opt(MFILE *); Xint RspList(MFILE *, struct option *); Xint RspSeq(MFILE *, struct option *); Xint Rsp(MFILE *, struct resplist *); Xint Cmd(MFILE *); Xint Flag(MFILE *); Xint MnuName(MFILE *); Xint ProcId(MFILE *); X#else X Xint MnuTree(),MnuList(),MnuSeq(),Mnu(),OptList(),OptSeq(),Opt(), X RspList(),RspSeq(),Rsp(),Cmd(),Flag(),MnuName(),ProcId(); X X#endif ________This_Is_The_END________ if test `wc -l < mparse.h` -ne 29; then echo 'shar: mparse.h was damaged during transit (should have been 29 lines)' fi fi ; : end of overwriting check echo 'x - version.h' if test -f version.h; then echo 'shar: not overwriting version.h'; else sed 's/^X//' << '________This_Is_The_END________' > version.h X#define VERSION "LUSH version 1.34, Mon Jan 8 03:04:15 EST 1990" ________This_Is_The_END________ if test `wc -l < version.h` -ne 1; then echo 'shar: version.h was damaged during transit (should have been 1 lines)' fi fi ; : end of overwriting check exit 0 -- Paul Shields, shields at nccn.yorku.ca (..!uunet!yunccn!shields) From aglew at oberon.csg.uiuc.edu Tue Jan 16 04:53:09 1990 From: aglew at oberon.csg.uiuc.edu (Andy Glew) Date: 15 Jan 90 17:53:09 GMT Subject: number recognition tools Message-ID: <AGLEW.90Jan15115309@oberon.csg.uiuc.edu> (My apologies if this is messy - I am unsure if this newsreader emails to the moderator for posts to moderated groups. Please ACK). The following is a set of tools for recognizing almost arbitrary number strings, both library functions and shell level command. It differs from atoi(), etc. in that it already supports natural notations like "0.5M-1", and can be easily customized for application specific notations. Man pages for the library routines and a shell level wrapper are provided. This package has been used for many years on V7, System V, and BSD systems. The posted version has recently been used on SUN3s and Motorola System V boxes. Porting problems should be minor. No install script is provided (because I have never been able to rely on a standard version of install in my travels). #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: Makefile README debug.h getnumber.c getnumber.man number.c # number.man test.c # Wrapped by aglew at rigel.csg.uiuc.edu on Mon Jan 15 11:58:45 1990 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Makefile'\" else echo shar: Extracting \"'Makefile'\" \(236 characters\) sed "s/^X//" >'Makefile' <<'END_OF_FILE' XCFLAGS=-g XCC=FP='' /bin/cc Xall: test number.o getnumber Xtests: test Xtest: test.o number.o X ${CC} -g -DTEST -o test test.o number.o -lm Xgetnumber: getnumber.o number.o X ${CC} -g -o getnumber getnumber.o number.o -lm Xnumber.o: number.c END_OF_FILE if test 236 -ne `wc -c <'Makefile'`; then echo shar: \"'Makefile'\" unpacked with wrong size! fi # end of 'Makefile' fi if test -f 'README' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'README'\" else echo shar: Extracting \"'README'\" \(966 characters\) sed "s/^X//" >'README' <<'END_OF_FILE' X/* X * number X * X * This is a directory for a family of routines that convert X * a string to an integer. The intention is to be able to freely X * recognize just about any format integer: X * X * Decimal 1342334 X * Hex 0xAB43 X * Octal 01377 X * Binary 0b100100011 X * Arbitrary Radix rrr#vvvvvvvv X * X * Because people often want to provide a special format over and above X * those that are already provided X * X * Eg. Hex 'ABC'Z X * Decimal 10. X * Ignore _ 100_677_888 X * X * the intent is to define a, possibly parametrized, recognizer function X * for each format, and then to pass a list of desired recognizer functions X * for your specific recognizer. X * X * This is not intended to be fast, only general. X * X * All recognizers are of the form: X * X * success = RECOGNIZER( string, resultptr ) X * int success; /* -1 indicates failure */ X * char *string; X * int *result; X * X */ X X X X END_OF_FILE if test 966 -ne `wc -c <'README'`; then echo shar: \"'README'\" unpacked with wrong size! fi # end of 'README' fi if test -f 'debug.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'debug.h'\" else echo shar: Extracting \"'debug.h'\" \(4127 characters\) sed "s/^X//" >'debug.h' <<'END_OF_FILE' X#ifndef DEBUG_H X X#define DEBUG_H 1 X X#ifdef DEBUG Xint DEBUG_was_defined; X#endif X X/* X * manual NAME debug.h - Andy Glew's debug header X * X * USAGE #define DEBUG 1 #include "debug.h" ... debugf((fmt,vars...)); X * X * DESCRIPTION X * X * The header file "debug.h" may be found in a directory near you. It X * contains macros to make the production of debugging messages more X * pleasant. X * X * debugf X * X * The most important/useful of these macros is debugf((...)). Debugf X * is a printf (to stdout by default, optionally to stderr or X * elsewhere). It accepts standard printf format strings and a X * variable number of arguments. The only syntactic difference is the X * necessity of double parentheses about the parameter list X * (necessary because C macros can't have variable numbers of X * arguments). Debugf usually produces one line of output per call, X * with a distinctive mark like "Debug in file XXX line NNN". X * X * Example: while( ... ) { debugf(("in loop\n")); ... } X * X * DEBUG X * X * To use debugf: #define DEBUG 1 #include "debug.h" DEBUG must be X * defined before debug.h is included, either in code or in a -dDEBUG X * flag when compiled. If DEBUG is not defined when debug.h is X * included, debugf and other debugging macros occupy no space in X * your program. X * X * nodebugf X * X * nodebugf((...)) is syntactic sugar to make it easy to turn debugfs X * off without having to remove them or go through convolutions X * setting a debug control variable. X * X * debugshow X * X * debugshow(var,fmt) produces the quintessential debugging output X * VARIABLE=VALUE_OF_VARIABLE. fmt is the format string you would use X * in printf, without the double quotes. X * X * Example: int Ingrid=77; debugshow(Ingrid,%d); Produces Debug in file X * XXX line NNN: Ingrid = 77 X * X * _debugf X * X * _debugf is the name of the function to be used to print the debugging X * output, printf by default. It can be changed at any time to X * another varargs function. eprintf is useful - just X * fprintf(stderr...) although it must be rewritten as a function due X * to the weaknesses of C. Logging functions, and the like, can also X * be useful. X * X * DebugCondition X * X * There are actually several layers of indirection in this macro X * system: X * X * debugshow -> debugf -> _ifdebugf -> _debugf X * X * _ifdebugf should not be changed; but the condition DebugCondition X * which it tests can usefully be changed. By default DebugCondition X * is defined as (1); it is often nice to set it to a variable that X * you can patch X * X * #define DebugCondition DebugVar int DebugVar = 0; #define DEBUG 1 X * #include "debug.h" X * X * I would have made a variable the default except for awkwardnesses X * some people have about adding modules to the standard C library. X * X * Some people like having multiple debug levels, although I don't. X * These can also be stacked. X * X * The function name __FUNC__ should be printed out as soon as the C X * compiler is fixed. X * X * manual X */ X X#if defined(DEBUG) X# define DEBUGcode( sl ) sl X# define DEBUGdecl( decl ) decl X#else X# define DEBUGcode( sl ) X# define DEBUGdecl( decl ) X#endif X X#define noDEBUGcode( sl ) X#define noDEBUGdecl( sl ) X X/* X * double brackets about _debugf's parmlist so that you can do X * #define _debugf(v) (printf v,uprintf v) which is useful in the X * kernel X */ X# if defined(DEBUG) X# if !defined(_debugf) X# define _debugf(parmlist) (printf parmlist) X# endif X X/* DebugCondition can be controlled by the user */ X# define _ifdebugf(parmlist) ( DebugCondition ? _debugf(parmlist) : 0 ) X# if !defined(DebugCondition) X# define DebugCondition (1) X# endif X# endif /* DEBUG */ X X# if defined(DEBUG) X# define debugf(parmlist) \ X ( _ifdebugf(("Debug in file %s line %d ",__FILE__,__LINE__)), \ X _ifdebugf(parmlist) \ X ) X# else X# define debugf(parmlist) X# endif X# define nodebugf(parmlist) X X /* debugshow - cannot use "s in arguments */ X#ifdef DEBUG X# define debugshow(var,fmt) debugf(("var = fmt\n",var)) X# define nodebugshow(var,fmt) X#else X# define debugshow(var,fmt) X# define nodebugshow(var,fmt) X#endif X X X#endif /* DEBUG_H */ END_OF_FILE if test 4127 -ne `wc -c <'debug.h'`; then echo shar: \"'debug.h'\" unpacked with wrong size! fi # end of 'debug.h' fi if test -f 'getnumber.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'getnumber.c'\" else echo shar: Extracting \"'getnumber.c'\" \(898 characters\) sed "s/^X//" >'getnumber.c' <<'END_OF_FILE' X/* User level wrapper for Dgetnumber */ X Xvoid exit(); X Xint Igetnumber(); Xint Dgetnumber(); X Xint DorI = 'D'; X Xchar *format = "%g"; X Xmain(argc,argv) X int argc; X char **argv; X{ X double dres; X int ires; X X for(;*++argv;) { X if( !strcmp(*argv,"-i") ) { X DorI = 'I'; X format = "%d"; X } X else if( !strcmp(*argv,"-d") ) { X DorI = 'D'; X format = "%g"; X } X else if( !strcmp(*argv,"-format") ) { X format = *++argv; X } X else { X switch( DorI ) { X default: X exit(-1); X case 'D': X if( Dgetnumber(*argv,&dres) == -1 ) { X (void)printf("invalid\n"); X } X else { X (void)printf(format,dres); X (void)printf("\n"); X } X break; X case 'I': X if( Igetnumber(*argv,&ires) == -1 ) { X (void)printf("invalid\n"); X } X else { X (void)printf(format,ires); X (void)printf("\n"); X } X break; X } X } X } X exit(0); X /*NOTREACHED*/ X} X END_OF_FILE if test 898 -ne `wc -c <'getnumber.c'`; then echo shar: \"'getnumber.c'\" unpacked with wrong size! fi # end of 'getnumber.c' fi if test -f 'getnumber.man' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'getnumber.man'\" else echo shar: Extracting \"'getnumber.man'\" \(2079 characters\) sed "s/^X//" >'getnumber.man' <<'END_OF_FILE' X.nf X NAME: X getnumber \- read a number in arbitrary notation X X SYNOPSIS: X getnumber [-i|-d|-format '%printf-format'] number-string ... X X DESCRIPTION: X getnumber is a program wrapped around the Dgetnumber and Igetnumber X family of routines (see their man pages). Getnumber converts number X in an almost arbitrary string representation, and prints the number X out on stdout as a decimal integer or double precision value, X or using a printf like string. X X getnumber is intended to be used in shell scripts that would like X to be able to recognize numbers typed in by the user in their natural X format. Eg. X ARG=0.5M-1 X ... X value=`getnumber -i $ARG` X XINTERFACE: X Getnumber processes its command line arguments and prints to stdout. X Stdin is not used. X X The command line option X X -i -- convert to an integer, using %d format to print X -d -- convert to a C double, using %g format to print X X -format %printf-format X -- format to be used in printing the result. X X Exits with error status -1 on a command line error. X Prints "invalid" on conversion errors, but continues to process. X XBACKGROUND: X See the man pages for the Dgetnumber and Igetnumber family X for more deatils (man number). X X The intention is to be able to freely recognize just about any X format number: X X Decimal 1342334 X Hex 0xAB43 X Octal 01377 X Binary 0b100100011 X Arbitrary Radix rrr#vvvvvvvv X H:M:S 1:20:33 X Real 1.45 X "Meg" 4M X Expressions (4M-1)*2 X Exponential 1.2E6 X X Expressions currently include: X infix binary: | ^ & << >> + - * / % **(exponent) X prefix unary: - + ~ X midfix grouping: () [] {} X and it is similarly easy to add new notations. X X All number representations and expressions can be intermixed: X [(2M-1)*4]>>0x03 X X NOTES: X X AUTHOR: X Andy Glew (aglew at uiuc.edu) X X HISTORY: X Originally written by Andy Glew at McGill University, 1983 X X BUGS: X END_OF_FILE if test 2079 -ne `wc -c <'getnumber.man'`; then echo shar: \"'getnumber.man'\" unpacked with wrong size! fi # end of 'getnumber.man' fi if test -f 'number.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'number.c'\" else echo shar: Extracting \"'number.c'\" \(18614 characters\) sed "s/^X//" >'number.c' <<'END_OF_FILE' X/* X * number X * X * This is a directory for a family of routines that convert X * a string to a number. X * X * X * The intention is to be able to freely recognize just about any X * format number: X * X * Decimal 1342334 X * Hex 0xAB43 X * Octal 01377 X * Binary 0b100100011 X * Arbitrary Radix rrr#vvvvvvvv X * H:M:S 1:20:33 X * Real 1.45 X * "Meg" 4M X * Expressions (4M-1)*2 X * Exponential 1.2E6 X * X * Because people often want to provide a special format over and above X * those that are already provided X * X * Eg. Hex 'ABC'Z X * Decimal 10. X * Ignore _ 100_677_888 X * X * the intent is to define a, possibly parametrized, recognizer function X * for each format, and then to pass a list of desired recognizer functions X * for your specific recognizer. X * X * This is not intended to be fast, only general. X * X * All recognizers are of the form: X * X * success = RECOGNIZER( string, resultptr ) X * int success; { -1 indicates failure } X * char *string; X * double *result; X * X * Recognition is done bottom up instead of top-down; X * instead of having a grammar that constrains notation, X * everything is passed to low-level recognizers that try to recognize X * the string, perhaps recursively, passing off to other recognizer X * in case of failure. X * X * The current recognizers are: X * X * Octal0 0<octal> eg. 0377 = 0xFF X * SimpleDecimalString <decimal> eg. 10 = 0xA X * Binary0b 0b<binary> eg. 0b011 = 3 X * Decimal0d 0d<decimal> eq. 10 = 0xA X * Hex0x 0x<hex> eg. 0xA = 10 X * ArbitraryRadix <decimalbase>#<radix> eq. 3#22 = 8 X * colon60 M:S eg. 1:20 = 80 X * colon60colon60 H:M:S eg. 2:1:20 = 7280 X * PowersOf2 <real>[KMG] eg. 0.5K = 512 X * RealDecimalString <real> eg. 0.5 X * Expressions eg. 0.5M-1 X * X * Expressions currently include: X * infix binary: | ^ & << >> + - * / % **(exponent) X * prefix unary: - + ~ X * midfix grouping: () [] {} X * and it is similarly easy to add new notations. X * X * All number representations and expressions can be intermixed: X * [(2M-1)*4]>>0x03 X * X * There are some functions useful in building other recognizers, like X * RadixString(), and the expression building functions. X * X * There are two top level recognizers, X * Dgetnumber(str,res) X * and Igetnumber(str,res); X * the "I" version is basically a call to the "D" version, which rounds, X * and errors if the rounded integer value is more than int_threshold X * away from the non-int value. X * X * Initially, this was integer only, but in Jan 89 I changed it X * to produce a floating point result - if you want integer, just X * integerize. X * This will have some lossage if your floating point format X * cannot represent all integer values exactly. Sorry - in that X * case, you'll just have to go back to the old routine. X * It has the advantage of one family of routines being able X * to handle intermediate cases - like 0.5M. X * It has the advantage of, on a system with decent floating X * point, being able to trap on overflow or underflow. X * Interim: add this for Motorola systems. X * If you can, use your system dependent way of trapping on inexact. X * Interim: if you have IEEE floating point, it would be nice to X * have this same routine read in NaNs. X */ X X#include <stdio.h> X#include <string.h> X#include <math.h> X Xextern double pow(); Xextern double floor(); Xextern double fabs(); Xextern char *malloc(); Xextern void free(); X X#define DEBUG 1 X#include "debug.h" X X#define index strchr Xchar *index(); X#define rindex strrchr Xchar *rindex(); X Xvoid exit(); X X/* Interim: no tree building. all recursive in place. */ X Xint MidfixExpression(str,res,preStr,postStr,MidfixFunc) X char *str; X double *res; X char *preStr, *postStr; X double (*MidfixFunc)(); X{ X char *midStr; X double midVal; X int strLen = strlen(str); X int preStrLen = strlen(preStr); X int postStrLen = strlen(postStr); X int match; X X nodebugf(("In midfix <%s> <%s> <%s>\n", str, preStr, postStr)); X X if( str == 0 || *str == 0) { X return -1; X } X X if( strncmp(str,preStr,preStrLen) != 0 ) { X return -1; X } X if( strcmp(str+strLen-postStrLen, postStr) != 0 ) { X return -1; X } X X midStr = malloc((unsigned)(strLen-preStrLen-postStrLen+1)); X if( !midStr ) { X (void)fprintf(stderr,"Error malloc'ing memory for expressions\n"); X exit(1); X } X (void)strncpy(midStr,str+preStrLen,strLen-preStrLen-postStrLen); X midStr[strLen-preStrLen-postStrLen] = '\0'; X nodebugf(("midStr=<%s>\n",midStr)); X match = (Dgetnumber(midStr,&midVal) != -1); X free(midStr); X if( !match ) { X return -1; X } X *res = MidfixFunc(midVal); X return 0; X} Xdouble Dnop(a) double a; { return a; } X X Xint PrefixExpression(str,res,PrefixStr,PrefixFunc) X char *str; X double *res; X char *PrefixStr; X double (*PrefixFunc)(); X{ X double Darg; X int PrefixStrLen = strlen(PrefixStr); X X if( str == 0 || *str == 0) { X return -1; X } X X if( strncmp(str,PrefixStr,PrefixStrLen) != 0 ) { X return -1; X } X else { X if( Dgetnumber(str+PrefixStrLen,&Darg) == -1 ) { X return -1; X } X *res = PrefixFunc(Darg); X return 0; X } X} Xdouble Dplussign(a) double a; { return a; } Xdouble Dnegsign(a) double a; { return -a; } Xdouble Dinvert(a) double a; { return (double)~(unsigned)a; } X X Xint InfixExpression(str,res,InfixStr,InfixFunc) X char *str; X double *res; X char *InfixStr; X double (*InfixFunc)(); X{ X char *left, *right; X double Dleft, Dright; X char *p1; X int match; X int InfixStrLen = strlen(InfixStr); X X if( str == 0 || *str == 0) { X return -1; X } X X /* Try splitting into subexpressions at all occurrences of the operator, X moving from left to handle 1-1-1. Retries will handle subexpressions. X */ X for( p1 = str + strlen(str);;p1--) { X if( p1 < str ) { X return -1; X } X if( !strncmp(p1,InfixStr,InfixStrLen) ) { X left = malloc((unsigned)(p1-str+1)); X right = malloc((unsigned)(strlen(p1+InfixStrLen))); X if( !left || !right ) { X (void)fprintf(stderr,"Error malloc'ing memory for expressions\n"); X exit(1); X } X (void)strncpy(left,str,p1-str); X left[p1-str] = '\0'; X (void)strcpy(right, p1+InfixStrLen ); X match = Dgetnumber(left,&Dleft) != -1 X && Dgetnumber(right,&Dright) != -1; X free(left); X free(right); X if( match ) { X *res = InfixFunc(Dleft,Dright); X return 0; X } X } X } X} X Xdouble Dplus(a,b) double a,b; { return a+b; } Xdouble Dsub(a,b) double a,b; { return a-b; } Xdouble Dtimes(a,b) double a,b; { return a*b; } Xdouble Ddivide(a,b) double a,b; { return a/b; } X/* Interim: need to indicate loss of info on these "pesudo-integer" ops */ Xdouble Dor(a,b) double a,b; { return (double)((unsigned)a | (unsigned)b); } Xdouble Dand(a,b) double a,b; { return (double)((unsigned)a & (unsigned)b); } Xdouble Dxor(a,b) double a,b; { return (double)((unsigned)a ^ (unsigned)b); } Xdouble Dremainder(a,b) double a,b; { return (double)((unsigned)a % (unsigned)b); } Xdouble Dlsh(a,b) double a,b; { return (double)((unsigned)a << (unsigned)b); } Xdouble Drsh(a,b) double a,b; { return (double)((unsigned)a >> (unsigned)b); } Xdouble Dexponent(a,b) double a,b; { extern double pow(); return pow(a,b); } X X Xint Expression(str,res) X char *str; X double *res; X{ X if( str == 0 || *str == 0) { X return -1; X } X X if( InfixExpression(str,res,"|",Dor) == 0 ) { X return 0; X } X if( InfixExpression(str,res,"^",Dxor) == 0 ) { X return 0; X } X if( InfixExpression(str,res,"&",Dand) == 0 ) { X return 0; X } X if( InfixExpression(str,res,"<<",Dlsh) == 0 ) { X return 0; X } X if( InfixExpression(str,res,">>",Drsh) == 0 ) { X return 0; X } X if( InfixExpression(str,res,"+",Dplus) == 0 ) { X return 0; X } X if( InfixExpression(str,res,"-",Dsub) == 0 ) { X return 0; X } X if( InfixExpression(str,res,"*",Dtimes) == 0 ) { X return 0; X } X if( InfixExpression(str,res,"/",Ddivide) == 0 ) { X return 0; X } X if( InfixExpression(str,res,"%",Dremainder) == 0 ) { X return 0; X } X if( InfixExpression(str,res,"**",Dexponent) == 0 ) { X return 0; X } X if( PrefixExpression(str,res,"+",Dplussign) == 0 ) { X return 0; X } X if( PrefixExpression(str,res,"-",Dnegsign) == 0 ) { X return 0; X } X if( PrefixExpression(str,res,"~",Dinvert) == 0 ) { X return 0; X } X if( MidfixExpression(str,res,"(",")",Dnop) == 0 ) { X return 0; X } X if( MidfixExpression(str,res,"[","]",Dnop) == 0 ) { X return 0; X } X if( MidfixExpression(str,res,"{","}",Dnop) == 0 ) { X return 0; X } X return -1; X} X X Xint SimpleDecimalString(str,res) X char *str; X double *res; X{ X if( str == 0 || *str == 0) { X return -1; X } X X return RadixString(str,10,res); X} X Xint Binary0b(str,res) X char *str; X double *res; X{ X if( str == 0 || *str == 0) { X return -1; X } X X if( str[0] == '0' && (str[1] == 'b' || str[1] == 'B') ) { X return RadixString(str+2,2,res); X } X return -1; X} X Xint Octal0(str,res) X char *str; X double *res; X{ X if( str == 0 || *str == 0) { X return -1; X } X X if( str[0] == '0' ) { X return RadixString(str+1,8,res); X } X return -1; X} X Xint Decimal0d(str,res) X char *str; X double *res; X{ X if( str == 0 || *str == 0) { X return -1; X } X X if( str[0] == '0' && (str[1] == 'd' || str[1] == 'D') ) { X return RadixString(str+2,10,res); X } X return -1; X} X Xint Hex0x(str,res) X char *str; X double *res; X{ X if( str == 0 || *str == 0) { X return -1; X } X X if( str[0] == '0' && (str[1] == 'x' || str[1] == 'X') ) { X return RadixString(str+2,16,res); X } X return -1; X} X Xint ArbitraryRadix(str,res) X char *str; X double *res; X{ X int radix; X int digval; X X if( str == 0 || *str == 0) { X return -1; X } X X for( radix = 0; (digval = DECIMAL_DIGIT_VALUE(*str)) != -1; str++ ) { X radix = radix*10 + digval; X } X if( *str != '#' ) X return -1; X return RadixString(str+1,radix,res); X} X Xint RadixString(str,radix,res) X char *str; X int radix; X double *res; X{ X int val; X int digval; X X if( str == 0 || *str == 0) { X return -1; X } X X val = 0; X for(;;) { X if( !IGNORE(*str) ) { X digval = DIGIT_VALUE(*str); X if( digval < 0 || digval >= radix ) X return -1; X val = val*radix + digval; X } X str++; X if( *str == '\0' ) X break; X } X *res = val; X X return 0; X} X X/* Recognisers for M:S and H:M:S forms */ X X#define PRECOLON() { \ X if( (colonpos = index(str,':')) == 0 ) { \ X return -1; \ X } \ X precolon_len = colonpos-str; \ X if( precolon_len > 128-1 ) { \ X /* string too long */ \ X return -1; \ X } \ X /* Copy the precolon string and interpret as a decimal number */ \ X (void)strncpy( precolon_str, str, precolon_len ); \ X precolon_str[precolon_len] = '\0'; \ X \ X if( SimpleDecimalString(precolon_str,&precolon_val) == -1 ) { \ X return -1; \ X } \ X if( precolon_val != (int) precolon_val || precolon_val < 0 ) { \ X return -1; \ X } \ X} X Xint colon60(str,res) X char *str; X double *res; X{ X char *colonpos; X char precolon_str[128]; X int precolon_len; X double precolon_val; X double postcolon_val; X X X if( str == 0 || *str == 0) { X return -1; X } X X PRECOLON(); X X if( DecimalString(colonpos+1,&postcolon_val) == -1 ) { X return -1; X } X if( postcolon_val < 0 || 60 <= postcolon_val ) { X return -1; X } X X *res = precolon_val*60 + postcolon_val; X return 0; X} Xint colon60colon60(str,res) X char *str; X double *res; X{ X char *colonpos; X char precolon_str[128]; X int precolon_len; X double precolon_val; X double postcolon_val; X X if( str == 0 || *str == 0) { X return -1; X } X X PRECOLON(); X X if( colon60(colonpos+1,&postcolon_val) == -1 ) { X return -1; X } X if( postcolon_val < 0 || 60*60 <= postcolon_val) { X return -1; X } X X *res = precolon_val*(60*60) + postcolon_val; X return 0; X} X X/* Recognize common powers of 2: 2^10=K, 2^20=M, 2^30=G X Interim: would handle 2^40=T if it didn't overflow */ X Xint PowersOf2(str,res) X char *str; X double *res; X{ X int sl = strlen(str); X double val; X char buf[128]; X X if( str == 0 || *str == 0) { X return -1; X } X X if( sl <= 0 || sl > 128-1 ) { X return -1; X } X (void)strcpy(buf,str); X buf[sl-1] = '\0'; X X if( str[sl-1] == 'K' ) { X if( DecimalString(buf,&val) == -1 ) { X return -1; X } X *res = val * 1024; X return 0; X } X else if( str[sl-1] == 'M' ) { X if( DecimalString(buf,&val) == -1 ) { X return -1; X } X *res = val * 1024*1024; X return 0; X } X else if( str[sl-1] == 'G' ) { X if( DecimalString(buf,&val) == -1 ) { X return -1; X } X *res = val * 1024*1024*1024; X return 0; X } X return -1; X} X X/* Floating point recognizer. X Interim: decimal floating point only. X iii.fffff form only. X Interim: should recognize scientific notation iii.fffEeeee */ X Xint RealDecimalString(str,res) X char *str; X double *res; X{ X double val; X int sl; X int infraction; X int scale; X X if( str == 0 || *str == 0) { X return -1; X } X X sl = strlen(str); X X if( sl <= 0 ) { X return -1; X } X X if( index(str,'.') == 0 ) { X return -1; X } X X /* accumulation of value down from least significant end X first, to reduce errors */ X val = 0; X infraction = 1; X scale = 1; X for(;sl-->0;) { X int d = DECIMAL_DIGIT_VALUE(str[sl]); X if( d == -1 ) { X if( str[sl] == '.' ) { X infraction = 0; X continue; X } X else { X return -1; X } X } X if( infraction ) { X val += d; X val /= 10.0; X } X else { X val = d*scale + val; X scale = scale*10; X } X } X *res = val; X return 0; X} X X X X Xint DecimalString(str,res) X char *str; X double *res; X{ X if( str == 0 || *str == 0) { X return -1; X } X X if( SimpleDecimalString(str,res) == -1 X && RealDecimalString(str,res) == -1 ) { X return -1; X } X return 0; X} X X X/* Generic routine for signs */ Xint Signed(func,str,res) X int (*func) (); X char *str; X double *res; X{ X double value; X int ret; X int neg; X X if( str == 0 || *str == 0) { X return -1; X } X X switch( str[0] ) { X case '+': X neg = 0; X ret = func(str+1,&value); X break; X case '-': X neg = 1; X ret = func(str+1,&value); X break; X default: X neg = 0; X ret = func(str,&value); X break; X } X if( ret == -1 ) { X return -1; X } X else { X if( neg ) value = -value; X *res = value; X return 0; X } X X} X X X X/* Scientific notation recognizer */ X Xint ScientificExponentialNotation(str,res) X char *str; X double *res; X{ X char *dupptr; X char *expptr; X double exponent; X double mantissa; X int retval; X X if( str == 0 || *str == 0) { X return -1; X } X X if( (dupptr = strdup(str)) == 0 ) { X (void)fprintf(stderr,"insufficient free memory to duplicate string\n"); X exit(1); X } X if( (expptr = strchr(dupptr,'E')) == 0 X && (expptr = strchr(dupptr,'e')) == 0 X ) { X retval = -1; X goto cleanup; X } X X *expptr++ = '\0'; X X /* dupptr is now a pointer to the mantissa, expptr to the exponent, X both null terminated strings */ X if( Signed(SimpleDecimalString,expptr,&exponent) == -1 ) { X retval = -1; X goto cleanup; X } X X if( Signed(RealDecimalString,dupptr,&mantissa) == -1 X && Signed(SimpleDecimalString,dupptr,&mantissa) == -1 ) { X retval = -1; X goto cleanup; X } X X *res = mantissa * pow(10.0,exponent); X retval = 0; X X cleanup: X free(dupptr); X X return retval; X} X X X/* Utility functions */ Xchar *IGNORE_CHARS = "_"; X Xint IGNORE(c) X char c; X{ X return index(IGNORE_CHARS,c) != 0; X} X Xint DIGIT_VALUE(d) X char d; X{ X int val; X X switch( d ) { X default: val = -1; break; X case '0': val = 0; break; X case '1': val = 1; break; X case '2': val = 2; break; X case '3': val = 3; break; X case '4': val = 4; break; X case '5': val = 5; break; X case '6': val = 6; break; X case '7': val = 7; break; X case '8': val = 8; break; X case '9': val = 9; break; X case 'a': case 'A': val = 0xA; break; X case 'b': case 'B': val = 0xB; break; X case 'c': case 'C': val = 0xC; break; X case 'd': case 'D': val = 0xD; break; X case 'e': case 'E': val = 0xE; break; X case 'f': case 'F': val = 0xF; break; X } X return val; X} X Xint DECIMAL_DIGIT_VALUE(d) X char d; X{ X int val = DIGIT_VALUE(d); X if( val < 0 || val >= 10 ) X return -1; X else X return val; X} X X X X Xtypedef int (*Recognizer)(); X XRecognizer DefaultRecognizers[] = { X Octal0, X SimpleDecimalString, X Binary0b, X Decimal0d, X Hex0x, X ArbitraryRadix, X colon60, X colon60colon60, X PowersOf2, X RealDecimalString, X Expression, X ScientificExponentialNotation, X 0 X}; X X/* Flags for DgetnumberList */ X#define PRIO_RESOLVE_AMBIGUITY 1 X Xint DgetnumberList(str,res,flags,RecognizerList) X char *str; X double *res; X int flags; X Recognizer RecognizerList[]; X{ X int found; X double oldval = 0; /* to silence lint "oldval may be used before set" */ X double newval; X Recognizer *fp; X X /* Special test for null strings. X All recognizers should really handle this, but... X */ X if( str == 0 || str[0] == 0 ) { X return -1; X } X X for(fp = RecognizerList, found=0; *fp; fp++) { X if( (*fp)(str,&newval) != -1 ) { X if( flags & PRIO_RESOLVE_AMBIGUITY ) { X found = 1; X break; X } X if( found ) { X if( newval != oldval ) { X return -1; X } X } X else { X oldval = newval; X found = 1; X } X } X } X if( found ) { X *res = newval; X return 0; X } X else { X return -1; X } X} X X X/* Recognizer form of the above, with the default list */ X Xint Dgetnumber(str,res) X char *str; X double *res; X{ X if( DgetnumberList(str,res, X PRIO_RESOLVE_AMBIGUITY, X DefaultRecognizers) X == -1 ) { X return -1; X } X return 0; X} X X X/* Integer version of the above. X Includes a threshold because arithmetic may be inexact (sigh) */ X/* Interim: should this be parametrized for "D" function to call, X threshold, and list of recognizers? I'm not sure. */ X Xdouble int_threshold = 0.00000001; X Xint Igetnumber(str,res) X char *str; X int *res; X{ X extern double floor(); X extern double fabs(); X double dres; X double delta; X X if( Dgetnumber(str,&dres) == -1 ) { X return -1; X } X *res = (int)floor(dres+0.5); X delta = (double)*res - dres; X if( fabs(delta) > int_threshold ) { X return -1; X } X return 0; X} END_OF_FILE if test 18614 -ne `wc -c <'number.c'`; then echo shar: \"'number.c'\" unpacked with wrong size! fi # end of 'number.c' fi if test -f 'number.man' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'number.man'\" else echo shar: Extracting \"'number.man'\" \(5262 characters\) sed "s/^X//" >'number.man' <<'END_OF_FILE' X.nf X NAME: X Dgetnumber, Igetnumber \- a family of string to number conversion routines X X SYNOPSIS: X X /* Default double precision recognizer */ X success = Dgetnumber( string, resultptr ) X int success; { -1 indicates failure } X char *string; X double *result; X X /* Default integer recognizer */ X success = Igetnumber( string, resultptr ) X int success; { -1 indicates failure } X char *string; X int *result; X X /* Threshold used for integerizing double precision values. */ X double int_threshold; X X DESCRIPTION: X X Dgetnumber and Igetnumber are two representatives (probably all that a typical X use may ever encounter) of a family of routines for string representations of X numbers to numbers in machine internal representation. X X They were written out of frustration with programs and routines that seldom X accept all of the "natural" representations of numbers for a problem -- X disk utilities that require decimal numbers as input, while disk error loggers X produce hex numbers on output, times that need to be converted from H:M:S X before they can be used, etc. X X The intention is to be able to freely recognize just about any X format number: X X Decimal 1342334 X Hex 0xAB43 X Octal 01377 X Binary 0b100100011 X Arbitrary Radix rrr#vvvvvvvv X H:M:S 1:20:33 X Real 1.45 X "Meg" 4M X Expressions (4M-1)*2 X Exponential 1.2E6 X X Because people often want to provide a special format over and above X those that are already provided X X Eg. Hex 'ABC'Z X Decimal 10. X Ignore _ 100_677_888 X X the intent is to define a, possibly parametrized, recognizer function X for each format, and then to pass a list of desired recognizer functions X for your specific recognizer. X X This is not intended to be fast, only general. X X All recognizers are of the form: X X success = RECOGNIZER( string, resultptr ) X int success; { -1 indicates failure } X char *string; X double *result; X X Recognition is done bottom up instead of top-down; X instead of having a grammar that constrains notation, X everything is passed to low-level recognizers that try to recognize X the string, perhaps recursively, passing off to other recognizer X in case of failure. X X The current recognizers are: X X Octal0 0<octal> eg. 0377 = 0xFF X SimpleDecimalString <decimal> eg. 10 = 0xA X Binary0b 0b<binary> eg. 0b011 = 3 X Decimal0d 0d<decimal> eq. 10 = 0xA X Hex0x 0x<hex> eg. 0xA = 10 X ArbitraryRadix <decimalbase>#<radix> eq. 3#22 = 8 X colon60 M:S eg. 1:20 = 80 X colon60colon60 H:M:S eg. 2:1:20 = 7280 X PowersOf2 <real>[KMG] eg. 0.5K = 512 X RealDecimalString <real> eg. 0.5 X Expressions eg. 0.5M-1 X X Expressions currently include: X infix binary: | ^ & << >> + - * / % **(exponent) X prefix unary: - + ~ X midfix grouping: () [] {} X and it is similarly easy to add new notations. X X All number representations and expressions can be intermixed: X [(2M-1)*4]>>0x03 X X There are some functions useful in building other recognizers, like X RadixString(), and the expression building functions. X X There are two top level recognizers, X Dgetnumber(str,res) X and Igetnumber(str,res); X the "I" version is basically a call to the "D" version, which rounds, X and errors if the rounded integer value is more than int_threshold X away from the non-int value. X X These use an internal function X X typedef int (*Recognizer)(); X X int DgetnumberList(str,res,flags,RecognizerList) X char *str; X double *res; X int flags; X Recognizer RecognizerList[]; X X which is called by default with X X Recognizer DefaultRecognizers[] X X An easy way for users to customize these routines is to X create a private list of recognizers, deleting standard recognizers X that are undesired, and adding user coded recognizers that have X not been provided (eg. nnCnnTnnB cylinder/track/block notation) X and then call DgetnumberList() from their own top-level wrapper. X X (Internal detail: a flag controls whether conflicting matches X should be an error or not). X X NOTES: X Initially, this was integer only, but in Jan 89 I changed it X to produce a floating point result - if you want integer, just X integerize. X This will have some lossage if your floating point format X cannot represent all integer values exactly. Sorry - in that X case, you'll just have to go back to the old routine. X It has the advantage of one family of routines being able X to handle intermediate cases - like 0.5M. X It has the advantage of, on a system with decent floating X point, being able to trap on overflow or underflow. X But this is not added. X If you can, use your system dependent way of trapping on inexact. X Interim: if you have IEEE floating point, it would be nice to X have this same routine read in NaNs. X X AUTHOR: X Andy Glew (aglew at uiuc.edu) X X HISTORY: X Originally written by Andy Glew at McGill University, 1983 X X BUGS: X END_OF_FILE if test 5262 -ne `wc -c <'number.man'`; then echo shar: \"'number.man'\" unpacked with wrong size! fi # end of 'number.man' fi if test -f 'test.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'test.c'\" else echo shar: Extracting \"'test.c'\" \(4519 characters\) sed "s/^X//" >'test.c' <<'END_OF_FILE' Xvoid exit(); X Xint verbose = 1; X Xint StopOnError = 1; X Xmain(argc,argv) X int argc; X char **argv; X{ X int aval; X int gval; X int gret; X X if( argc == 1 ) { X AutoTests(); X } X else for(;*++argv;) { X if(0) ; X else if( !strcmp(*argv,"-auto") ) { X AutoTests(); X } X else if( !strcmp(*argv,"-verbose") ) { X verbose = 1; X } X else if( !strcmp(*argv,"-noverbose") ) { X verbose = 0; X } X else if( !strcmp(*argv,"-stoponerror") ) { X StopOnError = 1; X } X else if( !strcmp(*argv,"-nostoponerror") ) { X StopOnError = 0; X } X else if( !strcmp(*argv,"-test") ) { X gret = Igetnumber(argv[1],&gval); X X if( !strcmp(argv[2],"invalid") ) { X if( gret == -1 ) X exit(0); X else { X (void)printf("<%s> <%s> failed - invalid\n",argv[1],argv[2]); X exit(1); X } X } X else { X aval = atoi(argv[2]); X if( gret == -1 ) { X (void)printf("<%s> invalid - should be <%s> %d\n",argv[1],argv[2],aval); X exit(1); X } X else { X if( aval != gval ) { X (void)printf("<%s> %d should be <%s> %d\n", X argv[1],gval,argv[2],aval); X exit(1); X } X else X exit(0); X } X } X } X else { X (void)printf("Unknown argument <%s>\n",*argv); X exit(1); X } X } X exit(0); X /*NOTREACHED*/ X} X Xstruct TestVec { X char *str; X int value; X int valid; X} TV[] = { X { "-111E0A", 0, 0 }, X { "-111E0", -111, 1 }, X { "+121E0", 121, 1 }, X { "100E-2", 1, 1 }, X { "-100E-2", -1, 1 }, X { "+100E-2", 1, 1 }, X { "1E+1", 10, 1 }, X { "1.2E1", 12, 1 }, X { "0.5E6", 500000, 1 }, X { "-111e0A", 0, 0 }, X { "-111e0", -111, 1 }, X { "+121e0", 121, 1 }, X { "100e-2", 1, 1 }, X { "-100e-2", -1, 1 }, X { "+100e-2", 1, 1 }, X { "1e+1", 10, 1 }, X { "1.2e1", 12, 1 }, X { "0.5e6", 500000, 1 }, X { "2**4+1", 17, 1 }, X { "(0xFF>>2)+1", 64, 1 }, X { "(1<<2)+1", 5, 1 }, X { "1<<2+1", 8, 1 }, X /* replicated because of an old stateful error */ X { "-(-(-(-(-(-3)))))", 3, 1 }, X { "-(-(-(-(-(-3)))))", 3, 1 }, X { "-(-(-(-(-(-3)))))", 3, 1 }, X { "[1+(2*3)]*{1+2}", 21, 1 }, X { "1+(2+3)", 6, 1 }, X { "1-1-1", -1, 1 }, X { "(0)", 0, 1 }, X { "(1K)+1", 1025, 1 }, X { "2*(1K)+1", 2049, 1 }, X { "2*(2K+1)+(2M/1K)", 6146, 1 }, X { "(0)", 0, 1 }, X { "(0)", 0, 1 }, X { "0b0000", 0, 1 }, X { "0b11", 3, 1 }, X { "-0b101", -5, 1 }, X { "-5K", -5120, 1 }, X { "0.5K", 512, 1 }, X { "13M", 13631488, 1 }, X { "1G", 1073741824, 1 }, X { "1:20", 80, 1 }, X { "2:1:20", 7280, 1 }, X { "I-0b101", 0, 0 }, X { "10.3", 0, 0 }, X { "x0", 0, 0 }, X { "0x", 0, 0 }, X { "-1-", 0, 0 }, X { "-1+", 0, 0 }, X { "-", 0, 0 }, X { "+", 0, 0 }, X { "-4+1", -3, 1 }, X { "-4*-3", 12, 1 }, X { "4*-3", -12, 1 }, X { "-4*3", -12, 1 }, X { 0, 0 } X}; X XAutoTests() X{ X int i; X struct TestVec *tv; X X for( tv=TV; tv->str; tv++ ) { X int val; X if( Igetnumber(tv->str,&val) == -1 ) { X if( tv->valid ) { X (void)printf("Error: <%s> invalid, should be %d\n", X tv->str, tv->value ); X if( StopOnError ) { X exit(1); X } X } X else { X if( verbose ) (void)printf("Passed: <%s> invalid\n",tv->str); X } X } X else { X if( tv->valid ) { X if( val != tv->value ) { X (void)printf("Error: <%s> %d, should be %d\n", X tv->str, val, tv->value ); X if( StopOnError ) { X exit(1); X } X } X else { X if( verbose ) (void)printf("Passed: <%s> %d\n", tv->str, val); X } X } X else { X (void)printf("Error: <%s> %d, should be invalid\n", X tv->str, val ); X if( StopOnError ) { X exit(1); X } X } X } X } X X X for(i=0;i<100;i++) X TestAllPatterns(i); X for(i=132;i<1000000000;i+=12331) X TestAllPatterns(i); X X} X XTestAllPatterns(i) X{ X TestFormat(i,"%d"); X TestFormat(i,"0%o"); X TestFormat(i,"0x%x"); X TestFormat(i,"0d%d"); X} XTestFormat(i,fstr) X int i; X char *fstr; X{ X char buf[128]; X X /* With no sign */ X (void)sprintf(buf+1,fstr,i); X TestBufferValue(buf+1,i); X /* With sign */ X buf[0]='+'; X TestBufferValue(buf,i); X buf[0]='-'; X TestBufferValue(buf,-i); X} XTestBufferValue(buf,i) X char *buf; X int i; X{ X int val; X if( Igetnumber(buf,&val) == -1 ) { X (void)printf("error - <%s> invalid, should be %d\n",buf,i); X if( StopOnError ) { X exit(1); X } X } X else if( val != i ) { X (void)printf("error - <%s> %d, should be %d\n",buf,val,i); X if( StopOnError ) { X exit(1); X } X } else { X if( verbose ) (void)printf("Passed: <%s> %d\n",buf,i); X } X} X X END_OF_FILE if test 4519 -ne `wc -c <'test.c'`; then echo shar: \"'test.c'\" unpacked with wrong size! fi # end of 'test.c' fi echo shar: End of shell archive. exit 0 -- Andy Glew, aglew at uiuc.edu From paul at devon.lns.pa.us Wed Jan 17 19:16:50 1990 From: paul at devon.lns.pa.us (Paul Sutcliffe Jr.) Date: 17 Jan 90 08:16:50 GMT Subject: Enhanced SYSV Getty, v1.1, part 4 of 4 Message-ID: <1990Jan17.081650.894@devon.lns.pa.us> #! /bin/sh # Make a new directory for the getty sources, cd to it, and run kits 1 # thru 4 through sh. When all 4 kits have been run, read README. echo "This is getty 1.1 kit 4 (of 4). If kit 4 is complete, the line" echo '"'"End of kit 4 (of 4)"'" will echo at the end.' echo "" export PATH || (echo "You didn't use sh, you clunch." ; kill $$) mkdir man 2>/dev/null echo Extracting Makefile.SH sed >Makefile.SH <<'!STUFFY!FUNK!' -e 's/X//' X: X# $Id: Makefile.SH,v 1.1 90/01/16 16:12:10 paul Exp Locker: paul $ X# X# Creates Makefile for getty distribution X# X# $Log: Makefile.SH,v $ X# Revision 1.1 90/01/16 16:12:10 paul X# Initial revision X# X# X Xcase $CONFIG in X'') X if test ! -f config.sh; then X ln ../config.sh . || \ X ln ../../config.sh . || \ X ln ../../../config.sh . || \ X (echo "Can't find config.sh."; exit 1) X fi X . config.sh X ;; Xesac Xcase "$0" in X*/*) cd `expr X$0 : 'X\(.*\)/'` ;; Xesac X X: add necessary modules based on config.sh Xcase "$d_getutent" in X"$define") X src="" X obj="" X ;; X"$undef") X src="getutent.c" X obj="getutent.o" X ;; Xesac Xcase "$d_strdup" in X"$undef") X src="$src strdup.c" X obj="$obj strdup.o" X ;; Xesac Xcase "$d_putenv" in X"$undef") X src="$src putenv.c" X obj="$obj putenv.o" X ;; Xesac X Xecho "Extracting Makefile (with variable substitutions)" X$spitshell >Makefile <<!GROK!THIS! X# X# Makefile for getty distribution X# X# To recreate this file, make any changes in config.sh and then X# say "sh Makefile.SH" X# X XSHELL= /bin/sh X X# compiler stuff -- check these XCC= $cc XCFLAGS= -O $ccflags $small XLFLAGS= $ldflags $split XLINT= lint -abchuvx XLLIB= $llib_termlib X X# where things go XBIN= $bin XUUBIN= $bin X X# what libraries are needed for termcap/terminfo routines? XTLIB= $termlib X X# what are we making XSH= Makefile.SH config.h.SH makedep.SH XHDRS= config.h defaults.h extern.h funcs.h getty.h patchlevel.h \\ X table.h tune.h XSRC= main.c funcs.c defaults.c table.c $src XOBJ= main.o funcs.o defaults.o table.o $obj XUUSRC= umain.c funcs.c defaults.c table.c $src XUUOBJ= umain.o funcs.o defaults.o table.o $obj X X# rules X Xall: getty uugetty manpages X Xclist: X @echo $(SRC) $(UUSRC) | $tr ' ' '\012' | $sort | $uniq > .clist X Xhlist: X @echo $(HDRS) | $tr ' ' '\012' > .hlist X Xshlist: X @echo $(SH) | $tr ' ' '\012' > .shlist X!GROK!THIS! X$spitshell >>Makefile <<'!NO!SUBS!' X Xgetty: $(OBJ) X $(CC) $(LFLAGS) -o $@ $(OBJ) $(TLIB) X Xuugetty: $(UUOBJ) X $(CC) $(LFLAGS) -o $@ $(UUOBJ) $(TLIB) X Xmanpages: X cd man; make X Xinstall: getty uugetty X -mv $(BIN)/getty $(BIN)/getty- X -mv $(UUBIN)/uugetty $(UUBIN)/uugetty- X cp getty $(BIN) X cp uugetty $(UUBIN) X chmod 700 $(BIN)/getty $(UUBIN)/uugetty X strip $(BIN)/getty $(UUBIN)/uugetty X cd man; make install X Xlint: $(SRC) umain.c X @echo "linting getty sources..." X echo "GETTY" >lint.out X $(LINT) $(SRC) $(LLIB) >>lint.out X @echo "linting uugetty sources..." X @echo ' ' >>lint.out X echo 'UUGETTY' >>lint.out X $(LINT) -DUUGETTY $(UUSRC) $(LLIB) >>lint.out X @echo "lint output is in lint.out" X Xclean: X rm -f umain.c *.o core *.out .*list Makefile.old X cd man; make clean X Xclobber: clean X rm -f getty uugetty X cd man; make clobber X Xrealclean: clobber X Xdepend: makedep umain.c tune.h X chmod +x makedep X ./makedep X X# special dependancies follow X Xumain.c: main.c X -ln main.c umain.c X Xumain.o: X $(CC) $(CFLAGS) -DUUGETTY -c umain.c X Xtune.h: tune.H X @echo "Making a tune.h from the tune.H prototype file." X @echo "You may wish to edit tune.h before continuing." X -cp tune.H tune.h X X# AUTOMATICALLY GENERATED MAKE DEPENDENCIES--PUT NOTHING BELOW THIS LINE X!NO!SUBS! Xchmod 644 Makefile X$eunicefix Makefile !STUFFY!FUNK! echo Extracting man/getutent.m4 sed >man/getutent.m4 <<'!STUFFY!FUNK!' -e 's/X//' X.\" +---------- X.\" | $Id: getutent.m4,v 1.1 90/01/16 16:02:41 paul Exp Locker: paul $ X.\" | X.\" | GETUTENT man page. X.\" | X.\" | Copyright 1989,1990 by Paul Sutcliffe Jr. X.\" | X.\" | Permission is hereby granted to copy, reproduce, redistribute, X.\" | or otherwise use this software as long as: there is no monetary X.\" | profit gained specifically from the use or reproduction or this X.\" | software, it is not sold, rented, traded or otherwise marketed, X.\" | and this copyright notice is included prominently in any copy X.\" | made. X.\" | X.\" | The author make no claims as to the fitness or correctness of X.\" | this software for any use whatsoever, and it is provided as is. X.\" | Any use of this software is at the user's own risk. X.\" | X.\" X.\" +---------- X.\" | $Log: getutent.m4,v $ X.\" | Revision 1.1 90/01/16 16:02:41 paul X.\" | Initial revision X.\" | X.\" | X.\" X.\" +---------- X.\" | M4 configuration X.\" Xinclude(config.m4).\" X.\" X.\" +---------- X.\" | Manpage source follows: X.\" X.TH GETUTENT _library_section_ X.SH NAME Xgetutent, getutline, setutent, endutent, Xutmpname \- access utmp file entry X.SH SYNOPSIS X.B \#include <utmp.h> X X.B struct utmp *getutent(); X X.B struct utmp *getutline(\fIline\fB)\fR; X.br X.B struct utmp *\fIline\fR; X X.B void setutent(); X X.B void endutent(); X X.B void utmpname(\fIfile\fB)\fR; X.br X.B char *\fIfile\fR; X.SH DESCRIPTION X.I Getutent Xand X.I getutline Xeach return a pointer to a structure of the following type: X.nf X X struct utmp { X char ut_line[8]; /* tty name */ X char ut_name[8]; /* user id */ X long ut_time; /* time on */ X }; X X.fi X.I Getutent Xreads in the next entry from a \fIutmp\fR\-like file. If the file is Xnot already open, it opens it. If it reaches the end of file, it Xfails. X.PP X.I Getutline Xsearches forward from the current point in the X.I utmp Xfile until it finds an entry which has a X.I ut_line Xstring matching the X.I line\->ut_line Xstring. If the end of file is reached without a match, it fails. X.PP X.I Setutent Xresets the input stream to the beginning of the file. This should be Xdone before each search for a new entry if it is desired that the Xentire file be examined. X.PP X.I Endutent Xcloses the currently open file. X.PP X.I Utmpname Xallows the user to change the name of the file examined, from X.B _utmp_ Xto any other file. It is most often expected that this other file Xwill be X.B _wtmp_\fR. XIf the file does not exist, this will not be apparent until the first Xattempt to reference the file is made. X.I Utmpname Xdoes not open the file. It just closes the old file if it is Xcurrently open and saves the new file name. X.SH FILES X_utmp_ X.br X_wtmp_ X.SH BUGS XThe most current entry is saved in a static structure. Multiple Xaccesses require that it be copied before further accesses are made. X.PP XThese routines use buffered standard I/O for input. X.SH "SEE ALSO" Xutmp(_file_section_) X.SH AUTHOR X.nf XPaul Sutcliffe, Jr. <paul at devon.lns.pa.us> XUUCP: ...!rutgers!devon!paul !STUFFY!FUNK! echo Extracting man/makeconfig sed >man/makeconfig <<'!STUFFY!FUNK!' -e 's/X//' X: X# X# $Id: makeconfig,v 1.1 90/01/16 16:03:33 paul Exp Locker: paul $ X# X# $Log: makeconfig,v $ X# Revision 1.1 90/01/16 16:03:33 paul X# Initial revision X# X# X Xcase $CONFIG in X'') X if test ! -f config.sh; then X ln ../config.sh . || \ X ln ../../config.sh . || \ X ln ../../../config.sh . || \ X (echo "Can't find config.sh."; exit 1) X fi X . config.sh X ;; Xesac Xcase "$0" in X*/*) cd `expr X$0 : 'X\(.*\)/'` ;; Xesac X Xtmp=/tmp/mc$$ Xrmlist="$tmp" Xtrap 'echo " "; $rm -f $rmlist; exit 1' 1 2 3 X X: where is the source Xsrc=.. Xtune=$src/tune.h Xpatchlevel=$src/patchlevel.h X X: is package complete Xif $test ! -f $tune; then X echo "Can't find tune.h." X exit 1 Xfi X X: things we can tell from tune.h Xcppout=".cppout" Xtuneout=".tune" Xrmlist="$cppout $tuneout $rmlist" X$cppstdin -I$src -I. $cppminus <<EOS >$cppout X#include <$tune> X#include <$patchlevel> Xconsole=CONSOLE Xdefaults=DEFAULTS Xissue=ISSUE Xlogin=LOGIN X#ifdef LOGUTMP Xlogutmp="$define" X#endif X#ifdef TRS16 Xtrs16="$define" X#endif X#ifdef TRYMAIL Xtrymail="$define" Xnotify=NOTIFY X#endif X#ifdef WARNCASE Xwarncase="$define" X#endif Xrelease=RELEASE Xdate=DATE XEOS X$sed 's/[ ]//' <$cppout >$tuneout Xchmod +x $tuneout X. $tuneout X Xdefaults=`$echo $defaults | $sed 's;/\%s;;'` X X: things we cannot tell from tune.h Xif $test ! -d /usr/lib/terminfo; then X termcap="$define" Xfi Xgtab=`basename $gettytab` X X: name the man pages Xcase "$xenix" in X"$define") X cmd=C; mcmd=M; system=S; library=S; file=F; misc=M X ;; X"$undef") X cmd=1; mcmd=1m; system=2; library=3; file=4; misc=7 X ;; Xesac X X$cat <<EOC >config.m4 X.\" +---------- X.\" | local GETTY configurations X.\" X.\" define(\`_cmd_section_', $cmd) X.\" define(\`_mcmd_section_', $mcmd) X.\" define(\`_system_section_', $system) X.\" define(\`_library_section_', $library) X.\" define(\`_file_section_', $file) X.\" define(\`_misc_section_', $misc) X.\" define(\`_console_', $console) X.\" define(\`_defaults_', $defaults) X.\" define(\`_gettytab_', $gettytab) X.\" define(\`_gtab_', $gtab) X.\" define(\`_issue_', $issue) X.\" define(\`_login_', $login) X.\" define(\`_utmp_', $utmp) X.\" define(\`_wtmp_', $wtmp) X.\" define(\`RELEASE', $release) X.\" define(\`DATE', $date) X.\" XEOC X Xcase "$logutmp" in X"$define") $cat <<EOC >>config.m4 X.\" define(\`logutmp') XEOC X;; Xesac Xcase "$termcap" in X"$define") $cat <<EOC >>config.m4 X.\" define(\`termcap') XEOC X;; Xesac Xcase "$trs16" in X"$define") $cat <<EOC >>config.m4 X.\" define(\`trs16') XEOC X;; Xesac Xcase "$trymail" in X"$define") $cat <<EOC >>config.m4 X.\" define(\`trymail') X.\" define(\`_notify_', $notify) XEOC X;; Xesac Xcase "$ttytype" in X"/*") $cat <<EOC >>config.m4 X.\" define(\`ttytype', $ttytype) XEOC X;; Xesac Xcase "$warncase" in X"$define") $cat <<EOC >>config.m4 X.\" define(\`warncase') XEOC X;; Xesac X X$rm -f $rmlist X# grrr, don't ask X$rm -f $cppout X$rm -f $tuneout !STUFFY!FUNK! echo Extracting man/putenv.m4 sed >man/putenv.m4 <<'!STUFFY!FUNK!' -e 's/X//' X.\" +---------- X.\" | $Id: putenv.m4,v 1.1 90/01/16 16:03:53 paul Exp Locker: paul $ X.\" | X.\" | PUTENV man page. X.\" | X.\" | Copyright 1989,1990 by Paul Sutcliffe Jr. X.\" | X.\" | Permission is hereby granted to copy, reproduce, redistribute, X.\" | or otherwise use this software as long as: there is no monetary X.\" | profit gained specifically from the use or reproduction or this X.\" | software, it is not sold, rented, traded or otherwise marketed, X.\" | and this copyright notice is included prominently in any copy X.\" | made. X.\" | X.\" | The author make no claims as to the fitness or correctness of X.\" | this software for any use whatsoever, and it is provided as is. X.\" | Any use of this software is at the user's own risk. X.\" | X.\" X.\" +---------- X.\" | $Log: putenv.m4,v $ X.\" | Revision 1.1 90/01/16 16:03:53 paul X.\" | Initial revision X.\" | X.\" | X.\" X.\" +---------- X.\" | M4 configuration X.\" Xinclude(config.m4).\" X.\" X.\" +---------- X.\" | Manpage source follows: X.\" X.TH PUTENV _library_section_ X.SH NAME Xputenv \- change or add value to environment X.SH SYNOPSIS X.B int putenv(\fIstring\fB)\fR; X.br X.B char *\fIstring\fR; X.SH DESCRIPTION X.I String Xpoints to a string of the form X.I name=value. X.I Putenv Xmakes the value of the environment variable X.I name Xequal to X.I value Xby altering an existing variable or creating a new one. In either Xcase, the string pointed to by X.I string Xbecomes part of the environment, so altering the string changes Xthe environment. The space used by X.I string Xis no longer used once a new string\-defining X.I name Xis passed to X.I putenv. X.SH "RETURN VALUE" X.I Putenv Xreturns non\-zero if it was unable to obtain enough space via X.I malloc Xfor an expanded environment, otherwise zero. X.SH "SEE ALSO" Xexec(_system_section_), Xgetenv(_library_section_), Xmalloc(_library_section_), Xenviron(_file_section_) X.SH WARNINGS X.I Putenv Xmanipulates the environment pointed to by X.I environ, Xand can be used in conjunction with X.I getenv. XHowever, X.I envp X(the third argument to X.I main\fR) Xis not changed. X.PP XThis routine uses X.I malloc(_library_section_) Xto enlarge the environment. X.PP XAfter X.I putenv Xis called, environmental variables are not in alphabetical order. X.PP XA potential error is to call X.I putenv Xwith an automatic variable as the argument, then exit the calling Xfunction while X.I string Xis still part of the environment. X.SH AUTHOR X.nf XPaul Sutcliffe, Jr. <paul at devon.lns.pa.us> XUUCP: ...!rutgers!devon!paul !STUFFY!FUNK! echo Extracting getty.h sed >getty.h <<'!STUFFY!FUNK!' -e 's/X//' X/* X** $Id: getty.h,v 1.1 90/01/16 16:15:30 paul Exp Locker: paul $ X** X** Included by all getty modules X*/ X X/* X** Copyright 1989,1990 by Paul Sutcliffe Jr. X** X** Permission is hereby granted to copy, reproduce, redistribute, X** or otherwise use this software as long as: there is no monetary X** profit gained specifically from the use or reproduction or this X** software, it is not sold, rented, traded or otherwise marketed, X** and this copyright notice is included prominently in any copy X** made. X** X** The author make no claims as to the fitness or correctness of X** this software for any use whatsoever, and it is provided as is. X** Any use of this software is at the user's own risk. X*/ X X/* X** $Log: getty.h,v $ X** Revision 1.1 90/01/16 16:15:30 paul X** Initial revision X** X*/ X X X#include <stdio.h> X#include <string.h> X#include <sys/types.h> X#include <termio.h> X#ifndef TCGETA X#include <sys/ioctl.h> X#endif /* TCGETA */ X#include <utmp.h> X X#include "config.h" X#include "extern.h" X#include "funcs.h" X X X/* General purpose defines X */ X X#ifndef FALSE X#define FALSE (0) X#endif /* FALSE */ X#ifndef TRUE X#define TRUE (1) X#endif /* TRUE */ X X#define OK (0) X X#define SUCCESS (0) /* normal return */ X#define FAIL (-1) /* error return */ X X#define STDIN fileno(stdin) X#define STDOUT fileno(stdout) X X#define strequal(s1, s2) (strcmp(s1, s2) == 0) X#define strnequal(s1, s2, n) (strncmp(s1, s2, n) == 0) X#define strncopy(s1, s2) (strncpy(s1, s2, sizeof(s1))) X Xtypedef struct termio TERMIO; X X X#ifdef DEBUG X X/* debug levels X */ X#define D_OPT 0001 /* option settings */ X#define D_DEF 0002 /* defaults file processing */ X#define D_UTMP 0004 /* utmp/wtmp processing */ X#define D_INIT 0010 /* line initialization (INIT) */ X#define D_GTAB 0020 /* gettytab file processing */ X#define D_GETL 0040 /* get login name routine */ X#define D_RUN 0100 /* other runtime diagnostics */ X X#ifdef UUGETTY X#define D_LOCK 0200 /* uugetty lockfile processing */ X#endif /* UUGETTY */ X X/* debug defs X */ X#define debug1(a,b) dprint(a,b) X#define debug2(a,b) debug(a,b) X#define debug3(a,b,c) debug(a,b,c) X#define debug4(a,b,c,d) debug(a,b,c,d) X#define debug5(a,b,c,d,e) debug(a,b,c,d,e) X#define debug6(a,b,c,d,e,f) debug(a,b,c,d,e,f) X X#else /* DEBUG */ X X#define debug1(a,b) /* define to nothing, disables debugging */ X#define debug2(a,b) X#define debug3(a,b,c) X#define debug4(a,b,c,d) X#define debug5(a,b,c,d,e) X#define debug6(a,b,c,d,e,f) X X#endif /* DEBUG */ X X X/* end of getty.h */ !STUFFY!FUNK! echo Extracting extern.h sed >extern.h <<'!STUFFY!FUNK!' -e 's/X//' X/* X** $Id: extern.h,v 1.1 90/01/16 16:14:05 paul Exp Locker: paul $ X** X** Defines all external values. X*/ X X/* X** Copyright 1989,1990 by Paul Sutcliffe Jr. X** X** Permission is hereby granted to copy, reproduce, redistribute, X** or otherwise use this software as long as: there is no monetary X** profit gained specifically from the use or reproduction or this X** software, it is not sold, rented, traded or otherwise marketed, X** and this copyright notice is included prominently in any copy X** made. X** X** The author make no claims as to the fitness or correctness of X** this software for any use whatsoever, and it is provided as is. X** Any use of this software is at the user's own risk. X*/ X X/* X** $Log: extern.h,v $ X** Revision 1.1 90/01/16 16:14:05 paul X** Initial revision X** X*/ X X X#ifdef MAIN /* define as "extern", except for MAIN, */ X#define EXTERN /* which is defined only in main.c */ X#else X#define EXTERN extern X#endif /* MAIN */ X X X/* Global variables X */ X X#ifdef MAIN XEXTERN STDCHAR MsgBuf[80]; /* message buffer */ X#else XEXTERN STDCHAR MsgBuf[]; X#endif /* MAIN */ X XEXTERN boolean Check; /* check a gettytab file? */ XEXTERN char *CheckFile; /* gettytab-like file to check */ XEXTERN char *Device; /* controlling line (minus "/dev/") */ XEXTERN char *GtabId; /* current gettytab id */ XEXTERN boolean NoHangUp; /* don't hangup line before setting speed */ XEXTERN char *LineD; /* line discipline */ XEXTERN char *MyName; /* this program name */ XEXTERN int Nusers; /* number of users currently logged in */ XEXTERN char *Speed; /* current baud rate (string literal) */ XEXTERN char *SysName; /* nodename of system */ XEXTERN int TimeOut; /* timeout value from command line */ XEXTERN char *Version; /* value of VERSION */ X X#ifdef WARNCASE XEXTERN boolean WarnCase; /* controls display of bad case message */ X#endif /* WARNCASE */ X X#ifdef DEBUG XEXTERN int Debug; /* debug value from command line */ XEXTERN FILE *Dfp; /* debug output file pointer */ X#endif /* DEBUG */ X X X/* System routines X */ X Xextern int fputc(); Xextern char *malloc(), *ttyname(); Xextern unsigned alarm(), sleep(); Xextern time_t time(); X X#ifndef STRDUP /* Is There In Truth No Strdup() ? */ Xextern char *strdup(); X#endif /* STRDUP */ X X#ifndef GETUTENT /* How about getutent() ? */ Xextern struct utmp *getutent(); Xextern void setutent(), endutent(); X#endif /* GETUTENT */ X X#ifndef PUTENV /* putenv() ? */ Xextern int putenv(); X#endif /* PUTENV */ X X X/* end of extern.h */ !STUFFY!FUNK! echo Extracting sample.files sed >sample.files <<'!STUFFY!FUNK!' -e 's/X//' XThese examples are from the author's system. X XSample `/etc/issue' file: X+--------- X| Devon Computer Services, Lancaster, PA (@S) X| Tandy XENIX/68000 Version @V X+--------- X XSample `/etc/default/getty' file: X+--------- X| ISSUE=/etc/issue X| VERSION=/etc/version X+--------- X XSample `/etc/default/uugetty' file: X+--------- X| CLEAR=NO X| ISSUE=Devon Computer Services - Tandy 6000 (@S)\n[@L, @B bps]\n X| INIT=A\pA\pA\pAT\r OK\r\n-ATZ\r-OK\r\n ATZ\r OK\r\n X| WAITCHAR=YES X| DELAY=15 X| TIMEOUT=60 X+--------- X XSample `/etc/gettydefs' file: X+--------- X| # X| # Sample /etc/gettydefs file; use at your own risk! X| # X| # default entry: X| 0# B9600 CS8 # B9600 CLOCAL TAB3 ECHO SANE #login: #0 X| X| # to toggle between 300 and 1200 baud on a modem line: X| # X| 1# B300 ISTRIP CS8 CR1 # B300 HUPCL CS8 TAB3 SANE CR1 #login: #2 X| X| 2# B1200 ISTRIP CS8 # B1200 HUPCL CS8 TAB3 SANE #login: #1 X| X| # to toggle between 300, 1200 and 2400 baud on a modem line: X| # X| 3# B300 ISTRIP CS8 CR1 # B300 HUPCL CS8 TAB3 SANE CR1 #login: #4 X| X| 4# B1200 ISTRIP CS8 # B1200 HUPCL CS8 TAB3 SANE #login: #5 X| X| 5# B2400 ISTRIP CS8 # B2400 HUPCL CS8 TAB3 SANE #login: #3 X| X| # a telebit tb plus: X| # X| 6# B9600 ISTRIP CS8 # B9600 HUPCL CS8 TAB3 SANE #FAST login: #7 X| X| 7# B2400 ISTRIP CS8 # B2400 HUPCL CS8 TAB3 SANE #login: #8 X| X| 8# B1200 ISTRIP CS8 # B1200 HUPCL CS8 TAB3 SANE #login: #6 X| X| # various hard-wired speeds X| a# B50 ISTRIP CS8 NL1 CR3 TAB2 # B50 CS8 CLOCAL SANE NL1 CR3 TAB2 #login: #a X| X| b# B75 ISTRIP CS8 NL1 CR2 TAB2 # B75 CS8 CLOCAL SANE NL1 CR2 TAB2 #login: #b X| X| c# B110 ISTRIP CS8 NL1 CR1 TAB1 # B110 CS8 CLOCAL SANE NL1 CR1 TAB1 #login: #c X| X| d# B134 ISTRIP CS8 NL1 CR1 TAB1 # B134 CS8 CLOCAL SANE NL1 CR1 TAB1 #login: #d X| X| e# B150 ISTRIP CS8 NL1 CR1 # B150 CS8 CLOCAL TAB3 SANE NL1 CR1 #login: #e X| X| f# B200 ISTRIP CS8 NL1 CR1 # B200 CS8 CLOCAL TAB3 SANE NL1 CR1 #login: #f X| X| g# B300 ISTRIP CS8 CR1 # B300 CS8 CLOCAL TAB3 SANE CR1 #login: #g X| X| h# B600 ISTRIP CS8 # B600 CS8 CLOCAL TAB3 SANE #login: #h X| X| i# B1200 ISTRIP CS8 # B1200 CS8 CLOCAL TAB3 SANE #login: #i X| X| j# B1800 ISTRIP CS8 # B1800 CS8 CLOCAL TAB3 SANE #login: #j X| X| k# B2400 ISTRIP CS8 # B2400 CS8 CLOCAL TAB3 SANE #login: #k X| X| l# B4800 ISTRIP CS8 # B4800 CS8 CLOCAL TAB3 SANE #login: #l X| X| m# B9600 ISTRIP CS8 # B9600 CS8 CLOCAL TAB3 SANE #login: #m X| X+--------- !STUFFY!FUNK! echo Extracting tune.H sed >tune.H <<'!STUFFY!FUNK!' -e 's/X//' X/* X** $Id: tune.H,v 1.1 90/01/16 16:20:41 paul Exp Locker: paul $ X** X** Getty tuneable parameters. X*/ X X/* X** Copyright 1989,1990 by Paul Sutcliffe Jr. X** X** Permission is hereby granted to copy, reproduce, redistribute, X** or otherwise use this software as long as: there is no monetary X** profit gained specifically from the use or reproduction or this X** software, it is not sold, rented, traded or otherwise marketed, X** and this copyright notice is included prominently in any copy X** made. X** X** The author make no claims as to the fitness or correctness of X** this software for any use whatsoever, and it is provided as is. X** Any use of this software is at the user's own risk. X*/ X X/* X** $Log: tune.H,v $ X** Revision 1.1 90/01/16 16:20:41 paul X** Initial revision X** X*/ X X X#define boolean int /* does your cc know about boolean? */ X X#define DEF_CFL (CS7 | PARENB) /* default word-len/parity */ X X X/* Feature selection X */ X X#undef DEBUG /* include debugging code */ X#define LOGUTMP /* need to update utmp/wtmp files */ X#define MY_CANON /* use my own ERASE and KILL chars */ X#define RCSID /* include RCS ID info in objects */ X#define SETTERM /* need to set TERM in environment */ X#define TRYMAIL /* mail errors if CONSOLE unavailable */ X#define WARNCASE /* warn user if login is UPPER case */ X X/* define your ERASE and KILL characters here X */ X#ifdef MY_CANON X#define MY_ERASE '\010' /* 010 = ^H, backspace */ X#define MY_KILL '\025' /* 025 = ^U, nak */ X#endif X X/* who should be notified of errors? X */ X#ifdef TRYMAIL X#define NOTIFY "root" X#endif X X X/* Where to find things X */ X X#define CONSOLE "/dev/console" /* place to log errors */ X#define DEFAULTS "/etc/default/%s" /* name of defaults file */ X#define ISSUE "/etc/issue" /* name of the issue file; X say "#undef ISSUE" to turn off X the issue feature */ X#define LOGIN "/bin/login" /* name of login program */ X X X/* Special cases X */ X X#undef TRS16 /* you are a Tandy 6000 or equivilent */ X X X/* You probably shouldn't fool with these X */ X X#define MAXDEF 100 /* max # lines in defaults file */ X#define MAXLINE 256 /* max # chars in a line */ X#define MAXID 12 /* max # chars in Gtab Id */ X#define MAXLOGIN 80 /* max # chars in Gtab Login */ X X X/* end of tune.h */ !STUFFY!FUNK! echo Extracting getutent.c sed >getutent.c <<'!STUFFY!FUNK!' -e 's/X//' X/* X** $Id: getutent.c,v 1.1 90/01/16 16:15:51 paul Exp Locker: paul $ X** X** Implements getutent(3). X*/ X X/* X** Copyright 1989,1990 by Paul Sutcliffe Jr. X** X** Permission is hereby granted to copy, reproduce, redistribute, X** or otherwise use this software as long as: there is no monetary X** profit gained specifically from the use or reproduction or this X** software, it is not sold, rented, traded or otherwise marketed, X** and this copyright notice is included prominently in any copy X** made. X** X** The author make no claims as to the fitness or correctness of X** this software for any use whatsoever, and it is provided as is. X** Any use of this software is at the user's own risk. X*/ X X/* X** $Log: getutent.c,v $ X** Revision 1.1 90/01/16 16:15:51 paul X** Initial revision X** X*/ X X X#include "getty.h" X X#if defined(RCSID) && !defined(lint) Xstatic char *RcsId = X"@(#)$Id: getutent.c,v 1.1 90/01/16 16:15:51 paul Exp Locker: paul $"; X#endif X Xtypedef struct utmp UTMP; X Xstatic char *utmpfil = UTMP_FILE; /* default utmp file */ Xstatic FILE *ufp = (FILE *) NULL; /* file pointer to utmp file */ X /* NULL = no utmp file open */ Xstatic UTMP ut; /* buffer for utmp record */ X X X/* X** getutent() - get next valid utmp entry X** X** Returns (UTMP*)NULL if no vaild entry found. X*/ X XUTMP * Xgetutent() X{ X if (ufp == (FILE *) NULL) X if ((ufp = fopen(utmpfil, "r+")) == (FILE *) NULL) X return((UTMP *) NULL); X X do { X if (fread((char *)&ut, sizeof(ut), 1, ufp) != 1) X return((UTMP *) NULL); X X } while (ut.ut_name[0] == '\0'); /* valid entry? */ X X return(&ut); X} X X X/* X** getutline() - get utmp entry that matches line. X** X** Returns (UTMP*)NULL if no match found. X*/ X XUTMP * Xgetutline(line) XReg1 UTMP *line; X{ X do { X if (strequal(ut.ut_line, line->ut_line)) X return(&ut); /* match! */ X X } while (getutent() != NULL); X X return((UTMP *) NULL); X} X X X/* X** setutent() - rewind utmp back to beginning X*/ X Xvoid Xsetutent() X{ X if (ufp != (FILE *) NULL) X rewind(ufp); X} X X X/* X** endutent() - close utmp file X*/ X Xvoid Xendutent() X{ X if (ufp != (FILE *) NULL) { X (void) fclose(ufp); X ufp = (FILE *) NULL; X } X} X X X/* X** utmpname() - change utmp file name to "file" X*/ X Xvoid Xutmpname(file) XReg1 char *file; X{ X endutent(); X utmpfil = strdup(file); X} X X X/* end of getutent.c */ !STUFFY!FUNK! echo Extracting man/Makefile.SH sed >man/Makefile.SH <<'!STUFFY!FUNK!' -e 's/X//' X: X# $Id: Makefile.SH,v 1.1 90/01/16 16:01:02 paul Exp Locker: paul $ X# X# Creates man/Makefile for getty distribution X# X# $Log: Makefile.SH,v $ X# Revision 1.1 90/01/16 16:01:02 paul X# Initial revision X# X# X Xcase $CONFIG in X'') X if test ! -f config.sh; then X ln ../config.sh . || \ X ln ../../config.sh . || \ X ln ../../../config.sh . || \ X (echo "Can't find config.sh."; exit 1) X fi X . config.sh X ;; Xesac Xcase "$0" in X*/*) cd `expr X$0 : 'X\(.*\)/'` ;; Xesac X Xgtab=`basename $gettytab` Xman="getty.man $gtab.man issue.man" Xcase "$d_getutent" in X"$undef") X man="$man getutent.man" X ;; Xesac Xcase "$d_strdup" in X"$undef") X man="$man strdup.man" X ;; Xesac Xcase "$d_putenv" in X"$undef") X man="$man putenv.man" X ;; Xesac X Xecho "Extracting man/Makefile (with variable substitutions)" X$spitshell >Makefile <<!GROK!THIS! X# X# Makefile for getty man pages X# X XSHELL= /bin/sh XROFF= nroff -man X XSRC= .. XTUNE= $(SRC)/tune.h XPATLVL= $(SRC)/patchlevel.h X X# what to make Xall: $man X Xinstall: X @echo "Installation must be done manually, Sorry." X X# how to make it X.SUFFIXES: .m4 .3 .man X X.m4.3: X m4 \$*.m4 > \$*.3 X X.3.man: X $(ROFF) \$*.3 > \$*.man X X# dependencies Xconfig.m4: $(SRC)/config.sh $(TUNE) $(PATLVL) X chmod +x makeconfig X ./makeconfig X Xgetty.1m: getty.m4 config.m4 X m4 getty.m4 > getty.1m X Xgetty.man: getty.1m X $(ROFF) getty.1m > getty.man X X$gtab.4: gettytab.m4 config.m4 X m4 gettytab.m4 > $gtab.4 X X$gtab.man: $gtab.4 X $(ROFF) $gtab.4 > $gtab.man X Xissue.4: issue.m4 config.m4 X m4 issue.m4 > issue.4 X Xissue.man: issue.4 X $(ROFF) issue.4 > issue.man X Xgetutent.3: getutent.m4 config.m4 X Xgetutent.man: getutent.3 X Xstrdup.3: strdup.m4 config.m4 X Xstrdup.man: strdup.3 X Xputenv.3: putenv.m4 config.m4 X Xputenv.man: putenv.3 X Xclean: X rm -f *.out config.m4 config.sh core X Xclobber: clean X rm -f *.1m *.[34] *.man X X!GROK!THIS! Xchmod 644 Makefile X$eunicefix Makefile !STUFFY!FUNK! echo Extracting man/issue.m4 sed >man/issue.m4 <<'!STUFFY!FUNK!' -e 's/X//' X.\" +---------- X.\" | $Id: issue.m4,v 1.1 90/01/16 16:03:09 paul Exp Locker: paul $ X.\" | X.\" | ISSUE man page. X.\" | X.\" | Copyright 1989,1990 by Paul Sutcliffe Jr. X.\" | X.\" | Permission is hereby granted to copy, reproduce, redistribute, X.\" | or otherwise use this software as long as: there is no monetary X.\" | profit gained specifically from the use or reproduction or this X.\" | software, it is not sold, rented, traded or otherwise marketed, X.\" | and this copyright notice is included prominently in any copy X.\" | made. X.\" | X.\" | The author make no claims as to the fitness or correctness of X.\" | this software for any use whatsoever, and it is provided as is. X.\" | Any use of this software is at the user's own risk. X.\" | X.\" X.\" +---------- X.\" | $Log: issue.m4,v $ X.\" | Revision 1.1 90/01/16 16:03:09 paul X.\" | Initial revision X.\" | X.\" | X.\" X.\" +---------- X.\" | M4 configuration X.\" Xinclude(config.m4).\" X.\" X.\" +---------- X.\" | Manpage source follows: X.\" X.TH ISSUE _file_section_ X.SH NAME Xissue \- issue identification file X.SH DESCRIPTION XThe file X.B _issue_ Xcontains the X.I issue Xor project identification to be printed as a login prompt. This Xis an ASCII file which is read by the program X.I getty Xand then written to the terminal just prior to printing the X.I login: Xprompt. X.PP XThe line(s) may contain various X.B @\fIchar\fR Xand X.B \\\\\fIchar\fR Xparameters. These are described in full in the X.I getty(_mcmd_section_) Xsection PROMPT SUBSTITUTIONS. X.SH FILES X_issue_ X.SH "SEE ALSO" Xgetty(_mcmd_section_) !STUFFY!FUNK! echo Extracting table.h sed >table.h <<'!STUFFY!FUNK!' -e 's/X//' X/* X** $Id: table.h,v 1.1 90/01/16 16:19:26 paul Exp Locker: paul $ X** X** Defines the structures and functions used to parse the X** gettytab file. X*/ X X/* X** Copyright 1989,1990 by Paul Sutcliffe Jr. X** X** Permission is hereby granted to copy, reproduce, redistribute, X** or otherwise use this software as long as: there is no monetary X** profit gained specifically from the use or reproduction or this X** software, it is not sold, rented, traded or otherwise marketed, X** and this copyright notice is included prominently in any copy X** made. X** X** The author make no claims as to the fitness or correctness of X** this software for any use whatsoever, and it is provided as is. X** Any use of this software is at the user's own risk. X*/ X X/* X** $Log: table.h,v $ X** Revision 1.1 90/01/16 16:19:26 paul X** Initial revision X** X*/ X X X#ifndef LDISC0 X#define LDISC0 0 /* default line discipline */ X#endif /* LDISC0 */ X X#ifndef GETTYTAB X#define GETTYTAB "/etc/gettydefs" /* default name of the gettytab file */ X#endif /* GETTYTAB */ X Xtypedef struct Gettytab { X char *cur_id; /* current label */ X TERMIO itermio; /* initial termio flags */ X TERMIO ftermio; /* final termio flags */ X char *login; /* login prompt */ X char *next_id; /* next label */ X} GTAB; X Xtypedef struct SymTab { X char *symbol; /* symbolic name */ X ushort value; /* actual value */ X} SYMTAB; X XGTAB *gtabvalue(); X X X/* end of table.h */ !STUFFY!FUNK! echo Extracting strdup.c sed >strdup.c <<'!STUFFY!FUNK!' -e 's/X//' X/* X** $Id: strdup.c,v 1.1 90/01/16 16:18:37 paul Exp Locker: paul $ X** X** Implements strdup(3c) [strdup(S) for you Xenix-types]. X*/ X X/* X** Copyright 1989,1990 by Paul Sutcliffe Jr. X** X** Permission is hereby granted to copy, reproduce, redistribute, X** or otherwise use this software as long as: there is no monetary X** profit gained specifically from the use or reproduction or this X** software, it is not sold, rented, traded or otherwise marketed, X** and this copyright notice is included prominently in any copy X** made. X** X** The author make no claims as to the fitness or correctness of X** this software for any use whatsoever, and it is provided as is. X** Any use of this software is at the user's own risk. X*/ X X/* X** $Log: strdup.c,v $ X** Revision 1.1 90/01/16 16:18:37 paul X** Initial revision X** X*/ X X X#include "getty.h" X X#if defined(RCSID) && !defined(lint) Xstatic char *RcsId = X"@(#)$Id: strdup.c,v 1.1 90/01/16 16:18:37 paul Exp Locker: paul $"; X#endif X X/* X** strdup() - duplicates string s in memory. X** X** Returns a pointer to the new string, or NULL if an error occurrs. X*/ X Xchar * Xstrdup(s) XReg1 char *s; X{ X Reg2 char *p = (char *) NULL; X X if (s != (char *) NULL) X if ((p = malloc((unsigned) (strlen(s)+1))) != (char *) NULL) X (void) strcpy(p, s); X X return(p); X} X X X/* end of strdup.c */ !STUFFY!FUNK! echo Extracting MANIFEST sed >MANIFEST <<'!STUFFY!FUNK!' -e 's/X//' XAfter all the getty kits are run you should have the following files: X XFilename Kit Description X-------- --- ----------- XConfigure 2 Determines system configuration. XMANIFEST 4 Packing list. XMakefile.SH 4 Creates Makefile file. XREADME 1 The Instructions. Xconfig.h.SH 3 Creates config.h file. Xdefaults.c 3 Routines to access the runtime defaults file. Xdefaults.h 4 Defines the defaults file structures. Xextern.h 4 Defines all external values. Xfuncs.c 1 Miscellaneous routines. Xfuncs.h 4 Definitions for miscellaneous routines. Xgetty.h 4 Common header for all modules. Xgetutent.c 4 Implements getutent(3). Xmain.c 1 Main body of program. Xmakedep.SH 2 Creates makedep file. Xman/Makefile.SH 4 Creates man/Makefile file. Xman/README 1 Notes about the manual pages. Xman/getty.m4 3 M4 source to getty manpage. Xman/gettytab.m4 3 M4 source to gettytab manpage. Xman/getutent.m4 4 M4 source to getutent manpage. Xman/issue.m4 4 M4 source to issue manpage. Xman/makeconfig 4 Creates config.m4 file. Xman/putenv.m4 4 M4 source to putenv manpage. Xman/strdup.m4 1 M4 source to strdup manpage. Xpatchlevel.h 2 Getty release/patchlevel. Xputenv.c 3 Implements putenv(3c). Xsample.files 4 Sample ancillary files. Xstrdup.c 4 Implements strdup(3c). Xtable.c 3 Routines to process the gettytab file. Xtable.h 4 Defines the gettytab structures. Xtune.H 4 Sample tune.h file. !STUFFY!FUNK! echo Extracting defaults.h sed >defaults.h <<'!STUFFY!FUNK!' -e 's/X//' X/* X** $Id: defaults.h,v 1.1 90/01/16 16:13:44 paul Exp Locker: paul $ X** X** Defines the structures and functions used to read runtime X** defaults. X*/ X X/* X** Copyright 1989,1990 by Paul Sutcliffe Jr. X** X** Permission is hereby granted to copy, reproduce, redistribute, X** or otherwise use this software as long as: there is no monetary X** profit gained specifically from the use or reproduction or this X** software, it is not sold, rented, traded or otherwise marketed, X** and this copyright notice is included prominently in any copy X** made. X** X** The author make no claims as to the fitness or correctness of X** this software for any use whatsoever, and it is provided as is. X** Any use of this software is at the user's own risk. X*/ X X/* X** $Log: defaults.h,v $ X** Revision 1.1 90/01/16 16:13:44 paul X** Initial revision X** X*/ X X X/* lines in defaults file are in the form "NAME=value" X */ X Xtypedef struct Default { X char *name; /* name of the default */ X char *value; /* value of the default */ X} DEF; X X XDEF **defbuild(); /* user-level routines */ Xchar *defvalue(); X XFILE *defopen(); /* low-level routines */ XDEF *defread(); Xint defclose(); X X X/* end of defaults.h */ !STUFFY!FUNK! echo Extracting funcs.h sed >funcs.h <<'!STUFFY!FUNK!' -e 's/X//' X/* X** $Id: funcs.h,v 1.1 90/01/16 16:14:53 paul Exp Locker: paul $ X** X** Defines the miscellaneous functions. X*/ X X/* X** Copyright 1989,1990 by Paul Sutcliffe Jr. X** X** Permission is hereby granted to copy, reproduce, redistribute, X** or otherwise use this software as long as: there is no monetary X** profit gained specifically from the use or reproduction or this X** software, it is not sold, rented, traded or otherwise marketed, X** and this copyright notice is included prominently in any copy X** made. X** X** The author make no claims as to the fitness or correctness of X** this software for any use whatsoever, and it is provided as is. X** Any use of this software is at the user's own risk. X*/ X X/* X** $Log: funcs.h,v $ X** Revision 1.1 90/01/16 16:14:53 paul X** Initial revision X** X*/ X X X/* States for settermio() X */ X#define INITIAL 0 X#define FINAL 1 X X/* Return values for getlogname() X */ X#define BADSPEED 1 X#define BADCASE 2 X#define NONAME 3 X X Xint Fputs(), initialize(), getlogname(); Xchar *getuname(); Xvoid settermio(), logerr(); X X#ifdef DEBUG Xvoid debug(), dprint(); X#endif /* DEBUG */ X X X/* end of funcs.h */ !STUFFY!FUNK! echo "" echo "End of kit 4 (of 4)" cat /dev/null >kit4isdone run='' config='' for iskit in 1 2 3 4; do if test -f kit${iskit}isdone; then run="$run $iskit" else todo="$todo $iskit" fi done case $todo in '') echo "You have run all your kits. Please read README and then type Configure." chmod 755 Configure ;; *) echo "You have run$run." echo "You still need to run$todo." ;; esac : Someone might mail this, so... exit INTERNET: paul at devon.lns.pa.us | If life's a bitch, then UUCP: ...!rutgers!devon!paul | we must be her puppies. From erc at khijol.UUCP Wed Jan 17 05:59:31 1990 From: erc at khijol.UUCP (Edwin R. Carp) Date: 16 Jan 90 18:59:31 GMT Subject: Getting the time over the phone from NBS Message-ID: <1043@khijol.UUCP> Here's the source for nbs_time.c that I scarfed from archive at mgse. I'm posting the source, rather than the binary+source, because by the time I wake up tomorrow morning, it'll probably have been ported to the Amiga, the PC, the Mac, and VMS, not to mention MVS, TSO, VM, and a host of others :-) Enjoy! ----------------------------- nbs_time.c ---------------------------- /* CHK=0x0603 */ /*+----------------------------------------------------------------------- SCO XENIX SYSTEM V.2 (Others too?) nbs_time.c -- call NBS, get time, hangup quickly, set system time, wait for top of minute, execute /etc/setclock to update cmos clock Warren H. Tucker, 150 West Lake Drive, Mountain Park, GA 30075 (404)587-5766 Note: must be root to execute Defined functions: create_lock_file(lock_file_name) hangup(sig) hayes_dial() hayes_send_cmd(cmd) lclose() lgetc(char_rtnd) lgetc_timeout(timeout_msec) lgets_timeout(lrwt) lkill_buf() lock_tty() lopen() lputc(lchar) lputs_paced(pace_msec,string) lrdchk() lset_baud_rate(ioctl_flag) lset_parity(ioctl_flag) main(argc,argv,envp) make_lock_name(ttyname,lock_file_name) other_lock_name(first_lock_name) to_lower(ch) to_upper(ch) ulcmpb(str1,str2) ulindex(str1,str2) unlock_tty() usage() valid_baud_rate(baud) Sample execution: % nbs - nbs_time Dialing 1(202)653-0351 ... INT to abort ... CONNECT 1200 '47361 201 020050 UTC' Connect time 1 second(s) Time retrieved from standard: Mon Jul 18 22:00:50 1988 Waiting for top of minute: Mon Jul 18 22:00:51 1988 Waiting for top of minute: Mon Jul 18 22:00:52 1988 Waiting for top of minute: Mon Jul 18 22:00:53 1988 Waiting for top of minute: Mon Jul 18 22:00:54 1988 Waiting for top of minute: Mon Jul 18 22:00:55 1988 Waiting for top of minute: Mon Jul 18 22:00:56 1988 Waiting for top of minute: Mon Jul 18 22:00:57 1988 Waiting for top of minute: Mon Jul 18 22:00:58 1988 /etc/setclock setting ... result: 0618220188 ------------------------------------------------------------------------*/ /*+:EDITS:*/ /*:07-18-1988-22:07-wht-working! */ /*:07-18-1988-17:27-wht-creation */ #include <stdio.h> #include <signal.h> #include <ctype.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/ioctl.h> #include <time.h> #include <string.h> #include <fcntl.h> #include <errno.h> #include <termio.h> #ifndef ushort #define ushort unsigned short #endif #ifndef uchar #define uchar unsigned char #endif #ifndef uint #define uint unsigned int #endif #ifndef ulong #define ulong unsigned long #endif char *lgets_timeout(struct lrwt *); char *other_lock_name(char *); char to_lower(char ); char to_upper(char ); int create_lock_file(char *); int hayes_dial(void); int hayes_send_cmd(char *); int lgetc_timeout(unsigned long ); int lock_tty(void); int lopen(void); int lrdchk(void); int lset_baud_rate(int ); int main(int ,char * *,char * *); int make_lock_name(char *,char *); int ulcmpb(unsigned char *,unsigned char *); int ulindex(char *,char *); int valid_baud_rate(unsigned int ); void hangup(int ); void lclose(void); void lgetc(char *); void lkill_buf(void); void lputc(char ); void lputs_paced(int ,char *); void lset_parity(int ); void unlock_tty(void); ushort geteuid(); ushort getuid(); long nap(long); long time(long *); char *ctime(long *); typedef struct lrwt /* param to lgets_timeout in eculine.c */ { ulong to1; /* timeout for 1st character (granularity 20) */ ulong to2; /* timeout for each next char (granularity 20) */ int raw_flag; /* !=0, rtn full buffer, ==0, rtn filtered hayes result */ char *buffer; /* buffer to fill */ int bufsize; /* size of buffer */ int count; /* from proc, count rcvd */ } LRWT; #define EPOCH 40587 /* UNIX starts JD 2440587, */ #define leap(y, m) ((y+m-1 - 70%m) / m) /* also known as 1/1/70 */ #define TONE '*' /* #define TIME "\n%05ld %03d %02d%02d%02d UTC" */ #define TIME "%05ld %03d %02d%02d%02d UTC" /* for better source line utilization, frequent use of 'fprintf' and 'stderr' warrants the following */ #define pf printf #define ff fprintf #define se stderr #define so stdout /* lopen() and related routines error codes */ #define LOPEN_INVALID -1 /* for invalid tty name */ #define LOPEN_UNKPID -2 /* unknown pid using line */ #define LOPEN_LCKERR -3 /* lock file open error */ #define LOPEN_NODEV -4 /* device does not exist */ #define LOPEN_OPNFAIL -5 /* count not open line */ #define LOPEN_ALREADY -6 /* line already open */ extern char *revision; /* ecurev.c temp file from buildrev */ extern char *numeric_revision; /*ecunumrev.c */ char LLCKname[128]; /* lock file name */ char Ltelno[64]; /* telephone number for remote or null */ char Lline[64]; /* line name */ int Liofd; /* file descriptor for line */ int Lparity; /* 0==NONE, 'e' == even, 'o' == odd */ struct termio Llv; /* attributes for the line to remote */ uint Lbaud; /* baud rate */ ushort euid; ushort uid; /*+------------------------------------------------------------------------- to_upper() / to_lower() one would think that these were relatively standard types of thing, but MSC/Xenix specifies toupper() to convert to upper case if not already and Unix says to adjust without testing, so, two stupid little routines here ASCII only -- no EBCDIC gradoo here please --------------------------------------------------------------------------*/ char to_upper(ch) register char ch; { return( ((ch >= 'a') && (ch <= 'z')) ? ch - 0x20 : ch); } /* end of to_upper() */ char to_lower(ch) register char ch; { return( ((ch >= 'A') && (ch <= 'Z')) ? ch + 0x20 : ch); } /* end of to_lower() */ /*+---------------------------------------------------------------------------- ulcmpb(str1,str) -- Upper/Lower [case insensitive] Compare Bytes Returns -1 if strings are equal, else failing character position If the second strings terminates with a null and both strings have matched character for character until that point, then -1 is returned. NOTE: this is not a test for complete equality of two strings, but allows discovery of a string as a substring in a larger containing string. -----------------------------------------------------------------------------*/ int ulcmpb(str1,str2) register unsigned char *str1; register unsigned char *str2; { register int istr; for( istr=0 ; ; ++istr ) { if(str2[istr] == '\0') /* if second string exhausts, match! */ return(-1); if((str1[istr] == '\0' ) || ( to_upper(str1[istr]) != to_upper(str2[istr]) )) return(istr); } /*NOTREACHED*/ } /* end of ulcmpb */ /*+------------------------------------------------------------------------- ulindex: Upper/Lower [case insensitive] Index functioni Returns position of 'str2' in 'str1' if found If 'str2' is null, then 0 is returned (null matches anything) Returns -1 if not found uses 'ulcmpb' --------------------------------------------------------------------------*/ int ulindex(str1,str2) register char *str1; /* the (target) string to search */ register char *str2; /* the (comparand) string to search for */ { register int istr1 = 0; /* moving index into str1 */ register char *mstr = str1; /* moving string pointer */ if(str2[0] == '\0') /* null string matches anything */ return(0); while(1) { if(*mstr == '\0') /* if we exhaust target string, flunk */ return(-1); /* Can we find either case of first comparand char in target? */ if( to_upper(*mstr) == to_upper(str2[0]) ) { /* we have a first char match... does rest of string match? */ if(ulcmpb(mstr,str2) == -1) /* if the rest matches, ... */ return(istr1); /* ... return match position */ } /* we did not match this time... increment istr1, mstr and try again */ ++istr1; ++mstr; } } /* end of ulindex */ /*+----------------------------------------------------------------------- hangup(sig) -- terminate program (with comm line cleanup) ------------------------------------------------------------------------*/ void hangup(sig) int sig; { void lclose(); ff(se,"\n"); if(Liofd != -1) lclose(); /* close line */ exit(sig); } /* end of hangup */ /*+------------------------------------------------------------------------- make_lock_name(ttyname,lock_file_name) --------------------------------------------------------------------------*/ make_lock_name(ttyname,lock_file_name) char *ttyname; char *lock_file_name; { register int itmp; register char *ttyptr; if((itmp = ulindex(ttyname,"/dev/tty")) != 0) return(LOPEN_INVALID); itmp = ulindex(ttyname,"tty"); ttyptr = &ttyname[itmp]; strcpy(lock_file_name,"/usr/spool/uucp/LCK.."); strcat(lock_file_name,ttyptr); return(0); } /* end of make_lock_name */ /*+----------------------------------------------------------------------- create_lock_file() Returns 0 if lock file created,else error codes: LOPEN_ if error else pid of process currently busy on device ------------------------------------------------------------------------*/ create_lock_file(lock_file_name) char *lock_file_name; { register int fd_lockf; int pid; int old_umask; int erc = 0; old_umask = umask(0); if((fd_lockf = open(lock_file_name,O_CREAT | O_EXCL | O_RDWR,0666)) < 0) { /* file already exists */ if((fd_lockf = open(lock_file_name,O_RDWR,0666)) < 0) { erc = LOPEN_LCKERR; goto RESTORE_UMASK; } else if(read(fd_lockf,(char *)&pid,sizeof(pid))) { if(kill(pid,0)) /* is owner pid already dead? */ { if(errno == ESRCH) /* this error sez so */ { pid = getpid(); /* so we will use it */ lseek(fd_lockf,0L,0); write(fd_lockf,(char *)&pid,sizeof(pid)); close(fd_lockf); erc = 0; goto RESTORE_UMASK; } } /* owner pid still active with lock */ close(fd_lockf); erc = pid; /* port is busy */ goto RESTORE_UMASK; } else { close(fd_lockf); erc = LOPEN_UNKPID; goto RESTORE_UMASK; } } pid = getpid(); write(fd_lockf,(char *)&pid,sizeof(pid)); close(fd_lockf); chmod(lock_file_name,0666); RESTORE_UMASK: (void)umask(old_umask); return(erc); } /* end of create_lock_file */ /*+------------------------------------------------------------------------- other_lock_name(first_lock_name) --------------------------------------------------------------------------*/ char * other_lock_name(first_lock_name) char *first_lock_name; { register int itmp; static char other_lock_name[64]; strcpy(other_lock_name,first_lock_name); itmp = strlen(other_lock_name) - 1; if(islower(other_lock_name[itmp])) other_lock_name[itmp] = toupper(other_lock_name[itmp]); else if(isupper(other_lock_name[itmp])) other_lock_name[itmp] = tolower(other_lock_name[itmp]); return(other_lock_name); } /* end of other_lock_name */ /*+------------------------------------------------------------------------- lock_tty() --------------------------------------------------------------------------*/ lock_tty() { register int itmp; struct stat ttystat; if(itmp = make_lock_name(Lline,LLCKname)) return(itmp); if(stat(Lline,&ttystat) < 0) return(LOPEN_NODEV); if(itmp = create_lock_file(LLCKname)) return(itmp); if(itmp = create_lock_file(other_lock_name(LLCKname))) { unlink(LLCKname); LLCKname[0] = 0; return(itmp); } } /* end of lock_tty */ /*+----------------------------------------------------------------------- void unlock_tty() ------------------------------------------------------------------------*/ void unlock_tty() { if(LLCKname[0] == 0) return; unlink(LLCKname); unlink(other_lock_name(LLCKname)); LLCKname[0] = 0; } /* end of unlock_tty */ /*+------------------------------------------------------------------------- valid_baud_rate(baud) -- returns (positive) baud rate selector or -1 if invalid baud rate --------------------------------------------------------------------------*/ valid_baud_rate(baud) uint baud; { switch(baud) { case 110: return(B110); case 300: return(B300); case 600: return(B600); case 1200: return(B1200); case 2400: return(B2400); case 4800: return(B4800); case 9600: return(B9600); case 19200: return(EXTA); case 38400: return(EXTB); default: return(-1); } } /* end of valid_baud_rate */ /*+----------------------------------------------------------------------- lset_baud_rate(ioctl_flag) If 'ioctl_flag' is set,then ioctl(Liofd,TCSETA,&Llv) is executed after setting baud rate ------------------------------------------------------------------------*/ lset_baud_rate(ioctl_flag) int ioctl_flag; { int baud_selector = valid_baud_rate(Lbaud); if(baud_selector < 0) { ff(se,"invalid baud rate: %u\n",Lbaud); ff(se,"valid rates: 110,300,600,1200,2400,4800,9600,19200\n"); return(1); } Llv.c_cflag &= ~CBAUD; Llv.c_cflag |= baud_selector; if(ioctl_flag) ioctl(Liofd,(int)TCSETA,(char *)&Llv); return(1); } /* end of lset_baud_rate */ /*+----------------------------------------------------------------------- lset_parity(ioctl_flag) If 'ioctl_flag' is set,then ioctl(Liofd,TCSETA,&Llv) is executed after setting parity ------------------------------------------------------------------------*/ void lset_parity(ioctl_flag) int ioctl_flag; { Llv.c_cflag &= ~(CS8 | PARENB | PARODD); switch(to_lower(Lparity)) { case 'e': Llv.c_cflag |= CS7 | PARENB; Llv.c_iflag |= ISTRIP; break; case 'o': Llv.c_cflag |= PARODD | CS7 | PARENB; Llv.c_iflag |= ISTRIP; break; default: ff(se,"invalid parity: %c ... defaulting to no parity\n"); case 0: case 'n': Llv.c_cflag |= CS8; Llv.c_iflag &= ~(ISTRIP); Lparity = 0; break; } if(ioctl_flag) ioctl(Liofd,(int)TCSETA,(char *)&Llv); } /* end of lset_parity */ /*+------------------------------------------------------------------------- lgetc(char_rtnd) --------------------------------------------------------------------------*/ void lgetc(char_rtnd) char *char_rtnd; { READ_AGAIN: errno = 0; if(read(Liofd,char_rtnd,1) < 1) { if(errno == EINTR) /* if signal interrupted, ... */ goto READ_AGAIN; hangup(254); } } /* end of lgetc */ /*+------------------------------------------------------------------------- lrdchk() -- rdchk(Liofd) --------------------------------------------------------------------------*/ int lrdchk() { return(rdchk(Liofd)); } /* end of lrdchk */ /*+----------------------------------------------------------------------- lputc(lchar) -- write lchar to comm line ------------------------------------------------------------------------*/ void lputc(lchar) char lchar; { while(write(Liofd,&lchar,1) != 1) { if(errno == EINTR) continue; hangup(255); } } /* end of lputc */ /*+----------------------------------------------------------------------- lputs_paced(pace_msec,string) -- write string to comm line with time between each character ------------------------------------------------------------------------*/ void lputs_paced(pace_msec,string) register int pace_msec; register char *string; { register long msec = (pace_msec) ? (long)pace_msec : (long)20; while(*string) { lputc(*string++); nap(msec); } } /* end of lputs_paced */ /*+------------------------------------------------------------------------- char *lgets_timeout(LRWT *) typedef struct lrwt { ulong to1; ulong to2; int raw_flag; char *buffer; int bufsize; int count; } LRWT; to1 and to2 are unsigned long values in milliseconds (not currently supported well under BSD4); to1 is the time to wait for the first character, to2 the time to wait for subsequent characters. if raw_flag 0, non-printables are stripped from beginning and end of received characters (i.e., modem response reads); NULs discarded, parity stripped if raw_flag 1, full raw read buffer returned if raw_flag 2, full buffer, NULs discarded, parity stripped buffer is address to read chars into bufsize is buffer max size (allowing room for terminating null) which should be at least 2 if raw_size includes 0x80 bit, else at least 12 characters if 0x80 omitted. count is a int which, at return, receives the actual count read --------------------------------------------------------------------------*/ char * lgets_timeout(lrwt) LRWT *lrwt; { register int actual_count = 0; register char *cptr = lrwt->buffer; int max_count = lrwt->bufsize; char *rtn_val; int timeout_counter; int qc1; int qc2; long quantum; long ltmp; /* minimum wait is 60 msec */ if(Lbaud < 300) if(lrwt->to2 < 300L) lrwt->to2 = 300L; if(Lbaud < 1200) if(lrwt->to2 < 200L) lrwt->to2 = 200L; else if(lrwt->to2 < 60L) lrwt->to2 = 60L; /* shortest interval */ ltmp = (lrwt->to1 < lrwt->to2) ? lrwt->to1 : lrwt->to2; /* calculate wait quantum */ quantum = ltmp / 10L; /* try for ten ticks */ if(quantum < 20L) quantum = 20L; qc1 = lrwt->to1 / quantum; if(!qc1) qc1 = 1L; qc2 = lrwt->to2 / quantum; if(!qc2) qc2 = 1L; /* perform the lrtw function input: qc1 is first nap count (for first charcters) qc2 is 2nd nap count (for subsequent characters) quantum is the nap period in milliseconds cptr is char* to receive read string max_count is max number of characters incl null lrwt->raw_flag as described above output: lrwt->count is actual count of return result lrwt->buffer is return read buffer */ max_count--; /* leave room for null */ lrwt->raw_flag &= 0x0F; /* get rid of 0xF0 flags */ timeout_counter = qc1; /* first timeout */ *cptr = 0; /* init result string */ while(timeout_counter--) { nap(quantum); while(lrdchk()) { lgetc(cptr); if(lrwt->raw_flag != 1) { *cptr &= 0x7F; if(*cptr == 0) continue; } *++cptr = 0; actual_count++; if(--max_count == 0) goto READ_LINE_POST_PROCESS; timeout_counter = qc2; } } READ_LINE_POST_PROCESS: if(lrwt->raw_flag) { lrwt->count = actual_count; return(lrwt->buffer); } cptr = lrwt->buffer; while(((*cptr >0) && (*cptr < 0x20)) || (*cptr >= 0x7F)) cptr++; rtn_val = cptr; actual_count = 0; while(((*cptr &= 0x7F) >= 0x20) && (*cptr <= 0x7E)) { cptr++; actual_count++; } *cptr = 0; strcpy(lrwt->buffer,rtn_val); lrwt->count = actual_count; return(lrwt->buffer); } /* end of lgets_timeout */ /*+------------------------------------------------------------------------- lgetc_timeout(timeout_msec) reads one character from line unless timeout_msec passes with no receipt. timeout_msec < 20 msec becomes 20 msec return char (raw - parity bit preserved) if received, else -1 if timeout --------------------------------------------------------------------------*/ int lgetc_timeout(timeout_msec) ulong timeout_msec; { LRWT lr; char getc_buf[2]; /* room for one char + null */ lr.to1 = timeout_msec; lr.to2 = timeout_msec; lr.raw_flag = 1; /* full raw read */ lr.buffer = getc_buf; lr.bufsize = sizeof(getc_buf); lgets_timeout(&lr); return( (lr.count == 1) ? (int)getc_buf[0] : -1 ); } /* end of lgetc_timeout */ /*+------------------------------------------------------------------------- lkill_buf() --------------------------------------------------------------------------*/ void lkill_buf() { ioctl(Liofd,(int)TCFLSH,(char *)2); /* flush input and output */ } /* end of lkill_buf */ /*+---------------------------------------------------------------------- lopen() returns negative LOPEN_ codes if failure else positive pid using line else 0 if successful open ------------------------------------------------------------------------*/ int lopen() { register int itmp; if(Liofd >= 0) return(LOPEN_ALREADY); if(itmp = lock_tty()) /* get lock file */ return(itmp); Liofd = open(Lline,O_RDWR,0777); if(Liofd < 0) return(LOPEN_OPNFAIL); else { ioctl(Liofd,(int)TCGETA,(char *)&Llv); Llv.c_iflag = (IGNPAR | IGNBRK | IXOFF ); Llv.c_cflag |= (CREAD | HUPCL); Llv.c_lflag = 0; Llv.c_cc[VMIN] = 1; Llv.c_cc[VTIME] = 1; lset_baud_rate(0); /* do not perform ioctl */ lset_parity(1); /* do perform ioctl */ } return(0); } /* end of lopen */ /*+----------------------------------------------------------------------- lclose() ------------------------------------------------------------------------*/ void lclose() { if(Liofd < 0) return; ioctl(Liofd,(int)TCGETA,(char *)&Llv); /* save initial state */ Llv.c_cflag |= HUPCL; ioctl(Liofd,(int)TCSETA,(char *)&Llv); close(Liofd); Liofd = -1; unlock_tty(); /* kill lock file */ } /* end of lclose */ /*+------------------------------------------------------------------------- hayes_send_cmd(cmd) 0: success (cmd accepted) -1: cannot talk to modem --------------------------------------------------------------------------*/ hayes_send_cmd(cmd) char *cmd; { register char *cptr; int retry = 0; cptr = cmd; lkill_buf(); while(1) { lputc(0x07); /* something random */ if(lgetc_timeout(500L) < 0) { if(retry) return(-1); retry = 1; lputs_paced(0,"ATQ0E1V1\r"); nap((long)1500); lkill_buf(); continue; } break; } while(*cptr) { lputc(*cptr++); if(lgetc_timeout(500L) < 0) return(-1); } lputc('\r'); if(lgetc_timeout(500L) < 0) return(-1); return(0); } /* end of hayes_send_cmd */ /*+----------------------------------------------------------------------- hayes_dial() returns 1 on success (CONNECT), 0 if failure to connect -1 if cannot talk to modem ------------------------------------------------------------------------*/ int hayes_dial() { register int itmp; char s128[128]; int rtn_code = -1; /* assume fail, CONNECT will chg to zero */ int s7; LRWT lr; s7 = 30; strcpy(s128,"ATV1E1S11=45DT" ); strcat(s128,Ltelno); if(itmp = hayes_send_cmd(s128)) return(itmp); /* some modems (ahem, the Hayes 2400) do not accurately honor S7 */ lr.to1 = s7 * 3 * 1000L; lr.to2 = 100L; lr.raw_flag = 0; lr.buffer = s128; lr.bufsize = sizeof(s128); ff(se,"Dialing %s ... INT to abort ... ",Ltelno); fflush(se); lgets_timeout(&lr); if(lr.count) ff(se,"%s\n",s128); if(strncmp(s128,"CONNECT",7) == 0) return(1); return(0); } /* end of hayes_dial */ /*+------------------------------------------------------------------------- usage() --------------------------------------------------------------------------*/ void usage() { ff(se,"Usage: nbs_time [-][-e][-o][-n][-b#][-t#]\n"); ff(se,"Defaults 1200-N %s %s\n",Ltelno,Lline); ff(se," - use defaults\n"); ff(se," -e even parity\n"); ff(se," -o odd parity\n"); ff(se," -n no parity\n"); ff(se," -b# baud rate\n"); ff(se," -t# telephone number\n"); ff(se," -l<name> line (/dev/tty??)\n"); exit(253); } /* end of usage */ /*+------------------------------------------------------------------------- main(argc,argv,envp) main() program forks to create rcvr process; then main() becomes the xmtr process ------------------------------------------------------------------------*/ main(argc,argv,envp) int argc; char **argv; char **envp; { char *cptr; int iargv; int swchar; int itmp; LRWT lr; char rd_buf[64]; long now; long julian; long connect_time; int day_of_year; int hour; int min; int sec; struct tm *lt; setbuf(stderr,NULL); setbuf(stdout,NULL); ff(se,"nbs_time\n"); /* init line variables */ strcpy(Lline,"/dev/tty1a"); strcpy(Ltelno,"1(202)653-0351"); Liofd = -1; Lbaud = 1200; Lparity = 0; if(argc < 2) usage(); if((argc == 2) && (!strcmp(argv[1],"-"))) ; else { for(iargv = 1; iargv < argc; iargv++) { if(*argv[iargv] != '-') continue; switch(*(argv[iargv] + 1)) { case 'e': Lparity = 'e'; break; case 'o': Lparity = 'o'; break; case 'n': Lparity = 0 ; break; case 'b': Lbaud = atoi(argv[iargv] + 2); break; case 't': strcpy(Ltelno,argv[iargv] + 2); break; case 'l': strcpy(Lline,argv[iargv] + 2); break; default: usage(); } } } uid = getuid(); euid = geteuid(); if((euid == 0) || (uid == 0)) /* if root running or prog text ... */ nice(-40); else { ff(se,"must be root\n"); exit(252); } signal(SIGHUP,hangup); signal(SIGQUIT,hangup); signal(SIGINT,hangup); signal(SIGTERM,hangup); if(itmp = lopen()) { switch(itmp) { case LOPEN_INVALID: ff(se,"invalid line name\n"); break; case LOPEN_UNKPID: ff(se,"unknown pid is using line\n"); break; case LOPEN_LCKERR: ff(se,"lock file error\n"); break; case LOPEN_NODEV: ff(se,"line does not exist\n"); break; case LOPEN_ALREADY: ff(se,"line already open\n"); break; case LOPEN_OPNFAIL: ff(se,"line open error\n"); break; default: ff(se,"pid %d using line\n",itmp); break; } exit(250); } if(!hayes_dial()) hangup(1); connect_time = time((long *)0); for(itmp = 0; itmp < 30; itmp++) { if(lgetc_timeout(500L) == TONE) break; } lr.to1 = 1100L; lr.to2 = 100L; lr.raw_flag = 0; /* full raw read */ lr.buffer = rd_buf; lr.bufsize = sizeof(rd_buf); lgets_timeout(&lr); fputs("'",stdout); fwrite(lr.buffer,1,lr.count,stdout); fputs("'\n",stdout); lclose(); fprintf(stdout,"Connect time %ld second(s)\n", time((long *)0) - connect_time); if(sscanf(lr.buffer,TIME, &julian, &day_of_year, &hour, &min, &sec) != 5) { ff(se,"garbled result: '%s'\n",lr.buffer); exit(240); } else { now = (((julian - EPOCH) * 24 + hour) * 60 + min) * 60 + sec; if(stime(&now) < 0) perror("stime"); fputs("Time retrieved from standard: ",stdout); fputs(ctime(&now), stdout); lt = localtime(&now); while(lt->tm_sec != 58) { nap(960L); now = time((long *)0); fputs("Waiting for top of minute: ",stdout); fputs(ctime(&now), stdout); lt = localtime(&now); } now += 60L; /* get top of next minute */ lt = localtime(&now); /* mmddhhmmyy */ /* 0718213488 */ /* The following statement was added because of a bug in the original code */ lt->tm_mon++; sprintf(rd_buf,"/etc/setclock %02d%02d%02d%02d%02d", lt->tm_mon,lt->tm_mday,lt->tm_hour,lt->tm_min,lt->tm_year); fputs("/etc/setclock setting ... ",stdout); system(rd_buf); fputs("result: ",stdout); system("/etc/setclock"); } exit(0); } /* end of main */ /* end of nbs_time.c */ -- Ed Carp N7EKG/5 (28.3-28.5) uunet!cs.utexas.edu!khijol!erc Austin, Texas (512) 832-5884 "Good tea. Nice house." - Worf From gary at oak.circa.ufl.edu Mon Jan 29 18:56:56 1990 From: gary at oak.circa.ufl.edu (gary at oak.circa.ufl.edu) Date: 29 Jan 90 07:56:56 GMT Subject: brilliance Message-ID: <21985@uflorida.cis.ufl.EDU> In article <1103 at crockpot.East.Sun.COM>, matthew at sunpix.East.Sun.COM ( Sun Visualization Products) writes... | Posting a cancel message should be a function of your news reader. One |option in you news reader should permit you to cancel the posting your |currently reading, if it was posted by you. Unfortunately, it doesn't appear to be a feature of this news reading program. I am using a VAX VMS system to access USEnet via the local UNIX system, thus this program is rather simplistic (and bug riddled). Apparently that is a feature that will have to be added on in the future, unless someone can suggest where a very complete VMS NEWS program can be found... | If you are inquisitive as to what a 'control' message actually looks like, |browse the 'control' subdirectory of your sites news spool directory. |(Typically, /usr/spool/news/control) I suppose that can be done with a friend who has a UNIX account. =============================================================================== gary%maple.decnet at pine.circa.ufl.edu : Internet "Trust me. I know what I'm doing." - Sledgehammer (the TV show) "We killed it. We killed it! FUUUUUUUUUUUUUCK YOU!!!!" - Tremors Bang the head that doesn't bang! - Metallica and alt.rock-n-roll.metal From jpp at tygra.UUCP Mon Jan 1 19:38:52 1990 From: jpp at tygra.UUCP (John Palmer) Date: 1 Jan 90 08:38:52 GMT Subject: X/Y/Z Modem Functions for XENIX Needed Message-ID: <36@tygra.UUCP> Sorry if this is redundant, but does anyone have the C source code for some functions which implement X, Y and Zmodem?? These will be needed for a XENIX system, not a DOS system. Thanks in advance. John Palmer E-MAIL: ...!uunet!samsung!sharkey!tygra!jpp -- = CAT-TALK Conferencing Network, Prototype Computer Conferencing System = - 1-800-446-4698, 300/1200/2400 baud, 8/N/1. New users use 'new' - = as a login id. E-Mail Address: ...!uunet!samsung!sharkey!tygra!jpp = - <<<Redistribution to GEnie PROHIBITED!!!>>>> - From gemini at geminix.UUCP Mon Jan 15 08:04:35 1990 From: gemini at geminix.UUCP (Uwe Doering) Date: 14 Jan 90 21:04:35 GMT Subject: FAS 2.05 async driver, part 2/2 Message-ID: <6FYBMJ@geminix.UUCP> #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # fas.c # fas.h # This archive created: Sun Jan 14 21:42:01 1990 export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'fas.c'" '(42626 characters)' if test -f 'fas.c' then echo shar: "will not over-write existing file 'fas.c'" else sed 's/^X//' << \SHAR_EOF > 'fas.c' X/* FAS Final Async Solution driver for 386 versions of system V UNIX */ X X/* Originally written by XJim Murray encore!cloud9!jjmhome!jjm X2 Mohawk Circle harvard!m2c!jjmhome!jjm XWestboro Mass 01581 jjm%jjmhome at m2c.m2c.org XUSA voice (508) 366-2813 X*/ X X/* Current author: XUwe Doering gemini at netmbx.UUCP XBillstedter Pfad 17 B X1000 Berlin 20 XWest Germany X*/ X X#ident "@(#)fas.c 2.05" X X/* Note: This source code was quite heavily optimized for speed. You X may wonder that register variables aren't used everywhere. X This is because there is an overhead in memory accesses X when using register variables. As you may know data accesses X usually need much more wait states on the memory bus than X code accesses (page or cache misses). Therefore saving some X data accesses has higher priority than saving code accesses. X You may also note some not very elegant constructions that X may be intentional because they are faster. If you want to X make style improvements you should check the assembler output X whether this wouldn't slow things down. X X Decisions for speed optimization were based on assembler X listings produced by the standard UNIX V 3.X/386 C compiler. X*/ X X#include <sys/fas.h> X X#if !defined (__GNUC__) X#include <sys/inline.h> X X/* This is a terrible ugly kludge to speed up the `inb' and `outb' X functions. I.e., originally, the `outb' inline function had an X overhead of four data memory accesses for parameter passing. This X parameter passing actually consumed more clock cycles than the X assembler `outb' command itself. Although this solution can't X prevent unnessessary register moves it limits them at least to X register to register moves that are much faster. You need a X line like the following in the declaration part of every X function that uses `inb' or `outb' calls: X X REGVAR; X X This hack should work with every compiler that knows about the X UNIX V 3.X/386 standard compiler's inline assembler directives. X*/ X Xasm void loadal (val) X{ X%reg val; X movl val,%eax X%mem val; X movb val,%al X} X Xasm void loaddx (val) X{ X%reg val; X movl val,%edx X%mem val; X movw val,%dx X} X Xasm void outbyte () X{ X outb (%dx) X} X Xasm int inbyte () X{ X xorl %eax,%eax X inb (%dx) X} X X/* The port parameter of the `outb' macro must be one of the predefined X port macros from `fas.h' or a simple uint variable (no indirection X is allowed). Additionally, `fip' must be a register variable in the X functions where `outb' is used. This prevents the destruction of the X `eax' CPU register while loading the `edx' register with the port X address. This is highly compiler implementation specific. X*/ X#define outb(port,val) (regvar = (val), loadal (regvar), regvar = (port), loaddx (regvar), outbyte ()) X X#define inb(port) (regvar = (port), loaddx (regvar), inbyte ()) X X#define REGVAR register uint regvar X X/* This function inserts the address optimization assembler pseudo-op X wherever called. X*/ X Xasm void optim () X{ X .optim X} X X/* This dummy function has nothing to do but to call optim so that X the `.optim' assembler pseudo-op will be included in the assembler X file. This must be the first of all functions. X*/ X X#if defined (OPTIM) /* Define for uPort, ISC doesn't know about */ Xstatic void /* `.optim', but has turned on optimization by */ Xdummy () /* default, so we don't need it there anyway. */ X{ X optim (); X} X#endif X X#else X X#define REGVAR X X#endif X X/* functions provided by this driver */ Xint fasinit (); Xint fasopen (); Xint fasclose (); Xint fasread (); Xint faswrite (); Xint fasioctl (); Xint fasintr (); Xstatic int fas_proc (); Xstatic void fas_param (); Xstatic void fas_mproc (); Xstatic uint fas_rproc (); Xstatic int fas_rxfer (); Xstatic void fas_cmd (); Xstatic void fas_open_device (); Xstatic void fas_close_device (); Xstatic int fas_test_device (); X X/* functions used by this driver */ Xextern int ttrstrt (); Xextern int ttinit (); Xextern int ttiocom (); Xextern int ttyflush (); Xextern int spltty (); Xextern int splx (); Xextern int sleep (); Xextern int wakeup (); Xextern int signal (); Xextern int timeout (); Xextern int delay (); Xextern void longjmp (); Xextern int printf (); X X/* the following stuff is defined in space.c */ Xextern uint fas_physical_units; Xextern uint fas_port []; Xextern uint fas_vec []; Xextern uint fas_mcb []; Xextern uint fas_flow []; Xextern uint fas_int_ack_port []; Xextern uint fas_int_ack []; Xextern uint fas_mux_ack_port []; Xextern uint fas_mux_ack []; Xextern struct fas_info fas_info []; Xextern struct tty fas_tty []; Xextern struct fas_info *fas_info_ptr []; Xextern struct tty *fas_tty_ptr []; X/* end of space.c references */ X X/* fas_is_initted X Flag to indicate that we have been thru init. X This is realy only necessary for systems that use asyputchar X and asygetchar but it doesn't hurt to have it anyway. X*/ Xint fas_is_initted = FALSE; X X/* array of linked lists of fas_info structures for each interrupt vector X this is filled in at init time X*/ Xstatic struct fas_info *fas_vector_users [NUM_INT_VECTORS]; X X/* the values for the various baud rates */ Xstatic uint fas_speeds [CBAUD + 1] = X{ 0, BAUD_BASE/50, X BAUD_BASE/75, BAUD_BASE/110, X (2*BAUD_BASE+134)/269, BAUD_BASE/150, X BAUD_BASE/200, BAUD_BASE/300, X BAUD_BASE/600, BAUD_BASE/1200, X BAUD_BASE/1800, BAUD_BASE/2400, X BAUD_BASE/4800, BAUD_BASE/9600, X BAUD_BASE/19200, BAUD_BASE/38400 X}; X X/* time for one character to completely leave the transmitter shift register */ Xstatic uint fas_ctimes [CBAUD + 1] = X{ 1, HZ*30/50+2, X HZ*30/75+2, HZ*30/110+2, X HZ*60/269+2, HZ*30/150+2, X HZ*30/200+2, HZ*30/300+2, X HZ*30/600+2, HZ*30/1200+2, X HZ*30/1800+2, HZ*30/2400+2, X HZ*30/4800+2, HZ*30/9600+2, X HZ*30/19200+2, HZ*30/38400+2 X}; X X/* lookup table for minor device number -> open mode flags translation */ Xstatic uint fas_open_modes [16] = X{ X OS_OPEN_FOR_DIALOUT | OS_FAKE_CARR_ON | OS_CLOCAL, X OS_OPEN_FOR_DIALOUT | OS_FAKE_CARR_ON | OS_CLOCAL | OS_HW_HANDSHAKE, X OS_OPEN_FOR_DIALOUT | OS_FAKE_CARR_ON, X OS_OPEN_FOR_DIALOUT | OS_FAKE_CARR_ON | OS_HW_HANDSHAKE, X OS_OPEN_FOR_DIALOUT | OS_CHECK_CARR_ON_OPEN, X OS_OPEN_FOR_DIALOUT | OS_CHECK_CARR_ON_OPEN | OS_HW_HANDSHAKE, X OS_OPEN_FOR_DIALOUT | OS_CHECK_CARR_ON_OPEN | OS_FAKE_CARR_ON, X OS_OPEN_FOR_DIALOUT | OS_CHECK_CARR_ON_OPEN | OS_FAKE_CARR_ON | OS_HW_HANDSHAKE, X OS_OPEN_FOR_GETTY | OS_WAIT_OPEN | OS_NO_DIALOUT, X OS_OPEN_FOR_GETTY | OS_WAIT_OPEN | OS_NO_DIALOUT | OS_HW_HANDSHAKE, X OS_OPEN_FOR_GETTY | OS_WAIT_OPEN | OS_NO_DIALOUT | OS_UNBLOCK_ON_RING, X OS_OPEN_FOR_GETTY | OS_WAIT_OPEN | OS_NO_DIALOUT | OS_UNBLOCK_ON_RING | OS_HW_HANDSHAKE, X OS_OPEN_FOR_GETTY | OS_WAIT_OPEN, X OS_OPEN_FOR_GETTY | OS_WAIT_OPEN | OS_HW_HANDSHAKE, X OS_OPEN_FOR_GETTY | OS_WAIT_OPEN | OS_UNBLOCK_ON_RING, X OS_OPEN_FOR_GETTY | OS_WAIT_OPEN | OS_UNBLOCK_ON_RING | OS_HW_HANDSHAKE X}; X X/* The following defines are used to take apart the minor device numbers. */ X#define GET_UNIT(dev) ((dev) & 0x0f) X#define GET_OPEN_MODE(dev) (fas_open_modes [((dev) >> 4) & 0x0f]) X X/* lock device against concurrent use */ X#define get_device_lock(fip) \ X{\ X /* sleep while device is used by an other process */\ X while ((fip)->device_flags.i & DF_DEVICE_LOCKED)\ X sleep((caddr_t) &(fip)->device_flags.i, PZERO - 1);\ X (fip)->device_flags.s |= DF_DEVICE_LOCKED;\ X} X X/* release device */ X#define release_device_lock(fip) \ X{\ X (fip)->device_flags.s &= ~DF_DEVICE_LOCKED;\ X /* wakeup the process that may wait for this device */\ X wakeup ((caddr_t) &(fip)->device_flags.i);\ X} X X/* fasinit X This routine checks for the presense of the devices in the fas_port X array and if the device is present tests and initializes it. X During the initialization if the device is determined to be a X NS16550A chip the DF_DEVICE_HAS_FIFO flag is set and the FIFO will X be used. X X At boot time you will see a status message on the screen with a string X of symbols that show the init state of the ports. The symbols are as X follows: X X - not defined in the fas_port array X ? can't initialize port X ! port test procedure failed X * port is initialized X F port is initialized and has FIFOs (NS16550) X X This is convenient to check whether you have entered the proper port X base addresses in space.c. X*/ X Xint Xfasinit () X{ X register struct fas_info *fip; X register uint unit; X uint logical_units; X uint port; X char port_stat [MAX_UNITS + 1]; X REGVAR; X X if (fas_is_initted) X return(0); X X fas_is_initted = TRUE; X X for (unit = 0, logical_units = fas_physical_units * 2; X unit < logical_units; unit++) X fas_tty_ptr [unit] = &fas_tty [unit]; X X for (unit = 0; unit < fas_physical_units; unit++) X { X fas_info_ptr [unit] = fip = &fas_info [unit]; X port_stat [unit] = '-'; X if (port = fas_port [unit]) X { X /* init all of its ports */ X RCV_DATA_PORT = port + RCV_DATA_OFFSET; X XMT_DATA_PORT = port + XMT_DATA_OFFSET; X INT_ENABLE_PORT = port + INT_ENABLE_OFFSET; X INT_ID_PORT = port + INT_ID_OFFSET; X FIFO_CTL_PORT = port + FIFO_CTL_OFFSET; X LINE_CTL_PORT = port + LINE_CTL_OFFSET; X MDM_CTL_PORT = port + MDM_CTL_OFFSET; X LINE_STATUS_PORT = port + LINE_STATUS_OFFSET; X MDM_STATUS_PORT = port + MDM_STATUS_OFFSET; X DIVISOR_LSB_PORT = port + DIVISOR_LSB_OFFSET; X DIVISOR_MSB_PORT = port + DIVISOR_MSB_OFFSET; X INT_ACK_PORT = fas_int_ack_port [unit]; X fip->int_ack = fas_int_ack [unit]; X fip->recv_ring_put_ptr = fip->recv_buffer; X fip->recv_ring_take_ptr = fip->recv_buffer; X fip->recv_ring_cnt = 0; X fip->h_mask = fas_flow [unit]; X X fip->ier.c = IE_NONE; /* disable all ints */ X outb (INT_ENABLE_PORT, fip->ier.i); X if (inb (INT_ENABLE_PORT) != fip->ier.i) X { X port_stat [unit] = '?'; X continue; /* a hardware error */ X } X X if (!fas_test_device (fip)) X { X port_stat [unit] = '!'; X continue; /* a hardware error */ X } X X fip->mcr.c = fas_mcb [unit] | (INITIAL_MDM_CONTROL); X outb (MDM_CTL_PORT, fip->mcr.i); X X fip->lcr.c = INITIAL_LINE_CONTROL; X outb (LINE_CTL_PORT, fip->lcr.i | LC_ENABLE_DIVISOR); X outb (DIVISOR_LSB_PORT, INITIAL_BAUD_RATE); X outb (DIVISOR_MSB_PORT, (INITIAL_BAUD_RATE) >> 8); X outb (LINE_CTL_PORT, fip->lcr.i); X port_stat [unit] = '*'; X X /* let's see if it's an NS16550 */ X outb (FIFO_CTL_PORT, STANDARD_FIFO_INIT); X if ((inb (INT_ID_PORT) & II_FIFO_ENABLED) X == II_FIFO_ENABLED) X { X fip->device_flags.s |= DF_DEVICE_HAS_FIFO; X port_stat [unit] = 'F'; X } X /* clear and disable the FIFO */ X outb (FIFO_CTL_PORT, STANDARD_FIFO_CLEAR); X X /* clear potential interrupts */ X inb (MDM_STATUS_PORT); X inb (RCV_DATA_PORT); X inb (RCV_DATA_PORT); X inb (LINE_STATUS_PORT); X inb (INT_ID_PORT); X if (INT_ACK_PORT) X outb (INT_ACK_PORT, fip->int_ack); X if (port = fas_mux_ack_port [fas_vec [unit]]) X outb (port, fas_mux_ack [fas_vec [unit]]); X X /* show that it is present and configured */ X fip->device_flags.s |= DF_DEVICE_CONFIGURED; X X /* link in as interrupt user */ X fip->next_interrupt_user = fas_vector_users [fas_vec [unit]]; X fas_vector_users [fas_vec [unit]] = fip; X } X } X port_stat [unit] = '\0'; X printf ("\nFAS 2.05 async driver: port 0-%d init state is [%s]\n\n", X unit - 1, X port_stat); X return(0); X} X X/* Open a line */ X X/* There are a few differences between this and a normal serial X device. X X For each physical port there are two logical minor devices. X For each logical minor device there are several operating modes X that are selected by some of the higher bits of the minor X device number. Only one logical minor device can be open at X the same time. X X - Minor devices that *don't* block on open if no carrier is present: X X Bitmap: 0 m m h x x x x X X `m m' are the mode bits as follows: X X 0 0 The DCD signal is totally ignored. With DCD high->low X *no* SIGHUP signal is generated. X 0 1 After an initial open, the DCD signal is ignored. X Although, DCD high->low generates a SIGHUP signal. From X thereon the device is DCD controlled until the last X process has closed the device. An ioctl call with a X TCSETA* command resets the device to ignore DCD again X until the next DCD high->low. X 1 0 The device is DCD controlled. Additionally, if on open X the DCD signal is low, a SIGHUP signal is sent immediately. X 1 1 The device behaves the same as with mode `0 1'. Additionally, X if on open the DCD signal is low, a SIGHUP signal is sent X immediately. X X - Minor devices that *do* block on open if no carrier is present: X X Bitmap: 1 m m h x x x x X X `m m' are the mode bits as follows: X X 0 0 The device is DCD controlled. X 0 1 The device is DCD controlled. A RING signal unblocks X the waiting open and I/O is possible regardless of X DCD until a DCD high->low. Thereafter the device is X again fully DCD controlled. X 1 0 Same as mode `0 0', but a parallel non-blocking open X is possible while waiting for carrier. X 1 1 Same as mode `0 1', but a parallel non-blocking open X is possible while waiting for carrier. X X - Description of the remaining bits of the bitmap: X X `h' If set to `1', the device has hardware handshake. Refer X to the `space.c' file to determine which port signals X are actually used for that purpose. X `x x x x' X This is the physical port number. This driver supports X up to 16 ports. If you need more, you should use an X intelligent serial card because more than 16 devices X will eat up to much CPU time with this dumb-port approach. X X - Note: If a device is DCD controlled, this implies the generation of X a SIGHUP signal with every DCD high->low. This is of course only X true if the CLOCAL flag is *not* set. X X If you use more than a few ports and you have a high volume of X receiver data at a high baud rate, the ports may lose characters. X This is simply a hardware limitation and can't be cured by any X software. But there is a pin-to-pin compatible replacement X for the i8250 and NS16450 devices. It's the NS16550 and has X separate 16-character I/O FIFOs. This will make any character X loss at least very improbable. Also, the system is loaded X much less because whenever possible up to 16 characters are X processed at a single port interrupt. X X On my own system I prefer a minor device number of `0011xxxx' X (48 + device #) for the non-blocking tty node and `1101xxxx' X (208 + device #) for the blocking tty node. This gives me X the SIGHUP signal on carrier loss and hardware flow control X with both logical devices. Dialout while a dialin open X is waiting for the carrier is also possible with this setup. X XThis function is called for every open, as opposed to the fasclose Xfunction which is called only with the last close. X*/ X Xint Xfasopen (dev, flag) Xint dev; Xint flag; X{ X register struct fas_info *fip; X register struct tty *ttyp; X register uint open_mode; X uint physical_unit; X int old_level; X X physical_unit = GET_UNIT (dev); X X /* check for valid port number */ X if (physical_unit >= fas_physical_units) X { X u.u_error = ENXIO; X return(-1); X } X X fip = fas_info_ptr [physical_unit]; X X /* was the port present at init time ? */ X if (!(fip->device_flags.i & DF_DEVICE_CONFIGURED)) X { X u.u_error = ENXIO; X return(-1); X } X X open_mode = GET_OPEN_MODE (dev); X X old_level = spltty (); X get_device_lock (fip); X X /* If this is a getty open and the device is already open X for dialout, wait until device is closed. X */ X while ((open_mode & OS_OPEN_FOR_GETTY) X && (fip->o_state & OS_OPEN_FOR_DIALOUT)) X { X release_device_lock (fip); X sleep ((caddr_t) &fip->o_state, TTIPRI); X get_device_lock (fip); X } X X /* If the device is already open and another open uses a different X open mode or if a getty open waits for DCD and doesn't allow X parallel dialout opens, return with I/O error. X */ X if ((fip->o_state & ((open_mode & OS_OPEN_FOR_GETTY) X ? (OS_OPEN_STATES | OS_WAIT_OPEN) X : (OS_OPEN_STATES | OS_NO_DIALOUT))) X && ((open_mode ^ fip->o_state) & OS_TEST_MASK)) X { X u.u_error = EIO; X release_device_lock (fip); X splx (old_level); X return(-1); X } X X /* set up pointer to tty structure */ X ttyp = (open_mode & OS_OPEN_FOR_GETTY) X ? fas_tty_ptr [physical_unit + fas_physical_units] X : fas_tty_ptr [physical_unit]; X X /* things to do on first open only */ X if (!(fip->o_state & ((open_mode & OS_OPEN_FOR_GETTY) X ? (OS_OPEN_STATES | OS_WAIT_OPEN) X : OS_OPEN_STATES))) X { X /* init data structures */ X fip->tty = ttyp; X ttinit (ttyp); X ttyp->t_proc = fas_proc; X fip->po_state = fip->o_state; X fip->o_state = open_mode & ~OS_OPEN_STATES; X /* open physical device if not yet open */ X if (!(fip->device_flags.i & DF_DEVICE_OPEN)) X fas_open_device (fip); X fas_param (fip); /* set up port registers */ X fas_mproc (fip); /* set up modem status flags */ X } X X /* If getty open and the FNDELAY flag is not set, X block and wait for DCD. X */ X if ((open_mode & OS_OPEN_FOR_GETTY) && !(flag & FNDELAY)) X { X /* sleep while open for dialout or no carrier */ X while ((fip->o_state & OS_OPEN_FOR_DIALOUT) X || !(ttyp->t_state & CARR_ON)) X { X ttyp->t_state |= WOPEN; X release_device_lock (fip); X sleep((caddr_t) &ttyp->t_canq, TTIPRI); X get_device_lock (fip); X ttyp->t_state &= ~WOPEN; X } X } X X (*linesw [ttyp->t_line].l_open) (ttyp); X X /* set open type flags */ X fip->o_state = open_mode; X X if ((open_mode & OS_CHECK_CARR_ON_OPEN) X && !(fip->msr & MS_DCD_PRESENT) X && !(fip->cflag & CLOCAL)) X { X signal (ttyp->t_pgrp, SIGHUP); X ttyflush (ttyp, FREAD | FWRITE); X } X X release_device_lock (fip); X splx (old_level); X return(0); X} X X/* Close a tty line. This is only called if there is no other X concurrent open left. A blocked getty open is not counted as X a concurrent open because in this state it isn't really open. X*/ Xint Xfasclose (dev) Xint dev; X{ X register struct fas_info *fip; X register struct tty *ttyp; X uint open_mode; X uint physical_unit; X int old_level; X X physical_unit = GET_UNIT (dev); X X fip = fas_info_ptr [physical_unit]; X X open_mode = GET_OPEN_MODE (dev); X X /* set up pointer to tty structure */ X ttyp = (open_mode & OS_OPEN_FOR_GETTY) X ? fas_tty_ptr [physical_unit + fas_physical_units] X : fas_tty_ptr [physical_unit]; X X old_level = spltty (); X X (*linesw [ttyp->t_line].l_close) (ttyp); X X get_device_lock (fip); X X if (open_mode & OS_OPEN_FOR_GETTY) X { X /* not waiting any more */ X ttyp->t_state &= ~WOPEN; X if (!(fip->o_state & OS_OPEN_FOR_DIALOUT)) X { X fas_close_device (fip); X fip->o_state = OS_DEVICE_CLOSED; X } X else X fip->po_state = OS_DEVICE_CLOSED; X } X else X { X fas_close_device (fip); X fip->o_state = OS_DEVICE_CLOSED; X /* If there is a waiting getty open on X this port, reopen the physical device. X */ X if (fip->po_state & OS_WAIT_OPEN) X { X /* get the getty version of the X tty structure X */ X fip->tty = fas_tty_ptr [physical_unit X + fas_physical_units]; X fip->o_state = fip->po_state; X fip->po_state = OS_DEVICE_CLOSED; X if (!(fip->device_flags.i & DF_DO_HANGUP)) X { X fas_open_device (fip); X fas_param (fip); /* set up port registers */ X fas_mproc (fip); /* set up modem status flags */ X } X } X wakeup ((caddr_t) &fip->o_state); X } X X if (!(fip->device_flags.i & DF_DO_HANGUP)) X release_device_lock (fip); X X splx (old_level); X return(0); X} X X/* read characters from the input buffer */ Xint Xfasread (dev) Xint dev; X{ X register struct fas_info *fip; X register struct tty *ttyp; X int old_level; X REGVAR; X X fip = fas_info_ptr [GET_UNIT (dev)]; X X ttyp = fip->tty; X X (*linesw [ttyp->t_line].l_read) (ttyp); X X old_level = spltty (); X X /* fill the unix buffer as much as possible */ X while (fip->recv_ring_cnt) X { X if (fas_rxfer (fip)) X break; X X splx (old_level); /* allow some interrupts */ X old_level = spltty (); X } X X /* If input buffer level has dropped below X the low water mark and input was stopped X by RTS low, set RTS high to restart input. X */ X if ((fip->device_flags.i & DF_HWISTOP) X && (fip->recv_ring_cnt < HW_LOW_WATER)) X { X fip->mcr.c |= MC_SET_RTS; X outb (MDM_CTL_PORT, fip->mcr.i); X fip->device_flags.s &= ~DF_HWISTOP; X } X X /* If input buffer level has dropped below X the low water mark and input was stopped X by XOFF, send XON to restart input. X */ X if ((fip->device_flags.i & DF_SWISTOP) X && (fip->recv_ring_cnt < SW_LOW_WATER)) X { X fip->device_flags.s &= ~DF_SWISTOP; X fip->device_flags.s ^= DF_SW_FC_REQ; X if (fip->device_flags.i & DF_SW_FC_REQ) X { X ttyp->t_state |= TTXON; X fas_cmd (fip, ttyp, T_OUTPUT); X } X else X ttyp->t_state &= ~TTXOFF; X } X X splx (old_level); X return(0); X} X X/* write characters to the output buffer */ Xint Xfaswrite (dev) Xint dev; X{ X register struct tty *ttyp; X X ttyp = fas_info_ptr [GET_UNIT (dev)]->tty; X X (*linesw [ttyp->t_line].l_write) (ttyp); X return(0); X} X X/* process ioctl calls */ Xint Xfasioctl (dev, cmd, arg3, arg4) Xint dev; Xint cmd; Xunion ioctl_arg arg3; Xint arg4; X{ X register struct fas_info *fip; X register struct tty *ttyp; X uint old_t_state; X int old_level; X X fip = fas_info_ptr [GET_UNIT (dev)]; X X ttyp = fip->tty; X X /* if it is a TCSETA* command, call fas_param () */ X if (ttiocom (ttyp, cmd, arg3, arg4)) X { X old_level = spltty (); X old_t_state = ttyp->t_state; X fas_param (fip); X /* if we switched off CLOCAL mode and the *real* carrier X is missing we send the SIGHUP signal once X */ X if (!(ttyp->t_state & CARR_ON) && (old_t_state & CARR_ON)) X { X signal (ttyp->t_pgrp, SIGHUP); X ttyflush (ttyp, FREAD | FWRITE); X } X splx (old_level); X } X return(0); X} X X/* pass fas commands to the fas multi-function procedure */ Xstatic int Xfas_proc (ttyp, arg2) Xstruct tty *ttyp; Xint arg2; X{ X register uint physical_unit; X int old_level; X X physical_unit = ttyp - &fas_tty [0]; X if (physical_unit >= fas_physical_units) X physical_unit -= fas_physical_units; X X old_level = spltty (); X fas_cmd (fas_info_ptr [physical_unit], ttyp, arg2); X splx (old_level); X return (0); X} X X/* set up a port according to the given termio structure */ Xstatic void Xfas_param (fip) Xregister struct fas_info *fip; X{ X register uint cflag; X uint divisor; X REGVAR; X X cflag = fip->tty->t_cflag; X X /* drop DTR if it is baud rate 0, else raise DTR */ X if ((cflag & CBAUD) == B0) X { X cflag = (cflag & ~CBAUD) | (fip->cflag & CBAUD); X fip->mcr.c &= ~MC_SET_DTR; X outb (MDM_CTL_PORT, fip->mcr.i); X } X else X { X if (!(fip->mcr.i & MC_SET_DTR)) X { X fip->mcr.c |= MC_SET_DTR; X outb (MDM_CTL_PORT, fip->mcr.i); X } X } X X /* set character size */ X switch (cflag & CSIZE) X { X default: X case CS8: X fip->lcr.c = LC_WORDLEN_8; X break; X X case CS5: X fip->lcr.c = LC_WORDLEN_5; X break; X X case CS6: X fip->lcr.c = LC_WORDLEN_6; X break; X X case CS7: X fip->lcr.c = LC_WORDLEN_7; X break; X } X X /* set # of stop bits */ X if (cflag & CSTOPB) X fip->lcr.c |= LC_STOPBITS_LONG; X X /* set parity */ X if (cflag & PARENB) X { X fip->lcr.c |= LC_ENABLE_PARITY; X X if (!(cflag & PARODD)) X fip->lcr.c |= LC_EVEN_PARITY; X } X X /* change counter divisor only if baud rate has changed */ X if ((cflag ^ fip->cflag) & CBAUD) X { X /* get counter divisor for selected baud rate */ X divisor = fas_speeds [cflag & CBAUD]; X outb (LINE_CTL_PORT, fip->lcr.i | LC_ENABLE_DIVISOR); X outb (DIVISOR_LSB_PORT, divisor); X outb (DIVISOR_MSB_PORT, divisor >> 8); X } X X outb (LINE_CTL_PORT, fip->lcr.i); X X /* disable modem control signals if required by open mode */ X if (fip->o_state & OS_CLOCAL) X cflag |= CLOCAL; X X /* Fake the carrier detect state flag if CLOCAL mode or if X requested by open mode. X */ X if ((fip->msr & MS_DCD_PRESENT) X || (fip->o_state & OS_FAKE_CARR_ON) X || (cflag & CLOCAL)) X fip->tty->t_state |= CARR_ON; X else X fip->tty->t_state &= ~CARR_ON; X X fip->cflag = cflag; X fip->iflag = fip->tty->t_iflag; X} X X/* Main fas interrupt handler. Actual character processing is splitted X into sub-functions. X*/ Xint Xfasintr (vect) Xint vect; X{ X register struct fas_info *fip; X register uint line_status; X int done = FALSE; X uint port; X REGVAR; X X /* I believe that the 8259 is set up for edge trigger. Therefore X I must loop until I make a complete pass without getting X any UARTs that are interrupting. X */ X while (!done) X { X done = TRUE; X X /* loop through all users of this interrupt vector */ X for (fip = fas_vector_users [vect]; fip; X fip = fip->next_interrupt_user) X { X /* process only ports that we expect ints from */ X if (!(fip->ier.c)) X continue; X X for (;;) X { X /* any ints left on this port ? */ X if (inb (INT_ID_PORT) & II_NO_INTS_PENDING) X { X /* clear the port interrupt */ X if (INT_ACK_PORT) X outb (INT_ACK_PORT, fip->int_ack); X break; X } X X done = FALSE; /* not done if we got one */ X X /* read in all the characters from the FIFO */ X if ((line_status = inb (LINE_STATUS_PORT)) X & LS_RCV_INT) X { X line_status = fas_rproc (fip, line_status); X sysinfo.rcvint++; X } X X /* Is it a transmitter empty int ? */ X if ((line_status & LS_XMIT_AVAIL) X && (fip->device_flags.i & DF_XMIT_BUSY)) X { X fip->device_flags.s &= ~DF_XMIT_BUSY; X fip->tty->t_state &= ~BUSY; X fas_cmd (fip, fip->tty, T_OUTPUT); X sysinfo.xmtint++; X } X X /* Has there been a polarity change on X some of the modem lines ? X */ X if ((inb (MDM_STATUS_PORT) ^ fip->msr) X & MS_ANY_PRESENT) X { X fas_mproc (fip); X sysinfo.mdmint++; X } X } X X /* process the characters in the ring buffer */ X if (fip->recv_ring_cnt) X { X fas_rxfer (fip); X /* If input buffer level has risen above the X high water mark and input is not yet X stopped, set RTS low to stop input. X */ X if ((fip->o_state & OS_HW_HANDSHAKE) X && !(fip->device_flags.i & DF_HWISTOP) X && (fip->recv_ring_cnt > HW_HIGH_WATER)) X { X fip->mcr.c &= ~MC_SET_RTS; X outb (MDM_CTL_PORT, fip->mcr.i); X fip->device_flags.s |= DF_HWISTOP; X } X /* If input buffer level has risen above the X high water mark and input is not yet X stopped, send XOFF to stop input. X */ X if ((fip->iflag & IXOFF) X && !(fip->device_flags.i & DF_SWISTOP) X && (fip->recv_ring_cnt > SW_HIGH_WATER)) X { X fip->device_flags.s |= DF_SWISTOP; X fip->device_flags.s ^= DF_SW_FC_REQ; X if (fip->device_flags.i & DF_SW_FC_REQ) X { X fip->tty->t_state |= TTXOFF; X fas_cmd (fip, fip->tty, T_OUTPUT); X } X else X fip->tty->t_state &= ~TTXON; X } X } X } X } X X /* clear the mux interrupt since we have scanned all X of the ports that share this interrupt vector X */ X if (port = fas_mux_ack_port [vect]) X outb (port, fas_mux_ack [vect]); X X return(0); X} X X/* modem status interrupt handler */ Xstatic void Xfas_mproc (fip) Xregister struct fas_info *fip; X{ X register struct tty *ttyp; X register uint mdm_state; X REGVAR; X X ttyp = fip->tty; X X mdm_state = inb (MDM_STATUS_PORT); X X /* Check the output flow control signals and set the state flag X accordingly. X */ X if (fip->o_state & OS_HW_HANDSHAKE) X { X if ((mdm_state & fip->h_mask) == fip->h_mask) X { X if (fip->device_flags.i & DF_HWOSTOP) X { X fip->device_flags.s &= ~DF_HWOSTOP; X fas_cmd (fip, ttyp, T_OUTPUT); X } X } X else X fip->device_flags.s |= DF_HWOSTOP; X } X X /* Check the carrier detect signal and set the state flags X accordingly. Also, if not in clocal mode, send SIGHUP on X carrier loss and flush the buffers. X */ X if (!(fip->cflag & CLOCAL)) X { X if (mdm_state & MS_DCD_PRESENT) X { X ttyp->t_state |= CARR_ON; X /* Unblock getty open only if it is ready to run. */ X if (fip->o_state & OS_WAIT_OPEN) X wakeup ((caddr_t) &ttyp->t_canq); X } X else X { X if (fip->msr & MS_DCD_PRESENT) X { X ttyp->t_state &= ~CARR_ON; X if (ttyp->t_state & ISOPEN) X { X signal (ttyp->t_pgrp, SIGHUP); X ttyflush (ttyp, FREAD | FWRITE); X } X } X } X } X X /* Check the ring signal. If low->high edge, fake CARR_ON state X flag and wake up getty open. X */ X if ((fip->o_state & OS_UNBLOCK_ON_RING) X && !(fip->cflag & CLOCAL) X && (mdm_state & MS_RING_PRESENT) X && !(fip->msr & MS_RING_PRESENT) X && (fip->o_state & OS_WAIT_OPEN)) X { X ttyp->t_state |= CARR_ON; X wakeup ((caddr_t) &ttyp->t_canq); X } X X fip->msr = mdm_state; X} X X/* Receiver interrupt handler. Translates input characters to character X sequences as described in TERMIO(7) man page. X*/ Xstatic uint Xfas_rproc (fip, line_status) Xregister struct fas_info *fip; Xuint line_status; X{ X struct tty *ttyp; X uint charac; X register uint csize; X unchar metta [4]; X REGVAR; X X ttyp = fip->tty; X X /* Translate characters from FIFO according to the TERMIO(7) X man page. X */ X do X { X charac = (line_status & LS_RCV_AVAIL) X ? inb (RCV_DATA_PORT) X : 0; /* was line status int only */ X X if (!(fip->cflag & CREAD) || !(ttyp->t_state & ISOPEN)) X continue; X X csize = 0; X X if (fip->iflag & ISTRIP) X charac &= 0x7f; X X if ((line_status & LS_PARITY_ERROR) X && !(fip->iflag & INPCK)) X line_status &= ~LS_PARITY_ERROR; X X if (line_status & (LS_PARITY_ERROR X | LS_FRAMING_ERROR X | LS_BREAK_DETECTED)) X { X if (line_status & LS_BREAK_DETECTED) X { X if (!(fip->iflag & IGNBRK)) X if (fip->iflag & BRKINT) X (*linesw [ttyp->t_line].l_input) X (ttyp, L_BREAK); X else X { X metta [csize] = 0; X csize++; X if (fip->iflag & PARMRK) X { X metta [csize] = 0; X csize++; X metta [csize] = 0xff; X csize++; X } X } X } X else if (!(fip->iflag & IGNPAR)) X if (fip->iflag & PARMRK) X { X metta [csize] = charac; X csize++; X metta [csize] = 0; X csize++; X metta [csize] = 0xff; X csize++; X } X else X { X metta [csize] = 0; X csize++; X } X } X else if (line_status & LS_RCV_AVAIL) X { X if (fip->iflag & IXON) X { X if (ttyp->t_state & TTSTOP) X { X if ((charac == CSTART) X || (fip->iflag & IXANY)) X { X ttyp->t_state &= ~TTSTOP; X /* fake transmitter busy flag X to restart output X */ X fip->device_flags.s |= X DF_XMIT_BUSY; X } X } X else X { X if (charac == CSTOP) X ttyp->t_state |= TTSTOP; X } X if ((charac == CSTART) || (charac == CSTOP)) X continue; X } X X if ((charac == 0xff) && (fip->iflag & PARMRK)) X { X metta [csize] = 0xff; X csize++; X } X X metta [csize] = charac; X csize++; X } X X if (fip->recv_ring_cnt > RECV_BUFF_SIZE - 4) X continue; X X fip->recv_ring_cnt += csize; X X /* store translation in ring buffer */ X while (csize) X { X *fip->recv_ring_put_ptr = metta [--csize]; X if (++fip->recv_ring_put_ptr X == &fip->recv_buffer [RECV_BUFF_SIZE]) X fip->recv_ring_put_ptr X = &fip->recv_buffer [0]; X } X } while ((line_status = inb (LINE_STATUS_PORT)) & LS_RCV_INT); X X return (line_status); X} X X/* Ring buffer -> UNIX buffer transfer function. */ Xstatic int Xfas_rxfer (fip) Xregister struct fas_info *fip; X{ X register struct tty *ttyp; X register uint num_to_input; X X ttyp = fip->tty; X X num_to_input = (TTYHOG - 1) - ttyp->t_rawq.c_cc; X X if (!num_to_input || !ttyp->t_rbuf.c_ptr) X return (1); /* input buffer full */ X X if (fip->recv_ring_cnt < num_to_input) X num_to_input = fip->recv_ring_cnt; X if (ttyp->t_rbuf.c_count < num_to_input) X num_to_input = ttyp->t_rbuf.c_count; X if (fip->device_flags.i & DF_DEVICE_HAS_FIFO) X { X if (INPUT_FIFO_SIZE * 2 < num_to_input) X num_to_input = INPUT_FIFO_SIZE * 2; X } X else X { X if (8 < num_to_input) X num_to_input = 8; X } X X fip->recv_ring_cnt -= num_to_input; X ttyp->t_rbuf.c_count -= num_to_input; X X while (num_to_input) X { X *ttyp->t_rbuf.c_ptr = *fip->recv_ring_take_ptr; X if (++fip->recv_ring_take_ptr X == &fip->recv_buffer [RECV_BUFF_SIZE]) X fip->recv_ring_take_ptr = &fip->recv_buffer [0]; X ttyp->t_rbuf.c_ptr++; X num_to_input--; X } X X ttyp->t_rbuf.c_ptr -= ttyp->t_rbuf.c_size X - ttyp->t_rbuf.c_count; X (*linesw [ttyp->t_line].l_input) (ttyp, L_BUF); X X return (0); X} X X/* Several functions for flow control, character output and special event X requests and handling. X*/ Xstatic void Xfas_cmd (fip, ttyp, arg2) Xregister struct fas_info *fip; Xregister struct tty *ttyp; Xint arg2; X{ X uint num_to_output, out_cnt, cbg_cnt; X REGVAR; X X switch (arg2) X { X case T_TIME: /* process delayed events */ X /* handle break request */ X if (fip->device_flags.i & DF_DO_BREAK) X { X if (fip->lcr.i & LC_SET_BREAK_LEVEL) X { X fip->lcr.c &= ~LC_SET_BREAK_LEVEL; X outb (LINE_CTL_PORT, fip->lcr.i); X fip->device_flags.s &= ~DF_DO_BREAK; X timeout (ttrstrt, ttyp, X fas_ctimes [fip->cflag & CBAUD]); X break; X } X else X { X fip->lcr.c |= LC_SET_BREAK_LEVEL; X outb (LINE_CTL_PORT, fip->lcr.i); X /* 250 msec */ X timeout (ttrstrt, ttyp, HZ / 4); X break; X } X } X /* handle hangup request */ X if (fip->device_flags.i & DF_DO_HANGUP) X { X if (fip->mcr.i & MC_SET_DTR) X { X fip->mcr.c &= ~MC_SET_DTR; X outb (MDM_CTL_PORT, fip->mcr.i); X timeout (ttrstrt, ttyp, HANGUP_TIME); X break; X } X else X { X ttyp->t_state &= ~TIMEOUT; X fip->device_flags.s &= ~(DF_DO_HANGUP X | DF_XMIT_DISABLED); X /* If there was a waiting getty open on this X port, reopen the physical device. X */ X if (fip->o_state & OS_WAIT_OPEN) X { X fas_open_device (fip); X fas_param (fip); /* set up port regs */ X fas_mproc (fip); /* set up mdm stat flags */ X } X release_device_lock (fip); X break; X } X } X ttyp->t_state &= ~TIMEOUT; X fip->device_flags.s &= ~DF_XMIT_DISABLED; X /* FALL THRU */ X X case T_OUTPUT: /* output characters to the transmitter */ Xstart: X /* proceed only if output not stopped internally */ X if (fip->device_flags.i & (DF_HWOSTOP | DF_XMIT_DISABLED X | DF_XMIT_BUSY)) X break; X X /* determine the transmitter FIFO size */ X num_to_output = (fip->device_flags.i & DF_DEVICE_HAS_FIFO) X ? OUTPUT_FIFO_SIZE X : 1; X X /* handle XON/XOFF input flow control requests */ X if (fip->device_flags.i & DF_SW_FC_REQ) X { X outb (XMT_DATA_PORT, (fip->device_flags.i & DF_SWISTOP) X ? CSTOP X : CSTART); X ttyp->t_state |= BUSY; X ttyp->t_state &= ~(TTXON | TTXOFF); X fip->device_flags.s |= DF_XMIT_BUSY; X fip->device_flags.s &= ~DF_SW_FC_REQ; X num_to_output--; X } X X /* bail out if output is suspended by XOFF */ X if (ttyp->t_state & TTSTOP) X break; X X /* init cbuffer get counter */ X cbg_cnt = 2; X X /* Fill the transmitter FIFO. We limit the number of times X a new cbuffer is requested because the request function X is time consuming and this loop is running with interrupts X disabled. X */ X while (num_to_output && cbg_cnt) X { X /* Check if tbuf is empty. If it is empty, reset buffer X pointer and counter and get the next chunk of output X characters. X */ X if (!ttyp->t_tbuf.c_ptr || !ttyp->t_tbuf.c_count) X { X if (ttyp->t_tbuf.c_ptr) X ttyp->t_tbuf.c_ptr -= ttyp->t_tbuf.c_size; X if (!((*linesw [ttyp->t_line].l_output) (ttyp) X & CPRES)) X break; X X cbg_cnt--; X } X X /* Determine how many chars to put into the transmitter X register. X */ X out_cnt = min (ttyp->t_tbuf.c_count, num_to_output); X num_to_output -= out_cnt; X ttyp->t_tbuf.c_count -= out_cnt; X X /* output characters to the transmitter register */ X while (out_cnt) X { X outb (XMT_DATA_PORT, *ttyp->t_tbuf.c_ptr); X ttyp->t_tbuf.c_ptr++; X out_cnt--; X } X /* signal that transmitter is busy now */ X ttyp->t_state |= BUSY; X fip->device_flags.s |= DF_XMIT_BUSY; X } X break; X X case T_SUSPEND: /* suspend character output */ X ttyp->t_state |= TTSTOP; X break; X X case T_RESUME: /* restart character output */ X ttyp->t_state &= ~TTSTOP; X goto start; X X case T_BLOCK: /* stop character input, request XOFF */ X ttyp->t_state |= TBLOCK; X break; /* note: we do our own XON/XOFF */ X X case T_UNBLOCK: /* restart character input, request XON */ X ttyp->t_state &= ~TBLOCK; X break; /* note: we do our own XON/XOFF */ X X case T_RFLUSH: /* flush input buffers and restart input */ X fip->recv_ring_take_ptr = fip->recv_ring_put_ptr; X fip->recv_ring_cnt = 0; X if (fip->device_flags.i & DF_DEVICE_HAS_FIFO) X outb (FIFO_CTL_PORT, STANDARD_FIFO_SETUP X | FIFO_CLR_RECV); X if (fip->device_flags.i & DF_HWISTOP) X { X fip->mcr.c |= MC_SET_RTS; X outb (MDM_CTL_PORT, fip->mcr.i); X fip->device_flags.s &= ~DF_HWISTOP; X } X ttyp->t_state &= ~TBLOCK; X if (fip->device_flags.i & DF_SWISTOP) X { X fip->device_flags.s &= ~DF_SWISTOP; X fip->device_flags.s ^= DF_SW_FC_REQ; X if (fip->device_flags.i & DF_SW_FC_REQ) X { X ttyp->t_state |= TTXON; X goto start; X } X else X ttyp->t_state &= ~TTXOFF; X } X break; X X case T_WFLUSH: /* flush output buffer and restart output */ X if (fip->device_flags.i & DF_DEVICE_HAS_FIFO) X outb (FIFO_CTL_PORT, STANDARD_FIFO_SETUP X | FIFO_CLR_XMIT); X if (ttyp->t_tbuf.c_ptr) X ttyp->t_tbuf.c_ptr -= ttyp->t_tbuf.c_size X - ttyp->t_tbuf.c_count; X do X { X ttyp->t_tbuf.c_count = 0; X } while ((*linesw [ttyp->t_line].l_output) (ttyp) & CPRES); X ttyp->t_state &= ~TTSTOP; X break; X X case T_BREAK: /* do a break on the transmitter line */ X /* set up break request flags */ X fip->device_flags.s |= DF_DO_BREAK | DF_XMIT_DISABLED; X ttyp->t_state |= TIMEOUT; X timeout (ttrstrt, ttyp, fas_ctimes [fip->cflag & CBAUD]); X break; X X case T_PARM: /* set up the port according to the termio structure */ X fas_param (fip); X break; X X case T_SWTCH: /* handle layer switch request */ X break; X } X} X X/* open device physically */ Xstatic void Xfas_open_device (fip) Xregister struct fas_info *fip; X{ X REGVAR; X X fip->device_flags.s &= DF_DEVICE_CONFIGURED | DF_DEVICE_HAS_FIFO X | DF_DEVICE_OPEN | DF_DEVICE_LOCKED; X fip->cflag = 0; X fip->iflag = 0; X fip->recv_ring_take_ptr = fip->recv_ring_put_ptr; X fip->recv_ring_cnt = 0; X X fip->msr = inb (MDM_STATUS_PORT); X inb (RCV_DATA_PORT); X inb (RCV_DATA_PORT); X inb (LINE_STATUS_PORT); X inb (INT_ID_PORT); X if (INT_ACK_PORT) X outb (INT_ACK_PORT, fip->int_ack); X if (fip->device_flags.i & DF_DEVICE_HAS_FIFO) X outb (FIFO_CTL_PORT, STANDARD_FIFO_INIT); X fip->ier.c = IE_INIT_MODE; X outb (INT_ENABLE_PORT, fip->ier.i); X X fip->mcr.c |= MC_SET_DTR | MC_SET_RTS; X outb (MDM_CTL_PORT, fip->mcr.i); X X fip->device_flags.s |= DF_DEVICE_OPEN; X} X X/* close device physically */ Xstatic void Xfas_close_device (fip) Xregister struct fas_info *fip; X{ X REGVAR; X X fip->device_flags.s &= ~DF_DEVICE_OPEN; X fip->ier.c = IE_NONE; /* disable all ints from UART */ X outb (INT_ENABLE_PORT, fip->ier.i); X if (INT_ACK_PORT) X outb (INT_ACK_PORT, fip->int_ack); X if (fip->cflag & HUPCL) X { X fip->mcr.c &= ~MC_SET_RTS; X outb (MDM_CTL_PORT, fip->mcr.i); X /* request hangup */ X fip->device_flags.s |= DF_DO_HANGUP | DF_XMIT_DISABLED; X fip->tty->t_state |= TIMEOUT; X timeout (ttrstrt, fip->tty, X max (fas_ctimes [fip->cflag & CBAUD], X HANGUP_DELAY)); X } X if (fip->device_flags.i & DF_DEVICE_HAS_FIFO) X outb (FIFO_CTL_PORT, STANDARD_FIFO_CLEAR); X} X X/* test device thoroughly */ Xstatic int Xfas_test_device (fip) Xregister struct fas_info *fip; X{ X register unchar *cptr; X int done; X REGVAR; X X /* make sure FIFO is off */ X outb (FIFO_CTL_PORT, STANDARD_FIFO_CLEAR); X X /* set counter divisor */ X outb (LINE_CTL_PORT, LC_ENABLE_DIVISOR); X outb (DIVISOR_LSB_PORT, fas_speeds [B38400]); X outb (DIVISOR_MSB_PORT, fas_speeds [B38400] >> 8); X outb (LINE_CTL_PORT, 0); X X /* switch to local loopback */ X outb (MDM_CTL_PORT, MC_SET_LOOPBACK); X delay (fas_ctimes [B38400]); X X /* clear flags */ X inb (RCV_DATA_PORT); X inb (RCV_DATA_PORT); X inb (LINE_STATUS_PORT); X X /* test pattern */ X cptr = (unchar *) "\377\125\252\045\244\0"; X X do X { X done = FALSE; X X /* test transmitter and receiver with parity odd */ X outb (LINE_CTL_PORT, LC_WORDLEN_8 | LC_ENABLE_PARITY); X if ((inb (LINE_STATUS_PORT) & (LS_XMIT_AVAIL | LS_XMIT_COMPLETE)) X != (LS_XMIT_AVAIL | LS_XMIT_COMPLETE)) X break; X X outb (XMT_DATA_PORT, *cptr); X delay (fas_ctimes [B38400]); X if ((inb (LINE_STATUS_PORT) & LS_RCV_INT) != LS_RCV_AVAIL) X break; X X if (inb (RCV_DATA_PORT) != *cptr) X break; X X /* test transmitter and receiver with parity even */ X outb (LINE_CTL_PORT, LC_WORDLEN_8 | LC_ENABLE_PARITY X | LC_EVEN_PARITY); X if ((inb (LINE_STATUS_PORT) & (LS_XMIT_AVAIL | LS_XMIT_COMPLETE)) X != (LS_XMIT_AVAIL | LS_XMIT_COMPLETE)) X break; X X outb (XMT_DATA_PORT, *cptr); X delay (fas_ctimes [B38400]); X if ((inb (LINE_STATUS_PORT) & LS_RCV_INT) != LS_RCV_AVAIL) X break; X X if (inb (RCV_DATA_PORT) != *cptr) X break; X X done = TRUE; X } while (*cptr++); X X if (done) X { X /* test pattern */ X cptr = (unchar *) "\005\140\012\220\006\120\011\240\017\360\0\0"; X X do X { X done = FALSE; X X /* test modem control and status lines */ X outb (MDM_CTL_PORT, *cptr | MC_SET_LOOPBACK); X if ((inb (MDM_STATUS_PORT) & MS_ANY_PRESENT) X != *(cptr + 1)) X break; X X done = TRUE; X } while (*((ushort *) cptr)++); X } X X /* switch back to normal operation */ X outb (MDM_CTL_PORT, 0); X delay (fas_ctimes [B38400]); X X return (done); X} X X#if defined (NEED_PUT_GETCHAR) X Xint Xasyputchar (arg1) Xunchar arg1; X{ X register struct fas_info *fip; X REGVAR; X X if (!fas_is_initted) X fasinit(); X X fip = &fas_info [0]; X if (fip->device_flags.i & DF_DEVICE_CONFIGURED) X { X while (!(inb (LINE_STATUS_PORT) & LS_XMIT_AVAIL)) X ; X outb (XMT_DATA_PORT, arg1); X if (arg1 == 10) X asyputchar(13); X } X return(0); X} X Xint Xasygetchar () X{ X register struct fas_info *fip; X REGVAR; X X if (!fas_is_initted) X fasinit(); X X fip = &fas_info [0]; X if ((fip->device_flags.i & DF_DEVICE_CONFIGURED) X && (inb (LINE_STATUS_PORT) & LS_RCV_AVAIL)) X return (inb (RCV_DATA_PORT)); X else X return (-1); X} X#endif X X#if defined (NEED_INIT8250) X X/* reset the requested port to be used directly by a DOS process */ Xint Xinit8250 (port, ier) Xushort port, ier; /* ier not used in this stub */ X{ X register struct fas_info *fip; X register uint physical_unit; X int old_level; X REGVAR; X X /* See if the port address matches a port that is used by X the fas driver. X */ X for (physical_unit = 0; physical_unit < fas_physical_units; X physical_unit++) X if (port == fas_port [physical_unit]) X break; X X if (physical_unit >= fas_physical_units) X return(-1); /* port didn't match */ X X fip = fas_info_ptr [physical_unit]; X X old_level = spltty (); X X fip->ier.c = IE_NONE; X outb (INT_ENABLE_PORT, fip->ier.i); X if (INT_ACK_PORT) X outb (INT_ACK_PORT, fip->int_ack); X X fip->mcr.c &= ~MC_SET_RTS; X outb (MDM_CTL_PORT, fip->mcr.i); X X if (fip->device_flags.i & DF_DEVICE_HAS_FIFO) X outb (FIFO_CTL_PORT, STANDARD_FIFO_CLEAR); X X inb (MDM_STATUS_PORT); X inb (RCV_DATA_PORT); X inb (RCV_DATA_PORT); X inb (LINE_STATUS_PORT); X inb (INT_ID_PORT); X splx (old_level); X return (0); X} X#endif SHAR_EOF if test 42626 -ne "`wc -c < 'fas.c'`" then echo shar: "error transmitting 'fas.c'" '(should have been 42626 characters)' fi fi echo shar: "extracting 'fas.h'" '(9355 characters)' if test -f 'fas.h' then echo shar: "will not over-write existing file 'fas.h'" else sed 's/^X//' << \SHAR_EOF > 'fas.h' X/* This file contains various defines for the FAS async driver. X If you change anything here you have to recompile the driver module. X*/ X X#ident "@(#)fas.h 2.05" X X#include <sys/param.h> X#include <sys/types.h> X#include <sys/signal.h> X#include <sys/buf.h> X#include <sys/iobuf.h> X#include <sys/dir.h> X#include <sys/user.h> X#include <sys/errno.h> X#include <sys/tty.h> X#include <sys/conf.h> X#include <sys/sysinfo.h> X#include <sys/file.h> X#include <sys/termio.h> X#include <sys/ioctl.h> X#include <macros.h> X X#if defined (TRUE) X#undef TRUE X#endif X#define TRUE (1) X X#if defined (FALSE) X#undef FALSE X#endif X#define FALSE (0) X X/* Uncomment the following line if you need asyputchar and asygetchar. X Bell Tech needs these. uPort has them burried in the kd device. X*/ X/* #define NEED_PUT_GETCHAR 1 /* */ X X/* Uncomment the following line if you need init8250. DosMerge needs X this function, but only if you link the kernel without the original X asy driver. X*/ X/* #define NEED_INIT8250 /* */ X X/* Initial line control register. Value will only be meaningfull for X asyputchar and asygetchar and they are only meaningfull if X NEED_PUT_GETCHAR is defined. X*/ X#define INITIAL_LINE_CONTROL LC_WORDLEN_8 X X/* Initial baud rate. Value will only be meaningfull for X asyputchar and asygetchar and they are only meaningfull if X NEED_PUT_GETCHAR is defined. X*/ X#define INITIAL_BAUD_RATE (BAUD_BASE/9600) X X/* Initial modem control register. This should probably not have to X be touched. It is here because some terminals used as the console X require one or more of the modem signals set. X*/ X#define INITIAL_MDM_CONTROL 0 X X/****************************************************/ X/* Nothing past this line should have to be changed */ X/****************************************************/ X X#define NUM_INT_VECTORS 16 /* sixteen vectors possible but only X the first eight are normally used X */ X X#define MAX_UNITS 16 /* we will only use that many units */ X X/* Miscellaneous Constants */ X X#define BAUD_BASE (1843200 / 16) /* 115200 bps */ X#define HANGUP_DELAY ((HZ) / 10) /* 100 msec */ X#define HANGUP_TIME ((HZ) / 2) /* 500 msec */ X#define RECV_BUFF_SIZE 1024 /* receiver ring buffer size */ X#define SW_LOW_WATER 512 /* sw flow control trigger levels */ X#define SW_HIGH_WATER 768 X#define HW_LOW_WATER 896 /* hw flow control trigger levels */ X#define HW_HIGH_WATER 960 X X/* define the local open flags */ X X#define OS_DEVICE_CLOSED 0x0000 X#define OS_OPEN_FOR_DIALOUT 0x0001 X#define OS_OPEN_FOR_GETTY 0x0002 X#define OS_WAIT_OPEN 0x0004 X#define OS_NO_DIALOUT 0x0008 X#define OS_CHECK_CARR_ON_OPEN 0x0010 X#define OS_FAKE_CARR_ON 0x0020 X#define OS_UNBLOCK_ON_RING 0x0040 X#define OS_CLOCAL 0x0080 X#define OS_HW_HANDSHAKE 0x0100 X X#define OS_OPEN_STATES (OS_OPEN_FOR_DIALOUT | OS_OPEN_FOR_GETTY) X#define OS_TEST_MASK (OS_OPEN_FOR_DIALOUT | OS_NO_DIALOUT \ X | OS_CHECK_CARR_ON_OPEN | OS_FAKE_CARR_ON \ X | OS_UNBLOCK_ON_RING | OS_CLOCAL \ X | OS_HW_HANDSHAKE) X X/* define the hardware handshake flags */ X X#define HH_CTS MS_CTS_PRESENT X#define HH_DSR MS_DSR_PRESENT X#define HH_BOTH (MS_CTS_PRESENT | MS_DSR_PRESENT) X X/* define the device status flags */ X X#define DF_DEVICE_CONFIGURED 0x0001 /* device is configured */ X#define DF_DEVICE_HAS_FIFO 0x0002 /* it's an NS16550 */ X#define DF_DEVICE_OPEN 0x0004 /* physical device is open */ X#define DF_DEVICE_LOCKED 0x0008 /* physical device locked */ X#define DF_SWISTOP 0x0010 /* input stopped by sw flow control */ X#define DF_SW_FC_REQ 0x0020 /* sw input flow control request */ X#define DF_HWOSTOP 0x0040 /* output stopped by hw handshake */ X#define DF_HWISTOP 0x0080 /* input stopped by hw handshake */ X#define DF_XMIT_DISABLED 0x0100 /* transmitter is disabled */ X#define DF_XMIT_BUSY 0x0200 /* transmitter is busy */ X#define DF_DO_BREAK 0x0400 /* delayed BREAK request */ X#define DF_DO_HANGUP 0x0800 /* delayed hangup request */ X X/* description of the NS16X50 Asychronous Communications Element */ X X#define RCV_DATA_OFFSET 0 X#define XMT_DATA_OFFSET 0 X#define INT_ENABLE_OFFSET 1 X#define INT_ID_OFFSET 2 X#define FIFO_CTL_OFFSET 2 X#define LINE_CTL_OFFSET 3 X#define MDM_CTL_OFFSET 4 X#define LINE_STATUS_OFFSET 5 X#define MDM_STATUS_OFFSET 6 X#define DIVISOR_LSB_OFFSET 0 X#define DIVISOR_MSB_OFFSET 1 X X/* define an easy way to refenence the absolute port addresses */ X X#define RCV_DATA_PORT (fip->rec_data_port) X#define XMT_DATA_PORT (fip->xmt_data_port) X#define INT_ENABLE_PORT (fip->int_ena_port) X#define INT_ID_PORT (fip->int_id_port) X#define FIFO_CTL_PORT (fip->fifo_ctrl_port) X#define LINE_CTL_PORT (fip->line_ctrl_port) X#define MDM_CTL_PORT (fip->mdm_ctrl_port) X#define LINE_STATUS_PORT (fip->line_stat_port) X#define MDM_STATUS_PORT (fip->mdm_stat_port) X#define DIVISOR_LSB_PORT (fip->div_lsb_port) X#define DIVISOR_MSB_PORT (fip->div_msb_port) X#define INT_ACK_PORT (fip->int_ack_port) X X/* modem status port */ X X#define MS_CTS_CHANGED 0x01 X#define MS_DSR_CHANGED 0x02 X#define MS_RING_CHANGED 0x04 X#define MS_DCD_CHANGED 0x08 X#define MS_CTS_PRESENT 0x10 X#define MS_DSR_PRESENT 0x20 X#define MS_RING_PRESENT 0x40 X#define MS_DCD_PRESENT 0x80 X X#define MS_ANY_PRESENT (MS_CTS_PRESENT | MS_DSR_PRESENT | MS_RING_PRESENT \ X | MS_DCD_PRESENT) X X/* interrupt enable port */ X X#define IE_NONE 0x00 X#define IE_RECV_DATA_AVAILABLE 0x01 X#define IE_XMIT_HOLDING_BUFFER_EMPTY 0x02 X#define IE_LINE_STATUS 0x04 X#define IE_MODEM_STATUS 0x08 X X#define IE_INIT_MODE (IE_RECV_DATA_AVAILABLE | IE_XMIT_HOLDING_BUFFER_EMPTY \ X | IE_LINE_STATUS | IE_MODEM_STATUS) X X/* interrupt id port */ X X#define II_NO_INTS_PENDING 0x01 X#define II_CODE_MASK 0x07 X#define II_MODEM_STATE 0x00 X#define II_XMTD_CHAR 0x02 X#define II_RCVD_CHAR 0x04 X#define II_RCV_ERROR 0x06 X#define II_FIFO_TIMEOUT 0x08 X#define II_FIFO_ENABLED 0xC0 X X/* line control port */ X X#define LC_WORDLEN_MASK 0x03 X#define LC_WORDLEN_5 0x00 X#define LC_WORDLEN_6 0x01 X#define LC_WORDLEN_7 0x02 X#define LC_WORDLEN_8 0x03 X#define LC_STOPBITS_LONG 0x04 X#define LC_ENABLE_PARITY 0x08 X#define LC_EVEN_PARITY 0x10 X#define LC_STICK_PARITY 0x20 X#define LC_SET_BREAK_LEVEL 0x40 X#define LC_ENABLE_DIVISOR 0x80 X X/* modem control port */ X X#define MC_SET_DTR 0x01 X#define MC_SET_RTS 0x02 X#define MC_SET_OUT1 0x04 X#define MC_SET_OUT2 0x08 /* tristates int line when false */ X#define MC_SET_LOOPBACK 0x10 X X/* line status port */ X X#define LS_RCV_AVAIL 0x01 X#define LS_OVERRUN 0x02 X#define LS_PARITY_ERROR 0x04 X#define LS_FRAMING_ERROR 0x08 X#define LS_BREAK_DETECTED 0x10 X#define LS_XMIT_AVAIL 0x20 X#define LS_XMIT_COMPLETE 0x40 X X#define LS_RCV_INT (LS_RCV_AVAIL | LS_OVERRUN | LS_PARITY_ERROR \ X | LS_FRAMING_ERROR | LS_BREAK_DETECTED) X X/* fifo control port (NS16550 only) */ X X#define FIFO_ENABLE 0x01 X#define FIFO_CLR_RECV 0x02 X#define FIFO_CLR_XMIT 0x04 X#define FIFO_START_DMA 0x08 X#define FIFO_SIZE_1 0x00 X#define FIFO_SIZE_4 0x40 X#define FIFO_SIZE_8 0x80 X#define FIFO_SIZE_14 0xC0 X#define FIFO_SIZE_MASK 0xC0 X X#define STANDARD_FIFO_CLEAR 0 X#define STANDARD_FIFO_SETUP (FIFO_SIZE_8 | FIFO_ENABLE) X#define STANDARD_FIFO_INIT (STANDARD_FIFO_SETUP | FIFO_CLR_RECV \ X | FIFO_CLR_XMIT) X X#define INPUT_FIFO_SIZE 16 X#define OUTPUT_FIFO_SIZE 16 X X X/* This structure contains everything one would like to know about X an open device. There is one of these for each physical unit. X X We use several unions to eliminate most integer type conversions X at run-time. The standard UNIX V 3.X/386 C compiler forces all X operands in expressions and all function parameters to type int. X To save some time, with the means of unions we deliver type int X at the proper locations while dealing with the original type X wherever int would be slower. X X This is highly compiler implementation specific. But for the sake X of speed the end justifies the means. X*/ X Xstruct fas_info X{ X struct tty *tty; /* the tty structure */ X struct fas_info *next_interrupt_user;/* link to next fas_info struct */ X uint iflag; /* current terminal input flags */ X uint cflag; /* current terminal hardware control flags */ X union { /* flags about the device */ X ushort s; X uint i; X } device_flags; X uint o_state; /* current open state */ X uint po_state; /* previous open state */ X uint h_mask; /* hardware handshake bit mask */ X uint msr; /* modem status register value */ X union { /* modem control register value */ X unchar c; X uint i; X } mcr; X union { /* line control register value */ X unchar c; X uint i; X } lcr; X union { /* interrupt enable register value */ X unchar c; X uint i; X } ier; X uint rec_data_port; /* receive data port */ X uint xmt_data_port; /* transmit data port */ X uint int_ena_port; /* interrupt mask port */ X uint int_id_port; /* interrupt identification port */ X uint fifo_ctrl_port; /* fifo control port (NS16550 only) */ X uint line_ctrl_port; /* line control port */ X uint mdm_ctrl_port; /* modem control port */ X uint line_stat_port; /* line status port */ X uint mdm_stat_port; /* modem status port */ X uint div_lsb_port; /* divisor lsb latch port */ X uint div_msb_port; /* divisor msb latch port */ X uint int_ack_port; /* int ack port */ X uint int_ack; /* int ack value */ X uint recv_ring_cnt; /* receiver ring buffer counter */ X unchar *recv_ring_put_ptr; /* recv ring buf put ptr */ X unchar *recv_ring_take_ptr; /* recv ring buf take ptr */ X unchar recv_buffer [RECV_BUFF_SIZE]; /* recv ring buf */ X}; SHAR_EOF if test 9355 -ne "`wc -c < 'fas.h'`" then echo shar: "error transmitting 'fas.h'" '(should have been 9355 characters)' fi fi exit 0 # End of shell archive -- Uwe Doering | Domain : gemini at netmbx.UUCP Berlin |--------------------------------------------------------------- West Germany | Bangpath : ...!uunet!unido!tmpmbx!netmbx!gemini From jv at mh.nl Thu Jan 4 09:09:36 1990 From: jv at mh.nl (Johan Vromans) Date: 3 Jan 90 22:09:36 GMT Subject: dotime.pl: aid in command timing Message-ID: <JV.90Jan3150937@mhres.mh.nl> The following perl script aids in timing commands. The command is run a number of times, and the avarage statistics are shown together with the statistics of each pass. Example: $ dotime 5 ls -l Running "ls -l" 1 2 3 4 5 done Avg Pass 1 2 3 4 5 ----- ------- ----- ----- ----- ----- real 1.8 3.7 1.4 1.4 1.2 1.2 user 0.6 0.7 0.6 0.6 0.6 0.5 sys 0.6 0.9 0.6 0.5 0.5 0.6 Have fun! Johan ------ begin of dotime -- ascii -- complete ------ #!/usr/bin/perl # @(#)@ dotime 1.1 - dotime # This program requires perl version 3.0, patchlevel 4 or later. # Copyright 1990 Johan Vromans, no rights reserved. # Usage: dotime repeat command die "usage: $0 <repeat> <command>\nstopped" unless $#ARGV >= 1; $repeat = shift (@ARGV); die "invalid repeat: $repeat, stopped" unless (($repeat > 0) && ($repeat < 999)); $command = "@ARGV"; $tt_real = $tt_user = $tt_sys = 0; @t_real = @t_user = @t_sys = (); $| = 1; for ($pass = 1; $pass <= $repeat; $pass++) { print STDOUT ($pass == 1) ? "Running \"$command\" 1 " : "$pass "; open (TIMES, "/bin/time $command 2>&1 |") || die ("cannot open /bin/time $command 2>&1 |"); while (<TIMES>) { if (/^real\s+(\d+\.\d+)\n/) { push (@t_real, 0+$1); $tt_real += $1; } elsif (/^user\s+(\d+\.\d+)/) { push (@t_user, 0+$1); $tt_user += $1; } elsif (/^sys\s+(\d+\.\d+)/) { push (@t_sys , 0+$1); $tt_sys += $1; } } close (TIMES); } $| = 0; print " done\n"; print "\n Avg Pass 1"; for ($pass = 2; $pass <= $repeat; $pass++) { printf "%6d", $pass; } print "\n"; print " ----- -------"; for ($pass = 2; $pass <= $repeat; $pass++) { print " -----"; } print "\n"; for $arg ("real","user","sys ") { eval ("printf \"$arg %5.1f \", \$tt_$arg/$repeat;". "for (\$pass = 1; \$pass <= $repeat; \$pass++) {". "printf \"%6.1f\", \$t_$arg[\$pass-1];". "}". "print \"\n\";"); } ------ end of dotime -- ascii -- complete ------ -- Johan Vromans jv at mh.nl via internet backbones Multihouse Automatisering bv uucp: ..!{uunet,hp4nl}!mh.nl!jv Doesburgweg 7, 2803 PL Gouda, The Netherlands phone/fax: +31 1820 62944/62500 ------------------------ "Arms are made for hugging" ------------------------- From clewis at eci386.uucp Sat Jan 13 09:42:36 1990 From: clewis at eci386.uucp (Chris Lewis) Date: 12 Jan 90 22:42:36 GMT Subject: Official Patch 7 for psroff. Phew.... Message-ID: <1990Jan12.224236.1398@eci386.uucp> This is officially patch 7 for psroff. I made a rather silly botch in patch 6 (diddling with the offset code), and decided to undo the diddling ASAP. Further, to reward you for your indulgence, this now supports SFP downloading to HP laserjets, and ditroff piping to jetroff. Code is in place to do TeX PK font downloading to HP laserjets, but there is a small piece of code missing from the distribution (utility pktype, which converts PK's to SFP's), which I will ship with patch 8. Aside from pktype, patch 8 will *only* be bug fixes. Patch 07 for psroff, please install it. To install the patch, please: cd to your psroff source directory restore the original defs.h and Makefile unshar this patch patch -p < Patch07 Please read README for patch 07 and see if any of the the changes affect your installation. Reconfigure the new defs.h and Makefile to match your system make su root make install #! /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 archive 1 (of 1)." # Contents: ./Intro.07 ./Patch07 # Wrapped by clewis at eci386 on Fri Jan 12 17:35:54 1990 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f './Intro.07' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./Intro.07'\" else echo shar: Extracting \"'./Intro.07'\" \(376 characters\) sed "s/^X//" >'./Intro.07' <<'END_OF_FILE' X Patch 07 for psroff, please install it. X X To install the patch, please: X X cd to your psroff source directory X restore the original defs.h and Makefile X unshar this patch X patch -p < Patch07 X Please read README for patch 07 and see if any of the X the changes affect your installation. X Reconfigure the new defs.h and Makefile to match your system X make X su root X make install END_OF_FILE if test 376 -ne `wc -c <'./Intro.07'`; then echo shar: \"'./Intro.07'\" unpacked with wrong size! fi # end of './Intro.07' fi if test -f './Patch07' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./Patch07'\" else echo shar: Extracting \"'./Patch07'\" \(33956 characters\) sed "s/^X//" >'./Patch07' <<'END_OF_FILE' X*** /usr4/public/src/t2current/./macros/tmac.an Fri Jan 12 17:34:08 1990 X--- ./macros/tmac.an Fri Jan 12 17:35:12 1990 X*************** X*** 2,8 **** X .so %%TMACDIR%%/common.pre X .so %%RTMACDIR%%/tmac.an X .\"Default offset (my version of the man macros uses it). X! .nr )O .963i X .\"See if someone's using the -rO option (ala MM) X .if \nO .nr )O \nOu X .po \n()Ou X--- 2,8 ---- X .so %%TMACDIR%%/common.pre X .so %%RTMACDIR%%/tmac.an X .\"Default offset (my version of the man macros uses it). X! .nr )O .463i X .\"See if someone's using the -rO option (ala MM) X .if \nO .nr )O \nOu X .po \n()Ou X*** /usr4/public/src/t2current/./macros/tmac.m Fri Jan 12 17:34:09 1990 X--- ./macros/tmac.m Fri Jan 12 17:35:12 1990 X*************** X*** 2,8 **** X .so %%TMACDIR%%/common.pre X .\"Default linewidth 6.5 inches & page offset .963 inches. X .if !\nW .nr W 6.5i X! .if !\nO .nr O .963i X .so %%RTMACDIR%%/tmac.m X .\"Clobber MM cut marks. X .rm )k X--- 2,8 ---- X .so %%TMACDIR%%/common.pre X .\"Default linewidth 6.5 inches & page offset .963 inches. X .if !\nW .nr W 6.5i X! .if !\nO .nr O .463i X .so %%RTMACDIR%%/tmac.m X .\"Clobber MM cut marks. X .rm )k X*** /usr4/public/src/t2current/./macros/tmac.s Fri Jan 12 17:34:09 1990 X--- ./macros/tmac.s Fri Jan 12 17:35:12 1990 X*************** X*** 1,5 **** X--- 1,9 ---- X .\"@(#)ident tmac.s %I% %E% X .so %%TMACDIR%%/common.pre X+ .\"Trick MS into thinking the initial page offset is .25i less than normal. X+ .\"(because of the .5inch rightshift in troff2ps) X+ .\"Then, defaulted MS will be exactly centered. X+ .po .713i X .so %%RTMACDIR%%/tmac.s X .\"Clobber cut marks. X .rm CM X*** /usr4/public/src/t2current/./gfnttab.sh Fri Jan 12 17:33:44 1990 X--- ./gfnttab.sh Fri Jan 12 17:34:44 1990 X*************** X*** 1,5 **** X : X! #@(#)gfnttab.sh 1.8 89/12/13 X # Set this to something non-null if you need a.out.h/COFF X # headers on your width files, and the COFF/HEADERSIZE X # defines cause dit2catwid to generate width tables that X--- 1,5 ---- X : X! #@(#)gfnttab.sh 1.9 90/01/12 X # Set this to something non-null if you need a.out.h/COFF X # headers on your width files, and the COFF/HEADERSIZE X # defines cause dit2catwid to generate width tables that X*************** X*** 39,44 **** X--- 39,48 ---- X then X sed -e '1,/charset/d' S2 >> /tmp/S X fi X+ if [ -r ST ] X+ then X+ sed -e '1,/charset/d' ST >> /tmp/S X+ fi X else X echo "WARNING: no symbol font!" X > /tmp/S X*************** X*** 66,72 **** X *) continue ;; X esac X trc=0 X! if [ "$i" != S2 ] X then X Cline=`sed -e '1q' $i | sed -e 's/^#[ ]*//'` X echo "$i $Cline" >> $ffile X--- 70,76 ---- X *) continue ;; X esac X trc=0 X! if [ "$i" != S2 -a "$i" != ST ] X then X Cline=`sed -e '1q' $i | sed -e 's/^#[ ]*//'` X echo "$i $Cline" >> $ffile X*************** X*** 75,81 **** X S) X args="-s /tmp/S R" X ;; X! S2) X continue X ;; X *) X--- 79,85 ---- X S) X args="-s /tmp/S R" X ;; X! S2 | ST) X continue X ;; X *) X*** /usr4/public/src/t2current/./lj.c Fri Jan 12 17:34:18 1990 X--- ./lj.c Fri Jan 12 17:34:46 1990 X*************** X*** 52,70 **** X X #ifndef SVR3 X #ifndef lint X! static char SCCSid[] = "@(#)lj.c: 1.11 Copyright 89/12/22 11:02:10 Chris Lewis"; X #endif X #else X! #ident "@(#)lj.c: 1.11 Copyright 89/12/22 11:02:10 Chris Lewis" /*(SVR3)*/ X #endif X X- #define USED 1 X- #define BUILTIN 2 X struct ljFts { X char *troffName; X char *fontSeq; X char *ascName; X! int flags; X } ljFts[MAXFONT+1]; X X struct ljFts *t2ljf[8]; X--- 52,71 ---- X X #ifndef SVR3 X #ifndef lint X! static char SCCSid[] = "@(#)lj.c: 1.14 Copyright 90/01/12 17:28:24 Chris Lewis"; X #endif X #else X! #ident "@(#)lj.c: 1.14 Copyright 90/01/12 17:28:24 Chris Lewis" /*(SVR3)*/ X #endif X X struct ljFts { X char *troffName; X char *fontSeq; X char *ascName; X! long loaded; /* is pointsize already there? */ X! long builtin; /* is pointsize builtin? */ X! long sfp; /* is pointsize SFP? */ X! long pk; /* is pointsize a PK? */ X } ljFts[MAXFONT+1]; X X struct ljFts *t2ljf[8]; X*************** X*** 93,133 **** X putchar(d); X } X X ljSetFont(font, points) X int font, points; { X X if (lastPoints != points || font != lastFont) { X register char *p; X #ifdef DOWNLOAD X! if (!(ljFts[font].flags&(USED|BUILTIN))) { X char buf[512]; X FILE *fontfile; X int count; X! sprintf(buf, "%s/%s.%s.%d", LIBDIR, be->bename, X! ljFts[font].troffName, points); X! if ((fontfile = fopen(buf, "r")) == NULL) { X! fprintf(stderr, "%s: Cannot open fontfile %s\n", progname, X buf); X } else { X! while(0 > (count = fread(buf, sizeof(char), 512, fontfile))) X fwrite(buf, sizeof(char), count, stdout); X! fclose(fontfile); X } X } X #endif X! ljFts[font].flags |= USED; X! for (p = ljFts[font].fontSeq; *p; p++) { X! if (*p == '\\') { X! putoct(p+1); X! p+=3; X! } else X! putchar(*p); X } X- printf("\033(s%dV", points); X- lastPoints = points; X- lastFont = font; X } X- X } X X ljChar(x, y, font, points, troffChar) X--- 94,212 ---- X putchar(d); X } X X+ static X+ long X+ ptcvt(points) X+ int points; { X+ switch (points) { X+ case 6: return 0; break; X+ case 7: return 1; break; X+ case 8: return 2; break; X+ case 9: return 3; break; X+ case 10: return 4; break; X+ case 11: return 5; break; X+ case 12: return 6; break; X+ case 14: return 7; break; X+ case 16: return 8; break; X+ case 18: return 9; break; X+ case 20: return 10; break; X+ case 22: return 11; break; X+ case 24: return 12; break; X+ case 28: return 13; break; X+ case 36: return 14; break; X+ default: return 15; break; X+ } X+ } X+ X+ static int sizes[] = {6, 7, 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 28, 36}; X+ X+ static X+ long X+ ptbit(points) X+ int points; { X+ return(1 << ptcvt(points)); X+ } X+ X ljSetFont(font, points) X int font, points; { X+ int pointdef = ptbit(points); X X if (lastPoints != points || font != lastFont) { X register char *p; X+ X+ lastPoints = points; X+ lastFont = font; X+ X+ #ifdef DOWNLOAD X+ if (ljFts[font].builtin&pointdef) { X+ #else X+ { X+ #endif X+ /* if builtin font, select it by characteristic */ X+ for (p = ljFts[font].fontSeq; *p; p++) { X+ if (*p == '\\') { X+ putoct(p+1); X+ p+=3; X+ } else X+ putchar(*p); X+ } X+ printf("\033(s%dV", points); X+ return; X+ } X+ X #ifdef DOWNLOAD X! if (!(ljFts[font].loaded&pointdef) && X! ((ljFts[font].sfp&pointdef) || (ljFts[font].pk&pointdef))) { X! X! /* font is not loaded, but is either sfp or pk format */ X! X! int sfp = ljFts[font].sfp&pointdef; X! X char buf[512]; X FILE *fontfile; X int count; X! X! if (sfp) { X! sprintf(buf, "%s/lj/sfp/%s.%d", LIBDIR, X! ljFts[font].troffName, points); X! fontfile = fopen(buf, "r"); X! } else { X! sprintf(buf, "%s/pktype -sS %s/lj/pk/%s.%d", LIBDIR, X! LIBDIR, ljFts[font].troffName, points); X! fontfile = popen(buf, "r"); X! } X! X! X! if (!fontfile) { X! fprintf(stderr, "%s: Cannot open fontfile via %s\n", progname, X buf); X } else { X! DEBUGPRINTF("Loading font %s.%d via %s\n", X! ljFts[font].troffName, points, buf); X! printf("\033*c%dD", (font << 4) + ptcvt(points)); X! printf("\033*c4F"); X! while(0 < (count = fread(buf, sizeof(char), 512, fontfile))) X fwrite(buf, sizeof(char), count, stdout); X! if (sfp) X! fclose(fontfile); X! else X! if (pclose(fontfile)) X! fprintf(stderr, "%s: pktype failure: %s\n", X! progname, buf); X } X+ ljFts[font].loaded |= pointdef; X } X #endif X! if (ljFts[font].loaded&pointdef) X! /* font is already loaded, select it by fontid */ X! printf("\033(%dX", (font << 4) + ptcvt(points)); X! else { X! fprintf(stderr, "Could not load font %s.%d\n", X! ljFts[font].troffName, points); X! /* fake it as builtin so no more complaints */ X! ljFts[font].builtin |= pointdef; X } X } X } X X ljChar(x, y, font, points, troffChar) X*************** X*** 208,221 **** X FILE *f; { X struct ljFts *p = ljFts; X extern char *malloc(); X! int flags; X char rbuf[512], nbuf[512], ljbuf[512], seqbuf[512]; X while(fgets(rbuf, sizeof(rbuf), f)) { X if (rbuf[0] == '#') X continue; X! switch(sscanf(rbuf, "%s%s%s%d", nbuf, ljbuf, seqbuf, &flags)) { X default: X break; X case 4: X if (nbuf[0] == '#') X break; X--- 287,303 ---- X FILE *f; { X struct ljFts *p = ljFts; X extern char *malloc(); X! char flags[20]; X char rbuf[512], nbuf[512], ljbuf[512], seqbuf[512]; X+ int i; X while(fgets(rbuf, sizeof(rbuf), f)) { X if (rbuf[0] == '#') X continue; X! switch(sscanf(rbuf, "%s%s%s%s", nbuf, ljbuf, seqbuf, flags)) { X default: X break; X+ case 3: X+ strcpy(flags, ""); X case 4: X if (nbuf[0] == '#') X break; X*************** X*** 230,242 **** X strcpy(p->ascName, ljbuf); X p->fontSeq = malloc((unsigned) strlen(seqbuf) + 1); X strcpy(p->fontSeq, seqbuf); X! p->flags = flags; X p++; X } X } X #ifdef DEBUG X! for (p = ljFts; p->troffName; p++) X DEBUGPRINTF("%s -> %s, seq: %s\n", p->troffName, p->ascName, p->fontSeq); X #endif X } X X--- 312,351 ---- X strcpy(p->ascName, ljbuf); X p->fontSeq = malloc((unsigned) strlen(seqbuf) + 1); X strcpy(p->fontSeq, seqbuf); X! for (i = 0; i < 15; i++) { X! if (i < strlen(flags)) { X! switch(flags[i]) { X! case 'b': p->builtin |= (1 << i); break; X! case 's': p->sfp |= (1 << i); break; X! case 'p': p->pk |= (1 << i); break; X! case ' ': break; X! case 'n': break; X! default: X! fprintf(stderr, "Bad font/point specifier in %s\n", X! flags); X! break; X! } X! } X! } X p++; X } X } X #ifdef DEBUG X! for (p = ljFts; p->troffName; p++) { X DEBUGPRINTF("%s -> %s, seq: %s\n", p->troffName, p->ascName, p->fontSeq); X+ for (i = 0; i < 15; i++) { X+ DEBUGPRINTF(" Size %d (%d points) is: ", i, sizes[i]); X+ if (p->builtin&(1 << i)) { X+ DEBUGPRINTF("builtin\n"); X+ } else if (p->sfp&(1 << i)) { X+ DEBUGPRINTF("an SFP\n"); X+ } else if (p->pk&(1 << i)) { X+ DEBUGPRINTF("a PK\n"); X+ } else { X+ DEBUGPRINTF("non existent\n"); X+ } X+ } X+ } X #endif X } X X*** /usr4/public/src/t2current/./dt.h Fri Jan 12 17:34:18 1990 X--- ./dt.h Fri Jan 12 17:34:48 1990 X*************** X*** 14,23 **** X X #ifndef SVR3 X #ifndef lint X! static char dtID[] = "@(#)dt.h: 1.3 Copyright 90/01/08 16:31:05 Chris Lewis"; X #endif X #else X! #ident "@(#)dt.h: 1.3 Copyright 90/01/08 16:31:05 Chris Lewis" X #endif X X /* This is actually done in the back-end */ X--- 14,23 ---- X X #ifndef SVR3 X #ifndef lint X! static char dtID[] = "@(#)dt.h: 1.3 Copyright 90/01/12 13:58:31 Chris Lewis"; X #endif X #else X! #ident "@(#)dt.h: 1.3 Copyright 90/01/12 13:58:31 Chris Lewis" X #endif X X /* This is actually done in the back-end */ X*************** X*** 24,34 **** X #define DTRESOLUTION 300 X /* Length scaling factor */ X #define DTSCALEFACTOR ((double) dtresolution / TROFFRESOLUTION) X! #define TROFF2DTX(x) ((x) * DTSCALEFACTOR) X /* 11" paper length */ X #define TROFF2DTY(y) ((y) * DTSCALEFACTOR) X X extern double pagelength; X X #define DTLIB "lib" X #define DTFONTS "fonts" X--- 24,38 ---- X #define DTRESOLUTION 300 X /* Length scaling factor */ X #define DTSCALEFACTOR ((double) dtresolution / TROFFRESOLUTION) X! /* Troff assumes 7.5" paper width, most macro packages print in X! 6.5" area within that. Sooo, we'll center the paperwidth on the X! physical page - implying .5" inch physical margins.*/ X! #define TROFF2DTX(x) ((x + pageoffset) * DTSCALEFACTOR) X /* 11" paper length */ X #define TROFF2DTY(y) ((y) * DTSCALEFACTOR) X X extern double pagelength; X+ extern double pageoffset; X X #define DTLIB "lib" X #define DTFONTS "fonts" X*** /usr4/public/src/t2current/./psroff.sh Fri Jan 12 17:34:20 1990 X--- ./psroff.sh Fri Jan 12 17:34:50 1990 X*************** X*** 11,26 **** X # Author: Chris Lewis X # Specs: troff driver X # X! #ident "@(#)psroff.sh: 1.24 Copyright 90/01/03 11:48:55 Chris Lewis" X troff=troff X #troff=/usr2/clewis/src/spx/tnroff/troff X term=false X fail=false X type=`basename $0 | sed -e 's/^\(..\).*/\1/'` X copies=1 X for i in $* X do X case $i in X -F) X fail=true X ;; X--- 11,30 ---- X # Author: Chris Lewis X # Specs: troff driver X # X! #ident "@(#)psroff.sh: 1.26 Copyright 90/01/12 16:42:08 Chris Lewis" X troff=troff X #troff=/usr2/clewis/src/spx/tnroff/troff X term=false X fail=false X+ pageoffset='.5i' X type=`basename $0 | sed -e 's/^\(..\).*/\1/'` X copies=1 X for i in $* X do X case $i in X+ -O*) X+ pageoffset=`echo $i | sed -e 's/-O//'` X+ ;; X -F) X fail=true X ;; X*************** X*** 90,95 **** X--- 94,101 ---- X esac X done X X+ debug="$debug -O$pageoffset" X+ X if [ -z "$seenfiles" ] X then X files="$files -" X*************** X*** 103,110 **** X--- 109,129 ---- X fi X X # If you add a driver, you will have to add it here too: X+ # You can add ditroff output variants by adding X+ # lines analogous to the "jt" variant. X+ X+ realtype=$type X+ trofftype=$type X+ X case $type in X lj) OUTPUT="%%LJOUTPUT%%" ;; X+ tp) OUTPUT="%%TPOUTPUT%%" X+ realtype=dt X+ trofftype=ps X+ ;; X+ jt) OUTPUT="%%JTOUTPUT%%" X+ realtype=dt X+ ;; X lk) OUTPUT="%%LKOUTPUT%%" ;; X dj) OUTPUT="%%DJOUTPUT%%" ;; X ps) OUTPUT="%%PSOUTPUT%%" ;; X*************** X*** 114,127 **** X exit 1 X ;; X esac X if $fail X then X! $troff -t -T$type $args $files > /dev/null X elif $term X then X! ( $troff -t -T$type $args $files 2>&1 ) | $t2 $length -T$type $debug X exit $? X else X! eval "( $troff -t -T$type $args $files 2>&1 ) | $t2 $length -T$type $debug $OUTPUT" X exit $? X fi X--- 133,147 ---- X exit 1 X ;; X esac X+ X if $fail X then X! $troff -t -T$trofftype $args $files > /dev/null X elif $term X then X! ( $troff -t -T$trofftype $args $files 2>&1 ) | $t2 $length -T$realtype $debug X exit $? X else X! eval "( $troff -t -T$trofftype $args $files 2>&1 ) | $t2 $length -T$realtype $debug $OUTPUT" X exit $? X fi X*** /usr4/public/src/t2current/./ps.h Fri Jan 12 17:34:20 1990 X--- ./ps.h Fri Jan 12 17:34:50 1990 X*************** X*** 13,22 **** X X #ifndef SVR3 X #ifndef lint X! static char psID[] = "@(#)ps.h: 1.17 Copyright 90/01/08 16:31:08 Chris Lewis"; X #endif X #else X! #ident "@(#)ps.h: 1.17 Copyright 90/01/08 16:31:08 Chris Lewis" X #endif X X /* Points per inch (default PostScript resolution) */ X--- 13,22 ---- X X #ifndef SVR3 X #ifndef lint X! static char psID[] = "@(#)ps.h: 1.18 Copyright 90/01/12 14:00:36 Chris Lewis"; X #endif X #else X! #ident "@(#)ps.h: 1.18 Copyright 90/01/12 14:00:36 Chris Lewis" X #endif X X /* Points per inch (default PostScript resolution) */ X*************** X*** 23,33 **** X #define PSRESOLUTION 72 X /* Length scaling factor */ X #define PSSCALEFACTOR ((double) PSRESOLUTION / TROFFRESOLUTION) X! #define TROFF2PSX(x) ((x) * PSSCALEFACTOR) X /* 11" paper length (note the reversed sign!) */ X #define TROFF2PSY(y) ((pagelength - (y)) * PSSCALEFACTOR) X X extern double pagelength; X X #define LASTPSFONT ('O') X X--- 23,37 ---- X #define PSRESOLUTION 72 X /* Length scaling factor */ X #define PSSCALEFACTOR ((double) PSRESOLUTION / TROFFRESOLUTION) X! /* Troff assumes 7.5" paper width, most macro packages print in X! 6.5" area within that. Sooo, we'll center the paperwidth on the X! physical page - implying .5" inch physical margins.*/ X! #define TROFF2PSX(x) ((x + pageoffset) * PSSCALEFACTOR) X /* 11" paper length (note the reversed sign!) */ X #define TROFF2PSY(y) ((pagelength - (y)) * PSSCALEFACTOR) X X extern double pagelength; X+ extern double pageoffset; X X #define LASTPSFONT ('O') X X*** /usr4/public/src/t2current/./lj.h Fri Jan 12 17:34:22 1990 X--- ./lj.h Fri Jan 12 17:34:53 1990 X*************** X*** 16,25 **** X X #ifndef SVR3 X #ifndef lint X! static char ljID[] = "@(#)lj.h: 1.8 Copyright 90/01/08 16:31:10 Chris Lewis"; X #endif X #else X! #ident "@(#)lj.h: 1.8 Copyright 90/01/08 16:31:10 Chris Lewis" X #endif X X /* We're using decipoints */ X--- 16,25 ---- X X #ifndef SVR3 X #ifndef lint X! static char ljID[] = "@(#)lj.h: 1.8 Copyright 90/01/12 13:58:38 Chris Lewis"; X #endif X #else X! #ident "@(#)lj.h: 1.8 Copyright 90/01/12 13:58:38 Chris Lewis" X #endif X X /* We're using decipoints */ X*************** X*** 27,39 **** X /* Length scaling factor */ X #define LJSCALEFACTOR ((double) LJRESOLUTION / TROFFRESOLUTION) X X! #define TROFF2LJX(x) ((x) * LJSCALEFACTOR) X X /* 11" paper length */ X #define TROFF2LJY(y) ((y) * LJSCALEFACTOR) X X /* change the DJ */ X #define TROFF2DJX(x) TROFF2LJX(x) X /* for length, we want .25 inch */ X /* margins top and bottom, so we'll */ X /* scale the requests and add .25 inch */ X--- 27,50 ---- X /* Length scaling factor */ X #define LJSCALEFACTOR ((double) LJRESOLUTION / TROFFRESOLUTION) X X! /* Troff assumes 7.5" paper width, most macro packages print in X! 6.5" area within that. Sooo, we'll center the paperwidth on the X! physical page - implying .5" inch physical margins.*/ X! #define TROFF2LJX(x) ((x + pageoffset) * LJSCALEFACTOR) X X /* 11" paper length */ X #define TROFF2LJY(y) ((y) * LJSCALEFACTOR) X X+ /* These won't work (ron at mlfarm, */ X+ /* 10.22.89) -- the offset of 1/2 inch */ X+ /* spoils it, and the length scaling */ X+ /* won't fit on a page. I'll only */ X /* change the DJ */ X+ #ifdef BROKEN_XENIX X+ #define TROFF2DJX(x) ((x + pageoffset) * LJSCALEFACTOR) X+ #else X #define TROFF2DJX(x) TROFF2LJX(x) X+ #endif X /* for length, we want .25 inch */ X /* margins top and bottom, so we'll */ X /* scale the requests and add .25 inch */ X*************** X*** 41,46 **** X--- 52,58 ---- X X X extern double pagelength; X+ extern double pageoffset; X X #define LASTLJFONT ('O') X X*** /usr4/public/src/t2current/./troff2.c Fri Jan 12 17:33:51 1990 X--- ./troff2.c Fri Jan 12 17:34:54 1990 X*************** X*** 15,24 **** X X #ifndef SVR3 X #ifndef lint X! static char SCCSid[] = "@(#)troff2.c: 1.23 Copyright 89/12/12 15:50:48 Chris Lewis"; X #endif X #else X! #ident "@(#)troff2.c: 1.23 Copyright 89/12/12 15:50:48 Chris Lewis" X #endif X X #define ESC 0x80 X--- 15,24 ---- X X #ifndef SVR3 X #ifndef lint X! static char SCCSid[] = "@(#)troff2.c: 1.25 Copyright 90/01/12 16:42:13 Chris Lewis"; X #endif X #else X! #ident "@(#)troff2.c: 1.25 Copyright 90/01/12 16:42:13 Chris Lewis" X #endif X X #define ESC 0x80 X*************** X*** 51,56 **** X--- 51,57 ---- X #define CTOINT(val,sig) ((~c)&sig) X X double pagelength = 11 * TROFFRESOLUTION; X+ double pageoffset = .5; X X #define CFONT (((mag == UPPER)<<2)|((rail == UPPER)<<1)|(tilt==DOWN)) X #ifdef FONT4 X*************** X*** 87,93 **** X else X driver = "ZZ"; X X! while((c = getopt(argc, argv, "T:VDd:l:MR:")) != EOF) X switch (c) { X case 'T': X driver = optarg; X--- 88,94 ---- X else X driver = "ZZ"; X X! while((c = getopt(argc, argv, "O:T:VDd:l:MR:")) != EOF) X switch (c) { X case 'T': X driver = optarg; X*************** X*** 125,130 **** X--- 126,134 ---- X break; X case 'd': X driver = optarg; X+ break; X+ case 'O': X+ pageoffset = calc(optarg); X break; X case 'l': X pagelength = calc(optarg); X*** /usr4/public/src/t2current/./defs.h Fri Jan 12 17:34:24 1990 X--- ./defs.h Fri Jan 12 17:34:56 1990 X*************** X*** 17,23 **** X #define LIBDIR "/usr/lib/troff2" X #endif X X! #define T2VERSION "Release 1 Patchlevel 6 89/12/29" X X /* Configuration parameters: X */ X--- 17,23 ---- X #define LIBDIR "/usr/lib/troff2" X #endif X X! #define T2VERSION "Release 1 Patchlevel 7 90/01/10" X X /* Configuration parameters: X */ X*************** X*** 118,127 **** X X #ifndef SVR3 X #ifndef lint X! static char defid[] = "@(#)defs.h: 1.24 Copyright 89/12/29 15:24:49 Chris Lewis"; X #endif X #else X! #ident "@(#)defs.h: 1.24 Copyright 89/12/29 15:24:49 Chris Lewis" X #endif X X #include <stdio.h> X--- 118,127 ---- X X #ifndef SVR3 X #ifndef lint X! static char defid[] = "@(#)defs.h: 1.25 Copyright 90/01/10 19:28:40 Chris Lewis"; X #endif X #else X! #ident "@(#)defs.h: 1.25 Copyright 90/01/10 19:28:40 Chris Lewis" X #endif X X #include <stdio.h> X*** /usr4/public/src/t2current/./ps.c Fri Jan 12 17:34:25 1990 X--- ./ps.c Fri Jan 12 17:34:59 1990 X*************** X*** 18,27 **** X X #ifndef SVR3 X #ifndef lint X! static char SCCSid[] = "@(#)ps.c: 1.33 Copyright 90/01/05 20:16:44 Chris Lewis"; X #endif X #else X! #ident "@(#)ps.c: 1.33 Copyright 90/01/05 20:16:44 Chris Lewis" /*(SVR3)*/ X #endif X X /* ps.c will generate some additional "print" commands to cause X--- 18,27 ---- X X #ifndef SVR3 X #ifndef lint X! static char SCCSid[] = "@(#)ps.c: 1.34 Copyright 90/01/10 19:39:57 Chris Lewis"; X #endif X #else X! #ident "@(#)ps.c: 1.34 Copyright 90/01/10 19:39:57 Chris Lewis" /*(SVR3)*/ X #endif X X /* ps.c will generate some additional "print" commands to cause X*************** X*** 570,575 **** X--- 570,576 ---- X #ifndef NOCHATTER X EMITPS("(Execution time (seconds): ) print\n"); X EMITPS("usertime btime sub 0.001 mul ( ) cvs print\n"); X+ EMITPS("(; Pages: %d) print\n", currentPage); X EMITPS("(\\n) print\n"); X #endif X EMITPS("GlobalSave restore\n"); X*** /usr4/public/src/t2current/./psroff.1 Fri Jan 12 17:34:26 1990 X--- ./psroff.1 Fri Jan 12 17:35:04 1990 X*************** X*** 1,4 **** X! .\"Copyright 1988 by Chris Lewis 1.8 89/12/29 X .TH PSROFF 1 local X .SH NAME X psroff,ljroff,xxroff \- troff replacement for PostScript or other printers X--- 1,4 ---- X! .\"Copyright 1988 by Chris Lewis 1.10 90/01/12 X .TH PSROFF 1 local X .SH NAME X psroff,ljroff,xxroff \- troff replacement for PostScript or other printers X*************** X*** 6,11 **** X--- 6,12 ---- X .IB xx roff X [-D] [-X] [-M] [-F] X .RI "[-R" nn "]" X+ .RI "[-O" offset "]" X .RI "[-T" xx "]" X .RI "[-rL" length "]" X .RI [ troffopts ] X*************** X*** 48,53 **** X--- 49,65 ---- X .I xx X will select which printer codes to generate. X .P X+ As shipped, the X+ .I psroff X+ .RI -T xx X+ understands ``ps'' (postscript), ``tp'' (ditroff->tpscript also postscript), X+ ``jt'' (ditroff->jetroff (HP PCL)), X+ ``lj'' (HP PCL), X+ ``lk'' (HP PCL with K cartridge), X+ and X+ ``dt'' (HP Deskjet). X+ However, one or more of the above may not be supported at your site. X+ .P X .I Psroff X invokes X .I troff X*************** X*** 62,67 **** X--- 74,97 ---- X used (see the documentation for MM and X .I troff2ps X for more details). X+ .P X+ The "-O" option allows you to specify a physical offset from the X+ left margin of the page. X+ Normal troff prohibits the total page offset plus line length from X+ being greater than 7.54 inches, which means that it would be impossible X+ to centre a 7.54 inch line on 8.5 inch wide paper. X+ The default -O is .5 inch (specified as .5i), which allows you to X+ centre a 7.5 inch line with a zero troff offset (.po directive). X+ The .5 inch default was originally a hardcoded offset in troff2ps. X+ The macro adapters have been tuned to centre the default line length X+ in a 8.5 inch page. X+ The value for the "-O" option can take any form allowed by the "-rL" X+ option in X+ .IR troffps . X+ This is not implemented as "-rO", because troff itself isn't supposed X+ to know about it. X+ The real line offset on a sheet of paper is the sum of the -O and X+ troff page offset (.po directive). X .SH MACROS X Included with the X .I psroff X*** /usr4/public/src/t2current/./Makefile Fri Jan 12 17:34:27 1990 X--- ./Makefile Fri Jan 12 17:35:04 1990 X*************** X*** 12,18 **** X # Note: This is a System V Makefile, so you may X # have some problems making a few of the items. X # X! #ident "@(#)Makefile: 1.44 Copyright 90/01/08 16:31:17 Chris Lewis" X X # Set to where you want the user-interfaces to go X BINDIR = /usr/lbin X--- 12,18 ---- X # Note: This is a System V Makefile, so you may X # have some problems making a few of the items. X # X! #ident "@(#)Makefile: 1.48 Copyright 90/01/12 17:28:39 Chris Lewis" X X # Set to where you want the user-interfaces to go X BINDIR = /usr/lbin X*************** X*** 29,36 **** X LJOUTPUT = | lp -dlaser -og -n$$copies X DJOUTPUT = $(LJOUTPUT) X LKOUTPUT = $(LJOUTPUT) X! # Ditroff output X! DTOUTPUT = | /usr/lib/troff/tpscript | rlp -dgate!AppleLaser -n$$copies X # Testing type: X TTYPE = ps X TFLAGS = -mm X--- 29,40 ---- X LJOUTPUT = | lp -dlaser -og -n$$copies X DJOUTPUT = $(LJOUTPUT) X LKOUTPUT = $(LJOUTPUT) X! # Tpscript output X! TPOUTPUT = | /usr/lib/troff/tpscript | rlp -dgate!AppleLaser -n$$copies X! # Jetroff output X! JTOUTPUT = | djet | rlp -dgate!AppleLaser X! # DiTROFF output (outputs ditroff on screen) X! DTOUTPUT = X # Testing type: X TTYPE = ps X TFLAGS = -mm X*************** X*** 55,61 **** X X # Dinna touch from here on X MAIN = troff2.o utils.o t2conf.o X! BACKENDS = lj.o ps.o lj.o ljtables.o dt.o X PLIBDIR = $(LIBDIR)/lib X X MACROS = $(TMACDIR)/common.post $(TMACDIR)/common.pre \ X--- 59,65 ---- X X # Dinna touch from here on X MAIN = troff2.o utils.o t2conf.o X! BACKENDS = lj.o ps.o ljtables.o dt.o X PLIBDIR = $(LIBDIR)/lib X X MACROS = $(TMACDIR)/common.post $(TMACDIR)/common.pre \ X*************** X*** 73,81 **** X--- 77,87 ---- X X SEDSCRIPT = sed -e 's;%%LJOUTPUT%%;$(LJOUTPUT);g' \ X -e 's;%%LKOUTPUT%%;$(LKOUTPUT);g' \ X+ -e 's;%%JTOUTPUT%%;$(JTOUTPUT);g' \ X -e 's;%%DJOUTPUT%%;$(DJOUTPUT);g' \ X -e 's;%%PSOUTPUT%%;$(PSOUTPUT);g' \ X -e 's;%%DTOUTPUT%%;$(DTOUTPUT);g' \ X+ -e 's;%%TPOUTPUT%%;$(TPOUTPUT);g' \ X -e 's;%%LIBDIR%%;$(LIBDIR);g' \ X -e 's;%%TMACDIR%%;$(TMACDIR);g' \ X -e 's;%%RTMACDIR%%;$(RTMACDIR);g' X*************** X*** 117,122 **** X--- 123,130 ---- X confid.ps lethead.ps X X all: $(UTILLIST) fonts X+ X+ utils: $(UTILLIST) X X macros: $(MACROS) X X*** /usr4/public/src/t2current/./fonts.lj Fri Jan 12 17:33:23 1990 X--- ./fonts.lj Fri Jan 12 17:35:07 1990 X*************** X*** 1,9 **** X! #@(#)fonts.lj 1.2 89/12/04 X # four fields: X # troff-name english-name HPLJ-code-to-transmit flags X # flags of interest: 02 indicates that it's a built-in font. X # \nnn sequences are only recognized in the HPLJ-code field. X # Don't put in *any* extraneous spaces. X # +----------------------------- Symbol set X # | +---------------------- 0=fixed, 1=proportional X # | | +-------------------- 0=upright, 1=italics X--- 1,42 ---- X! #@(#)fonts.lj 1.3 90/01/12 X # four fields: X # troff-name english-name HPLJ-code-to-transmit flags X # flags of interest: 02 indicates that it's a built-in font. X # \nnn sequences are only recognized in the HPLJ-code field. X # Don't put in *any* extraneous spaces. X+ # X+ # The source flags is a string of characters up to 15 long, X+ # where each character indicates where the font at a specific size X+ # *is*, and the point sizes go from troff's lowest to highest. X+ # The character mapping is: X+ # X+ # n: non existant - you will get a complaint if selected. X+ # b: builtin - font is selected by *characteristic*, X+ # and is either a ROM font/size, or a manually downloaded X+ # one. I suggest that if you manually download fonts, X+ # you select fontid's > 1000. (see below) X+ # s: there is a SFP at LIBDIR/lj/sfp/<troffname>.pointsize X+ # where troffname is troff's name for a font. Eg: "R". X+ # And pointsize is troff's point size. X+ # p: there is a TeX PK format font file at X+ # LIBDIR/lj/pk/<troffname>.pointsize. see "s" for X+ # naming conventions. X+ # X+ # SFP and PK's are downloaded automatically by the LJ driver. X+ # X+ # They are assigned a LJ fontid calculated by: X+ # "index of the font in this table" * 16 + "index of pointsize" X+ # (6 is 0, 7 is 1, 36 is 14.) X+ # They are selected by this fontid. (eg: it doesn't matter if the X+ # font descriptor in a SFP has the correct characteristics or not) X+ # X+ # non-existant ones give you a complaint if they're used, and X+ # selected as if they were builtin. (which means that they might X+ # even work reasonably...) X+ # X+ # If the source string is too short or omitted, the missing point X+ # sizes are assumed "builtin". Ditto if DOWNLOAD is undefined. X+ # X # +----------------------------- Symbol set X # | +---------------------- 0=fixed, 1=proportional X # | | +-------------------- 0=upright, 1=italics X*************** X*** 10,26 **** X # | | | +----------------- stroke weight -7...7 X # | | | | +-------------- Typeface X # | | | | | X! # | | | | | +----------- 2 == builtin X # | | | | | | X # v v v v v v X! R Times-Roman \033(8U\033(s1p0s00b05T 2 X! I Times-Italic \033(8U\033(s1p1s-3b05T 2 X! B Times-Bold \033(8U\033(s1p0s03b05T 2 X! S Symbol \033(8U\033(s0p0s00b03T 2 X! BI Times-BoldItalic \033(8U\033(s1p1s03b05T 2 X! C Courier \033(8U\033(s0p0s00b03T 2 X! CI Courier-Italic \033(8U\033(s0p1s-3b03T 2 X! CB Courier-Bold \033(8U\033(s0p0s03b03T 2 X! L LinePrinter \033(8U\033(s0p0s00b00T 2 X! LI LinePrinter-Ital \033(8U\033(s0p1s-3b00T 2 X! LB LinePrinter-Bold \033(8U\033(s0p0s03b00T 2 X--- 43,67 ---- X # | | | +----------------- stroke weight -7...7 X # | | | | +-------------- Typeface X # | | | | | X! # | | | | | +----------- source flags... X # | | | | | | X+ # | | | | | | X+ # | | | | | | X+ # | | | | | | X # v v v v v v X! # 678910 14 20 28 X! # 11 16 22 36 X! # 12 18 24 X! # ||||||||||||||| X! # vvvvvvvvvvvvvvv X! R Times-Roman \033(8U\033(s1p0s00b05T sssssssssssssss X! I Times-Italic \033(8U\033(s1p1s-3b05T sssssssssssssss X! B Times-Bold \033(8U\033(s1p0s03b05T sssssssssssssss X! S Symbol \033(8U\033(s0p0s00b03T sssssssssssssss X! BI Times-BoldItalic \033(8U\033(s1p1s03b05T sssssssssssssss X! C Courier \033(8U\033(s0p0s00b03T ssssbsbssssssss X! CI Courier-Italic \033(8U\033(s0p1s-3b03T ssssbsbssssssss X! CB Courier-Bold \033(8U\033(s0p0s03b03T ssssbsbssssssss X! L LinePrinter \033(8U\033(s0p0s00b00T sssssssssssssss X! LI LinePrinter-Ital \033(8U\033(s0p1s-3b00T sssssssssssssss X! LB LinePrinter-Bold \033(8U\033(s0p0s03b00T sssssssssssssss X*** /usr4/public/src/t2current/./README Fri Jan 12 17:34:29 1990 X--- ./README Fri Jan 12 17:35:14 1990 X*************** X*** 1,4 **** X! README 1.23 90/01/08 X See defs.h for the patchlevel X X Please read this document, especially any new patches near the end before X--- 1,4 ---- X! README 1.26 90/01/12 X See defs.h for the patchlevel X X Please read this document, especially any new patches near the end before X*************** X*** 430,439 **** X (eg: upload, showfont, tmac.t2). X 6) tmac.t2 is no longer a source file - it's now tmac.t2.sh. X X Coming features (watch this space!) X- - Patch 7 will contain Ron Florence's SFP download improvements. X- (but this will be superceded by SFP/PK downloading whenever X- I get around to it). X - automatic macro/pre/post-processor determination (ala Doug X Gwyn's doctype function) X - More complete listings of Postscript font widths. X--- 430,469 ---- X (eg: upload, showfont, tmac.t2). X 6) tmac.t2 is no longer a source file - it's now tmac.t2.sh. X X+ Patch 7: Jan 12 1990 X+ 1) Undid patch 6 (3). You're stupid Chris! And added a -O X+ option to specify a page offset in troff2ps, default .5i. X+ (troff allows .po+.ll to be at most 7.54, unless troff2ps X+ adds it's own independent offset, it is impossible to X+ centre 7.5 inch lines on 8.5 inch paper). X+ The macro adapters have been adjusted to centre the X+ default linelength. See psroff.1 X+ 2) Added page count to CHATTER stuff. X+ 3) Built in psroff support for jetroff, differentiated "dt" X+ as being bare ditroff to stdout, and "tp" as being X+ an invocation of tpscript. These are examples of how to use X+ ditroff output with different ditroff->printer converters. X+ 4) A primitive form of LJ downloading is supported, supporting X+ either HP SFP's or TeX PK format files. (however, I haven't X+ shipped the pktype program, so PK's won't work unless you ask X+ me for it). Do *not* ask me for PK or SFP files, you will X+ have to find your own. However, if you really want, I X+ can mail you a PK font defined by Rick Richardson X+ that has characters not in normal TeX PK files. Note that X+ Rick's company owns the copyright on this font, and he has X+ graciously permitted me to ship it (the "cmtrf" font) ONLY X+ for use with psroff. Any other usage (other than jetroff or X+ psroff) violates his permission, and is downright unfriendly. X+ X+ This version does *not* prevent you from asking for more fonts X+ than the HPLJ will support simultaneously. Nor are any characters X+ except for the most common ASCII characters likely to appear X+ when you expect them to. X+ X+ Besides, it hasn't been tested very well either... (they X+ stole my IIP ;-) X+ X Coming features (watch this space!) X - automatic macro/pre/post-processor determination (ala Doug X Gwyn's doctype function) X - More complete listings of Postscript font widths. END_OF_FILE if test 33956 -ne `wc -c <'./Patch07'`; then echo shar: \"'./Patch07'\" unpacked with wrong size! fi # end of './Patch07' fi echo shar: End of archive 1 \(of 1\). cp /dev/null ark1isdone MISSING="" for I in 1 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have the archive. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 -- Chris Lewis, Elegant Communications Inc, {uunet!attcan,utzoo}!lsuc!eci386!clewis Ferret mailing list: eci386!ferret-list, psroff mailing list: eci386!psroff-list From jimmy at pyrltd.UUCP Tue Jan 16 00:11:33 1990 From: jimmy at pyrltd.UUCP (Jimmy Aitken) Date: 15 Jan 90 13:11:33 GMT Subject: cl[fs] - print compressed directory listings Message-ID: <1683@pyrltd.UUCP> Theis is a conversion of a shell script that I use quite often to list directories with long filenames in it. It originally was a shell script which I converted to perl for speed. If anyone can suggest improvements, I'm willing to listen. I've lost who posted the original version, but the RCS header on my copy was: "$Header: cls,v 1.2 88/02/03 14:21:20 jerryp Exp $" so if that is you my aplogies for not giving full attribution. Link cls to cls2 clf2 and clf for all the options. ------------------------------CUT-HERE------------------------------ #! /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: cls # Wrapped by jimmy at pyrrot on Mon Jan 15 13:05:27 1990 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'cls' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'cls'\" else echo shar: Extracting \"'cls'\" \(1968 characters\) sed "s/^X//" >'cls' <<'END_OF_FILE' X#!/usr/local/bin/perl X# "clf","cls","clf2","cls2" - X# compressed "ls" and "ls -F" directory listings X# Usage: cmd [dirs] X# X# "clf", "cls", "clf2", and "cls2" are substitutes for ls -f and ls. X# they make compressed listings of the directory. names longer X# than 14 characters are truncated like this: X# - on all regular files (not executable, directories, etc.), X# the 14th and succeeding characters are replaced with a ">". X# - when using "clf" and "clf2": executable files, directories, X# etc. with names longer than 13 characters... the 13th X# character is replaced with ">", and the 14th character X# will be a * for executable files, / for directories, etc. X# X# "cls" and "clf" list files alphabetically down screen, like ls does: X# a d k p s X# b j n r z X# "cls2" and "clf2" list them alphabetically across the screen: X# a b d j k X# n p r s z X X X$pr='|pr -5 -t -w78'; X$comm="ls -F1 @ARGV |" if $0=~/clf2$/; X$comm="ls -1 @ARGV |" if $0=~/cls2$/; X$comm="ls -F1 @ARGV |" if $0=~/clf$/; X$comm="ls -1 @ARGV |" if $0=~/cls$/; X$across=1 if $0=~/2$/; # Sorting across the screen X Xopen(PIPE,$comm); Xopen(OUT,$pr." -l1") if $across; # pr does this easily for us Xwhile(<PIPE>) { X# If line is over 14 characters and ends with symbol "*", "/", "@", OR "=" X# truncate after 12 and replace with >symbol... X# otherwise, if name is over 14 characters, truncate after 13; add a ">" X X s/^(............)...*([\/@*=][\/@*=]*)$/$1>$2/ if /[\/@*=]$/; X s/^(.............)...*/$1>/; X if ($across) { X print OUT; X } else { X push(@line,$_); X } X} Xclose(PIPE); Xif ($across) { X close(OUT); X exit(0); X} X X# These commands only done by cls and clf. X# length of listing = ( number of files / 5 ) + 1, use as ar angument to 'pr' X$length=int($#line/5)+1; X$comm="$pr -l$length"; Xopen(PIPE,$comm); Xwhile ($_=shift(@line)) { X print PIPE; X} Xclose(PIPE); Xexit(0); END_OF_FILE if test 1968 -ne `wc -c <'cls'`; then echo shar: \"'cls'\" unpacked with wrong size! fi chmod +x 'cls' echo "Remember to link cls to clf, cls2 and clf" # end of 'cls' fi echo shar: End of shell archive. exit 0 -- -m------- Jimmy Aitken ...!mcvax!ukc!pyrltd!jimmy ---mmm----- Pyramid Technology Ltd jimmy at pyra.co.uk -----mmmmm--- Pyramid House, Solartron Rd jimmy at pyramid.pyramid.com -------mmmmmmm- Hants GU14 7PL, ENGLAND (+44) 252 373035 From sampson at attctc.Dallas.TX.US Sat Jan 6 16:43:11 1990 From: sampson at attctc.Dallas.TX.US (Steve Sampson) Date: 6 Jan 90 05:43:11 GMT Subject: Dynamic Substitution Cipher [sci.crypt] Message-ID: <10550@stag.math.lsa.umich.edu> Archive-name: dynsub/v1.01 Original-posting-by: sampson at attctc.Dallas.TX.US (Steve Sampson) Original-subject: Dynamic Substitution (debugged) Reposted-by: emv at math.lsa.umich.edu (Edward Vielmetti) [This is an experimental alt.sources re-posting from the newsgroup(s) sci.crypt. Comments on this service to emv at math.lsa.umich.edu (Edward Vielmetti).] My earlier bug question was answered by Yves Gallot who determined that I needed 'unsigned char' for it to work. In case anyone is interested in trying Terry Ritter's Dynamic Substitution algorithm: /* * dynsub.c * * Dynamic Substitution Cipher Filter * * Evaluation Version 1.01, January 1990 * * Copyright (c) November 5, 1989, By Terry F. Ritter * All Rights Reserved * * Modified for Turbo-C by sampson at attctc.dallas.tx.us (steve) * with help from cernvax!galloty at relay.EU.net (yves gallot) */ #include <stdio.h> #ifdef __TURBOC__ #include <stdlib.h> #include <fcntl.h> #include <io.h> #else #define random(x) (rand() % (x)) #endif #define BSIZE 256 unsigned char f[BSIZE], finv[BSIZE], buf[BSIZE]; void ExchangeChars(x, y) unsigned char *x, *y; { unsigned char t; t = *x; *x = *y; *y = t; } void DynSubInit() { register int i; for (i = 0; i < BSIZE; i++) f[i] = (unsigned char)i; for (i = 0; i < BSIZE; i++) ExchangeChars(&f[i], &f[random(BSIZE)]); } void InvDynSubInit() { register int i; DynSubInit(); for (i = 0; i < BSIZE; i++) finv[f[i]] = (unsigned char)i; } unsigned char DynSubF(xi) unsigned char xi; { unsigned char t; t = f[xi]; ExchangeChars(&f[xi], &f[random(BSIZE)]); return t; } unsigned char InvDynSubF(yi) unsigned char yi; { unsigned char j, xi, yj; xi = finv[yi]; j = random(BSIZE); yj = f[j]; ExchangeChars(&finv[yi], &finv[yj]); ExchangeChars(&f[xi], &f[j]); return xi; } void encipher() { register int i, got; DynSubInit(); for (;;) { if ((got = fread(buf, sizeof(char), BSIZE, stdin)) < 1) return; for (i = 0; i < got; i++) buf[i] = DynSubF(buf[i]); fwrite(buf, sizeof(char), got, stdout); } } void decipher() { register int i, got; InvDynSubInit(); for (;;) { if ((got = fread(buf, sizeof(char), BSIZE, stdin)) < 1) return; for (i = 0; i < got; i++) buf[i] = InvDynSubF(buf[i]); fwrite(buf, sizeof(char), got, stdout); } } main(argc, argv) int argc; char **argv; { #ifdef __TURBOC__ /* * Change stdin/stdout to binary mode, big buffers */ setmode(0, O_BINARY); setmode(1, O_BINARY); setvbuf(stdin, NULL, _IOFBF, BSIZE); setvbuf(stdout, NULL, _IOFBF, BSIZE); #endif if (argc == 3) { argv++; srand(atoi(*argv)); } else srand(1); argv++; if (**argv == 'd') decipher(); else if (**argv == 'e') encipher(); else { puts("Usage: dynsub [key 0 - 65536] e|d <infile >outfile"); exit(1); } exit(0); } From aglew at oberon.csg.uiuc.edu Fri Jan 19 09:38:13 1990 From: aglew at oberon.csg.uiuc.edu (Andy Glew) Date: 18 Jan 90 22:38:13 GMT Subject: number recognition tools In-Reply-To: aglew@oberon.csg.uiuc.edu's message of 15 Jan 90 11:53:0 References: <AGLEW.90Jan15115309@oberon.csg.uiuc.edu> Message-ID: <AGLEW.90Jan18163813@oberon.csg.uiuc.edu> Urghh... I like showing people my source code, but I *hate* it when they find embarassing errors (egoless programmer, I'm not). Swallowing foot, let me acknowledge Joseph Pepin's bug report (which he couldn't post) to the number recognition tools I posted recently. I will posted a cleaner version soon. Return-Path: <att!cbnewsl!joepepin at uxc.cso.uiuc.edu> Date: Thu, 18 Jan 90 15:26:53 EST From: jdp at tarpon.att.com (Joseph Pepin) To: aglew at oberon.csg.uiuc.edu Subject: Re: number recognition tools Newsgroups: alt.sources In-Reply-To: <AGLEW.90Jan15115309 at oberon.csg.uiuc.edu> Organization: AT&T Bell Laboratories Two serious bugs: 1) The shar file is corrupt: the END-OF-FILE after each man page is preceeded by an "X", causing the next file not to be unshar'ed. Maybe the original files were not terminated by a NL. 2) Executing "getnumber -100e-2" dumps core on a 3B2 and a 6386WGS running SVR3.2. The problem is you don't malloc enough space for the right side of an infix expression: Line 218 of number.c: right = malloc ... InfixStrLen))); should be: right = malloc ... InfixStrLen))+1); I suspect that other systems treat malloc(0) as malloc(1). Please fix these bugs and/or post this message: my newsserver discourages postings. -- Andy Glew, aglew at uiuc.edu From coleman at lll-lcc.UUCP Fri Jan 5 10:35:04 1990 From: coleman at lll-lcc.UUCP (Sam Coleman) Date: 4 Jan 90 23:35:04 GMT Subject: Postscript code for Composite characters [comp.lang.postscript] References: <2708@lll-lcc.UUCP> Message-ID: <10523@stag.math.lsa.umich.edu> Archive-name: ps-composite/release Original-posting-by: coleman at lll-lcc.UUCP (Sam Coleman) Original-subject: Composite characters Original-message-id: <2708 at lll-lcc.UUCP> Reposted-by: emv at math.lsa.umich.edu (Edward Vielmetti) [This is an experimental alt.sources re-posting from the newsgroup(s) comp.lang.postscript. Comments on this service to emv at math.lsa.umich.edu (Edward Vielmetti).] There was some discussion recently about composite characters. Composites are mentioned in sections 7.8 and 7.9 of the Green Book, but there's no explanation of how to do it. The Postscript code below represents one way to create composites, with two or more standard characters or combinations of standard characters and custom characters. The sample below includes some accented characters and some characters used in medieval texts. There are actually four fonts, with italic, bold, etc. The code is loosely based on the sample on page 145 of the Green Book. Incidently, the fonts also include some fractions. It seems that within a font fractions are easier than program 8 in the Blue Book. I suppose that News will fold the lines that exceed 80 characters, but hopefully it will still be readable. I'd appreciate comments on other ways to create composites or improvements to this code. Sam Coleman coleman at lll-lcc.llnl.gov [Remainder deleted, fetch it from comp.lang.postscript (ca. 300 lines)]. From thad at cup.portal.com Fri Jan 19 22:35:01 1990 From: thad at cup.portal.com (Thad P Floryan) Date: 19 Jan 90 11:35:01 GMT Subject: Getting the time over the phone from NBS References: <1043@khijol.UUCP> <899@tridom.uucp> <BOB.90Jan17123008@volitans.MorningStar.Com> Message-ID: <26101@cup.portal.com> In article <BOB.90Jan17123008 at volitans.MorningStar.Com> by bob at MorningStar.Com (Bob Sutterfield) to alt.sources,rec.ham-radio, he writes: " In article <899 at tridom.uucp> wht at tridom.uucp (Warren Tucker) writes: v03i079 contains a GREAT program utc.c which allows your system to mimic NBS and provide esentially the same service via a local call. Only the most ultimate time freaks who've replaced their PC's crystal with an atomic clock can tell the difference (I'm pretty bad, but not that bad) :-). I'd hope that only folks either running a local radio clock, or a low- stratum NTP peer, would offer their system's time as a community standard. However, this would be a really nice service for Internet- connected folks to offer to their UUCP-only neighbors. " Is there some ESP going on here? :-) I've put together a prototype system that does just what Karl describes. My time reference is a HeathKit GC-1000 "Most Accurate Clock" which locks onto NIST's (formerly NBS') WWV at 5, 10 or 15 MHz to provide +/- 10 mSec Universal Time Coordinated on its RS-232c port. I've been testing the setup since: $ loglook utc Login ID First Last Name -------- ---------------------- ---------------------- -------------------- utc Sat 14-Oct-89 17:59:07 Thu 18-Jan-90 23:12:28 UTC time service ^^^^^^^^^ Note that date; 3 days later my antenna snapped during the earthquake, and I haven't repaired it ... I'm in Silicon Valley, and the antenna is a huge inverted "V" whose apex WAS at the top of a 40' tower. :-( At the moment, one of my systems calls the US Naval Observatory service in Washington DC every 2 days to maintain time-sync locally, but once I repair the antenna AND get some more phone lines installed, this service will be publicly online and I'll post its availability along with all the software. I use the service to coordinate time for all my LAN-based systems. The server provides a time reference identical to the USNO per: * jjjjj ddd hhmmss UTC where: jjjjj Julian date modulo 2400000 ddd days since beginning of year hhmmss time of day in Universal Time Coordinated based on a program by Michael Scott Baldwin of AT&T Bell Labs. If you'd like to install and provide such a service on your system, you need an accurate time reference (the Heath clock is my recommendation: kit price from their Winter 1990 Catalog No. 219 is $249.95 for the clock and $49.95 for the RS-232 interface (see page 28)), and: $ ls -l /usr/local/bin/utcs* -rwxr-xr-x 1 thad users 3156 Oct 14 17:22 /usr/local/bin/utcservice $ file /usr/local/bin/utcs* /usr/local/bin/utcservice: mc68k executable (shared demand paged with \ shared library) -F (0413 demand paged) and entries for /etc/passwd: utc::50:50:UTC time service:/usr/local/bin:/usr/local/bin/utcservice and /etc/group: utcpub::50:utc All a client system(s) need do is install the "capture" program and execute it per: # must run this as super-user # echo "\nutc" | cu thadlabs | /usr/local/bin/utcset -s exit 0 from a crontab entry like the following: #Mn Hr Da Mo Da (0=SUN, 1=MON, 2=TUE, 3=WED, 4=THU, 5=FRI, 6=SAT) #of of of of of #Hr Da Mo Yr Wk Command # 03 3 * * * /bin/su root -c "/usr/local/bin/utcset.sh >/dev/null" assuming one has a /usr/lib/uucp/Systems (or L.sys) entry for the server. The above is how I've configured the service to date. Because some "cu" don't seem to respond to SIGPIPE properly, I'm planning on generalizing the client program to itself connect and retrieve the server info, and will post the whole package when it's complete. If someone would like to help (my time is VERY limited) and/or you'd like some more info, feel welcome to contact me: Thad Floryan [ thad at cup.portal.com (OR) ..!sun!portal!cup.portal.com!thad ] From joe at dayton.UUCP Thu Jan 4 08:22:00 1990 From: joe at dayton.UUCP (Joseph P. Larson) Date: 3 Jan 90 21:22:00 GMT Subject: lin: solves systems of linear equations. Message-ID: <6901@dayton.UUCP> This is a really simple program for anyone about to take Linear Algebra or perhaps who just wants to solve systems of linear equations. To save it, cut everything above the comment line plus the signature at the end, save it to lin.c and type "make lin". Caveat: if you're about to study linear algebra, I would *not* recommend you use lin in lieu of learning the material. Use it to help in your studies, not replace them. (Of course, you could check your problem sets over...) Watch here in the future for more advance programs. -Joe /* * lin: solve systems of linear equations. * * Description: * * lin solves systems of linear equations. Actually, it's * not currently that smart -- all it does is solve very simple * systems -- the kind with only one solution. I whipped this * while bored one day and will probably eventually make it a * very smart little program. But I thought, with a new term * starting, there might be a few students out there about to * take linear algebra who could use a tiny bit of help. All * it will do is try to mutilate the initial set of equations * so that you can directly read off the values for x1, x2, etc. * * A future version will solve systems with an infinite number * of solutions. * * See the code or the "usage" line for any help you need running it. * * Author: * * Joe Larson * (currently joe at dayton.dhdsc.mn.org) * * I hereby place this program in the public domain, as if it's big enough * for anyone to care, anyways. -Joe */ #include <stdio.h> #include <ctype.h> #define MAXVAR 20 #define MAXEQN 20 double strtod(); short vcount, ecount; double matrix[MAXEQN][MAXVAR+1]; char showstep = 0; main(argc,argv) int argc; char **argv; { char *c, line[132], x; short i,j; for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-s")) showstep = 1; else usage(argv[0]); } printf("This program solves systems of linear equations involving\n"); printf("n variables and m unknowns.\n"); while(1) { while (1) { printf("Number of variables: "); fflush(stdout); gets(line); vcount = atoi(line); if (vcount > MAXVAR) { printf("Max variables = %d. ", MAXVAR); continue; } if (vcount) break; exit(0); } while (1) { printf("Number of equations: "); fflush(stdout); gets(line); ecount = atoi(line); if (ecount > MAXEQN) { printf("Max equations = %d. ", MAXEQN); continue; } if (ecount) break; exit(0); } printf("Equations are of the form: \n"); for (i = 0; i < vcount; i++) { if (i) printf("+ "); printf(" c%d * x%d ", i, i); } printf("= result\n"); printf("For each equation, enter the %d constants plus the result,\n", vcount); printf("separated by spaces.\n"); for (i = 0; i < ecount; i++) { printf("\nEquation %d\n", i+1); gets(line); for (c = line, j = 0; *c && j < ecount; j++) matrix[i][j] = strtod(c, &c); matrix[i][ecount] = strtod(c, &c); } printf("The system: \n"); show(); /* * Now solve the equation in the following manner: * * for each variable: * find an equation with a 1 for constant. * (if non, find one with a non-zero for constant * and multiply to make it a 1.) * add multiples of this equiation to others as needed * to zero-out their constants. */ for (i = 0; i < ecount; i++) { /* Find an equation to place here */ x = 0; for (j = i; j < ecount; j++) if (matrix[j][i] == 1.0) { swap(i, j); x = 1; break; } if (!x) for (j = i; j < ecount; j++) if (matrix[j][i] != 0.0) { swap(i,j); x = 1; mult(i, 1.0 / matrix[i][i]); break; } if (!x) { /* This variable doesn't matter. */ continue; } /* * Now -- zero out everyone else. */ for (j = 0; j < ecount; j++) { if (j == i) continue; if (matrix[j][i] == 0.0) continue; add(j, i, -matrix[j][i]); } } printf("The system: \n"); show(); } } swap(i,j) short i,j; /* * Swap two rows of the matrix. */ { double temp; short x; if (i == j) return; for (x = 0; x <= vcount; x++) { temp = matrix[i][x]; matrix[i][x] = matrix[j][x]; matrix[j][x] = temp; } if (showstep) { printf("Swap row %d and %d leaving:\n", i, j); show(); } } mult(i, f) short i; double f; /* * Multiply row i by constant f. */ { short x; for (x = 0; x <= vcount; x++) matrix[i][x] *= f; if (showstep) { printf("Multiply row %d by %f leaving:\n", i, f); show(); } } add(i,j,f) short i,j; double f; /* * Add to row i row (j*f). */ { short x; for (x = 0; x <= vcount; x++) matrix[i][x] += matrix[j][x] * f; if (showstep) { printf("Add (%f times row %d) to row %d:\n", f, j, i); show(); } } show() /* * Show the equation */ { short i,j; for (i = 0; i < ecount; i++) { for (j = 0; j < vcount; j++) printf(" %8.4f", matrix[i][j]); printf(" %8.4f\n", matrix[i][j]); } } usage(arg) char *arg; { fprintf(stderr, "\ Usage: %d [-s]\n\ where -s selects display of steps used to solve the set of equations.\n", arg); exit(0); } -- UUCP: rutgers!dayton!joe (Picts 1-16 are DHDSC - Joe Larson/MIS 1060 ATT : (612) 375-3537 now ready.) 700 on the Mall, Mpls, Mn. 55402 From jeff at quark.WV.TEK.COM Wed Jan 31 03:23:06 1990 From: jeff at quark.WV.TEK.COM (Jeff Beadles) Date: 30 Jan 90 16:23:06 GMT Subject: Animated graphics in csh Message-ID: <6004@orca.wv.tek.com> (Catchy title, eh?) This is something that I thought of one night when doing too many late-night compiles. It's an animated graphic view of the mountains, turned on its side. To view, just run the script, and turn your head to the right. To stop, ^C. There are no copyrights on this work of "art". Feel free to do as you wish with it, but please don't leave my name attached. (This IS alt.sources right :-) -Jeff -- Jeff Beadles jeff at quark.WV.TEK.COM #--------------------cut here--------------------- #!/bin/csh -f cd; while ( 1 ) ; repeat 37 pushd ~ ; repeat 37 popd ; end #--------------------cut here--------------------- From shields at yunccn.UUCP Tue Jan 9 10:15:20 1990 From: shields at yunccn.UUCP (Paul Shields) Date: 8 Jan 90 23:15:20 GMT Subject: Menu software... version 1.35 upgrade to "lush" part 1/1 References: <3888@yunccn.UUCP> Message-ID: <3890@yunccn.UUCP> Note: I haven't compiled lush for MS-DOS in at least a year. You may have to work on it. You'll also need a termcap library that will work on MS-DOS. I ported the GNU termcap to MS-DOS and posted it to comp.sources.misc some time ago (last year? I don't recall.) Drop me a note if you can't find it anywhere, and I'll send it to you. #--------------------------------CUT HERE------------------------------------- #! /bin/sh # # This is a shell archive. Save this into a file, edit it # and delete all lines above this comment. Then give this # file to sh by executing the command "sh file". The files # will be extracted into the current directory owned by # you with default permissions. # # The files contained herein are: # # -rw-r--r-- 1 shields staff 1941 Jan 8 17:48 Makefile.MS # -rw-r--r-- 1 shields staff 1185 Jan 8 16:04 config.h # -rw-r--r-- 1 shields staff 1643 Jan 8 16:47 defs.h # -rw-r--r-- 1 shields staff 6587 Jan 8 16:37 edit.c # -rw-r--r-- 1 shields staff 8788 Jan 8 16:51 envinit.c # -rw-r--r-- 1 shields staff 701 Jan 8 16:41 login.c # -rw-r--r-- 1 shields staff 66 Jan 8 17:07 version.h # echo 'x - Makefile.MS' if test -f Makefile.MS; then echo 'shar: not overwriting Makefile.MS'; else sed 's/^X//' << '________This_Is_The_END________' > Makefile.MS X# Makefile.MS - Generic MS-DOS Makefile for lush X# This file is untested, so it will probably need work, especially in X# the link phase. --Note -- Microsoft make won't work on this Makefile. X# Use something like NdMake. X X# You'll probably want to change LIBDIR and BINDIR to something more sane. X# Don't forget to change config.h as well. X XLIBDIR=\usr\lib\lush XBINDIR=\usr\local\bin X X# compiler definitions you might want to have: X# X# -DPROTOTYPE if your compiler can handle prototype statements X# -DMULTIUSER for MSDOS users, if you have getuid(), getpwnam(), ttyname(), getgrpnam() X XDEBUG = XDEFS = -DMSDOS XCFLAGS = $(DEBUG) $(DEFS) XLDFLAGS= XLIBS = -lc -ltermcap X XHFILES = mparse.h mlex.h mfile.h menu.h edit.h lush.h defs.h version.h config.h XCFILES = mparse.c mlex.c mfile.c menu.c edit.c lush.c envinit.c getin.c login.c XOBJS = mparse.obj mlex.obj mfile.obj menu.obj edit.obj lush.obj envinit.obj\ X getin.obj login.obj X X# ----------------------------- dependencies -------------------------------- X Xlush.exe: $(OBJS) X $(CC) $(LDFLAGS) $(OBJS) $(LIBS) -o lush.exe X Xclean: X -del lush.exe X -del errs X -del *.obj X -del *.map X Xinstall: lush.exe lushrc menu X -mkdir $(BINDIR) X -mkdir $(LIBDIR) X copy lush.exe $(BINDIR) X copy lushrc $(LIBDIR) X copy menu $(LIBDIR) X Xmparse.obj: mparse.c mparse.h mlex.h mfile.h menu.h lush.h defs.h config.h X $(CC) $(CFLAGS) mparse.c -c X Xmlex.obj: mlex.c mlex.h mfile.h lush.h defs.h X $(CC) $(CFLAGS) mlex.c -c X Xmfile.obj: mfile.c mfile.h lush.h defs.h X $(CC) $(CFLAGS) mfile.c -c X Xmenu.obj: menu.c menu.h lush.h defs.h config.h X $(CC) $(CFLAGS) menu.c -c X Xedit.obj: edit.c edit.h lush.h defs.h config.h X $(CC) $(CFLAGS) edit.c -c X Xenvinit.obj: envinit.c lush.h defs.h config.h X $(CC) $(CFLAGS) envinit.c -c X Xlogin.obj: login.c defs.h X $(CC) $(CFLAGS) login.c -c X Xgetin.obj: getin.c defs.h X $(CC) $(CFLAGS) getin.c -c X Xlush.obj: lush.c lush.h defs.h config.h version.h X $(CC) $(CFLAGS) lush.c -c ________This_Is_The_END________ if test `wc -l < Makefile.MS` -ne 71; then echo 'shar: Makefile.MS was damaged during transit (should have been 71 lines)' fi fi ; : end of overwriting check echo 'x - config.h' if test -f config.h; then echo 'shar: not overwriting config.h'; else sed 's/^X//' << '________This_Is_The_END________' > config.h X/* config.h - some definitions you might want to change. */ X X#define GLOBALFILE "/usr/lib/lush/lushrc" /* global config file */ X#define MENUFILE "/usr/lib/lush/menu" /* menu file */ X#define ROOTMENU "MAIN_MENU" /* the default root menu */ X X#ifdef MSDOS X#define LUSHRC "~/lushrc" /* user config file */ X/* #define MULTIUSER */ /* if you have the getpwiud() library. */ X#else X#define LUSHRC "~/.lushrc" X#define MULTIUSER /* UNIX is always multiuser, right? */ X#endif X X#define ILLEGAL "|<>;&" /* disallowed user-input characters */ X#define TERM "dumb" /* terminal type if none in environment */ X X/* things you probably don't want to change... */ X#define LJ_MAX 20 /* Max size of setjmp() stack. This governs how X many levels down in the menu hierarchy you can go. */ X X#define MAX_OPTIONS 20 /*(menu.h) max options per menu */ X#define MAX_RESP 10 /*(menu.h) max number of responses per option */ X#define NAME_SIZE 20 /*(menu.h) Max size of a menu name or option word */ X X#define MAX_MENUS 50 /*(mparse.c) max number of menus in the system */ X X#define MAX_TOKENS 200 /*(mlex.c) Max number of lexical tokens. */ ________This_Is_The_END________ if test `wc -l < config.h` -ne 28; then echo 'shar: config.h was damaged during transit (should have been 28 lines)' fi fi ; : end of overwriting check echo 'x - defs.h' if test -f defs.h; then echo 'shar: not overwriting defs.h'; else sed 's/^X//' << '________This_Is_The_END________' > defs.h X/* File: defs.h X Author: PAS X Date: Sept 7, 1987 X Purpose: Contains global definitions for lush and other programs. X */ X/* -- standard headers -------------------------------------------------- */ X X#ifdef DEBUG X#include <stdio.h> X#endif X#include <fcntl.h> X X/* #ifdef MSDOS X#include <stdlib.h> X#include <dos.h> X#include <float.h> X#endif */ X X#include <string.h> X#include <ctype.h> X#include <time.h> X#ifdef MULTIUSER X#include <pwd.h> X#include <grp.h> X#endif X#include <signal.h> X#include <setjmp.h> X#include <errno.h> X X#ifndef PROTOTYPE /* function declarations are not done for us. */ Xextern char *malloc(); Xextern int getopt(); Xextern char *getenv(); Xextern int putenv(); X#ifdef MULTIUSER Xextern char *ttyname(); Xextern char *getlogin(); X#endif X#endif X X/* -- system dependent defs --------------------------------------------- */ X X#ifdef MSDOS X#define access laccess /* our own access() function. */ X#define TTY "con" /* default terminal. */ X#else X#define TTY "/dev/null" /* no default terminal. */ X#endif X X#ifdef MULTIUSER /* have getpwiud() library? */ X#define GROUP "/etc/group" /* various group access permissions. */ X#define PASSWD "/etc/passwd" /* where to find the passwords. */ X#else X#define USER "nobody" /* user name */ X#define HOMEDIR "/" /* home directory */ X#endif X X/* -- immutable defs ---------------------------------------------------- */ X X/* function return values... */ X#define OK 0 X#define ERROR -1 X#define FALSE 0 X#define TRUE 1 X X#define MAX_LEN 255 /* maximum line length in a file */ X#define PATH_LEN 64 /* max length of a path. */ ________This_Is_The_END________ if test `wc -l < defs.h` -ne 67; then echo 'shar: defs.h was damaged during transit (should have been 67 lines)' fi fi ; : end of overwriting check echo 'x - edit.c' if test -f edit.c; then echo 'shar: not overwriting edit.c'; else sed 's/^X//' << '________This_Is_The_END________' > edit.c X/* File: edit.c X Author: Paul Shields X Date: May 15, 1987 X Purpose: this is where the real work is done. X */ X X#include "lush.h" X#ifndef DEBUG X#include <stdio.h> X#endif X#include "edit.h" X X#ifdef PROTOTYPE Xint (*funcs[])(char *) = /* array of pointers to functions taking char* and returning int. */ X#else Xint (*funcs[])() = X#endif X{ ChgDir, /* 00 change directory */ X ChkPort, /* 01 check port access */ X ChkTerm, /* 02 check terminal type */ X Pause, /* 03 pause with "Press enter: " message */ X ChkRdAcc, /* 04 check read access to a file list */ X CallCmd, /* 05 system() to a command with parameters */ X SecurChk, /* 06 perform a security check */ X ChkWrAcc, /* 07 check write access to a file list */ X Expert, /* 08 toggle novice/expert mode */ X P1name, /* 09 write prompt, get parameter. */ X P2name, /* 10 write prompt, get second parameter. */ X ChkAccess, /* 11 check read/write access to a file list */ X SetEnvt, /* 12 set environment variable */ X SaveStr, /* 13 save string in (global) recall-buffer */ X P1Recall, /* 14 put recall-buffer in parameter 1 */ X P2Recall /* 15 put recall-buffer in parameter 2 */ X}; X Xstatic char param1[MAX_LEN]; /* parameter for CallCmd. */ Xstatic char param2[MAX_LEN]; /* parameter for CallCmd. */ Xstatic char recall[MAX_LEN]; /* global recall-buffer. */ X Xint ChgDir(dn) /* change to a directory. */ Xchar *dn; X{ X char *buf, pbuf[MAX_LEN]; X X sprintf(pbuf, dn, param1, param2); /* add the parameter(s) to the command. */ X buf = envsubst(pbuf); /* substitute environment variables if nec. */ X X if(chdir(buf) != 0) { X perror(buf); X return ERROR; X } X return OK; X} X Xint lookupfile(nam, str) /* find a string in a file. */ Xchar *nam, *str; X{ X FILE *fp; X char line[MAX_LEN+1]; X int i = strlen(str); X X line[MAX_LEN] = '\0'; X if((fp = fopen(nam, "r")) != NULL) { X while(fgets(line, MAX_LEN, fp) != NULL) X if(strncmp(str, line, i) == 0) { X fclose(fp); X return OK; X } X fclose(fp); X } else X perror(nam); X X return ERROR; X} X Xint ChkPort(c) /* check for local mode */ Xchar *c; X{ X if(lookupfile(c, tty) == OK) X return OK; X X printf("\nThis command is unavailable from TTY %s\n", tty); X return ERROR; X} X Xint ChkTerm(c) /* check for remote mode */ Xchar *c; X{ X if(lookupfile(c, term) == OK) X return OK; X X printf("\nThis command is unavailable on terminals of type %s\n", term); X return ERROR; X} X Xint Pause(c) /* wait for user */ Xchar *c; X{ X getin("Press enter: "); X return OK; X} X Xint ChkRdAcc(list) /* 04 */ Xchar *list; X{ X printf("\nFile Access Check failed\n"); X return ERROR; X} X Xint ChkWrAcc(list) /* 07 */ Xchar *list; X{ X printf("\nFile Access Check failed\n"); X return ERROR; X} X Xint ChkAccess(list) /* 11 */ Xchar *list; X{ X printf("\nFile Access Check failed\n"); X return ERROR; X} X Xint P1name(prompt) Xchar *prompt; X{ X int i; X char *p; X X p = getin(prompt); X X if(strlen(p) > 0) { X /* none of that funny stuff... */ X i = strcspn(p, ILLEGAL); X } X else i=0; X X strncpy(param1, p, i); X param1[i] = '\0'; X X return OK; /* null is ok. */ X} X Xint P2name(prompt) Xchar *prompt; X{ X int i; X char *p; X X p = getin(prompt); X X if(strlen(p) > 0) { X /* none of that funny stuff... */ X i = strcspn(p, ILLEGAL); X } X else i=0; X X strncpy(param2, p, i); X param2[i] = '\0'; X X return OK; /* null is ok. */ X} X Xint CallCmd(cmd) /* use the system function to execute a command. */ Xchar *cmd; /* name of command to call. */ X{ X int ret; X char *buf, pbuf[MAX_LEN]; X X sprintf(pbuf, cmd, param1, param2); /* add the parameter(s) to the command. */ X buf = envsubst(pbuf); /* substitute environment variables if nec. */ X X#ifdef DEBUG X if(debuglevel & 1) X fprintf(stderr,"CallCmd(%s)= system(\"%s\")\n", cmd, buf); X#endif X if((ret = system(buf)) == 0) X return OK; X X#ifdef DEBUG X fprintf(stderr,"--returned error %d--\n", errno); X perror(buf); X#endif X return ERROR; X} X X/* Return TRUE if user is a member of the group, ow FALSE. X */ Xstatic int member(gr) Xchar *gr; X{ X#ifdef MULTIUSER X struct group *grp; X char **n; X X if((grp = getgrnam(gr)) != NULL) { X for(n = grp->gr_mem; *n != NULL && strcmp(user, *n) != 0; n++) X#ifdef DEBUG X if(debuglevel & 1) X fprintf(stderr, "%s ",*n) X#endif X ; X return (*n != NULL); X } X /* else invalid group. */ X printf("\nSystem error verifying group %s. Please consult system administrator\n",gr); X return FALSE; X#else X /* in single-user system, always return TRUE */ X X return TRUE; X#endif X} X Xint SecurChk(gr) /* check to see that the user is a member of the */ Xchar *gr; /* permitted groups... */ X{ X#ifdef DEBUG X if(debuglevel & 1) X fprintf(stderr,"SecurChk(%s) ",gr); X#endif X#ifdef MULTIUSER X if(getuid() == 0) X return OK; X X if(*gr == '!') { /* user must not be member of this group. */ X if(!member(++gr)) return OK; X } else X if(member(gr)) return OK; X X printf("\nYou are not allowed to use this command.\n"); X return ERROR; X#else X return OK; /* single-user system, always return TRUE. */ X#endif X} X Xint Expert(w) /* toggle novice/expert mode */ Xchar *w; X{ X novice ^= TRUE; /* xor */ X return OK; X} X Xint SetEnvt(w) /* set environment variable. allocates memory for it, */ Xchar *w; /* and substitutes parameters, etc. */ X{ X char *buf, pbuf[MAX_LEN]; X X sprintf(pbuf, w, param1, param2); /* add the parameter(s) to the command. */ X buf = envsubst(pbuf); /* substitute environment variables if nec. */ X X if((w = malloc(strlen(buf)+1)) == NULL) /* allocate in static storage */ X return ERROR; X strcpy(w, buf); X X if(putenv(w) != 0) { X free(w); X return ERROR; X } X return OK; X} X Xint SaveStr(w) /* save string in global recall buffer. */ Xchar *w; X{ X strncpy(w, recall, MAX_LEN-1); X recall[MAX_LEN] = 0; X return OK; X} X Xint P1Recall(w) /* save string in global recall buffer. */ Xchar *w; X{ X strcpy(recall, param1); X return OK; X} Xint P2Recall(w) /* save string in global recall buffer. */ Xchar *w; X{ X strcpy(recall, param2); X return OK; X} ________This_Is_The_END________ if test `wc -l < edit.c` -ne 283; then echo 'shar: edit.c was damaged during transit (should have been 283 lines)' fi fi ; : end of overwriting check echo 'x - envinit.c' if test -f envinit.c; then echo 'shar: not overwriting envinit.c'; else sed 's/^X//' << '________This_Is_The_END________' > envinit.c X/* File: envinit.c X Author: Paul Shields X Date: May 13, 1987 X Purpose: sets up variables for the environment. X */ X X#include "lush.h" X#ifndef DEBUG X#include <stdio.h> X#endif X X/* We logged into the console, a local tty, or a remote tty. Certain things X are unavailable from a remote tty, so we'll need to compare the environment X variable TTY with a list of permitted devices when the need calls for it. X */ Xchar *root_menu = NULL, /* default main menu name. */ X *menufile = NULL, /* name of menu file. */ X *globalrc = NULL, /* name of global rc file. */ X *userrc = NULL, /* name of user rc file. */ X *user, /* name of the user. */ X *tty, /* TTY environment variable. */ X *term = NULL; /* TERM environment variable. */ X Xchar *CL, *SO, *SE; /* termcap Clear-screen, Stand-out, Unstand-out */ Xint LI, CO; /* lines, columns */ X X Xchar * Xgethome(u) /* allocate and return user home dir or null. */ Xchar *u; X{ X#ifdef MULTIUSER X struct passwd *pw; X /* if u is null, use default of current user. */ X if(u == NULL || strlen(u) == 0) X u = user; X if((pw = getpwnam(u)) == NULL) X return NULL; X if((u = malloc(strlen(pw->pw_dir)+1)) == NULL) X return NULL; X strcpy(u,pw->pw_dir); X return u; X#else X return HOMEDIR; X#endif X} X X/* allocate and store an environment variable. */ Xchar *mputenv(var,def) Xchar *var,*def; X{ X char *ut; X if((ut = malloc(strlen(var)+1+strlen(def)+1)) == NULL) X return NULL; X sprintf(ut, "%s=%s",var,def); X putenv(ut); X return ut; X} X X#define trim(s) {char *tl; while(*s && isspace(*s)) s++; \ X for(tl=s; *tl; tl++) ; for(tl--; tl > s; tl--) \ X { if(isspace(*tl)) *tl = '\0'; else break; } } X X/* Process a line in the global rc. X Allow environment definitions. X Do translation of $VAR and ~user strings. X *** Yet to add: System() out to commands enclosed in ``. X X Side-effects: writes junk into the line. X */ Xstatic int proc_global(line) Xchar *line; X{ X char *tl, *var, *def; X X#ifdef DEBUG X if(debuglevel & 1) X fprintf(stderr,"line: |%s|\n",line); X#endif X X/***/ /* this won't do. need to convert to use the scanner in mparse.c */ X if((tl = strpbrk(line,"#")) != NULL) /* strip comments */ X *tl = '\0'; X X /* look for = and break into two: "A=B" => "A","B" */ X if((def = strpbrk(line, "=")) != NULL) { X var = strtok(line, "="); X def++; X trim(var); /* zap leading/trailing white space */ X trim(def); X tl = envsubst(def); /* do $ and ~ substitutions */ X mputenv(var, tl); X } else { X trim(line); X if(strlen(line) > 0) X return ERROR; X } X return OK; X} X X/* Process a line in the user rc. X Only environment definitions allowed. X Restrict to ones already defined. X */ Xstatic int proc_user(line) Xchar *line; X{ X return proc_global(line); /***/ /* for now, do the same. */ X} X X/* Get and process the global rc file */ Xstatic int getrc_global(name) Xchar *name; X{ X FILE *fp; X char line[MAX_LEN+1]; X int ln; X X if((fp=fopen(name, "r")) == NULL) { X perror(name); X return ERROR; X } X for(ln=1; fgets(line, MAX_LEN, fp) != NULL; ln++) X if(proc_global(line) == ERROR) X fprintf(stderr,"%s: syntax error: line %d\n",name,ln); X fclose(fp); X return OK; X} X X/* Get and process the user rc file */ Xstatic int getrc_user(name) Xchar *name; X{ X FILE *fp; X char line[MAX_LEN+1]; X int ln; X X if((fp=fopen(name, "r")) == NULL) { X perror(name); X return ERROR; X } X for(ln=1; fgets(line, MAX_LEN, fp) != NULL; ln++) X if(proc_user(line) == ERROR) X fprintf(stderr,"%s: syntax error: line %d\n",name,ln); X fclose(fp); X return OK; X} X Xint envinit(argc,argv) Xint argc; Xchar *argv[]; X{ X register char *h; X char *ut; /* temporary */ X int err = 0, c; X extern char *optarg; X X#ifndef MSDOS X if(getenv("SHELL") != argv[0]) /* security. */ X mputenv("SHELL",argv[0]); X#endif X X /* find out who we are. */ X#ifdef MULTIUSER X if((user = getlogin()) == NULL) { X struct passwd *pw; X if((pw = getpwuid(getuid())) == NULL) { X fprintf(stderr,"Can't find your username anywhere.\n"); X return ERROR; X } X ut = pw->pw_name; X if((user = malloc(strlen(ut)+1)) == NULL) X { perror("envinit()"); return ERROR; } X strcpy(user,ut); X } X#else X user=USER; X#endif X mputenv("USER",user); X#ifdef DEBUG X if(debuglevel & 1) X fprintf(stderr,"USER=<%s> ",user); X#endif X X if((ut = getenv("HOME")) == NULL) { X if((ut = gethome(user)) == NULL) { X fprintf(stderr,"No home directory.\n"); X return ERROR; X } X mputenv("HOME",ut); X } X#ifdef DEBUG X if(debuglevel & 1) X fprintf(stderr,"HOME=<%s> ",ut); X#endif X X /* process the command line options... */ X while ((c = getopt(argc, argv, "f:R:M:G:U:")) != EOF) X switch((char)c) { X case 'f': X case 'M': X if((menufile=malloc(strlen(optarg)+1)) == NULL) X { perror("envinit()"); return ERROR; } X strcpy(menufile,optarg); X break; X case 'R': X if((root_menu=malloc(strlen(optarg)+1)) == NULL) X { perror("envinit()"); return ERROR; } X strcpy(root_menu,optarg); X break; X case 'G': X if((globalrc=malloc(strlen(optarg)+1)) == NULL) X { perror("envinit()"); return ERROR; } X strcpy(globalrc,optarg); X break; X case 'U': X if((userrc=malloc(strlen(optarg)+1)) == NULL) X { perror("envinit()"); return ERROR; } X strcpy(userrc,optarg); X break; X case '?': X err = TRUE; X } X if(err) { X fprintf(stderr, "Usage: %s [-G global-config-file] [-M menufile]\n",argv[0]); X fprintf(stderr, " [-R rootmenu] [-U user-config-file]\n"); X return ERROR; X } X X if(globalrc == NULL) /* default global rc file location */ X globalrc = GLOBALFILE; X X#ifdef DEBUG X if(debuglevel & 1) X fprintf(stderr,"global rc=<%s>\n",globalrc); X#endif X /* Now process global rc file... must always exist. */ X getrc_global(globalrc); X X if(menufile == NULL) /* default menu file location */ X if((menufile = getenv("MENUFILE")) == NULL) X menufile = MENUFILE; X X if(root_menu == NULL) /* default root menu name */ X if((root_menu = getenv("ROOTMENU")) == NULL) X root_menu = ROOTMENU; X X if(userrc == NULL) X if((userrc = getenv("LUSHRC")) == NULL) X userrc = LUSHRC; X X#ifdef DEBUG X if(debuglevel & 1) X printf("userrc: <%s>, menufile: <%s>, root_menu: <%s>\n", X userrc, menufile, root_menu); X#endif X /***/ /* note: may need to subst ~ in userrc here. */ X X /* now process the user rc file... */ X getrc_user(userrc); X X if((tty = getenv("TTY")) == NULL) { /* default terminal */ X#ifdef MULTIUSER X if((ut = ttyname(fileno(stdin))) == NULL) X tty = TTY; X else { X tty = malloc(strlen(ut)+1); X strcpy(tty, ut); X } X#else X tty = TTY; X#endif X mputenv("TTY",tty); X } X X if((term = getenv("TERM")) == NULL) { /* default to "dumb" terminal */ X term = TERM; X mputenv("TERM",term); X } X X return OK; X} X X/* Initialize the termcap variables. Some of this code is from MicroEMACS X by Daniel M. Lawrence (and others.) */ Xint Xtcapinit() /* important. call envinit() before this. */ X{ X char *tgetstr(); X int tgetnum(); X char tcbuf[1024]; X static char strbuf[128]; X char *str = strbuf; X X if (term == NULL) { X fprintf(stderr,"Environment variable TERM not defined!\n"); X return ERROR; X } X X if ((tgetent(tcbuf, term)) <= 0) { X fprintf(stderr, "Unknown terminal type %s!\n", term); X return ERROR; X } X X LI = tgetnum("li"); /* lines & columns */ X CO = tgetnum("co"); X X if((CL = tgetstr("cl",&str)) == NULL) /* clear screen */ X CL = "\n------------------------------------------------------------------------------\n"; X X if((SO = tgetstr("so",&str)) == NULL) /* stand-out enter */ X SO = ""; X X if((SE = tgetstr("se", &str)) == NULL) /* stand-out end */ X SE = ""; X X /* caution: we lose access to tcbuf now. don't call any more termcap X functions. CL, SO, and SE are in static memory. */ X X return OK; X} X Xstatic char retbuf[BUFSIZ]; X#define scanword(s, var) {char *tmp; \ X tmp = ++(s); while(isalnum(*(s))) (s)++; \ X strncpy(var, tmp, (s)-tmp); \ X (var)[(s)-tmp] = '\0'; } X Xchar * /* substitute environment values in "$VAR" strings for s. */ Xenvsubst(s) /* returns with static data which is overwritten by the next call. */ Xchar *s; X{ X char *r = retbuf, *tmp; X static char var[MAX_LEN]; X X while(*r = *s) { X if(*s == '\\') /* escape with \$ or \~. */ X *++r = *++s; X if(*s == '$') { /* substitute */ X scanword(s, var); X if((tmp = getenv(var)) == NULL) /* look it up.. */ X tmp = ""; /* Nothing there */ X while(*r = *tmp++) /* copy */ X r++; X continue; X } X if(*s == '~') { /* look for ~user */ X scanword(s, var); X X if((tmp = gethome(var)) == NULL) X tmp = ""; /* no translation */ X X while(*r = *tmp++) /* copy */ X r++; X continue; X } X s++; X r++; X } X X return retbuf; X} ________This_Is_The_END________ if test `wc -l < envinit.c` -ne 362; then echo 'shar: envinit.c was damaged during transit (should have been 362 lines)' fi fi ; : end of overwriting check echo 'x - login.c' if test -f login.c; then echo 'shar: not overwriting login.c'; else sed 's/^X//' << '________This_Is_The_END________' > login.c X/* File: login.c X Author: Paul Shields X Date: May 13, 1987 X Purpose: Miscellaneous esoteric system-dependent functions X */ X X#include "defs.h" X#ifndef NULL X#define NULL (char *)0 X#endif X X/***/ /* the following is a stub. it does nothing. */ Xvoid login(p) /* log in operator. */ Xchar *p; /* oper name */ X{ X#ifdef MULTIUSER X struct passwd *pwd = getpwuid(getuid()); X X if((char *)pwd != NULL) X strcpy(p,pwd->pw_name); /* set operator name */ X#else X strcpy(p,USER); X#endif X X /***/ /* remember login time. */ X} X X/***/ /* the following is a stub. it does nothing. */ Xvoid logout(p) /* log out operator */ Xchar *p; /* oper name */ X{ /* log system use */ X} ________This_Is_The_END________ if test `wc -l < login.c` -ne 32; then echo 'shar: login.c was damaged during transit (should have been 32 lines)' fi fi ; : end of overwriting check echo 'x - version.h' if test -f version.h; then echo 'shar: not overwriting version.h'; else sed 's/^X//' << '________This_Is_The_END________' > version.h X#define VERSION "LUSH version 1.35, Mon Jan 8 17:06:49 EST 1990" ________This_Is_The_END________ if test `wc -l < version.h` -ne 1; then echo 'shar: version.h was damaged during transit (should have been 1 lines)' fi fi ; : end of overwriting check exit 0 -- Paul Shields, shields at nccn.yorku.ca (..!uunet!yunccn!shields) From gemini at geminix.UUCP Mon Jan 15 08:00:15 1990 From: gemini at geminix.UUCP (Uwe Doering) Date: 14 Jan 90 21:00:15 GMT Subject: FAS 2.05 async driver, part 1/2 Message-ID: <2FYB0G@geminix.UUCP> Hi netlanders! Here it is: The public domain async driver FAS 2.05 (mentioned a few times in comp.unix.i386). This driver was tested under ISC 386/ix 2.0.2 and MicroPort SYSV/386 Vers. 3.0e and has the following features: - It supports the NS16550 UART chip in FIFO mode. - Modem sharing for dial-in and dial-out on the same port is possible. - It has hardware flow control. >From the many postings during the last months about problems with the vendors standard serial drivers I conclude that there is a need for a full-featured driver that really works. You really should buy some NS16550A chips as replacements for the 8250 or NS16450 devices on your serial card. They are the key to highspeed serial ports without losing characters. And they are much less expensive than an "intelligent" serial card. To the sites that have some earlier test-releases of FAS in use: As this is the first official release all previous releases are void. The first release I will support is 2.05. Therefor, please upgrade! Note: I won't email you any sources or patches because international mailing costs are prohibitive in West Germany. But of course I will post patches. Uwe #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # INSTALLATION # PATCHLEVEL # README # config-c1-2 # config-c1-3 # config-mux4 # i_fas-c1-2 # i_fas-c1-3 # i_fas-mux4 # makefile.ISC # makefile.uPort # n_fas-c1-2 # n_fas-c1-3 # n_fas-mux4 # s_fas-c1-2 # s_fas-c1-3 # s_fas-mux4 # space-c1-2 # space-c1-3 # space-mux4 # This archive created: Sun Jan 14 21:46:07 1990 export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'INSTALLATION'" '(7535 characters)' if test -f 'INSTALLATION' then echo shar: "will not over-write existing file 'INSTALLATION'" else sed 's/^X//' << \SHAR_EOF > 'INSTALLATION' XInstallation guide for the FAS Final Async Solution driver X---------------------------------------------------------- X XTo install this driver you need a manual of your serial card, Xyour system manuals and a certain knowledge about what actually Xis a serial driver. X XYou have to be user root to compile and install the driver! X X XCompilation phase X================= X XFirst of all you should copy the makefile that matches your system Xto the file `makefile'. Make sure that the makefile contains the Xproper compiler switches for your system. You may also look at X`fas.c' to find out what defines are possible for conditional Xcompilation. You should also check the paths and file names used Xin the makefile. X XAfter that you chose one of the space-xxxxx configuration files Xthat matches your serial card and copy this to `space.c'. If you Xdon't find a matching space file you should copy the one that Xcomes closest to your card to `space.c'. X XIn any case you should check the entries in that file against your Xcard's manual and jumper settings. The space files contain explanations Xabout what data you have to enter. X XIf your `space.c' is filled in properly you simply type `make' to Xcompile the driver. If you don't get error messages you may begin Xwith the actual installation. Otherwise you have to find the cause of Xthe trouble. Some error reasons may be missing include files, macros Xthat are defined in different include files or missing at all, you Xuse an ANSI compiler that complains about non-ANSI constructions. XIn the latter case you need to convince the compiler somehow to Xwork in non-ANSI (standard C) mode. X X XInstallation phase X================== X XIf you want to have both the original asy and the new FAS driver in Xthe kernel the only restriction is that ports and interrupt vectors Xcan't be shared between the two drivers. Each driver controls its own Xseparate set of ports and IRQs. X XuPort: Copy one of the config-xxxxx files to `config'. Check out X whether the interrupt vectors in this file reflect the X jumper settings on your serial card. Note that an IRQ2 on X your card is an interrupt vector of 9. All other IRQ numbers X correspond to the vector number, though. X X Next you have to tell the config program to include the new X driver at kernel link time. This is done by a line in the file X /etc/atconf/systems/system.std. Look for the line containing X `asy' followed by an asterisk (`*') and a comment. Create a X similar line where `asy' is substituted with `fas'. Add a X proper comment. If you don't want to use any ports under the X DOS emulator you should insert an asterisk at the beginning X of the line that contains the word `asy'. This excludes the X asy driver from the kernel. But if you want to have it in the X kernel you have to configure it to only use the ports you X need under DOS. The remaining ports should be controlled by X the FAS driver. X X Now type `make install' and after that you are ready to link X a new kernel. Refer to your system manuals on how to do that. X X Before you reboot the new kernel make sure that you create X the proper tty device nodes in /dev. But first you should X remove all device nodes belonging to the original asy driver X that you don't need any more. X X Now create your own tty device nodes that fit your needs. X The default device name prefix for the FAS driver is `ttyF'. X That is, ttyF00, ttyF01 ... and ttyFM00, ttyFM01 ... X You may chose another prefix, but note that some utilities X like uustat depend on tty-devices beginning with `tty'! X X The default value for the major device number is 4, and X sane values for the minor device numbers are 48 + device # X for the dialout node and 208 + device # for the dialin (getty) X node. Device # counts from 0 and reflects the actual port number. X Refer to fas.c (function `fasopen') for a description of the X possible minor device numbers. X X Remember to change the inittab file to the new device names. X Other files that contain tty-names for some reason should be X updated, too (ttytype, Devices etc.). X X After you have booted the new kernel, provided your configuration X was correct, you should be able to use the serial devices. X X XISC: Copy one of the s_fas-xxxxx files to `s_fas'. Make sure X that you have a separate line in it for each block of contiguous X port addresses assigned to the same interrupt vector (check X the jumper settings on your serial card). Each line contains X the number of ports bound to that interrupt, the start and X end address of the first (lowest or only) port on this interrupt X line and other data. Refer to your ISC manuals if you need to X change this file. Note that an IRQ2 on your card is an interrupt X vector of 9. All other IRQ numbers correspond to the vector X number, though. X X Then you copy one of the n_fas-xxxxx files to `n_fas'. This X file contains data needed to automatically create tty device X nodes at installation time. Things you may want to change are X the tty node name and the minor device number (last field) for X that node. Make sure you have a node for every port on your X serial card in this file. X X Sane values for the minor device numbers are 48 + device # X for the dialout node and 208 + device # for the dialin (getty) X node. Device # counts from 0 and reflects the actual port number. X Refer to fas.c (function `fasopen') for a description of the X possible minor device numbers. X X Now copy one of the i_fas-xxxxx files to `i_fas'. This file X contains the getty lines for the inittab file which is rebuild X every time a new kernel is installed. Make sure that you use the X same device names here as in the file `n_fas'. X X Next you have to modify the configuration files for your original X asy driver to create only those devices you need for the DOS X emulator. Make sure that the asy driver only controls ports and X interrupt vectors not used by the FAS driver. If you don't need X the asy driver at all you can exclude it from the kernel. X X To tell the kernel config program how to link in the FAS driver X you have to add the following line to the file /etc/conf/cf.d/mdevice: X X fas Iocrwi iHct fas 0 4 1 16 -1 X X The 6th field contains the major device number of the driver. You X may change this if it collides with another driver. X X All this is in the ISC manuals. Read them carefully. X X Now type `make install' and after that you are ready to link X a new kernel. Refer to your system manuals on how to do that. X X You may have to change files that contain tty-names for some X reason to the new device names (ttytype, Devices etc.). Take X the names from `n_fas'. X X After you have booted the new kernel, provided your configuration X was correct, you should be able to use the serial devices. X X XOther flavors of UNIX X===================== X XCheck out if one of the above installation schemes is similar to the Xone you need for your system. Make the appropriate changes and try Xout if it works. If your system is entirely different you have to Xfind out from your manuals how to install device drivers. But if Xyou use a UNIX SYSV/386 3.X you should get it to work eventually. X XGood luck. SHAR_EOF if test 7535 -ne "`wc -c < 'INSTALLATION'`" then echo shar: "error transmitting 'INSTALLATION'" '(should have been 7535 characters)' fi fi echo shar: "extracting 'PATCHLEVEL'" '(26 characters)' if test -f 'PATCHLEVEL' then echo shar: "will not over-write existing file 'PATCHLEVEL'" else sed 's/^X//' << \SHAR_EOF > 'PATCHLEVEL' Xrelease 2.05 patchlevel 0 SHAR_EOF if test 26 -ne "`wc -c < 'PATCHLEVEL'`" then echo shar: "error transmitting 'PATCHLEVEL'" '(should have been 26 characters)' fi fi echo shar: "extracting 'README'" '(20046 characters)' if test -f 'README' then echo shar: "will not over-write existing file 'README'" else sed 's/^X//' << \SHAR_EOF > 'README' XREADME file for the FAS Final Async Solution driver X--------------------------------------------------- X XWhat is this package: X X This is an alternate async driver for 386 based unix systems that X adds several features that are not supported by vendors drivers. X X 1. It supports the NS16550 UART chips in full FIFO mode. X 2. It supports modem sharing for input and output. X Microport almost supported this feature but none X of the other vendors did. X 3. It supports hardware flow control. X X X This driver should work with most of the UNIX SYS V/386 3.X ports X currently available. You can have both this and the original X vendor driver in the same kernel. Each driver controls its own X separate set of serial ports. The only restriction here is that X any int vector must not be used by more than one of the drivers. X The kernel config program will complain otherwise. X X Note: This driver supports neither VP/ix nor DosMerge virtual X serial devices. If you need COM ports for your DOS programs X you have to connect the needed devices to ports that are X controlled by the original vendor async driver. You won't X have the special features of the FAS driver on these ports, X though. If you don't need to access serial ports from DOS X the vendor driver can be removed from the kernel. X X------------------------------------------------------------------------ X XA little about what it does: X X This driver supports shared line usage by having two logical X devices sharing one physical line. To those familiar with X Microport this is very similar. For the other readers a X brief description follows. For each line there are two X names. For example for the first line the names are ttyF00 X (minor device 0) and ttyFM00 (minor device 192). The ttyF00 X is used for cu, kermit, and other programs that want to dial X out. It ignores the modem signals and just goes to it. The X ttyFM00 line is strictly for getty. When getty calls open on X ttyFM00 the driver hangs the open until the modem asserts DCD X and then lets the open complete. If cu opens ttyF00 while X getty is waiting for the open to complete the device is X given to cu and the getty open must wait for cu to finish X and then will again wait for DCD. If cu tries to open the X ttyF00 line while getty has ttyFM00 open cu will get an error. X If getty tries to open ttyFM00 while cu has ttyF00 open the X getty open will just hang and wait for cu to close the line X and then wait for DCD. To put it simply you should put up a X getty on ttyFM00 with a -t 60 and use ttyF00 for cu and X uucico. X X The modem devices ttyFMxx is the minor device of ttyFxx plus X 192. There are several other possible minor devices for X each port. See the description in `fas.c'. X X------------------------------------------------------------------------ X XA little about what it supports: X X The driver supports and has been tested on many async cards X and mux boards. It supports most combinations of shared X interrupts. The current driver supports NS16450, NS16550 and X um82450. It is also reported to work on the 8250B. I X suspect that it will not work on some of the earlier 8250 and X 8250A parts, due to various bugs and speed problems in these X early parts. Since these parts have no place in an 386 or other X high performance systems I did nothing to try to support them. X X Take a look at the various samples of space-xxxx for details X of how to set up for various devices. X X X A WORD ABOUT CHARACTER LOSSES X ----------------------------- X X If you experienced character losses with your vendor async X driver at high baud rates you shouldn't blame the vendor for X that. The real reason for this problem lies in the ancient port X devices used in most 386 systems: The 8250 and the NS16450. X X They have only one receiver character buffer. This implies that X the operating system must read a character from this buffer before X the next one arrives from the port's shift register. For the old X IBM PC with DOS this was sufficient. But for UNIX and with baud X rates up to 38400 this is simply a joke. X X UNIX is not a real-time operating system. That means that it's X kernel isn't optimized for fast interrupt responses. With the X proper hardware this is no problem. But because the vendors have X to adapt UNIX to the standard hardware found in 386 systems they X also have to cope with the NS16450 ports which are in there simply X to be compatible with IBM PCs, XTs and ATs. X X It is impossible to make it work at high baud rates without a X major redesign of the AT&T supplied UNIX kernel. But then it X wouldn't be UNIX SYSV any more. X X Luckily, there is a pin-to-pin replacement available from X National Semiconductors: The NS16550A. X X This device has separate 16 character FIFOs for the receiver and X the transmitter. With these FIFOs the interrupt latency of the X kernel can be quiet high without losing any characters. X Additionally, because with most interrupts many characters are X processed at once the system is loaded much less. X X As you see, the necessary hardware is available. Therefor, if you X have to blame the UNIX vendor then blame him for not telling you X that you should buy some NS16550A and/or for not supplying you X with a serial driver that supports these port devices. X X But as you have the FAS driver now and if you use the NS16550A X devices you shouldn't have this kind of trouble any more. This is X the philosophy behind the driver's name `Final Async Solution'. X X Enjoy! X X------------------------------------------------------------------------ X XWhats in this package: X X README This file. X X INSTALLATION A description about how to install the driver X on your system. X X PATCHLEVEL Just a reference file for future updates. X X fas.h The header file for the driver. X X fas.c The driver itself. X X space-xxxxx These are samples of what `space.c' must look X like. You can either copy one of these to X `space.c' or use it as a template to create your X own `space.c'. X X space-c1-2 For com1 and com2. X X space-c1-3 For com1, com2 and com3. X X space-mux4 For the MU-440 four line mux board. X X config-xxxxx This is for uPort SYS V/386 only. X Kernel configuaration file. You should pick the one X that matches your configuration and copy it to `config'. X X config-c1-2 For com1 and com2. X X config-c1-3 For com1, com2 and com3. X X config-mux4 For the MU-440 four line mux board. X X s_fas-xxxxx This is for ISC 386/ix only. X Kernel configuration file. You should pick the one X that matches your configuration and copy it to `s_fas'. X X s_fas-c1-2 For com1 and com2. X X s_fas-c1-3 For com1, com2 and com3. X X s_fas-mux4 For the MU-440 four line mux board. X X n_fas-xxxxx This is for ISC 386/ix only. X Tty device nodes file. You should pick the one X that matches your configuration and copy it to `n_fas'. X X n_fas-c1-2 For com1 and com2. X X n_fas-c1-3 For com1, com2 and com3. X X n_fas-mux4 For the MU-440 four line mux board. X X i_fas-xxxxx This is for ISC 386/ix only. X Inittab getty lines file. You should pick the one X that matches your configuration and copy it to `i_fas'. X X i_fas-c1-2 For com1 and com2. X X i_fas-c1-3 For com1, com2 and com3. X X i_fas-mux4 For the MU-440 four line mux board. X X makefile.uPort A makefile for uPort SYS V/386 systems. This is generic X and should work for all configurations of lines X and interrupts. X X makefile.ISC A makefile for ISC 386/ix systems. This is generic X and should work for all configurations of lines X and interrupts. X X------------------------------------------------------------------------ X XWhat you will need to use this package: X X You will need a one of the above mentioned systems with the X link kit and the software development package. X X------------------------------------------------------------------------ X X XRelease History: X X release 1.1a Sat Nov 11, 1989 X X This is an unofficial release as I'm not the original author X of this async driver. X X Uwe Doering gemini at netmbx.UUCP X Billstedter Pfad 17 B X 1000 Berlin 20 X West Germany X X New Features: X X Added a third minor tty device number for every physical X port. See description preceding the asyopen function in X asy.c. Changed the behavior of ttyxx, too. X X Added output hardware handshake support for DSR. Now you X can do handshake with CTS, DSR or both. Input hardware X handshake is on if you use at least one of the output X handshake signals. X X More flexible support of additional interrupt registers X on mux boards. This is fully configurable now. X X Added support for the CREAD flag. If not set, receiver X interrupts are still serviced, but the received characters X are simply thrown away. This is not as elegant as disabeling X the interrupts themselves, but with the already existing X driver it was the easiest way, and the most new-bugs-preventing, X too. X X Added a lot of comments to the source so that the curious X user can understand why and how things are done. X X X Bug Fixes: X X The hang-up-on-last-close flag (HUPCL) was ignored. DTR X was asserted regardless of this flag. X X Made the detection of CTS and DCD more bullet-proof. X Especially because between a close and the next open of X a line, where interrupts are ignored, the software copys of X CTS and DCD must be set up propperly in the asyopen function X or the tty line would be blocked under certain circum- X stances. For similar reasons, there is also a setup in the X asyparam function. X X Rewrote the input character processing function to work X according to the TERMIO(7) man page. X X Changed the behavior of BREAK generation to let the X transmitter drain before TX is set to low. X X Changed line hangup procedure so that the closing X process returns immediately and doesn't sleep during X the hangup delay/time. Instead, if an other process tries X to open the line while hangup is still in progress, this X process will sleep until hangup is competed. X X With DOS Merge, on MicroPort V/386 3.0e the linker was X missing the function `init8250'. Reengineered this from X a disassembler listing of MicroPort's original driver and X modified it to work with the NS16550 16-bit FIFO. This X funktion was added simply to be able to link the kernel. X DOS Merge's virtual COM ports are still unusable with this X release, though. To include this function, add a `-DMERGE' X to the CFLAGS line in your makefile. X X Made a lot of other corrections and enhancements in both X speed and functionallity. As a result of all my effords X I think this driver is slightly faster, more versatile X and much more stable than the original release. X X ------------------------------------------------------------ X X release 1.1b Sat Nov 25, 1989 X X New Features: X X Changed the minor device number scheme again. X There are now two main groups: The unblocked open X and the blocked open. Every group has four sub-modes X and an additional hardware handshake flag. All this X is coded in the higher four bits of the minor device X number. Because of this, the maximum of 32 ports was X reduced to 16 ports so that the port number fits into X the remaining lower four bits of the minor device number. X 32 dumb ports in a single machine would have been overkill X anyway. For more details refer to the comment above the X `asyopen' function in the file `asy.c'. X X ------------------------------------------------------------ X X release 2.00 Mon Nov 27, 1989 X X As this release differs so much from the original version I got, X I now declare this as independant from the original author X Jim Murray. This allows me to introduce new release levels X without wondering whether they will collide with Jim's releases. X Of course many credits to Jim for writing this software in the X first place. Without his driver as a base I never would have X been able to do such kernel driver development. X X Bug Fixes: X X If there were glitches on the hardware handshake lines X and the DCD line a getty on this port would sometimes X hang and become an immortal process. I think this was X because the output buffer wasn't flushed properly X on carrier loss. I hope I fixed this now. We'll see. X X ------------------------------------------------------------ X X release 2.01 Tue Nov 28, 1989 X X Did some cleanup in the source code. X X I splitted the driver into two parts: The driver itself and X the file `space.c'. X `space.c' contains all data structures necessary to configure X the driver and is compiled at kernel link time. Therefore if you X change your serial card configuration you simply change `space.c' X directly in the link kit directory and relink the kernel. No X driver recompilation or installation is necessary for this. X But note that whenever you use `make install' your setup in X the link kit directory is overwritten by the original `space.c' X file. Therefore you should copy your new `space.c' back to X the source directory when you are finished with the configuration. X X Renamed the package to `FAS Final Async Solution'. The following X files have been renamed: X asy.c -> fas.c X asy.h -> fas.h X asy_conf-xxxxx -> space-xxxxx X X ISC 386/ix is supported now. There are separate makefiles X for uPort and ISC to cope with the differences in link kit X installation. X X Bug Fixes: X X `getty' still hung sometimes on a line with hardware X handshake. Tried to fix it this time. X X ------------------------------------------------------------ X X release 2.02 Thu Nov 30, 1989 X X Abandoned the distinction between space-xxxxx files with X and without hardware flow control because this is selected X by the minor device number now. X X Bug Fixes: X X Set the high and low water marks for hardware input flow X control to higher values than software flow control. This X gives precedence to software flow control if both methods X are used. These marks are self-adjusting and don't need to X be changed if some flavor of UNIX has a different buffer X size than the standard 256 characters. Before this change X concurrent use of both flow controls could cause trouble X with some high-speed modems. This is fixed now. X X A flush read or write buffer request now also clears the X receiver or transmitter FIFO, respectively. An ioctl X call with a TCSETA* command clears the FIFOs, too. X X ------------------------------------------------------------ X X release 2.03 Fri Dec 01, 1989 X X Wrote an installation guide. The driver should be quite X easy to install now. X X Added tty node configuration files for ISC. X X Hardware input flow control is bound now to the level of the X receiver ring buffer instead of the UNIX input buffer. This X has the advantage that buffer size and trigger levels are X defined in the driver and therefore can be varied as needed. X X New Features: X X Added a boot time status message that shows the init X state of each port. This tells you immediately what X ports are found and initted by the driver. Useful to X determine hardware configuration problems. Refer to X file fas.c (function `asyinit') for a description. X Thanks to Kritt Gierlewsen for this proposal. X X ------------------------------------------------------------ X X release 2.04 Thu Dec 07, 1989 X X Did some cleanup in the source. X X Removed the FIFO clear from the ioctl function. We don't want X to do things there that aren't in the book. X X An ioctl call that switches off the CLOCAL flag will create X a SIGHUP signal if the carrier is actually missing at this X time. X X Every device is tested now quite thoroughly during initialization. X If the test fails the corresponding device keeps unconfigured. X X ------------------------------------------------------------ X X release 2.05 Sat Jan 13, 1990 X X This is the first public release of the FAS driver. X X Special thanks to the sysops of my test sites, Axel Fischer and X Kritt Gierlewsen. X X FAS is now an independant driver with its own driver name (`fas'), X major device number, link kit directory and other things necessary X for a driver. The original asy driver may or may not be linked X with the kernel. You only need it if you want to access some X serial devices via the virtual COM ports of the DOS emulator X (DosMerge or VP/ix) because the FAS driver doesn't have this X (really vendor dependant) feature. X X The default prefix for tty device node names is `ttyF' now. X This prevents mix-ups with the device names of the original X asy driver. X X Dropped the SYSV/AT support. I couldn't test the driver X for several release generations on uPort SYSV/AT, and because X there are not very much systems left with that flavor of UNIX X it doesn't make sense to try to maintain compatibility with it. X If someone really wants to use this driver on a 286 he has X to port it himself. X X Improved the transmitter FIFO fill procedure. Now it will try X harder to fill the FIFO as much as possible to cut down on X transmitter interrupts. X X Software input flow control (XON/XOFF) is controlled by the driver now. X It is bound to the level of the receiver ring buffer (as is hardware X flow control). As usual, it can be switched on and off by the X IXOFF flag in the termio structure. X X Changed and speeded up the ring buffer -> unix buffer processing. X X For ISC, the getty lines for the inittab file are installed X by the makefile now. X X The conditional compilation of the function `init8250' (for X DosMerge) is now controlled by a define in `fas.h'. The compiler X switch `-DMERGE' is not used any more. X X Improved the documentation. X X Bug Fixes: X X The task state busy flag wasn't reset in some rare cases. X This could cause processes to become immortal while waiting X for the busy flag. X X--------------------------------------------------------------------- X XOriginally written by XJim Murray encore!cloud9!jjmhome!jjm X2 Mohawk Circle harvard!m2c!jjmhome!jjm XWestboro Mass 01581 jjm%jjmhome at m2c.m2c.org XUSA voice (508) 366-2813 X XCurrent author: XUwe Doering gemini at netmbx.UUCP XBillstedter Pfad 17 B X1000 Berlin 20 XWest Germany SHAR_EOF if test 20046 -ne "`wc -c < 'README'`" then echo shar: "error transmitting 'README'" '(should have been 20046 characters)' fi fi echo shar: "extracting 'config-c1-2'" '(253 characters)' if test -f 'config-c1-2' then echo shar: "will not over-write existing file 'config-c1-2'" else sed 's/^X//' << \SHAR_EOF > 'config-c1-2' X* its character device number 4 Xcharacter(4) X X* its name Xprefix = fas X X* The interrupt vectors handled by this controller Xintvec = 4,3 X X* its mask level Xintpri = SPLTTY X X* the functions it supports Xfunctions = init, open, close, read, write, ioctl, tty SHAR_EOF if test 253 -ne "`wc -c < 'config-c1-2'`" then echo shar: "error transmitting 'config-c1-2'" '(should have been 253 characters)' fi fi echo shar: "extracting 'config-c1-3'" '(255 characters)' if test -f 'config-c1-3' then echo shar: "will not over-write existing file 'config-c1-3'" else sed 's/^X//' << \SHAR_EOF > 'config-c1-3' X* its character device number 4 Xcharacter(4) X X* its name Xprefix = fas X X* The interrupt vectors handled by this controller Xintvec = 4,3,9 X X* its mask level Xintpri = SPLTTY X X* the functions it supports Xfunctions = init, open, close, read, write, ioctl, tty SHAR_EOF if test 255 -ne "`wc -c < 'config-c1-3'`" then echo shar: "error transmitting 'config-c1-3'" '(should have been 255 characters)' fi fi echo shar: "extracting 'config-mux4'" '(251 characters)' if test -f 'config-mux4' then echo shar: "will not over-write existing file 'config-mux4'" else sed 's/^X//' << \SHAR_EOF > 'config-mux4' X* its character device number 4 Xcharacter(4) X X* its name Xprefix = fas X X* The interrupt vectors handled by this controller Xintvec = 4 X X* its mask level Xintpri = SPLTTY X X* the functions it supports Xfunctions = init, open, close, read, write, ioctl, tty SHAR_EOF if test 251 -ne "`wc -c < 'config-mux4'`" then echo shar: "error transmitting 'config-mux4'" '(should have been 251 characters)' fi fi echo shar: "extracting 'i_fas-c1-2'" '(72 characters)' if test -f 'i_fas-c1-2' then echo shar: "will not over-write existing file 'i_fas-c1-2'" else sed 's/^X//' << \SHAR_EOF > 'i_fas-c1-2' XF0:2345:off:/etc/getty ttyFM00 9600 XF1:2345:off:/etc/getty ttyFM01 9600 SHAR_EOF if test 72 -ne "`wc -c < 'i_fas-c1-2'`" then echo shar: "error transmitting 'i_fas-c1-2'" '(should have been 72 characters)' fi fi echo shar: "extracting 'i_fas-c1-3'" '(108 characters)' if test -f 'i_fas-c1-3' then echo shar: "will not over-write existing file 'i_fas-c1-3'" else sed 's/^X//' << \SHAR_EOF > 'i_fas-c1-3' XF0:2345:off:/etc/getty ttyFM00 9600 XF1:2345:off:/etc/getty ttyFM01 9600 XF2:2345:off:/etc/getty ttyFM02 9600 SHAR_EOF if test 108 -ne "`wc -c < 'i_fas-c1-3'`" then echo shar: "error transmitting 'i_fas-c1-3'" '(should have been 108 characters)' fi fi echo shar: "extracting 'i_fas-mux4'" '(144 characters)' if test -f 'i_fas-mux4' then echo shar: "will not over-write existing file 'i_fas-mux4'" else sed 's/^X//' << \SHAR_EOF > 'i_fas-mux4' XF0:2345:off:/etc/getty ttyFM00 9600 XF1:2345:off:/etc/getty ttyFM01 9600 XF2:2345:off:/etc/getty ttyFM02 9600 XF3:2345:off:/etc/getty ttyFM03 9600 SHAR_EOF if test 144 -ne "`wc -c < 'i_fas-mux4'`" then echo shar: "error transmitting 'i_fas-mux4'" '(should have been 144 characters)' fi fi echo shar: "extracting 'makefile.ISC'" '(1266 characters)' if test -f 'makefile.ISC' then echo shar: "will not over-write existing file 'makefile.ISC'" else sed 's/^X//' << \SHAR_EOF > 'makefile.ISC' X# Makefile for ISC SYS V/386 X XINCLSYS=/usr/include/sys XLKDRVRDIR=/etc/conf/pack.d/fas XLKSCONFDIR=/etc/conf/sdevice.d XLKNCONFDIR=/etc/conf/node.d XLKICONFDIR=/etc/conf/init.d XDRVRNAME=Driver.o XCONFNAME=fas X XCFLAGS = -O -DINKERNEL X XOBJS = fas.o X Xfas.o: fas.c $(INCLSYS)/fas.h X Xinstall: fas.o space.c s_$(CONFNAME) n_$(CONFNAME) i_$(CONFNAME) X -mkdir $(LKDRVRDIR) 2> /dev/null X chmod 755 $(LKDRVRDIR) X cp fas.o $(LKDRVRDIR)/$(DRVRNAME) X chmod 644 $(LKDRVRDIR)/$(DRVRNAME) X cp space.c $(LKDRVRDIR)/space.c X chmod 644 $(LKDRVRDIR)/space.c X cp s_$(CONFNAME) $(LKSCONFDIR)/$(CONFNAME) X chmod 644 $(LKSCONFDIR)/$(CONFNAME) X cp n_$(CONFNAME) $(LKNCONFDIR)/$(CONFNAME) X chmod 644 $(LKNCONFDIR)/$(CONFNAME) X cp i_$(CONFNAME) $(LKICONFDIR)/$(CONFNAME) X chmod 644 $(LKICONFDIR)/$(CONFNAME) X Xspace.c: X @echo "You must link the proper space-xxxxx file to \`space.c'" X @false X Xs_$(CONFNAME): X @echo "You must link the proper s_$(CONFNAME)-xxxxx file to \`s_$(CONFNAME)'" X @false X Xn_$(CONFNAME): X @echo "You must link the proper n_$(CONFNAME)-xxxxx file to \`n_$(CONFNAME)'" X @false X Xi_$(CONFNAME): X @echo "You must link the proper i_$(CONFNAME)-xxxxx file to \`i_$(CONFNAME)'" X @false X X$(INCLSYS)/fas.h: fas.h X cp fas.h $(INCLSYS)/fas.h X Xclean: X rm -f fas.o X Xclobber: clean X SHAR_EOF if test 1266 -ne "`wc -c < 'makefile.ISC'`" then echo shar: "error transmitting 'makefile.ISC'" '(should have been 1266 characters)' fi fi echo shar: "extracting 'makefile.uPort'" '(814 characters)' if test -f 'makefile.uPort' then echo shar: "will not over-write existing file 'makefile.uPort'" else sed 's/^X//' << \SHAR_EOF > 'makefile.uPort' X# Makefile for uPort SYS V/386 X XINCLSYS=/usr/include/sys XLKDRVRDIR=/etc/atconf/modules/fas XLKCONFDIR=/etc/atconf/modules/fas XDRVRNAME=fas.o XCONFNAME=config X XCFLAGS = -O -DINKERNEL -DOPTIM X XOBJS = fas.o X Xfas.o: fas.c $(INCLSYS)/fas.h X Xinstall: fas.o space.c $(CONFNAME) X -mkdir $(LKDRVRDIR) 2> /dev/null X chmod 755 $(LKDRVRDIR) X cp fas.o $(LKDRVRDIR)/$(DRVRNAME) X chmod 644 $(LKDRVRDIR)/$(DRVRNAME) X cp space.c $(LKDRVRDIR)/space.c X chmod 644 $(LKDRVRDIR)/space.c X cp $(CONFNAME) $(LKCONFDIR)/$(CONFNAME) X chmod 644 $(LKCONFDIR)/$(CONFNAME) X Xspace.c: X @echo "You must link the proper space-xxxxx file to \`space.c'" X @false X X$(CONFNAME): X @echo "You must link the proper $(CONFNAME)-xxxxx file to \`$(CONFNAME)'" X @false X X$(INCLSYS)/fas.h: fas.h X cp fas.h $(INCLSYS)/fas.h X Xclean: X rm -f fas.o X Xclobber: clean X SHAR_EOF if test 814 -ne "`wc -c < 'makefile.uPort'`" then echo shar: "error transmitting 'makefile.uPort'" '(should have been 814 characters)' fi fi echo shar: "extracting 'n_fas-c1-2'" '(68 characters)' if test -f 'n_fas-c1-2' then echo shar: "will not over-write existing file 'n_fas-c1-2'" else sed 's/^X//' << \SHAR_EOF > 'n_fas-c1-2' Xfas ttyF00 c 48 Xfas ttyF01 c 49 Xfas ttyFM00 c 208 Xfas ttyFM01 c 209 SHAR_EOF if test 68 -ne "`wc -c < 'n_fas-c1-2'`" then echo shar: "error transmitting 'n_fas-c1-2'" '(should have been 68 characters)' fi fi echo shar: "extracting 'n_fas-c1-3'" '(102 characters)' if test -f 'n_fas-c1-3' then echo shar: "will not over-write existing file 'n_fas-c1-3'" else sed 's/^X//' << \SHAR_EOF > 'n_fas-c1-3' Xfas ttyF00 c 48 Xfas ttyF01 c 49 Xfas ttyF02 c 50 Xfas ttyFM00 c 208 Xfas ttyFM01 c 209 Xfas ttyFM02 c 210 SHAR_EOF if test 102 -ne "`wc -c < 'n_fas-c1-3'`" then echo shar: "error transmitting 'n_fas-c1-3'" '(should have been 102 characters)' fi fi echo shar: "extracting 'n_fas-mux4'" '(136 characters)' if test -f 'n_fas-mux4' then echo shar: "will not over-write existing file 'n_fas-mux4'" else sed 's/^X//' << \SHAR_EOF > 'n_fas-mux4' Xfas ttyF00 c 48 Xfas ttyF01 c 49 Xfas ttyF02 c 50 Xfas ttyF03 c 51 Xfas ttyFM00 c 208 Xfas ttyFM01 c 209 Xfas ttyFM02 c 210 Xfas ttyFM03 c 211 SHAR_EOF if test 136 -ne "`wc -c < 'n_fas-mux4'`" then echo shar: "error transmitting 'n_fas-mux4'" '(should have been 136 characters)' fi fi echo shar: "extracting 's_fas-c1-2'" '(52 characters)' if test -f 's_fas-c1-2' then echo shar: "will not over-write existing file 's_fas-c1-2'" else sed 's/^X//' << \SHAR_EOF > 's_fas-c1-2' Xfas Y 1 7 1 4 3f8 3ff 0 0 Xfas Y 1 7 1 3 2f8 2ff 0 0 SHAR_EOF if test 52 -ne "`wc -c < 's_fas-c1-2'`" then echo shar: "error transmitting 's_fas-c1-2'" '(should have been 52 characters)' fi fi echo shar: "extracting 's_fas-c1-3'" '(78 characters)' if test -f 's_fas-c1-3' then echo shar: "will not over-write existing file 's_fas-c1-3'" else sed 's/^X//' << \SHAR_EOF > 's_fas-c1-3' Xfas Y 1 7 1 4 3f8 3ff 0 0 Xfas Y 1 7 1 3 2f8 2ff 0 0 Xfas Y 1 7 1 9 3e8 3ef 0 0 SHAR_EOF if test 78 -ne "`wc -c < 's_fas-c1-3'`" then echo shar: "error transmitting 's_fas-c1-3'" '(should have been 78 characters)' fi fi echo shar: "extracting 's_fas-mux4'" '(26 characters)' if test -f 's_fas-mux4' then echo shar: "will not over-write existing file 's_fas-mux4'" else sed 's/^X//' << \SHAR_EOF > 's_fas-mux4' Xfas Y 4 7 1 4 2a0 2a7 0 0 SHAR_EOF if test 26 -ne "`wc -c < 's_fas-mux4'`" then echo shar: "error transmitting 's_fas-mux4'" '(should have been 26 characters)' fi fi echo shar: "extracting 'space-c1-2'" '(4247 characters)' if test -f 'space-c1-2' then echo shar: "will not over-write existing file 'space-c1-2'" else sed 's/^X//' << \SHAR_EOF > 'space-c1-2' X/* Async device configuration file for the FAS async driver. */ X X/* This version is for the standard COM1 and COM2 ports. X*/ X X/* Originally written by XJim Murray encore!cloud9!jjmhome!jjm X2 Mohawk Circle harvard!m2c!jjmhome!jjm XWestboro Mass 01581 jjm%jjmhome at m2c.m2c.org XUSA voice (508) 366-2813 X*/ X X/* Current author: XUwe Doering gemini at netmbx.UUCP XBillstedter Pfad 17 B X1000 Berlin 20 XWest Germany X*/ X X#ident "@(#)space.c 2.05" X X#include <sys/fas.h> X X/* This is the number of devices to be handled by this driver. X You may define up to 16 devices. If this number is changed X the arrays below must be filled in accordingly. X*/ X#define NUM_PHYSICAL_UNITS 2 X X#if NUM_PHYSICAL_UNITS > MAX_UNITS X#undef NUM_PHYSICAL_UNITS X#define NUM_PHYSICAL_UNITS MAX_UNITS X#endif X X/* let the driver know the number of devices */ Xuint fas_physical_units = NUM_PHYSICAL_UNITS; X X/* array of base port addresses */ Xuint fas_port [NUM_PHYSICAL_UNITS] = X{ X 0x3f8, 0x2f8 X}; X X/* array of interrupt vectors */ Xuint fas_vec [NUM_PHYSICAL_UNITS] = X{ X 0x4, 0x3 X}; X X/* modem control port info X This value is ored into the modem control value for each UART. This is X normaly used to force out2 which is used to enable the interrupts form X the standard com1 and com2 ports. Several brands of cards have modes X that allow them to work in compatible mode like com1 and com2 or as a X mux. One of these cards is the MU-440 card by DFI. When this card is X used with the common interrupt out2 must not be set or there will be X a fight on the bus. X X Note: This is one of the major trouble-spots with mux cards. Check X your manual. X*/ X Xuint fas_mcb [NUM_PHYSICAL_UNITS] = X{ X MC_SET_OUT2, MC_SET_OUT2 X}; X X/* array of hardware flow control flags X You can choose which signals to use for output handshake. See fas.h X for possible names and values. Whether or not hardware handshake is X used is determined by the minor device number at open time. X*/ Xuint fas_flow [NUM_PHYSICAL_UNITS] = X{ X HH_BOTH, HH_BOTH X}; X X/* additional configurations for multiplexed interrupt boards X If you have a mux board, you may have to acknowledge interrupts X by writing to a special register. There may be a separate register X for every single port or for every interrupt vector or both. X The following arrays contain the special register addresses and X the corresponding values that are written to them in response X to an interrupt. X*/ X X/* array of int ack register addresses X These registers are written to every time after all interrupt X sources in the corresponding UART have been cleared. X Enter the addresses on a per unit base. An address of zero X disables this feature. X*/ X Xuint fas_int_ack_port [NUM_PHYSICAL_UNITS] = X{ X 0, 0 X}; X X/* array of int ack values X These values are written to the corresponding int ack register X in response to an interrupt. X*/ X Xuint fas_int_ack [NUM_PHYSICAL_UNITS] = X{ X 0, 0 X}; X X/* array of int ack mux register addresses X These registers are written to every time after all interrupt X sources in all of the UARTs that are tied to the corresponding X interrupt vector have been cleared. X Enter the addresses on a per vector base. An address of zero X disables this feature. X*/ X Xuint fas_mux_ack_port [NUM_INT_VECTORS] = X{ X 0, 0, 0, 0, X 0, 0, 0, 0, X 0, 0, 0, 0, X 0, 0, 0, 0 X}; X X/* array of int ack mux values X These values are written to the corresponding int ack mux register X in response to an interrupt. X*/ X Xuint fas_mux_ack [NUM_INT_VECTORS] = X{ X 0, 0, 0, 0, X 0, 0, 0, 0, X 0, 0, 0, 0, X 0, 0, 0, 0 X}; X X/* NOTHING NEEDS TO BE CHANGED BELOW THIS LINE. X ============================================ X*/ X X/* array of structures to hold all info for a physical minor device */ Xstruct fas_info fas_info [NUM_PHYSICAL_UNITS]; X X/* array of ttys for logical minor devices */ Xstruct tty fas_tty [NUM_PHYSICAL_UNITS * 2]; X X/* array of pointers to fas_info structures X this prevents time consuming multiplications for index calculation X*/ Xstruct fas_info *fas_info_ptr [NUM_PHYSICAL_UNITS]; X X/* array of pointers to fas_tty structures X this prevents time consuming multiplications for index calculation X*/ Xstruct tty *fas_tty_ptr [NUM_PHYSICAL_UNITS * 2]; SHAR_EOF if test 4247 -ne "`wc -c < 'space-c1-2'`" then echo shar: "error transmitting 'space-c1-2'" '(should have been 4247 characters)' fi fi echo shar: "extracting 'space-c1-3'" '(4310 characters)' if test -f 'space-c1-3' then echo shar: "will not over-write existing file 'space-c1-3'" else sed 's/^X//' << \SHAR_EOF > 'space-c1-3' X/* Async device configuration file for the FAS async driver. */ X X/* This version is for the standard COM1 and COM2 and additional COM3 X ports. X*/ X X/* Originally written by XJim Murray encore!cloud9!jjmhome!jjm X2 Mohawk Circle harvard!m2c!jjmhome!jjm XWestboro Mass 01581 jjm%jjmhome at m2c.m2c.org XUSA voice (508) 366-2813 X*/ X X/* Current author: XUwe Doering gemini at netmbx.UUCP XBillstedter Pfad 17 B X1000 Berlin 20 XWest Germany X*/ X X#ident "@(#)space.c 2.05" X X#include <sys/fas.h> X X/* This is the number of devices to be handled by this driver. X You may define up to 16 devices. If this number is changed X the arrays below must be filled in accordingly. X*/ X#define NUM_PHYSICAL_UNITS 3 X X#if NUM_PHYSICAL_UNITS > MAX_UNITS X#undef NUM_PHYSICAL_UNITS X#define NUM_PHYSICAL_UNITS MAX_UNITS X#endif X X/* let the driver know the number of devices */ Xuint fas_physical_units = NUM_PHYSICAL_UNITS; X X/* array of base port addresses */ Xuint fas_port [NUM_PHYSICAL_UNITS] = X{ X 0x3f8, 0x2f8, 0x3e8 X}; X X/* array of interrupt vectors */ Xuint fas_vec [NUM_PHYSICAL_UNITS] = X{ X 0x4, 0x3, 0x9 X}; X X/* modem control port info X This value is ored into the modem control value for each UART. This is X normaly used to force out2 which is used to enable the interrupts form X the standard com1 and com2 ports. Several brands of cards have modes X that allow them to work in compatible mode like com1 and com2 or as a X mux. One of these cards is the MU-440 card by DFI. When this card is X used with the common interrupt out2 must not be set or there will be X a fight on the bus. X X Note: This is one of the major trouble-spots with mux cards. Check X your manual. X*/ X Xuint fas_mcb [NUM_PHYSICAL_UNITS] = X{ X MC_SET_OUT2, MC_SET_OUT2, MC_SET_OUT2 X}; X X/* array of hardware flow control flags X You can choose which signals to use for output handshake. See fas.h X for possible names and values. Whether or not hardware handshake is X used is determined by the minor device number at open time. X*/ Xuint fas_flow [NUM_PHYSICAL_UNITS] = X{ X HH_BOTH, HH_BOTH, HH_BOTH X}; X X/* additional configurations for multiplexed interrupt boards X If you have a mux board, you may have to acknowledge interrupts X by writing to a special register. There may be a separate register X for every single port or for every interrupt vector or both. X The following arrays contain the special register addresses and X the corresponding values that are written to them in response X to an interrupt. X*/ X X/* array of int ack register addresses X These registers are written to every time after all interrupt X sources in the corresponding UART have been cleared. X Enter the addresses on a per unit base. An address of zero X disables this feature. X*/ X Xuint fas_int_ack_port [NUM_PHYSICAL_UNITS] = X{ X 0, 0, 0 X}; X X/* array of int ack values X These values are written to the corresponding int ack register X in response to an interrupt. X*/ X Xuint fas_int_ack [NUM_PHYSICAL_UNITS] = X{ X 0, 0, 0 X}; X X/* array of int ack mux register addresses X These registers are written to every time after all interrupt X sources in all of the UARTs that are tied to the corresponding X interrupt vector have been cleared. X Enter the addresses on a per vector base. An address of zero X disables this feature. X*/ X Xuint fas_mux_ack_port [NUM_INT_VECTORS] = X{ X 0, 0, 0, 0, X 0, 0, 0, 0, X 0, 0, 0, 0, X 0, 0, 0, 0 X}; X X/* array of int ack mux values X These values are written to the corresponding int ack mux register X in response to an interrupt. X*/ X Xuint fas_mux_ack [NUM_INT_VECTORS] = X{ X 0, 0, 0, 0, X 0, 0, 0, 0, X 0, 0, 0, 0, X 0, 0, 0, 0 X}; X X/* NOTHING NEEDS TO BE CHANGED BELOW THIS LINE. X ============================================ X*/ X X/* array of structures to hold all info for a physical minor device */ Xstruct fas_info fas_info [NUM_PHYSICAL_UNITS]; X X/* array of ttys for logical minor devices */ Xstruct tty fas_tty [NUM_PHYSICAL_UNITS * 2]; X X/* array of pointers to fas_info structures X this prevents time consuming multiplications for index calculation X*/ Xstruct fas_info *fas_info_ptr [NUM_PHYSICAL_UNITS]; X X/* array of pointers to fas_tty structures X this prevents time consuming multiplications for index calculation X*/ Xstruct tty *fas_tty_ptr [NUM_PHYSICAL_UNITS * 2]; SHAR_EOF if test 4310 -ne "`wc -c < 'space-c1-3'`" then echo shar: "error transmitting 'space-c1-3'" '(should have been 4310 characters)' fi fi echo shar: "extracting 'space-mux4'" '(4371 characters)' if test -f 'space-mux4' then echo shar: "will not over-write existing file 'space-mux4'" else sed 's/^X//' << \SHAR_EOF > 'space-mux4' X/* Async device configuration file for the FAS async driver. */ X X/* This version is for the DFI MU440 mux board in expanded mode. This board X is reported to be compatible with the AST 4-port card. X*/ X X/* Originally written by XJim Murray encore!cloud9!jjmhome!jjm X2 Mohawk Circle harvard!m2c!jjmhome!jjm XWestboro Mass 01581 jjm%jjmhome at m2c.m2c.org XUSA voice (508) 366-2813 X*/ X X/* Current author: XUwe Doering gemini at netmbx.UUCP XBillstedter Pfad 17 B X1000 Berlin 20 XWest Germany X*/ X X#ident "@(#)space.c 2.05" X X#include <sys/fas.h> X X/* This is the number of devices to be handled by this driver. X You may define up to 16 devices. If this number is changed X the arrays below must be filled in accordingly. X*/ X#define NUM_PHYSICAL_UNITS 4 X X#if NUM_PHYSICAL_UNITS > MAX_UNITS X#undef NUM_PHYSICAL_UNITS X#define NUM_PHYSICAL_UNITS MAX_UNITS X#endif X X/* let the driver know the number of devices */ Xuint fas_physical_units = NUM_PHYSICAL_UNITS; X X/* array of base port addresses */ Xuint fas_port [NUM_PHYSICAL_UNITS] = X{ X 0x2a0, 0x2a8, 0x2b0, 0x2b8 X}; X X/* array of interrupt vectors */ Xuint fas_vec [NUM_PHYSICAL_UNITS] = X{ X 0x4, 0x4, 0x4, 0x4 X}; X X/* modem control port info X This value is ored into the modem control value for each UART. This is X normaly used to force out2 which is used to enable the interrupts form X the standard com1 and com2 ports. Several brands of cards have modes X that allow them to work in compatible mode like com1 and com2 or as a X mux. One of these cards is the MU-440 card by DFI. When this card is X used with the common interrupt out2 must not be set or there will be X a fight on the bus. X X Note: This is one of the major trouble-spots with mux cards. Check X your manual. X*/ X Xuint fas_mcb [NUM_PHYSICAL_UNITS] = X{ X 0, 0, 0, 0 X}; X X/* array of hardware flow control flags X You can choose which signals to use for output handshake. See fas.h X for possible names and values. Whether or not hardware handshake is X used is determined by the minor device number at open time. X*/ Xuint fas_flow [NUM_PHYSICAL_UNITS] = X{ X HH_BOTH, HH_BOTH, HH_BOTH, HH_BOTH X}; X X/* additional configurations for multiplexed interrupt boards X If you have a mux board, you may have to acknowledge interrupts X by writing to a special register. There may be a separate register X for every single port or for every interrupt vector or both. X The following arrays contain the special register addresses and X the corresponding values that are written to them in response X to an interrupt. X*/ X X/* array of int ack register addresses X These registers are written to every time after all interrupt X sources in the corresponding UART have been cleared. X Enter the addresses on a per unit base. An address of zero X disables this feature. X*/ X Xuint fas_int_ack_port [NUM_PHYSICAL_UNITS] = X{ X 0, 0, 0, 0 X}; X X/* array of int ack values X These values are written to the corresponding int ack register X in response to an interrupt. X*/ X Xuint fas_int_ack [NUM_PHYSICAL_UNITS] = X{ X 0, 0, 0, 0 X}; X X/* array of int ack mux register addresses X These registers are written to every time after all interrupt X sources in all of the UARTs that are tied to the corresponding X interrupt vector have been cleared. X Enter the addresses on a per vector base. An address of zero X disables this feature. X*/ X Xuint fas_mux_ack_port [NUM_INT_VECTORS] = X{ X 0, 0, 0, 0, X 0x2bf, 0, 0, 0, X 0, 0, 0, 0, X 0, 0, 0, 0 X}; X X/* array of int ack mux values X These values are written to the corresponding int ack mux register X in response to an interrupt. X*/ X Xuint fas_mux_ack [NUM_INT_VECTORS] = X{ X 0, 0, 0, 0, X 0x80, 0, 0, 0, X 0, 0, 0, 0, X 0, 0, 0, 0 X}; X X/* NOTHING NEEDS TO BE CHANGED BELOW THIS LINE. X ============================================ X*/ X X/* array of structures to hold all info for a physical minor device */ Xstruct fas_info fas_info [NUM_PHYSICAL_UNITS]; X X/* array of ttys for logical minor devices */ Xstruct tty fas_tty [NUM_PHYSICAL_UNITS * 2]; X X/* array of pointers to fas_info structures X this prevents time consuming multiplications for index calculation X*/ Xstruct fas_info *fas_info_ptr [NUM_PHYSICAL_UNITS]; X X/* array of pointers to fas_tty structures X this prevents time consuming multiplications for index calculation X*/ Xstruct tty *fas_tty_ptr [NUM_PHYSICAL_UNITS * 2]; SHAR_EOF if test 4371 -ne "`wc -c < 'space-mux4'`" then echo shar: "error transmitting 'space-mux4'" '(should have been 4371 characters)' fi fi exit 0 # End of shell archive -- Uwe Doering | Domain : gemini at netmbx.UUCP Berlin |--------------------------------------------------------------- West Germany | Bangpath : ...!uunet!unido!tmpmbx!netmbx!gemini From shields at yunccn.UUCP Mon Jan 8 20:49:59 1990 From: shields at yunccn.UUCP (Paul Shields) Date: 8 Jan 90 09:49:59 GMT Subject: Menu software... Here it is: "lush" version 1.34, part 1/2 Message-ID: <3888@yunccn.UUCP> This is the little menu shell program I bragged about in comp.unix.xenix last thursday. I hope you all didn't get false expectations about it. I took the time to generate a few example menu files and double-check to make sure it still compiles on the Sun over at ISTS. Doubtless there are still problems with it. But I'm always open to constructive criticism. So give it a try. Enjoy! Paul Shields. #--------------------------------CUT HERE------------------------------------- #! /bin/sh # # This is a shell archive. Save this into a file, edit it # and delete all lines above this comment. Then give this # file to sh by executing the command "sh file". The files # will be extracted into the current directory owned by # you with default permissions. # # The files contained herein are: # # -rw-r--r-- 1 bin staff 2051 Jan 8 03:03 HISTORY # -rw-r--r-- 1 bin staff 3678 Jan 8 01:46 INSTALL # -rw-r--r-- 2 bin staff 1706 Jan 8 02:10 Makefile # -rw-r--r-- 1 bin staff 1653 Jan 8 02:12 Makefile.BSD # -rw-r--r-- 1 bin staff 1659 Jan 8 02:14 Makefile.Sun # -rw-r--r-- 2 bin staff 1706 Jan 8 02:10 Makefile.Xenix # -rw-r--r-- 1 bin staff 940 Jan 8 01:23 PROBLEMS # -rw-r--r-- 1 bin staff 983 Jan 7 19:35 README # -rw-r--r-- 1 bin staff 3330 Jan 8 03:08 WARRANTY # -rw-r--r-- 1 bin staff 711 Jan 7 19:50 login.sample # -rw-r--r-- 1 bin staff 726 Jan 8 02:57 lush.doc # -rw-r--r-- 1 bin staff 300 Jan 8 02:44 lushrc.sample # -rw-r--r-- 1 bin staff 148 Jan 8 01:11 lushrc.test # -rw-r--r-- 1 bin staff 12973 Jan 8 02:42 menu.sample # -rw-r--r-- 1 bin staff 1325 Jan 7 19:56 menu.test # echo 'x - HISTORY' if test -f HISTORY; then echo 'shar: not overwriting HISTORY'; else sed 's/^X//' << '________This_Is_The_END________' > HISTORY Xlush Revision History X--------------------- X X1987: X May ??. v0.00 (PAS) MS-DOS version. X Sep 6. v0.10 (PAS) Port to Xenix SysV. X Load config file from $LUSHRC; X security feature: strip user input: "<|>"; X Case is now insensitive. X Nov ??. v0.20 (PAS) Alpha test phase begins. X X1988: X Mar 11. v1.00 (PAS) Alpha version debugged and tested on X SysV Xenix and MS-DOS. Beta phase begins. X Mar ??. v1.10 (PAS) Added simple termcap support. X Apr 15. v1.11 (PAS) debugged termcap support. X Apr 11. v1.20 (PAS) extended support to SunOs 3.5, X (BSD4.2 variant, non-ANSI C compiler.) X Apr 16, v1.21 (PAS) merged v1.11+1.20. X May 11. v1.22 (PAS) corrected a problem in the Makefiles. X May 29. v1.23 (PAS) security fix: ignore SIGTSTP. X Jun 13. v1.30 (PAS) several valuable enhancements: X added "invisible" commands. X added switches on the command line: X lush -f rcfile -R rootmenu X Handle ~user X Enable setenv (function #12.) X X1989: X Mar 1. v1.31 (PAS) added a primitive to quit to main menu. X X1990: X Jan 5. v1.32 (PAS) security feature: strip ";&" from user input. X Jan 5. v1.32 (PAS) Generated documentation for the public release. X Jan 7. v1.33 (PAS) Lots. X Added switches -M, -U, -G. -f is now a synonym for -M. X Created the config.h file. X Added global and local environment configuration files. This is X to enable lush to run as the top level shell. These files are X of the format VAR=string, and are placed into the environment X before the menu file is loaded. X Redefined the meaning of the LUSHRC environment variable. Now, X it points to the user environment config file, whereas before it X pointed to the menu file itself. This radical change is X justified to avoid confusion when the first public release is X put out. X Broke mparse.c down into mfile.c, mlex.c, and mparse.c. This is X to facilitate letting other parts of the code use the lexical X analyser. X Added more documentation and sample files. X Jan 8. v1.34 (PAS) Froze the files for public release. ________This_Is_The_END________ if test `wc -l < HISTORY` -ne 51; then echo 'shar: HISTORY was damaged during transit (should have been 51 lines)' fi fi ; : end of overwriting check echo 'x - INSTALL' if test -f INSTALL; then echo 'shar: not overwriting INSTALL'; else sed 's/^X//' << '________This_Is_The_END________' > INSTALL XThis file gives instructions on how to set up lush. It assumes you have Xsystem manager privileges. X X. Choose the correct Makefile based on your system and compiler. The X SysV and Xenix configutations should be the same. You may want to X change BINDIR and LIBDIR in the Makefile. X X. Type make to build the program. X X. Test that it is working, with the following command: X X ./lush -M menu.test -G lushrc.test X X This should place a test menu on the screen. Try each option. X X. Create and configure the files lushrc (the system config file) and X menu (the system menu file.) There are samples (lushrc.sample, X menu.sample) of each of these. This is typically very site-specific. X Documentation for the syntax of the menu file is included in X menu.sample. The syntax of the lushrc file is apparent from the sample. X X. Type make install to place the binary in BINDIR and the config X files in LIBDIR. X X. Create a test account to use the menu system. You can make this use X lush as the login shell or run it from another shell. X X The single remaining problem with using lush as the login shell is X that there is no good way to set the terminal type. This may be done X from sh or csh in the usual way. Lush needs to have the environment variable X TERM in order to work properly. If term is not set at all, lush will X try "dumb" as a last resort. X X BEWARE: If you run lush from another shell... X (1) You must trap interrupt and quit signals in the .profile of the X other shell. Lush handles these, but if you do not trap them, X there is a time window in which the user could break through to X the bare shell. X (2) Be sure to add a logout statement after lush exits, since lush X won't automatically log out the user if run as a sub-shell. X XNotes: X X1.If you invoke lush from a another shell, you may place switches X on the command line: X X lush [-M menu-file] [-R root-menu] [-G global-config-file] X [-U user-config-file] X X The optional switch '-G' tells lush the location of the global run-time X configuration file (see lushrc.sample). The default value, set in X config.h, is usually /usr/lib/lush/lushrc. This file contains a list X of environment definitions that will be set up before any other file X is loaded. These environment variables are used as defaults to the X other parameters below, and are available to the designer of the menu X file (see menu.sample) during execution. X X The optional switch '-U' tells lush the location of the user run-time X configuration file. The default is the $LUSHRC environment variable. X If not defined, the value set in config.h (usually ~/.lushrc) is used. X It is similar to the global rc file, above, but serves to permit X configuration on a per-user basis. X X The optional switch '-M' tells lush where to find the menu X specification file. The default is the $MENUFILE environment X variable. If not defined, the value set in config.h (usually X /usr/lib/lush/menu) is used as a last resort. X X The switch '-R' tells lush which menu is the root, (the first X menu to be displayed.) The default is the $ROOTMENU environment X variable. If not defined, the value set in config.h (usually X MAIN_MENU) is used as a last resort. X X2.When lush runs, it ensures that the following environment variables X are initialized: X X Variable Default Purpose X -------- ------- ------- X SHELL argv[0] the name of the shell X USER in /etc/passwd your username (security feature) X TTY ttyname() your terminal name (security feature) X TERM "dumb" your terminal type (specific terminal handling) X HOME in /etc/passwd your home directory ________This_Is_The_END________ if test `wc -l < INSTALL` -ne 83; then echo 'shar: INSTALL was damaged during transit (should have been 83 lines)' fi fi ; : end of overwriting check echo 'x - Makefile' if test -f Makefile; then echo 'shar: not overwriting Makefile'; else sed 's/^X//' << '________This_Is_The_END________' > Makefile X# Makefile.Xenix X# Xenix System V Generic Makefile for lush X XLIBDIR=/usr/lib/lush XBINDIR=/usr/local/bin X X# compiler definitions you might want to have: X# X# -DPROTOTYPE if your compiler can handle prototype statements X# -DMSDOS if you are running under MS-DOS X# -DSUN if you are running on a Sun workstation X XCC = cc -M0s -i -Zi XDEBUG = XDEFS = -DPROTOTYPE XCFLAGS = $(DEBUG) $(DEFS) XLDFLAGS= -Fmlush.map XLIBS = -lc -ltermcap X XHFILES = mparse.h mlex.h mfile.h menu.h edit.h lush.h defs.h version.h config.h XCFILES = mparse.c mlex.c mfile.c menu.c edit.c lush.c envinit.c getin.c login.c XOBJS = mparse.o mlex.o mfile.o menu.o edit.o lush.o envinit.o getin.o login.o X X# ----------------------------- dependencies -------------------------------- X Xlush: $(OBJS) X $(CC) $(LDFLAGS) $(OBJS) $(LIBS) -o lush X Xclean: X -rm -f lush a.out core errs *.o *.map X Xinstall: lush lushrc menu X -test -d $(BINDIR) || mkdir $(BINDIR) X -test -d $(LIBDIR) || mkdir $(LIBDIR) X -strip lush X chmod 755 lush X chmod 644 lushrc menu X cp lush $(BINDIR) X cp lushrc menu $(LIBDIR) X Xmparse.o: mparse.c mparse.h mlex.h mfile.h menu.h lush.h defs.h config.h X $(CC) $(CFLAGS) mparse.c -c X Xmlex.o: mlex.c mlex.h mfile.h lush.h defs.h X $(CC) $(CFLAGS) mlex.c -c X Xmfile.o: mfile.c mfile.h lush.h defs.h X $(CC) $(CFLAGS) mfile.c -c X Xmenu.o: menu.c menu.h lush.h defs.h config.h X $(CC) $(CFLAGS) menu.c -c X Xedit.o: edit.c edit.h lush.h defs.h config.h X $(CC) $(CFLAGS) edit.c -c X Xenvinit.o: envinit.c lush.h defs.h config.h X $(CC) $(CFLAGS) envinit.c -c X Xlogin.o: login.c defs.h X $(CC) $(CFLAGS) login.c -c X Xgetin.o: getin.c defs.h X $(CC) $(CFLAGS) getin.c -c X Xlush.o: lush.c lush.h defs.h config.h version.h X $(CC) $(CFLAGS) lush.c -c ________This_Is_The_END________ if test `wc -l < Makefile` -ne 66; then echo 'shar: Makefile was damaged during transit (should have been 66 lines)' fi fi ; : end of overwriting check echo 'x - Makefile.BSD' if test -f Makefile.BSD; then echo 'shar: not overwriting Makefile.BSD'; else sed 's/^X//' << '________This_Is_The_END________' > Makefile.BSD X# Makefile.BSD X# Generic BSD4.2 Makefile for lush X XLIBDIR=/usr/lib/lush XBINDIR=/usr/local/bin X X# compiler definitions you might want to have: X# X# -DPROTOTYPE if your compiler can handle prototype statements X# -DMSDOS if you are running under MS-DOS X# -DSUN if you are running on a Sun workstation X XDEBUG = XDEFS = -DBSD XCFLAGS = $(DEBUG) $(DEFS) XLDFLAGS= XLIBS = -ltermcap X XHFILES = mparse.h mlex.h mfile.h menu.h edit.h lush.h defs.h version.h config.h XCFILES = mparse.c mlex.c mfile.c menu.c edit.c lush.c envinit.c getin.c login.c XOBJS = mparse.o mlex.o mfile.o menu.o edit.o lush.o envinit.o getin.o login.o X X# ----------------------------- dependencies -------------------------------- X Xlush: $(OBJS) X $(CC) $(LDFLAGS) $(OBJS) $(LIBS) -o lush X Xclean: X -rm -f lush a.out core errs *.o *.map X Xinstall: lush lushrc menu X -test -d $(BINDIR) || mkdir $(BINDIR) X -test -d $(LIBDIR) || mkdir $(LIBDIR) X -strip lush X chmod 755 lush X chmod 644 lushrc menu X cp lush $(BINDIR) X cp lushrc menu $(LIBDIR) X Xmparse.o: mparse.c mparse.h mlex.h mfile.h menu.h lush.h defs.h config.h X $(CC) $(CFLAGS) mparse.c -c X Xmlex.o: mlex.c mlex.h mfile.h lush.h defs.h X $(CC) $(CFLAGS) mlex.c -c X Xmfile.o: mfile.c mfile.h lush.h defs.h X $(CC) $(CFLAGS) mfile.c -c X Xmenu.o: menu.c menu.h lush.h defs.h config.h X $(CC) $(CFLAGS) menu.c -c X Xedit.o: edit.c edit.h lush.h defs.h config.h X $(CC) $(CFLAGS) edit.c -c X Xenvinit.o: envinit.c lush.h defs.h config.h X $(CC) $(CFLAGS) envinit.c -c X Xlogin.o: login.c defs.h X $(CC) $(CFLAGS) login.c -c X Xgetin.o: getin.c defs.h X $(CC) $(CFLAGS) getin.c -c X Xlush.o: lush.c lush.h defs.h config.h version.h X $(CC) $(CFLAGS) lush.c -c ________This_Is_The_END________ if test `wc -l < Makefile.BSD` -ne 65; then echo 'shar: Makefile.BSD was damaged during transit (should have been 65 lines)' fi fi ; : end of overwriting check echo 'x - Makefile.Sun' if test -f Makefile.Sun; then echo 'shar: not overwriting Makefile.Sun'; else sed 's/^X//' << '________This_Is_The_END________' > Makefile.Sun X# Makefile.Sun X# SunOs BSD 4.2 Makefile for lush X XLIBDIR=/usr/lib/lush XBINDIR=/usr/local/bin X X# compiler definitions you might want to have: X# X# -DPROTOTYPE if your compiler can handle prototype statements X# -DMSDOS if you are running under MS-DOS X# -DSUN if you are running on a Sun workstation X XDEBUG = XDEFS = -DBSD -DSUN XCFLAGS = $(DEBUG) $(DEFS) XLDFLAGS= XLIBS = -ltermcap X XHFILES = mparse.h mlex.h mfile.h menu.h edit.h lush.h defs.h version.h config.h XCFILES = mparse.c mlex.c mfile.c menu.c edit.c lush.c envinit.c getin.c login.c XOBJS = mparse.o mlex.o mfile.o menu.o edit.o lush.o envinit.o getin.o login.o X X# ----------------------------- dependencies -------------------------------- X Xlush: $(OBJS) X $(CC) $(LDFLAGS) $(OBJS) $(LIBS) -o lush X Xclean: X -rm -f lush a.out core errs *.o *.map X Xinstall: lush lushrc menu X -test -d $(BINDIR) || mkdir $(BINDIR) X -test -d $(LIBDIR) || mkdir $(LIBDIR) X -strip lush X chmod 755 lush X chmod 644 lushrc menu X cp lush $(BINDIR) X cp lushrc menu $(LIBDIR) X Xmparse.o: mparse.c mparse.h mlex.h mfile.h menu.h lush.h defs.h config.h X $(CC) $(CFLAGS) mparse.c -c X Xmlex.o: mlex.c mlex.h mfile.h lush.h defs.h X $(CC) $(CFLAGS) mlex.c -c X Xmfile.o: mfile.c mfile.h lush.h defs.h X $(CC) $(CFLAGS) mfile.c -c X Xmenu.o: menu.c menu.h lush.h defs.h config.h X $(CC) $(CFLAGS) menu.c -c X Xedit.o: edit.c edit.h lush.h defs.h config.h X $(CC) $(CFLAGS) edit.c -c X Xenvinit.o: envinit.c lush.h defs.h config.h X $(CC) $(CFLAGS) envinit.c -c X Xlogin.o: login.c defs.h X $(CC) $(CFLAGS) login.c -c X Xgetin.o: getin.c defs.h X $(CC) $(CFLAGS) getin.c -c X Xlush.o: lush.c lush.h defs.h config.h version.h X $(CC) $(CFLAGS) lush.c -c ________This_Is_The_END________ if test `wc -l < Makefile.Sun` -ne 65; then echo 'shar: Makefile.Sun was damaged during transit (should have been 65 lines)' fi fi ; : end of overwriting check echo 'x - Makefile.Xenix' if test -f Makefile.Xenix; then echo 'shar: not overwriting Makefile.Xenix'; else sed 's/^X//' << '________This_Is_The_END________' > Makefile.Xenix X# Makefile.Xenix X# Xenix System V Generic Makefile for lush X XLIBDIR=/usr/lib/lush XBINDIR=/usr/local/bin X X# compiler definitions you might want to have: X# X# -DPROTOTYPE if your compiler can handle prototype statements X# -DMSDOS if you are running under MS-DOS X# -DSUN if you are running on a Sun workstation X XCC = cc -M0s -i -Zi XDEBUG = XDEFS = -DPROTOTYPE XCFLAGS = $(DEBUG) $(DEFS) XLDFLAGS= -Fmlush.map XLIBS = -lc -ltermcap X XHFILES = mparse.h mlex.h mfile.h menu.h edit.h lush.h defs.h version.h config.h XCFILES = mparse.c mlex.c mfile.c menu.c edit.c lush.c envinit.c getin.c login.c XOBJS = mparse.o mlex.o mfile.o menu.o edit.o lush.o envinit.o getin.o login.o X X# ----------------------------- dependencies -------------------------------- X Xlush: $(OBJS) X $(CC) $(LDFLAGS) $(OBJS) $(LIBS) -o lush X Xclean: X -rm -f lush a.out core errs *.o *.map X Xinstall: lush lushrc menu X -test -d $(BINDIR) || mkdir $(BINDIR) X -test -d $(LIBDIR) || mkdir $(LIBDIR) X -strip lush X chmod 755 lush X chmod 644 lushrc menu X cp lush $(BINDIR) X cp lushrc menu $(LIBDIR) X Xmparse.o: mparse.c mparse.h mlex.h mfile.h menu.h lush.h defs.h config.h X $(CC) $(CFLAGS) mparse.c -c X Xmlex.o: mlex.c mlex.h mfile.h lush.h defs.h X $(CC) $(CFLAGS) mlex.c -c X Xmfile.o: mfile.c mfile.h lush.h defs.h X $(CC) $(CFLAGS) mfile.c -c X Xmenu.o: menu.c menu.h lush.h defs.h config.h X $(CC) $(CFLAGS) menu.c -c X Xedit.o: edit.c edit.h lush.h defs.h config.h X $(CC) $(CFLAGS) edit.c -c X Xenvinit.o: envinit.c lush.h defs.h config.h X $(CC) $(CFLAGS) envinit.c -c X Xlogin.o: login.c defs.h X $(CC) $(CFLAGS) login.c -c X Xgetin.o: getin.c defs.h X $(CC) $(CFLAGS) getin.c -c X Xlush.o: lush.c lush.h defs.h config.h version.h X $(CC) $(CFLAGS) lush.c -c ________This_Is_The_END________ if test `wc -l < Makefile.Xenix` -ne 66; then echo 'shar: Makefile.Xenix was damaged during transit (should have been 66 lines)' fi fi ; : end of overwriting check echo 'x - PROBLEMS' if test -f PROBLEMS; then echo 'shar: not overwriting PROBLEMS'; else sed 's/^X//' << '________This_Is_The_END________' > PROBLEMS XThis file is for documenting bugs and misfeatures. Your comments and Xsuggestions for how to improve lush are always welcome. X X1. Lush will run as the login shell, but BEWARE: X The single remaining problem with using lush as the login shell X is that there is no good way to set the terminal type. X This is not good for dialup users, who may be calling from any X type of terminal. X X I'm working on it. X X2. Lush uses termcap. I haven't even thought about terminfo. X X3. Though it uses termcap, it is still command based. That is, You Xcan't use the cursor keys to make a selection. I'm currently thinking Xabout what this would entail, and I want to maintain portability to XMS-DOS. X X4. The MS-DOS part of the code has not been exercised in a while. X X5. Ctrl-D is currently ignored. Perhaps it should pop back one menu? X X6. Function numbers 4 (CHK_RDACC), 7 (CHK_WRACC), and 11 (CHK_ACCESS) Xare defined but not currently used. ________This_Is_The_END________ if test `wc -l < PROBLEMS` -ne 24; then echo 'shar: PROBLEMS was damaged during transit (should have been 24 lines)' fi fi ; : end of overwriting check echo 'x - README' if test -f README; then echo 'shar: not overwriting README'; else sed 's/^X//' << '________This_Is_The_END________' > README XPlease read the file "WARRANTY" in this directory. X XLush is a user interface intended to ease the learning curve required to Xmake effective use of UNIX. System administrators may install it to run Xas the top-level shell in /etc/passwd, or it may run another shell. It Xprovides a simple menu for the user, and switches amongst sub-menus or Xcalls programs based on the menu configuration file. X XIt has a partially visual interface, which supports various terminals Xthrough termcap. X XAt this time, it has been tested on BSD 4.2, Xenix System V, and MS-DOS. XTo compile it under MS-DOS, you will need a library of functions which Xemulate many of the UNIX system calls (available from me for Lattice C Xv3.20.) The DOS code has not been exercised in over a year, so it may Xrequire some work. X XTo install it, follow the instructions in the file INSTALL, in this Xdirectory. X XCurrently lush is at version 1.32. X XGood luck, and enjoy. XPaul Shields, XFri Jan 5 16:31:09 EST 1990 XToronto. ________This_Is_The_END________ if test `wc -l < README` -ne 26; then echo 'shar: README was damaged during transit (should have been 26 lines)' fi fi ; : end of overwriting check echo 'x - WARRANTY' if test -f WARRANTY; then echo 'shar: not overwriting WARRANTY'; else sed 's/^X//' << '________This_Is_The_END________' > WARRANTY XCopyright(C)1987,1988,1989,1990 by Paul A. Shields. Permission is Xgranted to redistribute this software as long as the complete source Xcode is included in the distribution, the files are not altered in any Xway, and no monetary profit is gained from its distribution. X XThis software is provided "as is", without any warranty. The author has Xmade every effort to test this software, however since it is provided Xwithout charge, he shall not be held responsible for damages resulting Xfrom its use nor from the inability to use it. You must assume all Xcosts of servicing it or replacing it if it does not perform as Xspecified, or does not meet your expectations. X XThe following is a list of the files you should expect to have: X Xtotal 198 X-rw-r--r-- 1 bin staff 2051 Jan 8 03:03 HISTORY X-rw-r--r-- 1 bin staff 3678 Jan 8 01:46 INSTALL X-rw-r--r-- 2 bin staff 1706 Jan 8 02:10 Makefile X-rw-r--r-- 1 bin staff 1653 Jan 8 02:12 Makefile.BSD X-rw-r--r-- 1 bin staff 1659 Jan 8 02:14 Makefile.Sun X-rw-r--r-- 2 bin staff 1706 Jan 8 02:10 Makefile.Xenix X-rw-r--r-- 1 bin staff 940 Jan 8 01:23 PROBLEMS X-rw-r--r-- 1 bin staff 983 Jan 7 19:35 README X-rw-r--r-- 1 bin staff 3330 Jan 8 03:07 WARRANTY X-rw-r--r-- 1 bin staff 1054 Jan 8 01:57 config.h X-rw-r--r-- 1 bin staff 1498 Jan 7 15:51 defs.h X-rw-r--r-- 1 bin staff 6473 Jan 5 18:16 edit.c X-rw-r--r-- 1 bin staff 1508 Mar 1 1989 edit.h X-rw-r--r-- 1 bin staff 8594 Jan 7 18:25 envinit.c X-rw-r--r-- 1 bin staff 809 Mar 11 1988 getin.c X-rw-r--r-- 1 bin staff 529 Mar 11 1988 login.c X-rw-r--r-- 1 bin staff 711 Jan 7 19:50 login.sample X-rw-r--r-- 1 bin staff 1586 Jan 7 22:26 lush.c X-rw-r--r-- 1 bin staff 726 Jan 8 02:57 lush.doc X-rw-r--r-- 1 bin staff 2156 Jan 7 17:56 lush.h X-rw-r--r-- 1 bin staff 300 Jan 8 02:44 lushrc.sample X-rw-r--r-- 1 bin staff 148 Jan 8 01:11 lushrc.test X-rw-r--r-- 1 bin staff 5054 Jan 7 14:35 menu.c X-rw-r--r-- 1 bin staff 1580 Jan 8 02:01 menu.h X-rw-r--r-- 1 bin staff 12973 Jan 8 02:42 menu.sample X-rw-r--r-- 1 bin staff 1325 Jan 7 19:56 menu.test X-rw-r--r-- 1 bin staff 2403 Jan 8 01:01 mfile.c X-rw-r--r-- 1 bin staff 1056 Jan 8 00:46 mfile.h X-rw-r--r-- 1 bin staff 2111 Jan 8 00:54 mlex.c X-rw-r--r-- 1 bin staff 1082 Jan 8 01:52 mlex.h X-rw-r--r-- 1 bin staff 9997 Jan 8 01:04 mparse.c X-rw-r--r-- 1 bin staff 661 Jan 7 23:14 mparse.h X-rw-r--r-- 1 bin staff 66 Jan 8 03:04 version.h X XIf you modify the software in any way for your own use, please send me a Xcontext-diff with a note explaining the modifications, and I will Xconsider it for inclusion in the public release. X XIf you have any questions about this software, you may reach me at these Xaddresses: X XE-Mail: shields at nccn.yorku.ca, (...uunet!yunccn!shields) X shields at ists.ists.ca, (...uunet!ists!shields) X XPost: Paul Shields, X Rm 217A Lumbers, York University, X 4700 Keele Street, X North York, Ontario, X M3J 1P3 X Canada ________This_Is_The_END________ if test `wc -l < WARRANTY` -ne 65; then echo 'shar: WARRANTY was damaged during transit (should have been 65 lines)' fi fi ; : end of overwriting check echo 'x - login.sample' if test -f login.sample; then echo 'shar: not overwriting login.sample'; else sed 's/^X//' << '________This_Is_The_END________' > login.sample X#!/bin/csh - sample .login file for csh, executes the "lush" menu system. X# X# assumes lush is in /usr/local/bin X# Xonintr - # ignore interrupts Xset dftype = dumb # initial default terminal type Xif ( -r ~/.ttype ) set dftype = `cat ~/.ttype` Xif ( $TERM != 'ansi' ) echo "Enter your terminal type or Press return for the default, \ X(eg: vt100,ansi,wy30,adm3a,dumb.)" X X# Use tset -S instead of tset -s in case disk space is exhausted. Xset noglob Xset term = (`tset -S -h -m ansi:ansi -m vt100:\?vt100 -m dialup:\?$dftype -m :\?unknown -I`) Xsetenv TERM $term[1] Xsetenv TERMCAP $term[2] Xunset term Xunset noglob X Xif ( $TERM == 'vt100' ) stty erase '^?' # delete deletes Xunset dftype X X/usr/local/bin/lush Xlogout ________This_Is_The_END________ if test `wc -l < login.sample` -ne 23; then echo 'shar: login.sample was damaged during transit (should have been 23 lines)' fi fi ; : end of overwriting check echo 'x - lush.doc' if test -f lush.doc; then echo 'shar: not overwriting lush.doc'; else sed 's/^X//' << '________This_Is_The_END________' > lush.doc XSoon to come... in lush 2.0: X X% cat /usr/lib/lush/lushrc X#!lush - sample global lushrc file X# X# ... program invocation using `` XTERM=`/bin/sh /usr/lib/lush/setterm` X# X# ... environment variable options with (a,b,c). XEDITOR=(/bin/red,/usr/bin/emacs) XNEWSREADER=(/usr/lib/news/vnews,/usr/lib/news/readnews) XPAGER=(/usr/bin/more,/usr/local/bin/less) XINTERFACE=(command,pointer) X X% cat ~test/.lushrc X#!lush... X# for security, X# user may choose only from list given in global config file. X# if the user fails to choose, or does so incorrectly, the default X# will be the first of the options. Need to provide a way for X# the user to edit it w/o worrying. XEDITOR=/usr/bin/emacs XNEWSREADER=/usr/bin/nn XPAGER=/usr/local/bin/less ________This_Is_The_END________ if test `wc -l < lush.doc` -ne 24; then echo 'shar: lush.doc was damaged during transit (should have been 24 lines)' fi fi ; : end of overwriting check echo 'x - lushrc.sample' if test -f lushrc.sample; then echo 'shar: not overwriting lushrc.sample'; else sed 's/^X//' << '________This_Is_The_END________' > lushrc.sample XSHELL=/usr/local/bin/lush XPATH=:/bin:/usr/bin:/usr/local/bin XMENUFILE=/usr/lib/lush/menu XROOTMENU=MAIN_MENU XLUSHRC=~/.lushrc XMAILER=/usr/bin/mail XEDITOR=/usr/local/bin/emacs XNEWSREADER=/usr/lib/news/vnews XNEWSBOX=~/ XPAGER=/usr/local/bin/less XLESS=-e -m -q MPMF< -->p< (q=Quit,f=Forward,u=Up,h=Help)> ________This_Is_The_END________ if test `wc -l < lushrc.sample` -ne 11; then echo 'shar: lushrc.sample was damaged during transit (should have been 11 lines)' fi fi ; : end of overwriting check echo 'x - lushrc.test' if test -f lushrc.test; then echo 'shar: not overwriting lushrc.test'; else sed 's/^X//' << '________This_Is_The_END________' > lushrc.test XROOTMENU=MAIN_MENU XLUSHRC=/dev/null XEDITOR=/usr/local/bin/emacs XPAGER=/usr/local/bin/less XLESS=-e -m -q MPMF< -->p< (q=Quit,f=Forward,u=Up,h=Help)> ________This_Is_The_END________ if test `wc -l < lushrc.test` -ne 5; then echo 'shar: lushrc.test was damaged during transit (should have been 5 lines)' fi fi ; : end of overwriting check echo 'x - menu.sample' if test -f menu.sample; then echo 'shar: not overwriting menu.sample'; else sed 's/^X//' << '________This_Is_The_END________' > menu.sample X#!lush X# file: menu.sample, lush v1.3 sample menu configuration script. X# X# Copyright(C)1987,1988,1989,1990 by Paul A. Shields. Permission is X# granted to redistribute this software as long as the complete source X# code is included in the distribution, the files are not altered in any X# way, and no monetary profit is gained from its distribution. X# X# This software is provided "as is", without any warranty. The author has X# made every effort to test this software, however since it is provided X# without charge, he shall not be held responsible for damages resulting X# from its use nor from the inability to use it. You must assume all X# costs of servicing it or replacing it if it does not perform as X# specified, or does not meet your expectations. X# X# Syntax: X# This file is free format, ie: space, tab, newline, and comments are X# treated as white space (comments lie between '#' and newline.) X# X# EBNF syntax for menu specification: X# menu_tree :== main_menu { ';' menu } '.'. X# main_menu :== 'MAIN_MENU' ':' menu_description menu_body. X# menu :== menu_title ':' menu_decsription menu_body. X# menu_title :== text. X# menu_description :== string. X# menu_body :== cmd_option {',' cmd_option}. X# cmd_option :== ['-'] cmd_name menu_title '(' [action_list] ')' cmd_description. X# cmd_description :== string. X# cmd_name :== text. X# action_list :== action {';' action}. X# action :== function_number parameter. X# parameter :== string. X# string :== delimiter text delimiter. X# X# Notes: X# 0) Lush reads the entire rc file before beginning, to check syntax. X# If a syntax error is discovered, it turfs its cookies and X# identifies the offending line number. X# X# 1) Lush traps SIGINT and SIGQUIT signals. SIGINT will abort a X# command or action-list in progress and return the user to the X# most recently accessed menu. SIGQUIT is ignored. X# X# 2) The standard menu title MAIN_MENU denotes the root. There are three X# other standard menu titles, NONE, RETURN and QUIT, which control X# movement through the structure. NONE indicates that there is no X# child menu, RETURN exits the menu, returning to the parent, and X# QUIT returns to the main menu. X# X# 3) Each menu title has a menu-description, which is a prompt for X# the user. X# X# 4) There will usually be several options for each menu. For X# every option there is an associated menu title, indicating the X# name of the menu to activate on successful completion of the X# action-list. X# X# User-typed commands are case insensitive. Further, the user need only X# enter the shortest unique string among the current menu options X# to identify the command, eg: q means Quit. X# X# Support for hidden options (ie: not displayed in menu) has been added. X# The appearance of a "-" before the option makes it hidden. X# X# 5) Currently the following function-numbers are defined: X# 0 = CHG_DIRECTORY - change to the named directory. X# 1 = CHK_PORT - Examines the environment string TTY and tries X# to find it in the specified file. If found, X# the operation is permitted. Otherwise it fails. X# 2 = CHK_TERM - Examines the environment string TERM and tries X# to find it in the specified file. If found, X# the operation is permitted. Otherwise it fails. X# 3 = PAUSE - pause with "Press enter: " message. X# 4 = - not used. X# 5 = CALL_CMD - perform a shell command. X# 6 = SECUR_CHECK - calls getgrnam() to check permission on named group. X# 7 = - not used. X# 8 = EXP_TOGGLE - Toggle expert mode. (no menus.) X# 9 = PNAME - prompt and get parameter name. X# 10 = P2NAME - prompt and get 2nd parameter name. X# 11 = - not used. X# 12 = SET_ENVT - set an environment variable X# 13 = SAVE_STR - save string in (global) recall-buffer X# 14 = RECALL_STR1 - put recall-buffer in parameter 1 X# 15 = RECALL_STR2 - put recall-buffer in parameter 2 X# X# 6) The menu structure is not necessarily a tree. It is a general X# directed graph. But there is no cycle detection in the X# initialization, so be careful! X# X# 7) Important! Every menu needs at least one option that will RETURN or X# QUIT. X# XMAIN_MENU: "Main Menu" X Tools TOOLS_MENU (6 "!alien") "Editing and printing tools", X Mail MAIL_MENU () "Send and Read mail", X News NEWS_MENU () "Post and Read news articles", X Phone NONE (5 "who"; X 9 "The above people are logged in. Username to call? "; X 5 "phone %s") "Call and talk to another user", X Help HELP_MENU () "Help on how to use the system", X Transfer XFER_MENU (6 "!alien") "Transferring files on the network", X Disk DISK_MENU (6 "!alien"; X 1 "/etc/ldevices") "Use the floppy disk", X Setup SETUP_MENU () "Change Terminal type and other things.", X-System MAINT_MENU (6 "!alien") "System maintenance", X-Bye QUIT (5 "echo Goodbye $USER, thanks for using the NCCN.") X "Sign off and hang up", X Logout QUIT (5 "echo Goodbye $USER, thanks for using the NCCN.") X "Sign off and hang up"; X XTOOLS_MENU: "Tools Menu" X Dir NONE (9 "Which directory (default is the current one)? "; X 5 "ls -las %s | $PAGER") X "Long listing of files in a directory", X Display NONE (5 "ls -axF"; X 9 "What file names (separated by spaces)? "; X 5 "$PAGER %s") X "Display a file ", X Edit NONE (5 "ls -axF"; X 9 "File name? "; X 5 "$EDITOR %s") "Edit a file", X Print NONE (5 "ls -axF"; X 9 "What file names (separated by spaces)? "; X 5 "lpr %s") "Print a file ", X Delete NONE (5 "ls -axF"; X 9 "What file names (separated by spaces)? "; X 5 "echo 'Answer y or n to each file.'; rm -i %s") X "Delete a file ", X Copy NONE (5 "ls -axF"; X 9 "from (file name)? "; X 10 "to (file name)? "; X 5 "cp %s %s") "Make a copy of a file", X Rename NONE (5 "ls -axF"; X 9 "Old file name? "; X 10 "New file name? "; X 5 "mv %s %s") "Rename a file", X Mkdir NONE (9 "New directory name? "; X 5 "mkdir %s") "Make a new directory (file folder)", X Cwd NONE (9 "Enter directory name? "; X 0 "%s") "Change your working directory", X Help NONE (5 "manual tools") "How to use the tools", X Return RETURN () "Return to previous menu", X Quit QUIT () "Go back to main menu"; X XMAIL_MENU: "Mail Menu" X Send NONE (9 "To: "; X 5 "$MAILER %s") "Send a message", X Read NONE (5 "$MAILER") "Read your messages", X X Who NONE (5 "/usr/local/bin/ulist | sort -u | $PAGER") X "List local users", X Mbox NONE (5 "$MAILER -f $HOME/mbox") X "Read old messages from your mbox", X Help NONE (5 "manual mail") "How to use Mail", X Quit QUIT () "Go back to main menu"; X XNEWS_MENU: "News Articles" X Groups NONE (5 "$PAGER /usr/lib/news/newsgroups") X "List available news groups", X-List NONE (5 "$PAGER /usr/lib/news/newsgroups") X "List available news groups", X Read NONE (6 "!alien"; X 6 "!user"; X 5 "$NEWSREADER -n general nccn to"; X 3 "") "Read NCCN news articles", X UNitex NONE (5 "$NEWSREADER -n unitex"; X 3 "") "Read United Nations news articles", X Usenet NONE (9 "which newsgroup(s)? "; X 5 "$NEWSREADER -n %s"; X 3 "") "Read Usenet news articles", X Post NONE (6 "!alien"; X 5 "postnews"; X 3 "") "Post a news article", X NBox NONE (5 "$MAILER -f $NEWSBOX/Articles") X "Read old messages in your Articles file", X Help NONE (5 "manual news") "How to use News", X Quit QUIT () "Go back to main menu"; X XHELP_MENU: "Help Menu" X NewUser NONE (5 "manual newuser") "How can I get an account?", X Emacs NONE (5 "echo 'Type ^X^C to exit' ; emacs /usr/local/man/emacs-tut.doc") X "Use Emacs on a tutorial file", X Topic NONE (5 "manual"; X 9 "What Topic? "; X 5 "manual %s") "Get help on a specific topic", X Operator NONE (5 "$MAILER root") "Send a mail message to the operator", X Guidelines NONE (5 "manual guidelines") "Guidelines for Using News", X Quit QUIT () "Go back to main menu"; X XMAINT_MENU: "System Maintenance" X Monitor NONE (6 "!alien"; X 6 "!group"; X 5 "monitor") "Monitor network performance", X Mkuser NONE (6 "root"; X 5 "/etc/mkuser") "Make a new user account", X Rmuser NONE (6 "root"; X 9 "Username? "; X 5 "remuser") "Remove a user's account", X Shell NONE (6 "!alien"; X 5 "echo Type exit to return to the menus ; csh -i") X "Spawns an interactive shell", X Tools TOOLS_MENU () "Editing and printing tools", X Help NONE (5 "manual maint") "Help on how to maintain the system", X Quit QUIT () "Go back to main menu"; X XXFER_MENU: "Transfer Menu" X Sendfile NONE (9 "Name of file(s) to send? "; X 10 "User to send to (in the format site!user)? "; X 5 "send -m -p %s %s") X "Send a file to another user", X Receive NONE (5 "receive") "Receive a file from another user", X Status NONE (5 "uustat -v -u$USER | $PAGER") X "Check the status of your UUCP requests", X CallOut NONE (1 "/etc/ldevices"; X 5 "call.out") "Call out to another system with kermit", X Kermit NONE (5 "kermit") "Start Kermit upload/download protocol", X Server NONE (1 "/etc/rdevices"; X 5 "kermit -x") "Start Kermit in server mode *CAREFUL*", X Download NONE (5 "ls -axF"; X 9 "What file names (separated by spaces)? "; X 5 "cat %s"; X 3 "") "Display a text file without paging or protocol", X Tools TOOLS_MENU () "Editing and printing tools", X Help NONE (5 "manual transfer") "How to perform file transfers", X Quit QUIT () "Go back to main menu"; X XDISK_MENU: "Floppy Disk Menu" X Dtype NONE (9 "Which disk (such as 0 or 1)? "; X 5 "dtype /dev/fd%s") "Determine what type of floppy disk you have", X Xenix TAR_MENU () "Use floppies in Xenix 'tar' format", X Dos DOS_MENU () "Use floppies in MS-DOS format", X Tools TOOLS_MENU () "Editing and printing tools", X Help NONE (5 "manual floppy") "How to use the floppy disk", X Quit QUIT () "Go back to main menu"; X XTAR_MENU: "Xenix Menu" X Dir NONE (9 "Which disk (such as 0 or 1)? "; X 10 "File or Directory names (optional)? "; X 5 "tar tv%s %s | $PAGER") X "Directory list of a 'tar' Disk", X From NONE (9 "Which disk (such as 0 or 1)? "; X 10 "File or Directory names (optional)? "; X 5 "tar xv%s %s") X "Copy a file FROM a 'tar' Disk", X To NONE (9 "Which disk (such as 0 or 1)? "; X 10 "File or Directory names? "; X 5 "tar cv%s %s") X "Copy a file TO a 'tar' Disk", X Format NONE (9 "Which disk (such as 0 or 1)? "; X 5 "format /dev/rfd%s48") X "Format a 360k 'tar' Disk", X HFormat NONE (9 "Which disk (such as 0 or 1)? "; X 5 "format /dev/rfd%s96") X "Format a 1.2M 'tar' Disk (High Density)", X Help NONE (5 "manual xenix") "How to transfer to/from Xenix disks", X Return RETURN () "Go to previous menu", X Quit QUIT () "Go back to Main Menu"; X X XDOS_MENU: "MS-DOS Menu" X Dir NONE (9 "Which disk (such as A: B: X: or Y:)? "; X 5 "dosdir %s | $PAGER") X "Directory list of a Disk", X From NONE (9 "Which disk and file names (no wildcards, eg: a:file)? "; X 5 "doscp %s .") X "Copy a file FROM a Disk", X To NONE (9 "File or Directory names? "; X 10 "Which disk (such as A: or B:)? "; X 5 "doscp %s %s") X "Copy a file TO a Disk", X BFrom NONE (9 "Which disk and file names (no wildcards)? "; X 5 "doscp -r %s .") X "Copy a Binary file FROM a Disk", X BTo NONE (9 "File or Directory names? "; X 10 "Which disk (such as A: or B:)? "; X 5 "doscp -r %s %s") X "Copy a Binary file TO a Disk", X Format NONE (9 "Which disk (such as A: or B:)? "; X 5 "dosformat %s") X "Format a 360k 'DOS' Disk", X HFormat NONE (9 "Which disk (such as X: or Y:)? "; X 5 "dosformat %s") X "Format a 1.2M 'DOS' Disk (High Density)", X Help NONE (5 "manual ms-dos") "How to transfer to/from MS-DOS disks", X Return RETURN () "Go to previous menu", X Quit QUIT () "Go back to Main Menu"; X XSETUP_MENU: "Setup Menu" X ListTerm NONE (5 "echo this command is not set up yet"; X 3 "") "List supported terminal types", X TermType NONE (5 "echo this command is not set up yet"; X 3 "") "Change your terminal type", X Erase NONE (5 "echo this command is not set up yet"; X 3 "") "Change the 'erase' character", X Interrupt NONE (5 "echo this command is not set up yet"; X 3 "") "Change the 'interrupt' character", X Eof NONE (5 "echo this command is not set up yet"; X 3 "") "Change the 'eof' character", X Password NONE (5 "passwd") "Change your password", X Help NONE (5 "echo this command is not set up yet"; X 3 "") "Get help on the Setup Menu", X Quit QUIT () "Go back to Main Menu". ________This_Is_The_END________ if test `wc -l < menu.sample` -ne 303; then echo 'shar: menu.sample was damaged during transit (should have been 303 lines)' fi fi ; : end of overwriting check echo 'x - menu.test' if test -f menu.test; then echo 'shar: not overwriting menu.test'; else sed 's/^X//' << '________This_Is_The_END________' > menu.test X#!lush X# file: menu.test, lush v1.3 menu configuration script. See the file X# menu.sample for explanation of the syntax. X XMAIN_MENU: "Main Menu" X One MENU_ONE () "Demonstrate infinite regress", X Two MENU_TWO () "Same as above, with different starting point", X Shell NONE (5 "echo Type exit to return to the menus ; csh -i") X "Spawns an interactive shell", X Test TEST_MENU () "Check out some environment variables.", X Bye QUIT (5 "echo Goodbye.") "Sign off and hang up"; X XMENU_ONE: "Sub-Menu One" X SubMenu MENU_TWO () "Go to sub-menu Two", X Return RETURN (5 "echo loop, endless: see endless loop"; X 3 "") "Go back 1 level.", X Quit QUIT () "Go back to main menu."; X XMENU_TWO: "Sub-Menu Two" X SubMenu MENU_ONE () "Go to sub-menu One", X Return RETURN (5 "echo endless loop: see loop, endless"; X 3 "") "Go back 1 level.", X Quit QUIT () "Go back to main menu."; X XTEST_MENU: "Test.Menu" X Lushrc NONE (5 "echo $LUSHRC"; 3 "") "Print LUSHRC name.", X Path NONE (5 "echo $PATH"; 3 "") "Print PATH.", X User NONE (5 "echo $USER"; 3 "") "Print USER name.", X Home NONE (5 "echo $HOME"; 3 "") "Print HOME name.", X Tty NONE (5 "echo $TTY"; 3 "") "Print TTY name.", X Term NONE (5 "echo $TERM"; 3 "") "Print TERM name.", X Pager NONE (5 "echo $PAGER"; 3 "") "Print PAGER name.", X Quit QUIT () "Go back to main menu.". ________This_Is_The_END________ if test `wc -l < menu.test` -ne 33; then echo 'shar: menu.test was damaged during transit (should have been 33 lines)' fi fi ; : end of overwriting check exit 0 -- Paul Shields, shields at nccn.yorku.ca (..!uunet!yunccn!shields) From davidsen at crdos1.crd.ge.COM Wed Jan 31 03:39:48 1990 From: davidsen at crdos1.crd.ge.COM (Wm E Davidsen Jr) Date: 30 Jan 90 16:39:48 GMT Subject: Patch for pcal Message-ID: <2066@crdos1.crd.ge.COM> I started trying the postscript calender and found that the input from alternate file didn't work. I also added a test so I can define the header file location on the command line instead of editing the source for each machine. Other than that it seems to work, although I may take a look at dynamic sizing of the text. *** pcal.old --- pcal.c ************** *** 27,33 #include <time.h> #include <string.h> ! /* Define this file accordingly. */ #define PROLOG_FILE "/usr1/joe/util/src/pcal.ps" --- 27,33 ----- #include <time.h> #include <string.h> ! #ifndef PROLOG_FILE /* Define this file accordingly. */ #define PROLOG_FILE "/usr1/joe/util/src/pcal.ps" #endif ************** *** 29,34 /* Define this file accordingly. */ #define PROLOG_FILE "/usr1/joe/util/src/pcal.ps" char *words[100], /* maximum number of words on a line */ --- 29,35 ----- #ifndef PROLOG_FILE /* Define this file accordingly. */ #define PROLOG_FILE "/usr1/joe/util/src/pcal.ps" + #endif char *words[100], /* maximum number of words on a line */ lbuf[512]; /* maximum line size */ ************** *** 30,36 /* Define this file accordingly. */ #define PROLOG_FILE "/usr1/joe/util/src/pcal.ps" - char *words[100], /* maximum number of words on a line */ lbuf[512]; /* maximum line size */ --- 31,36 ----- #define PROLOG_FILE "/usr1/joe/util/src/pcal.ps" #endif char *words[100], /* maximum number of words on a line */ lbuf[512]; /* maximum line size */ ************** *** 87,93 /* * Handle the arglist. */ ! while ((m = getopt(argc, argv, "efpr:m:y:t:d:")) != EOF) switch (m) { case 'p': doprolog = 0; break; --- 87,93 ----- /* * Handle the arglist. */ ! while ((m = getopt(argc, argv, "ef:pr:m:y:t:d:")) != EOF) switch (m) { case 'p': doprolog = 0; break; -- bill davidsen (davidsen at crdos1.crd.GE.COM -or- uunet!crdgw1!crdos1!davidsen) "Stupidity, like virtue, is its own reward" -me From erlkonig at walt.cc.utexas.edu Wed Jan 17 21:10:11 1990 From: erlkonig at walt.cc.utexas.edu (Christopher North-Keys) Date: 17 Jan 90 10:10:11 GMT Subject: nuxdsp.c module ERRATA Message-ID: <23285@ut-emx.UUCP> The nuxdsp.c module requires that the algbr() and VerifyMove() functions from uxdsp.c be inserted between TerminateSearch() and InputCommand(). No other changes may be necessary. Note: the nuxdsp.c module also corrects the amazingly broken game save/restore seen in 1.53 (nuxdsp.c was coded on a Sun 3/150 running 3.5, later 4.0.3) ------------------------------------/\---------------------------------------- Seo: Harp[@Mcc.Com] / \/\ ^*^ Christopher North-Keys Tha mi gu trang a'cluich. / \ \ Assoc. Systems Analyst, MCC --------------------------------(disclaimer)---------------------------------- From paul at devon.lns.pa.us Wed Jan 17 18:44:09 1990 From: paul at devon.lns.pa.us (Paul Sutcliffe Jr.) Date: 17 Jan 90 07:44:09 GMT Subject: Enhanced SYSV Getty, v1.1, part 1 of 4 Message-ID: <1990Jan17.074409.526@devon.lns.pa.us> This has evolved from a private project to get a SysV-like getty running on my Tandy 6000 (Xenix System III). I'm releasing it here in the hopes that you alt.sources-types will find any bugs and report them to me so they can be fixed before I submit this to comp.sources.{misc,unix}. If you want to know more details, the README file is the first thing in the shell archive below. - paul #! /bin/sh # Make a new directory for the getty sources, cd to it, and run kits 1 # thru 4 through sh. When all 4 kits have been run, read README. echo "This is getty 1.1 kit 1 (of 4). If kit 1 is complete, the line" echo '"'"End of kit 1 (of 4)"'" will echo at the end.' echo "" export PATH || (echo "You didn't use sh, you clunch." ; kill $$) mkdir man 2>/dev/null echo Extracting README sed >README <<'!STUFFY!FUNK!' -e 's/X//' X X Getty Kit, Version 1.1 X X Copyright (c) 1989,1990, Paul Sutcliffe Jr. X X------------------------------------------------------------------------------- X X Permission is hereby granted to copy, reproduce, redistribute, X or otherwise use this software as long as: there is no monetary X profit gained specifically from the use or reproduction or this X software, it is not sold, rented, traded or otherwise marketed, X and this copyright notice is included prominently in any copy X made. X X The author make no claims as to the fitness or correctness of X this software for any use whatsoever, and it is provided as is. X Any use of this software is at the user's own risk. X X------------------------------------------------------------------------------- X X XWHY THIS GETTY: X XAs most people have seen, the stock getty provided on Unix/Xenix Xsystems lacks many features that can be useful. The getty included in Xthis distribution adds several features that I needed on my own system, Xplus includes several "Wouldn't it be nice if ..." features I've heard Xmentioned around UseNet. X XGetty 1.1 trys to emulate a "standard" System V getty in every way it Xcan. For instance, it uses the SysV /etc/gettydefs file (although you Xmay give it a different name). It also uses an /etc/issue file, if one Xis present. X XAdded features include: X X + Can be used as a normal getty, or as "uugetty" to allow X bi-directional usage of modem lines. X X + Reads a "defaults" file at runtime, so that a single binary X can be configured differently on individual lines. This also X allows you to change getty's behavior without recompiling. X X + Let's you specify default erase and kill characters, instead X of the ancient '#' and '@' convention still used in some X "modern" gettys. X X + Extensive debugging (to a log file) can be enabled at compile- X time. The command line argument to envoke debugging is an X octal number -- the bit pattern determines which aspects of X getty's behavior are logged. X X + Let's you specify a program other than "login" to be executed X after the user name is entered. X X + (and the best for last:) The line can be "initialized" X before sending the login banner (/etc/issue) and prompt with X the use of an expect/send sequence not unlike that used by the X UUCP L.sys (or Systems) file. X X XREQUIREMENTS: X XGetty 1.1 should drop right in to any AT&T (System III or V) Unix Xor derivitive. It has already been successfully installed on: X X Tandy 6000 Tandy Xenix 3.2 (Microsoft Xenix 3.0) X NCR Tower 32/400 Unix SVR[23] X 80386 clone SCO Xenix V/386 2.2 X X XINSTALLATION: X XPlease read all the directions below before you proceed any further, and Xthen follow them carefully. Failure to do so may void your warranty. :-) X XAfter you have unpacked your kit(s), you should have all the files listed Xin MANIFEST. X X1) Run Configure. This will figure out various things about your system. X Some things Configure will figure out for itself, other things it will X ask you about. It will then proceed to make config.h, config.sh, and X Makefile. X X You might possibly have to trim # comments from the front of Configure X if your sh doesn't handle them, but all other # comments will be taken X care of. X X2) Glance through config.h to make sure system dependencies are correct. X Most of them should have been taken care of by running the Configure X script. X X If you have any additional changes to make to the C definitions, they X can be done in the Makefile, or in config.h. Bear in mind that they X will get undone next time you run Configure. X X3) Copy the sample file tune.H to tune.h and edit tune.h to reflect the X special needs of your system and your desired features. Use the X following as a guide: X X boolean If your compiler supports a (boolean) type, you may X remove this definition. X X DEF_CFL Define this to the <termio.h> parameters that will X identify your system's normal word length and parity. X Possible values are: X X (CS8) /* 8-bit, no parity */ X (CS7|PARENB) /* 7-bit, even parity */ X (CS7|PARENB|PARODD) /* 7-bit, odd parity */ X X Be sure to use only symbols defined in <termio.h> on X your system. X X DEBUG Define this if you want the runtime debugging code X included in the executables. See the section on X DEBUGGING in this readme for instructions in usage. X X LOGUTMP Define this if your utmp file (/etc/utmp) records X getty processes as a LOGIN_PROCESS. This is true X for all SYS V sites that I'm aware of. X X MY_CANON Define this if you want to define your own ERASE and X KILL characters. You may wish to do this if you are a X SYS V site whose defaults are the ancient '#' and '@' X characters. See MY_ERASE and MY_KILL below. X X RCSID Define this if you want RCS version strings compiled X into the executables. These can later be found with X the what (SCCS) or ident (RCS) commands. X X SETTERM Define this if you want getty to export the TERM X environment variable before calling login. This will X only be done if getty knows what kind of terminal is X attached to the line it's running on. X X TRYMAIL Define this if you want getty to send email if it has X and error and cannot access the CONSOLE device. X X WARNCASE Define this to allow getty to warn a user if he/she has X used only upper-case letters in their login id. If the X user re-enters his/her id a second time in upper-case, X that value is accepted and process accordingly. X X MY_ERASE If you've defined MY_CANON, use these to define the values X MY_KILL you want for erase and kill characters. X X NOTIFY If you've defined TRYMAIL, use this to define the account X to which the email will be sent. X X CONSOLE Define this to the name of the console device. X X DEFAULTS Define this to the name of the defaults file. The %s is X necessary, and will be replaced (via an sprintf()) by the X name of the executable--either getty or uugetty. X X ISSUE Define this to the name of your issue file. If this X is undefined, no issue file will be displayed during X getty's startup. X X LOGIN Define this to the name of the login program to be called. X X TRS16 Define this only if you're compiling getty on a Tandy 6000. X This define handles the different command line required due X to the V7 based /etc/init and also the dain-bramaged X /etc/inittab used on Tandy Xenix-68000 3.2 X X4) make depend X X This will look for all the includes and modify Makefile accordingly. X Configure will offer to do this for you. X X5) make X X This will attempt to make getty and uugetty in the current directory. X It will also go to the man sub-directory and use m4 to create X nroff-able man pages. It will then run nroff on the m4 output. X X6) make install X X This will put getty/uugetty into a public directory (normally /etc). X It will also make sure the man pages have been created. It will not X install them. You may need to be root to do this. If you are not X root, you must own the directories in question and you should ignore X any messages about chown not working. X X Also, if you don't already have an /etc/gettydefs file, you'll need X to create one. This goes for the /etc/default files (if you are X using them) and the /etc/issue file. There are examples of these X in the `sample.files' file. X X7) Read the manual entries before running getty/uugetty. X X8) IMPORTANT! Help save the world! Communicate any problems and suggested X patches to me, paul at devon.lns.pa.us (Paul Sutcliffe Jr.), so we can X keep the world in sync. If you have a problem, there's someone else X out there who either has had or will have the same problem. X X If possible, send in patches such that the patch program will apply them. X Context diffs are the best, then normal diffs. Don't send ed scripts-- X I've probably changed my copy since the version you have. X X Watch for getty patches in comp.sources.bugs. Patches will generally be X in a form usable by the patch program. If you are just now bringing up X getty and aren't sure how many patches there are, write to me and I'll X send any you don't have. Your current patch level is shown in patchlevel.h. X X XDEBUGGING: X XTo use debugging, you must define DEBUG (in config.h) before compiling. X XTo envoke debugging, use the "-D onum" command line argument. Onum is Xan octal number. To turn on all levels of debugging, use "-D 0377". XTo pick specific areas to be watched, look at the defines in the "debug Xlevels" section of getty.h. The value for onum will be the result of XOR-ing the values you want. For instance, to debug the defaults file Xand gettytab file processing, use "-D 022". X X XHave fun. X X- paul X XINTERNET: paul at devon.LNS.PA.US | How many whales do you have to XUUCP: ...!rutgers!devon!paul | save to get a toaster? !STUFFY!FUNK! echo Extracting man/README sed >man/README <<'!STUFFY!FUNK!' -e 's/X//' X X Getty 1.1 manual page files. X XThis README describes the files used and created by the Makefile. X XIn general, a file with a `.m4' extension is nroff source intersperced Xwith m4 macros. These files are processed by m4 to yield nroff-able Xfiles, and use the macros to create man pages whose content matches the Xway you've configured your getty/uugetty executables. Running m4 on Xthe .m4 files produce ready-for-nroff files with either a `.1m', `.3' Xor `.4' extension, depending upon the chapter to which the man page Xbelongs. The makefile will also run nroff on these files, producing Xfiles with a `.man' extension. X XAfter running make in this directory, you will have the following files: X X getty.1m nroff-ready man page for getty X getty.man nroff'd getty man page X gettytab.4 * nroff-ready man page for the gettytab file X gettytab.man * nroff'd gettytab man page X issue.4 nroff-ready man page for the issue file X issue.man nroff'd issue man page X X* Note: the name `gettytab' will be replaced by the actual name you X assigned for that file -- usually `gettydefs'. X XAlso, you may have some (or all) of the following files, depending upon Xthe configuration of your Unix/Xenix. These files describe library Xroutines used by getty that were not found in your libc.a (and thus Xhomegrown versions were used): X X getutent.3 nroff-ready man page for getutent(3) X getutent.man nroff'd getutent man page X strdup.3 nroff-ready man page for strdup(3) X strdup.man nroff'd strdup man page X putenv.3 nroff-ready man page for putenv(3) X putenv.man nroff'd putenv man page X XYou will need to manually install the man pages. Use either the .{1m,3,4} X(pre-nroff) or .man (post-nroff) files, according to the needs of your Xsystem. X X- paul X XINTERNET: paul at devon.LNS.PA.US | How many whales do you have to XUUCP: ...!rutgers!devon!paul | save to get a toaster? !STUFFY!FUNK! echo Extracting main.c sed >main.c <<'!STUFFY!FUNK!' -e 's/X//' X/* X** $Id: main.c,v 1.1 90/01/16 16:16:10 paul Exp Locker: paul $ X** X** Main body of program. X*/ X X/* X** Copyright 1989,1990 by Paul Sutcliffe Jr. X** X** Permission is hereby granted to copy, reproduce, redistribute, X** or otherwise use this software as long as: there is no monetary X** profit gained specifically from the use or reproduction or this X** software, it is not sold, rented, traded or otherwise marketed, X** and this copyright notice is included prominently in any copy X** made. X** X** The author make no claims as to the fitness or correctness of X** this software for any use whatsoever, and it is provided as is. X** Any use of this software is at the user's own risk. X*/ X X/* X** $Log: main.c,v $ X** Revision 1.1 90/01/16 16:16:10 paul X** Initial revision X** X*/ X X X#define MAIN X X#include "getty.h" X#include "defaults.h" X#include "table.h" X#include <signal.h> X#include <fcntl.h> X#include <sys/stat.h> X#include <pwd.h> X X#if defined(RCSID) && !defined(lint) Xstatic char *RcsId = X"@(#)$Id: main.c,v 1.1 90/01/16 16:16:10 paul Exp Locker: paul $"; X#endif X X#if !defined(lint) X#include "patchlevel.h" Xstatic char *Release = RELEASE; Xstatic char *RelDate = DATE; X#endif X X/* how does this thing work X */ X#define USAGE "Usage:\t%s %s%s\n\t%s -c checkfile\n" X#ifdef TRS16 X#define UREQ " speed [defaultfile]" /* Tandy Xenix/68k 3.2 */ X#define UOPT "" X#else /* TRS16 */ X#define UREQ " line [speed [type [lined]]]" /* real System V */ X#define UOPT "[-d defaultfile] [-h] [-r delay] [-t timeout]" X#endif /* TRS16 */ X X#define VALUE(cptr) ((cptr == (char *) NULL) ? "NULL" : cptr) X Xstruct speedtab { X ushort cbaud; /* baud rate */ X char *speed; /* speed in display format */ X} speedtab[] = { X { B50, "50" }, X { B75, "75" }, X { B110, "110" }, X { B134, "134" }, X { B150, "150" }, X { B200, "200" }, X { B300, "300" }, X { B600, "600" }, X { B1200, "1200" }, X { B1800, "1800" }, X { B2400, "2400" }, X { B4800, "4800" }, X { B9600, "9600" }, X#ifdef B19200 X { B19200,"19200"}, X#endif /*B19200*/ X { EXTA, "EXTA" }, X { EXTB, "EXTB" }, X { 0, "" } X}; X Xsig_t timeout(); Xint tputc(); Xvoid exit_usage(); Xstruct passwd *getpwuid(); Xstruct utmp *getutent(); X#ifdef DEBUG Xchar *ctime(); X#endif /* DEBUG */ X X X#ifdef UUGETTY X X#include <errno.h> X Xextern int errno; X Xchar *lock, *altlock; X Xint makelock(), readlock(); Xboolean checklock(); Xsig_t rmlocks(); X X#endif /* UUGETTY */ X X X#ifdef WARNCASE Xchar *bad_case[] = { X "\r\n", X "If your terminal supports lower case letters, please\r\n", X "use them. Login again, using lower case if possible.\r\n", X (char *) NULL X}; X#endif /* WARNCASE */ X X Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X Reg1 int c; X Reg2 int i; X Reg3 int fd; X int cbaud, flags; X char ch, *p, devname[MAXLINE+1]; X STDCHAR buf[MAXLINE+1]; X char termcap[1024], tbuf[64]; X char *tgetstr(); X DEF **def; X TERMIO termio; X GTAB *gtab; X FILE *fp; X struct utmp *utmp; X X#if defined(DEBUG) || defined(LOGUTMP) X time_t clock; X#endif /* DEBUG || LOGUTMP */ X X#ifndef TRS16 X char lined[MAXLINE+1]; X#endif /* TRS16 */ X X#ifdef UUGETTY X struct passwd *pwd; X UIDTYPE uucpuid = 0; X GIDTYPE uucpgid = 0; X#else /* UUGETTY */ X struct stat st; X#endif /* UUGETTY */ X X#ifdef TTYTYPE X char name[16], line[16]; X#endif /* TTYTYPE */ X X#ifdef LOGUTMP X int pid; X#endif /* LOGUTMP */ X X#ifdef ISSUE X char *issue = ISSUE; /* default issue file */ X#endif /* ISSUE */ X X boolean clear = TRUE; /* clear screen flag */ X char *login = LOGIN; /* default login program */ X char *clrscr = (char *) NULL; /* string to clear screen */ X char *defname = (char *) NULL; /* defaults file name */ X char *init = (char *) NULL; /* value of INIT */ X char term[16]; /* terminal type */ X boolean waitchar = FALSE; /* wait for char flag */ X unsigned int delay = 0; /* #sec's delay before prompt */ X X extern int optind; X extern char *optarg; X X /* startup X */ X (void) signal(SIGINT, SIG_IGN); X (void) signal(SIGQUIT, SIG_DFL); X (void) signal(SIGTERM, SIG_DFL); X X (void) strcpy(term, "unknown"); X NoHangUp = FALSE; X Check = FALSE; X CheckFile = (char *) NULL; X#ifdef DEBUG X Debug = 0; X#endif /* DEBUG */ X Device = "unknown"; X GtabId = (char *) NULL; X LineD = (char *) NULL; X TimeOut = 0; X#ifdef WARNCASE X WarnCase = TRUE; X#endif /* WARNCASE */ X X /* who am I? X */ X#ifdef UUGETTY X MyName = "uugetty"; X#else X MyName = "getty"; X#endif /* UUGETTY */ X X /* process the command line X */ X X while ((c = getopt(argc, argv, "D:c:d:ht:")) != EOF) { X switch (c) { X#ifdef DEBUG X case 'D': X (void) sscanf(optarg, "%o", &Debug); X Dfp = stderr; X break; X#endif /* DEBUG */ X case 'c': X Check = TRUE; X CheckFile = optarg; X break; X case 'd': X defname = optarg; X break; X case 'h': X NoHangUp = TRUE; X break; X case 'r': X waitchar = TRUE; X delay = (unsigned) atoi(optarg); X break; X case 't': X TimeOut = atoi(optarg); X break; X case '?': X exit_usage(2); X } X } X X /* just checking? X */ X if (Check) { X (void) signal(SIGINT, SIG_DFL); X (void) gtabvalue((char *) NULL); X exit(0); X } X X#ifdef TRS16 X X /* special handling for v7-based init X */ X X if (optind < argc) X GtabId = argv[optind++]; X else { X logerr("no speed given"); X exit_usage(2); X } X X /* Tandy Xenix/68k 3.2 /etc/inittab allows one optional argument X * after the speed flag. The best use I could do with it here is X * to assume that it's the name of the defaults file to be used. X * X * Sigh. Actually, it's not optional -- if none is given in X * /etc/inittab, then it appears here as a 0-length string. X */ X if (optind < argc) X if (strlen(argv[optind]) > 0) X defname = argv[optind++]; X X if ((p = ttyname(STDIN)) != (char *) NULL) X Device = p+5; /* strip off "/dev/" */ X else { X logerr("cannot determine line"); X exit_usage(2); X } X X#else /* TRS16 */ X X /* normal System V handling X */ X X if (optind < argc) X Device = argv[optind++]; X else { X logerr("no line given"); X exit_usage(2); X } X if (optind < argc) X GtabId = argv[optind++]; X if (optind < argc) X (void) strncpy(term, argv[optind++], sizeof(term)); X if (optind < argc) { X (void) strncpy(lined, argv[optind++], sizeof(lined)); X LineD = lined; X } X X#endif /* TRS16 */ X X#ifdef TTYTYPE X X if (strequal(term, "unknown")) { X if ((fp = fopen(TTYTYPE, "r")) == (FILE *) NULL) { X (void) sprintf(MsgBuf, "cannot open %s", TTYTYPE); X logerr(MsgBuf); X } else { X while ((fscanf(fp, "%s %s", name, line)) != EOF) { X if (strequal(line, Device)) { X (void) strncpy(term,name,sizeof(term)); X break; X } X } X (void) fclose(fp); X } X } X X#endif /* TTYTYPE */ X X /* need full name of the device X */ X (void) sprintf(devname, "/dev/%s", Device); X X /* command line parsed, now build the list of X * runtime defaults; this may override things set above. X */ X def = defbuild(defname); X X#ifdef DEBUG X X /* debugging on? X */ X if ((p = defvalue(def, "DEBUG")) != (char *) NULL) X (void) sscanf(p, "%o", &Debug); X X if (Debug) { X (void) sprintf(buf, "/tmp/getty:%s", Device); X if ((Dfp = fopen(buf, "a+")) == (FILE *) NULL) { X logerr("cannot open debug file"); X exit(FAIL); X } else { X if (fileno(Dfp) < 3) { X if ((fd = fcntl(fileno(Dfp), F_DUPFD, 3)) > 2) { X (void) fclose(Dfp); X Dfp = fdopen(fd, "a+"); X } X } X (void) time(&clock); X (void) fprintf(Dfp, "%s Started: %s", X MyName, ctime(&clock)); X } X } X X debug(D_OPT, "command line values:\n"); X debug(D_OPT, " [-d] defname = (%s)\n", VALUE(defname)); X debug(D_OPT, " [-h] NoHangUp = (%s)\n", (NoHangUp) ? "TRUE" : "FALSE"); X debug(D_OPT, " [-r] waitchar = (%s)\n", (waitchar) ? "TRUE" : "FALSE"); X debug(D_OPT, " delay = (%u)\n", delay); X debug(D_OPT, " [-t] TimeOut = (%d)\n", TimeOut); X debug(D_OPT, " line = (%s)\n", VALUE(Device)); X debug(D_OPT, " speed = (%s)\n", VALUE(GtabId)); X debug(D_OPT, " type = (%s)\n", term); X debug(D_OPT, " lined = (%s)\n", VALUE(LineD)); X debug(D_RUN, "loading defaults\n"); X X#endif /* DEBUG */ X X /* setup all runtime values X */ X X if ((SysName = defvalue(def, "SYSTEM")) == (char *) NULL) X SysName = getuname(); X X if ((Version = defvalue(def, "VERSION")) != (char *) NULL) X if (*Version == '/') { X if ((fp = fopen(Version, "r")) != (FILE *) NULL) { X (void) fgets(buf, sizeof(buf), fp); X (void) fclose(fp); X buf[strlen(buf)-1] = '\0'; X Version = strdup(buf); X } X } X X if ((p = defvalue(def, "LOGIN")) != (char *) NULL) X login = p; X if ((p = defvalue(def, "INIT")) != (char *) NULL) X init = p; X#ifdef ISSUE X if ((p = defvalue(def, "ISSUE")) != (char *) NULL) X issue = p; X#endif /* ISSUE */ X if ((p = defvalue(def, "CLEAR")) != (char *) NULL) X if (strequal(p, "NO")) X clear = FALSE; X if ((p = defvalue(def, "HANGUP")) != (char *) NULL) X if (strequal(p, "NO")) X NoHangUp = TRUE; X if ((p = defvalue(def, "WAITCHAR")) != (char *) NULL) X if (strequal(p, "YES")) X waitchar = TRUE; X if ((p = defvalue(def, "DELAY")) != (char *) NULL) X delay = (unsigned) atoi(p); X if ((p = defvalue(def, "TIMEOUT")) != (char *) NULL) X TimeOut = atoi(p); X X /* find out how to clear the screen X */ X if (!strequal(term, "unknown")) { X p = tbuf; X if ((tgetent(termcap, term)) == 1) X if ((clrscr = tgetstr("cl", &p)) == (char *) NULL) X clrscr = ""; X } X X#ifdef UUGETTY X X debug2(D_RUN, "check for lockfiles\n"); X X /* deal with the lockfiles; we don't want to charge X * ahead if uucp, kermit or something is already X * using the line. X */ X X /* name the lock file(s) X */ X (void) sprintf(buf, LOCK, Device); X lock = strdup(buf); X altlock = defvalue(def, "ALTLOCK"); X if (altlock != (char *) NULL) { X (void) sprintf(buf, LOCK, altlock); X altlock = strdup(buf); X } X debug3(D_LOCK, "lock = (%s)\n", lock); X debug3(D_LOCK, "altlock = (%s)\n", VALUE(altlock)); X X /* check for existing lock file(s) X */ X if (checklock(lock) == TRUE) { X while (checklock(lock) == TRUE) X (void) sleep(60); X exit(0); X } X X /* there's a race condition just asking for trouble here :-( X */ X if (altlock != (char *) NULL && checklock(altlock) == TRUE) { X while (checklock(altlock) == TRUE) X (void) sleep(60); X exit(0); X } X X /* allow uucp to access the device X */ X (void) chmod(devname, 0666); X if ((pwd = getpwuid(UUCPID)) != (struct passwd *) NULL) { X uucpuid = pwd->pw_uid; X uucpgid = pwd->pw_gid; X } X (void) chown(devname, uucpuid, uucpgid); X X#else /* UUGETTY */ X X (void) chmod(devname, 0622); X if (stat(devname, &st) == 0) X (void) chown(devname, 0, st.st_gid); X else X (void) chown(devname, 0, 0); X X#endif /* UUGETTY */ X X /* the line is mine now ... X */ X X debug2(D_RUN, "open stdin, stdout and stderr\n"); X X /* get a new fd X */ X if ((fd = open(devname, O_RDWR)) < 0) { /* open the device */ X logerr("cannot open line"); X exit(FAIL); X } X X /* make new fd == stdin if it isn't already X */ X if (fd > 0) { X (void) close(0); X if (dup(fd) != 0) { X logerr("cannot open stdin"); X exit(FAIL); X } X } X X /* make stdout and stderr, too X */ X (void) close(1); X (void) close(2); X if (dup(0) != 1) { X logerr("cannot open stdout"); X exit(FAIL); X } X if (dup(0) != 2) { X logerr("cannot open stderr"); X exit(FAIL); X } X X if (fd > 0) X (void) close(fd); X X /* no buffering X */ X setbuf(stdin, (char *) NULL); X setbuf(stdout, (char *) NULL); X setbuf(stderr, (char *) NULL); X X debug2(D_RUN, "setup terminal\n"); X X /* get the required info from the gettytab file X */ X gtab = gtabvalue(GtabId); X X /* setup terminal X */ X if (!NoHangUp) { X (void) ioctl(STDIN, TCGETA, &termio); X termio.c_cflag &= ~CBAUD; /* keep all but CBAUD bits */ X termio.c_cflag |= B0; /* set speed == 0 */ X (void) ioctl(STDIN, TCSETAF, &termio); X } X settermio(&(gtab->itermio), INITIAL); X X /* handle init sequence if requested X */ X if (init != (char *) NULL) { X debug2(D_RUN, "perform line initialization\n"); X if (initialize(init) == FAIL) X logerr("warning: INIT sequence failed"); X } X X /* do we need to wait ? X */ X if (waitchar) { X X /* clear O_NDELAY flag X */ X flags = fcntl(STDIN, F_GETFL, 0); X (void) fcntl(STDIN, F_SETFL, flags & ~(O_NDELAY)); X X debug2(D_RUN, "waiting for any char ...\n"); X X (void) read(STDIN, &ch, 1); /* this will block */ X X debug2(D_RUN, "... got one!\n"); X X if (delay) { X (void) sleep(delay); X /* eat up any garbage from the line (modem) */ X (void) fcntl(STDIN, F_SETFL, flags | O_NDELAY); X while (read(STDIN, &ch, 1) == 1) X ; X } X X /* put back original flags X */ X (void) fcntl(STDIN, F_SETFL, flags); X X } X X#ifdef UUGETTY X X debug2(D_RUN, "locking the line\n"); X X /* try to lock the line X */ X if (makelock(lock) == FAIL) { X while (checklock(lock) == TRUE) X (void) sleep(60); X exit(0); X } X if (altlock != (char *) NULL && makelock(altlock) == FAIL) { X while (checklock(altlock) == TRUE) X (void) sleep(60); X exit(0); X } X X /* set to remove lockfile(s) on certain signals X */ X (void) signal(SIGINT, rmlocks); X (void) signal(SIGQUIT, rmlocks); X (void) signal(SIGTERM, rmlocks); X X#endif /* UUGETTY */ X X#ifdef LOGUTMP X X debug2(D_RUN, "update utmp/wtmp files\n"); X X pid = getpid(); X while ((utmp = getutent()) != (struct utmp *) NULL) { X if (utmp->ut_type == INIT_PROCESS && utmp->ut_pid == pid) { X X debug2(D_UTMP, "logutmp entry made\n"); X /* show login process in utmp X */ X strncopy(utmp->ut_line, Device); X strncopy(utmp->ut_user, "LOGIN"); X utmp->ut_pid = pid; X utmp->ut_type = LOGIN_PROCESS; X (void) time(&clock); X utmp->ut_time = clock; X pututline(utmp); X X /* write same record to end of wtmp X */ X if ((fp = fopen(WTMP_FILE, "w+")) != (FILE *) NULL) { X (void) fseek(fp, 0L, 2); X (void) fwrite((char *)utmp,sizeof(*utmp),1,fp); X (void) fclose(fp); X } X } X } X endutent(); X X#endif /* LOGUTMP */ X X debug2(D_RUN, "entering login loop\n"); X X /* loop until a successful login is made X */ X for (;;) { X X /* set Nusers value X */ X Nusers = 0; X setutent(); X while ((utmp = getutent()) != (struct utmp *) NULL) { X#ifdef USER_PROCESS X if (utmp->ut_type == USER_PROCESS) X#endif /* USER_PROCESS */ X { X Nusers++; X debug3(D_UTMP, "utmp entry (%s)\n", X utmp->ut_name); X } X } X endutent(); X debug3(D_UTMP, "Nusers=%d\n", Nusers); X X /* set Speed value X */ X cbaud = gtab->itermio.c_cflag & CBAUD; X for (i=0; speedtab[i].cbaud != cbaud; i++) X ; X Speed = speedtab[i].speed; X X#ifdef ISSUE X if (clear && *clrscr) /* clear screen */ X (void) tputs(clrscr, 1, tputc); X X (void) fputc('\r', stdout); /* just in case */ X X if (def == (DEF **) NULL) /* no defaults file */ X (void) Fputs("@S\n", stdout); X X /* display ISSUE, if present X */ X if (*issue != '/') { X (void) Fputs(issue, stdout); X (void) fputs("\r\n", stdout); X } else if ((fp = fopen(issue, "r")) != (FILE *) NULL) { X while (fgets(buf, sizeof(buf), fp) != (char *) NULL) X (void) Fputs(buf, stdout); X (void) fclose(fp); X } X#endif /* ISSUE */ X X login_prompt: X /* display login prompt X */ X (void) Fputs(gtab->login, stdout); X X /* eat any chars from line noise X */ X (void) ioctl(STDIN, TCFLSH, 0); X X /* start timer, if required X */ X if (TimeOut > 0) { X (void) signal(SIGALRM, timeout); X (void) alarm((unsigned) TimeOut); X } X X /* handle the login name X */ X switch (getlogname(&termio, buf, MAXLINE)) { X case SUCCESS: X /* stop alarm clock X */ X if (TimeOut > 0) X (void) alarm((unsigned) 0); X X /* setup terminal X */ X termio.c_iflag |= gtab->ftermio.c_iflag; X termio.c_oflag |= gtab->ftermio.c_oflag; X termio.c_cflag |= gtab->ftermio.c_cflag; X termio.c_lflag |= gtab->ftermio.c_lflag; X termio.c_line |= gtab->ftermio.c_line; X settermio(&termio, FINAL); X#ifdef DEBUG X if (Debug) X (void) fclose(Dfp); X#endif /* DEBUG */ X X#ifdef SETTERM X (void) sprintf(MsgBuf, "TERM=%s", term); X (void) putenv(strdup(MsgBuf)); X#endif /* SETTERM */ X X /* hand off to login X */ X (void) execl(login, "login", buf, (char *) NULL); X (void) execl("/bin/sh", "sh", "-c", X login, buf, (char *) NULL); X (void) sprintf(MsgBuf, "cannot execute %s", login); X logerr(MsgBuf); X exit(FAIL); X X case BADSPEED: X /* go to next entry X */ X GtabId = gtab->next_id; X gtab = gtabvalue(GtabId); X settermio(&(gtab->itermio), INITIAL); X break; X X#ifdef WARNCASE X case BADCASE: X /* first try was all uppercase X */ X for (i=0; bad_case[i] != (char *) NULL; i++) X (void) fputs(bad_case[i], stdout); X goto login_prompt; X#endif /* WARNCASE */ X X case NONAME: X /* no login name entered X */ X break; X X } X } X} X X X/* X** timeout() - handles SIGALRM X*/ X Xsig_t Xtimeout() X{ X TERMIO termio; X X /* say bye-bye X */ X (void) sprintf(MsgBuf, "\nTimed out after %d seconds.\n", TimeOut); X (void) Fputs(MsgBuf, stdout); X (void) Fputs("Bye Bye.\n", stdout); X X /* force a hangup X */ X (void) ioctl(STDIN, TCGETA, &termio); X termio.c_cflag &= ~CBAUD; X termio.c_cflag |= B0; X (void) ioctl(STDIN, TCSETAF, &termio); X X exit(1); X} X X X/* X** tputc() - output a character for tputs() X*/ X Xint Xtputc(c) Xchar c; X{ X fputc(c, stdout); X} X X X/* X** exit_usage() - exit with usage display X*/ X Xvoid Xexit_usage(code) Xint code; X{ X FILE *fp; X X if ((fp = fopen(CONSOLE, "w")) != (FILE *) NULL) { X (void) fprintf(fp, USAGE, MyName, UOPT, UREQ, MyName); X (void) fclose(fp); X } X exit(code); X} X X X#ifdef UUGETTY X X/* X** makelock() - attempt to create a lockfile X** X** Returns FAIL if lock could not be made (line in use). X*/ X Xint Xmakelock(name) Xchar *name; X{ X int fd, pid; X char *temp, buf[MAXLINE+1]; X#ifdef ASCIIPID X char apid[16]; X#endif /* ASCIIPID */ X int getpid(); X char *mktemp(); X X debug3(D_LOCK, "makelock(%s) called\n", name); X X /* first make a temp file X */ X (void) sprintf(buf, LOCK, "TM.XXXXXX"); X if ((fd = creat((temp=mktemp(buf)), 0444)) == FAIL) { X (void) sprintf(MsgBuf, "cannot create tempfile (%s)", temp); X logerr(MsgBuf); X return(FAIL); X } X debug3(D_LOCK, "temp = (%s)\n", temp); X X /* put my pid in it X */ X#ifdef ASCIIPID X (void) sprintf(apid, "%09d", getpid()); X (void) write(fd, apid, strlen(apid)); X#else X pid = getpid(); X (void) write(fd, (char *)&pid, sizeof(pid)); X#endif /* ASCIIPID */ X (void) close(fd); X X /* link it to the lock file X */ X while (link(temp, name) == FAIL) { X debug3(D_LOCK, "link(temp,name) failed, errno=%d\n", errno); X if (errno == EEXIST) { /* lock file already there */ X if ((pid = readlock(name)) == FAIL) X continue; X if ((kill(pid, 0) == FAIL) && errno == ESRCH) { X /* pid that created lockfile is gone */ X (void) unlink(name); X continue; X } X } X debug2(D_LOCK, "lock NOT made\n"); X (void) unlink(temp); X return(FAIL); X } X debug2(D_LOCK, "lock made\n"); X (void) unlink(temp); X return(SUCCESS); X} X X/* X** checklock() - test for presense of valid lock file X** X** Returns TRUE if lockfile found, FALSE if not. X*/ X Xboolean Xchecklock(name) Xchar *name; X{ X int pid; X struct stat st; X X debug3(D_LOCK, "checklock(%s) called\n", name); X X if ((stat(name, &st) == FAIL) && errno == ENOENT) { X debug2(D_LOCK, "stat failed, no file\n"); X return(FALSE); X } X X if ((pid = readlock(name)) == FAIL) { X debug2(D_LOCK, "couldn't read lockfile\n"); X return(FALSE); X } X X if ((kill(pid, 0) == FAIL) && errno == ESRCH) { X debug2(D_LOCK, "no active process has lock, will remove\n"); X (void) unlink(name); X return(FALSE); X } X X debug2(D_LOCK, "active process has lock, return(TRUE)\n"); X return(TRUE); X} X X/* X** readlock() - read contents of lockfile X** X** Returns pid read or FAIL on error. X*/ X Xint Xreadlock(name) Xchar *name; X{ X int fd, pid; X#ifdef ASCIIPID X char apid[16]; X#endif /* ASCIIPID */ X X if ((fd = open(name, O_RDONLY)) == FAIL) X return(FAIL); X X#ifdef ASCIIPID X (void) read(fd, apid, sizeof(apid)); X (void) sscanf(apid, "%d", &pid); X#else X (void) read(fd, (char *)&pid, sizeof(pid)); X#endif /* ASCIIPID */ X X (void) close(fd); X return(pid); X} X X/* X** rmlocks() - remove lockfile(s) X*/ X Xsig_t Xrmlocks() X{ X if (altlock != (char *) NULL) X (void) unlink(altlock); X X (void) unlink(lock); X} X X#endif /* UUGETTY */ X X X/* end of main.c */ !STUFFY!FUNK! echo Extracting funcs.c sed >funcs.c <<'!STUFFY!FUNK!' -e 's/X//' X/* X** $Id: funcs.c,v 1.1 90/01/16 16:14:28 paul Exp Locker: paul $ X** X** Miscellaneous routines. X*/ X X/* X** Copyright 1989,1990 by Paul Sutcliffe Jr. X** X** Permission is hereby granted to copy, reproduce, redistribute, X** or otherwise use this software as long as: there is no monetary X** profit gained specifically from the use or reproduction or this X** software, it is not sold, rented, traded or otherwise marketed, X** and this copyright notice is included prominently in any copy X** made. X** X** The author make no claims as to the fitness or correctness of X** this software for any use whatsoever, and it is provided as is. X** Any use of this software is at the user's own risk. X*/ X X/* X** $Log: funcs.c,v $ X** Revision 1.1 90/01/16 16:14:28 paul X** Initial revision X** X*/ X X X#include "getty.h" X#include "table.h" X#include <ctype.h> X#include <time.h> X#include <sys/utsname.h> X#include <setjmp.h> X#include <signal.h> X#ifdef DEBUG X#include <varargs.h> X#endif /* DEBUG */ X X#if defined(RCSID) && !defined(lint) Xstatic char *RcsId = X"@(#)$Id: funcs.c,v 1.1 90/01/16 16:14:28 paul Exp Locker: paul $"; X#endif X X#ifndef MAXBUF X#define MAXBUF 512 /* buffer size */ X#endif /* MAXBUF */ X X#ifndef EXPFAIL X#define EXPFAIL 30 /* num seconds to wait for expected input */ X#endif /* EXPFAIL */ X X#define SEND 0 /* states for initialize() */ X#define EXPECT 1 X Xchar *unquote(); Xint expect(), send(); Xsig_t expalarm(); X X X/* X** Fputs() - does fputs() with '\' and '@' expansion X** X** Returns EOF if an error occurs. X*/ X Xint XFputs(s, stream) XReg1 char *s; XReg2 FILE *stream; X{ X char c, n, tbuf[9], ubuf[32]; X time_t clock; X struct tm *lt, *localtime(); X X while (c = *s++) { X if ((c == '@') && (n = *s++)) { X switch (n) { X case 'B': /* baud rate */ X if (*Speed && Fputs(Speed, stream) == EOF) X return(EOF); X break; X case 'D': /* date */ X (void) time(&clock); X lt = localtime(&clock); X (void) sprintf(tbuf, "%02d/%02d/%02d", X ++(lt->tm_mon), X lt->tm_mday, lt->tm_year); X if (Fputs(tbuf, stream) == EOF) X return(EOF); X break; X case 'L': /* line */ X if (*Device && Fputs(Device, stream) == EOF) X return(EOF); X break; X case 'S': /* system node name */ X if (*SysName && Fputs(SysName, stream) == EOF) X return(EOF); X break; X#ifdef M_XENIX X /* Special case applys here: SCO XENIX's X * /etc/gettydefs file has "\r\n@!login: " as X * the login field value, and replaces the "@" X * with the system node name. This will do X * the same thing. X */ X case '!': X if (*SysName && Fputs(SysName, stream) == EOF) X return(EOF); X (void) fputc(n, stream); X break; X#endif /* M_XENIX */ X case 'T': /* time */ X (void) time(&clock); X lt = localtime(&clock); X (void) sprintf(tbuf, "%02d:%02d:%02d", X lt->tm_hour, X lt->tm_min, lt->tm_sec); X if (Fputs(tbuf, stream) == EOF) X return(EOF); X break; X case 'U': /* number of active users */ X (void) sprintf(ubuf, "%d", Nusers); X if (Fputs(ubuf, stream) == EOF) X return(EOF); X break; X case 'V': /* version */ X if (*Version && Fputs(Version, stream) == EOF) X return(EOF); X break; X case '@': /* in case '@@' was used */ X if (fputc(n, stream) == EOF) X return(EOF); X break; X } X } else { X if (c == '\\') X s = unquote(s, &c); X /* we're in raw mode: send CR before every LF X */ X if (c == '\n' && (fputc('\r', stream) == EOF)) X return(EOF); X if (c && fputc(c, stream) == EOF) X return(EOF); X } X } X return(SUCCESS); X} X X X/* X** getuname() - retrieve the system's node name X** X** Returns pointer to name or a zero-length string if not found. X*/ X Xchar * Xgetuname() X{ X#ifdef HOSTNAME /* hardwire the name */ X X static char name[] = HOSTNAME; X X return(name); X X#else /* HOSTNAME */ X X#ifdef M_XENIX X#define SYSTEMID "/etc/systemid" X static FILE *fp; X#endif /* M_XENIX */ X X struct utsname uts; X static char name[80]; X X name[0] = '\0'; X X#ifdef DOUNAME /* dig it out of the kernel */ X X if (uname(&uts) != FAIL) X (void) strcpy(name, uts.nodename); X X#endif /* DOUNAME */ X X#ifdef M_XENIX /* if Xenix's uts.nodename is empty */ X if (strlen(name) == 0) { X if ((fp = fopen(SYSTEMID, "r")) != (FILE *) NULL) { X (void) fgets(name, sizeof(name), fp); X (void) fclose(fp); X name[strlen(name)-1] = '\0'; X } X } X#endif /* M_XENIX */ X X#ifdef PHOSTNAME /* get it from the shell */ X X if (strlen(name) == 0) { X FILE *cmd; X if ((cmd = popen(PHOSTNAME, "r")) != (FILE *) NULL) { X (void) fgets(name, sizeof(name), cmd); X (void) pclose(cmd); X name[strlen(name)-1] = '\0'; X } X } X X#endif /* PHOSTNAME */ X X return(name); X X#endif /* HOSTNAME */ X} X X X/* X** settermio() - setup tty according to termio values X*/ X Xvoid Xsettermio(termio, state) XReg2 TERMIO *termio; Xint state; X{ X Reg1 int i; X static TERMIO setterm; X X#ifdef TRS16 X /* Tandy 16/6000 console's BREAK key sends ^C X */ X char Cintr = (strequal(Device, "console")) ? '\003' : CINTR; X#else X char Cintr = CINTR; X#endif /* TRS16 */ X X#ifdef MY_ERASE X char Cerase = MY_ERASE; X#else X char Cerase = CERASE; X#endif /* MY_ERASE */ X X#ifdef MY_KILL X char Ckill = MY_KILL; X#else X char Ckill = CKILL; X#endif /* MY_KILL */ X X (void) ioctl(STDIN, TCGETA, &setterm); X X switch (state) { X case INITIAL: X setterm.c_iflag = termio->c_iflag; X setterm.c_oflag = termio->c_oflag; X setterm.c_cflag = termio->c_cflag; X setterm.c_lflag = termio->c_lflag; X setterm.c_line = termio->c_line; X X /* single character processing X */ X setterm.c_lflag &= ~(ICANON); X setterm.c_cc[VMIN] = 1; X setterm.c_cc[VTIME] = 0; X X /* sanity check X */ X if ((setterm.c_cflag & CBAUD) == 0) X setterm.c_cflag |= B9600; X if ((setterm.c_cflag & CSIZE) == 0) X setterm.c_cflag |= DEF_CFL; X setterm.c_cflag |= (CREAD | HUPCL); X setterm.c_lflag |= ECHO; X X (void) ioctl(STDIN, TCSETAF, &setterm); X break; X X case FINAL: X setterm.c_iflag = termio->c_iflag; X setterm.c_oflag = termio->c_oflag; X setterm.c_cflag = termio->c_cflag; X setterm.c_lflag = termio->c_lflag; X setterm.c_line = termio->c_line; X X /* sanity check X */ X if ((setterm.c_cflag & CBAUD) == 0) X setterm.c_cflag |= B9600; X if ((setterm.c_cflag & CSIZE) == 0) X setterm.c_cflag |= DEF_CFL; X setterm.c_cflag |= CREAD; X setterm.c_lflag |= ECHO; X X /* set c_cc[] chars to reasonable values X */ X for (i=0; i < NCC; i++) X setterm.c_cc[i] = CNUL; X setterm.c_cc[VINTR] = Cintr; X setterm.c_cc[VQUIT] = CQUIT; X setterm.c_cc[VERASE] = Cerase; X setterm.c_cc[VKILL] = Ckill; X setterm.c_cc[VEOF] = CEOF; X#ifdef CEOL X setterm.c_cc[VEOL] = CEOL; X#endif /* CEOL */ X X (void) ioctl(STDIN, TCSETAW, &setterm); X break; X X } X} X X X/* X** initialize() - handle expect/send init sequence to Device X** X** Returns FAIL if an error occurs. X*/ X Xint Xinitialize(s) Xchar *s; X{ X Reg1 int state = SEND; X boolean finished = FALSE, if_fail = FALSE; X char c, *p; X char word[MAXLINE+1]; /* buffer for next word */ X X debug3(D_INIT, "initialize(%s) called\n", s); X X while (!finished) { X p = word; X while (((c = (*s++ & 0177)) != '\0') && c != ' ' && c != '-') X *p++ = (c) ? c : '\177'; X if (c == '\0') X finished = TRUE; X if (c == '-') X if_fail = (if_fail == FALSE) ? TRUE : FALSE; X *p = '\0'; X switch (state) { X case SEND: X if (send(word) == FAIL) X return(FAIL); X state = EXPECT; X break; X case EXPECT: X if (expect(word) == FAIL) { X if (if_fail == FALSE) X return(FAIL); /* no if-fail seq */ X } else { X /* eat up rest of current sequence X */ X if (if_fail == TRUE) { X while ((c = (*s++ & 0177)) != '\0' && X c != ' ') X ; X if (c == '\0') X finished = TRUE; X } X } X state = SEND; X break; X } X continue; X } X debug2(D_INIT, "initialize() successful\n"); X return (SUCCESS); X} X X X/* X** unquote() - decode char(s) after a '\' is found. X** X** Returns the pointer s; decoded char in *c. X*/ X Xchar * Xunquote(s, c) Xchar *s, *c; X{ X int octal; X char n; X X n = *s++; X switch (n) { X case 'b': X *c = '\b'; break; X case 'c': X if ((n = *s++) == '\n') X *c = '\0'; X else X *c = n; X break; X case 'f': X *c = '\f'; break; X case 'n': X *c = '\n'; break; X case 'r': X *c = '\r'; break; X case 's': X *c = ' '; break; X case 't': X *c = '\t'; break; X case '\n': X *c = '\0'; break; /* ignore NL which follows a '\' */ X case '\\': X *c = '\\'; break; /* '\\' will give a single '\' */ X default: X if (isdigit(n)) { X octal = 0; X do { X octal = (octal * 8) + (int) n; X n = *s++; X } while (isdigit(n)); X *c = (char) (octal & 0177); X } else { X *c = n; X } X break; X } X return(s); X} X X X/* X** send() - send a string to stdout X*/ X Xint Xsend(s) XReg1 char *s; X{ X Reg2 int retval = SUCCESS; X char ch; X X debug2(D_INIT, "SEND: ("); X while (ch = *s++) { X if (ch == '\\') { X switch (*s) { X case 'p': /* '\p' == pause */ X debug2(D_INIT, "[pause]"); X (void) sleep(1); X s++; /* skip past 'p' */ X continue; X case 'd': /* '\d' == delay */ X debug2(D_INIT, "[delay]"); X (void) sleep(2); X s++; X continue; X default: X s = unquote(s, &ch); X break; X } X } X debug3(D_INIT, ((ch < ' ') ? "^%c" : "%c"), X ((ch < ' ') ? ch | 0100 : ch)); X if (write(STDOUT, &ch, 1) == FAIL) { X retval = FAIL; X break; X } X } X debug3(D_INIT, ") -- %s\n", (retval == SUCCESS) ? "OK" : "Failed"); X return(retval); X} X X X/* X** expect() - look for a specific string on stdin X*/ X Xjmp_buf env; /* here so expalarm() sees it */ X Xint Xexpect(s) XReg1 char *s; X{ X Reg2 int i; X Reg3 retval = FAIL; X char ch, *p, word[MAXLINE+1], buf[MAXBUF]; X sig_t (*oldalarm)(); X X#ifdef lint X /* shut lint up about 'warning: oldalarm may be used before set' */ X oldalarm = signal(SIGALRM, SIG_DFL); X#endif /* lint */ X X if (setjmp(env)) { /* expalarm returns non-zero here */ X debug3(D_INIT, "[timed out after %d seconds]\n", EXPFAIL); X (void) signal(SIGALRM, oldalarm); X return(FAIL); X } X X /* look for escape chars in expected word X */ X for (p = word; ch = (*s++ & 0177);) { X if (ch == '\\') X s = unquote(s, &ch); X *p++ = (ch) ? ch : '\177'; X } X *p = '\0'; X X oldalarm = signal(SIGALRM, expalarm); X (void) alarm((unsigned) EXPFAIL); X X debug2(D_INIT, "EXPECT: ("); X debug1(D_INIT, word); X debug2(D_INIT, ")\n"); X p = buf; X while (read(STDIN, &ch, 1) == 1) { X debug3(D_INIT, ((ch < ' ') ? "^%c" : "%c"), X ((ch < ' ') ? ch | 0100 : ch)); X *p++ = (char) ((int) ch & 0177); X *p = '\0'; X if (strlen(buf) >= strlen(word)) { X for (i=0; buf[i]; i++) X if (strnequal(&buf[i], word, strlen(word))) { X retval = SUCCESS; X break; X } X } X if (retval == SUCCESS) X break; X } X (void) alarm((unsigned) 0); X (void) signal(SIGALRM, oldalarm); X debug3(D_INIT, " -- %s\n", (retval == SUCCESS) ? "got it" : "Failed"); X return(retval); X} X X X/* X** expalarm() - called when expect()'s SIGALRM goes off X*/ X Xsig_t Xexpalarm() X{ X longjmp(env, 1); X} X X X/* X** getlogname() - get the users login response X** X** Returns int value indicating success. X*/ X Xint Xgetlogname(termio, name, size) XTERMIO *termio; XReg1 char *name; Xint size; X{ X Reg2 int count; X Reg3 int lower = 0; X Reg4 int upper = 0; X char ch, *p; X ushort lflag; X X#ifdef MY_ERASE X char Erase = MY_ERASE; X#else X char Erase = CERASE; X#endif /* MY_ERASE */ X#ifdef MY_KILL X char Kill = MY_KILL; X#else X char Kill = CKILL; X#endif /* MY_KILL */ X X debug2(D_GETL, "getlogname() called\n"); X X (void) ioctl(STDIN, TCGETA, termio); X lflag = termio->c_lflag; X X termio->c_iflag = 0; X termio->c_oflag = 0; X termio->c_cflag = 0; X termio->c_lflag = 0; X X p = name; /* point to beginning of buffer */ X count = 0; /* nothing entered yet */ X X do { X if (read(STDIN, &ch, 1) != 1) /* nobody home */ X exit(0); X if ((ch = (char) ((int) ch & 0177)) == CEOF) X if (p == name) /* ctrl-d was first char */ X exit(0); X if (ch == CQUIT) /* user wanted out, i guess */ X exit(0); X if (ch == '\0') { X debug2(D_GETL, "returned (BADSPEED)\n"); X return(BADSPEED); X } X if ((lflag & ECHO) == 0) { X (void) putc(ch, stdout); X (void) fflush(stdout); X } X if (ch == Erase) { X if (count) { X if ((lflag & ECHOE) == 0) { X (void) fputs(" \b", stdout); X (void) fflush(stdout); X } X --p; X --count; X } X } else if (ch == Kill) { X if ((lflag & ECHOK) == 0) { X (void) fputs("\r\n", stdout); X (void) fflush(stdout); X } X p = name; X count = 0; X } else { X *p++ = ch; X count++; X if (islower(ch)) X lower++; X if (isupper(ch)) X upper++; X } X } while ((ch != '\n') && (ch != '\r') && (count < size)); X X *(--p) = '\0'; /* terminate buffer */ X X if (ch == '\r') { X (void) putc('\n', stdout); X (void) fflush(stdout); X termio->c_iflag |= ICRNL; /* turn on cr/nl xlate */ X termio->c_oflag |= ONLCR; X } else if (ch == '\n') { X (void) putc('\r', stdout); X (void) fflush(stdout); X } X X if (strlen(name) == 0) { X debug2(D_GETL, "returned (NONAME)\n"); X return(NONAME); X } X X if (upper && !lower) { X#ifdef WARNCASE X if (WarnCase) { X WarnCase = FALSE; X debug2(D_GETL, "returned (BADCASE)\n"); X return(BADCASE); X } X#endif /* WARNCASE */ X for (p=name; *p; p++) /* make all chars UC */ X *p = toupper(*p); X termio->c_iflag |= IUCLC; X termio->c_oflag |= OLCUC; X termio->c_lflag |= XCASE; X } X X debug3(D_GETL, "returned (SUCCESS), name=(%s)\n", *name); X return(SUCCESS); X} X X X/* X** logerr() - display an error message X*/ X Xvoid Xlogerr(msg) XReg1 char *msg; X{ X Reg2 FILE *co; X char *errdev; X X errdev = (Check) ? "/dev/tty" : CONSOLE; X X if ((co = fopen(errdev, "w")) != (FILE *) NULL) { X (void) fprintf(co, "\r\n%s (%s): %s\r\n", MyName, Device, msg); X (void) fclose(co); X } X X#ifdef TRYMAIL X else { X char buf[MAXLINE]; X FILE *popen(); X X (void) sprintf(buf, "%s %s", MAILER, NOTIFY); X if ((co = popen(buf, "w")) != (FILE *) NULL) { X (void) fprintf(co, "To: %s\n", NOTIFY); X (void) fprintf(co, "Subject: %s problem\n\n", MyName); X (void) fprintf(co, "%s: %s\n", Device, msg); X (void) pclose(co); X } X } X#endif /* TRYMAIL */ X X} X X X#ifdef DEBUG X X/* X** debug() - an fprintf to the debug file X** X** Only does the output if the requested level is "set." X*/ X X/*VARARGS2*/ Xvoid Xdebug(lvl, fmt, va_alist) Xint lvl; Xchar *fmt; Xva_dcl X{ X va_list args; X X va_start(args); X if (Debug & lvl) { X (void) vfprintf(Dfp, fmt, args); X (void) fflush(Dfp); X } X va_end(args); X} X X/* X** dprint() - like debug(), but shows control chars X*/ X Xvoid Xdprint(lvl, word) Xint lvl; Xchar *word; X{ X char *p, *fmt, ch; X X if (Debug & lvl) { X p = word; X while (ch = *p++) { X if (ch < ' ') { X fmt = "^%c"; X ch = ch | 0100; X } else { X fmt = "%c"; X } X (void) fprintf(Dfp, fmt, ch); X } X (void) fflush(Dfp); X } X} X X#endif /* DEBUG */ X X X/* end of funcs.c */ !STUFFY!FUNK! echo Extracting man/strdup.m4 sed >man/strdup.m4 <<'!STUFFY!FUNK!' -e 's/X//' X.\" +---------- X.\" | $Id: strdup.m4,v 1.1 90/01/16 16:04:12 paul Exp Locker: paul $ X.\" | X.\" | STRDUP man page. X.\" | X.\" | Copyright 1989,1990 by Paul Sutcliffe Jr. X.\" | X.\" | Permission is hereby granted to copy, reproduce, redistribute, X.\" | or otherwise use this software as long as: there is no monetary X.\" | profit gained specifically from the use or reproduction or this X.\" | software, it is not sold, rented, traded or otherwise marketed, X.\" | and this copyright notice is included prominently in any copy X.\" | made. X.\" | X.\" | The author make no claims as to the fitness or correctness of X.\" | this software for any use whatsoever, and it is provided as is. X.\" | Any use of this software is at the user's own risk. X.\" | X.\" X.\" +---------- X.\" | $Log: strdup.m4,v $ X.\" | Revision 1.1 90/01/16 16:04:12 paul X.\" | Initial revision X.\" | X.\" | X.\" X.\" +---------- X.\" | M4 configuration X.\" Xinclude(config.m4).\" X.\" X.\" +---------- X.\" | Manpage source follows: X.\" X.TH STRDUP _library_section_ X.SH NAME Xstrdup \- duplicate a string in memory X.SH SYNOPSIS X.B char *strdup(\fIstring\fB)\fR; X.br X.B char *\fIstring\fR; X.SH DESCRIPTION X.I Strdup Xallocates storage space (with a call to X.I malloc(_library_section_)) Xfor a copy of X.I string Xand returns a pointer to the storage space containing the copied Xstring. X.SH "RETURN VALUE" X.I Strdup Xreturns NULL if storage cannot be allocated. Otherwise, a valid Xpointer is returned. X.SH "SEE ALSO" Xmalloc(_library_section_), Xstring(_library_section_) X.SH AUTHOR X.nf XPaul Sutcliffe, Jr. <paul at devon.lns.pa.us> XUUCP: ...!rutgers!devon!paul !STUFFY!FUNK! echo "" echo "End of kit 1 (of 4)" cat /dev/null >kit1isdone run='' config='' for iskit in 1 2 3 4; do if test -f kit${iskit}isdone; then run="$run $iskit" else todo="$todo $iskit" fi done case $todo in '') echo "You have run all your kits. Please read README and then type Configure." chmod 755 Configure ;; *) echo "You have run$run." echo "You still need to run$todo." ;; esac : Someone might mail this, so... exit INTERNET: paul at devon.lns.pa.us | If life's a bitch, then UUCP: ...!rutgers!devon!paul | we must be her puppies. From bill at twwells.com Mon Jan 8 02:26:43 1990 From: bill at twwells.com (T. William Wells) Date: 7 Jan 90 15:26:43 GMT Subject: System V getty clone Message-ID: <1990Jan7.152643.15781@twwells.com> This is basically a drop in replacement for the System V getty program. There are some minor differences and a number of enhancements. There is a manual page (not troff, sorry) for this getty. I'll be posting this to comp.sources.unix but I know that some people want it now and c.s.u. appears to be dormant. echo x - README sed 's/^X//' >README <<'*-*-END-of-README-*-*' XThis is getty version 1.0, released January 1, 1990. It is very nearly Xa drop in replacement for the System V getty, though there are some Xminor differences. Send bug reports and suggestions to Xbill at twwells.com. I have made the code as clean as I can; if you don't Xunderstand something, and the problem is not just that you don't like Xmy coding style, let me know. I'll either comment or recode as Xnecessary. X XI use this getty on my system, a Microport V/386 3.0e, and it works Xthere, but I have no practical way to test it on other systems. I Xunderstand that others have run this with little trouble on other SysV Xsystems. X XThis is pretty much a direct replacement for the standard getty that Xcame with my Microport V/386 3.0e system. There are two reasons I Xwrote it: for logging terminal activity and so that the terminal Xcharacteristics are set up properly for better system security. Some Xother features: the standard getty has a few irksome bugs and is Xpoorly documented. These are gone. As for whatever bugs appear in this Xone, well we now have source. The documentation is, I believe, more Xuseful than the original getty document. I don't recommend replacing Xyour getty with this new code till you have made sure that you still Xhave a way into your system; wouldn't it be embarassing to have to Xjump through the installation hoops again just because getty won't Xtalk to you? X XRead the copyright notices in the individual files to determine Xexactly what their restrictions are. Basically, they are free Xdistribution, no direct commercial use, and keep a modification log in Xthe code if you distribute modified versions. X XThere are several changes I'm thinking about for the next version: X X Permit the specification of the terminal control characters in X the gettydefs file. This means that you can set up the X terminal to default to ^C as the control character instead of X whatever brain damage your system provides. X X Add a new field to the gettydefs entries to permit X specification of the program to run; this would let you use X different login programs on different lines. X X Change the -c display to interpretable by humans, e.g., show X the modes symbolically instead of in octal. X X Add a manual page for /etc/gettydefs. X X Put all the regular configuration stuff into the Makefile. X X Arrange that all static nonconstant variables are initialized by code. X X Eliminate the dependence on the ASCII character set. X X There are still a few line length limits which should go. *-*-END-of-README-*-* echo x - getty.8 sed 's/^X//' >getty.8 <<'*-*-END-of-getty.8-*-*' XNAME X getty -- set terminal types, modes, speed, line discipline X XSYNOPSIS X X getty [-P] [-T] [-h] [-s] X [-l logfile] [-t timeout] [-i issue_file] X line [speed [type [linedisc]]] X getty -c [file] X XCOPYRIGHT X X Copyright 1989 By T. William Wells. All Rights Reserved. X X You may distribute this document and its derivatives so long X as you do not charge for them; you may charge a fee sufficient X to cover distribution costs. You may not include it in a X product to be sold. You may not use it as an inducement to X buy. X X You may not modify this copyright notice; you may only add to X the modification log that follows this copyright notice. X X You may modify this document. If you modify the document and X distribute it, you must update the modification log to say who X you are and when you made the change. X XMODIFICATION LOG X X Send bug reports to T. William Wells, bill at twwells.com. X Version 0.1, written by T. William Wells, released March 19, 1989. X Version 0.2, modified by T. William Wells, released June 25, 1989. X Version 1.0, modified by T. William Wells, released January 1, 1990. X XDESCRIPTION X X Getty is one of the programs used to connect a terminal to the X system. The normal procedure is for init to fork a getty, X getty to exec login, and login to run a shell. Getty can only X be executed by the super-user, except when the -c option is X used. X X Getty uses its arguments and the contents of /etc/gettydefs to X set up an initial connection to the user. It displays a X connect message from /etc/issue and prompts the user for a set X of arguments. It reads those arguments and passes them along X to login. While reading the arguments, getty determines some X terminal characteristics which it uses to set various terminal X modes just before calling login. If getty reads a NUL X character, normally created by the user pressing the break X key, getty will change the line speed as specified in the X /etc/gettydefs file. X X `Line' is the name of the terminal device to be opened by X getty. It is found by looking in /dev. The terminal modes are X set to 0660 by getty; the owner and group ids are set from the X effective ids of the getty. X X `Speed' is the label for an entry in /etc/gettydefs. Each X entry contains the terminal parameters to be established by X the getty, including the terminal speed, the login prompt, and X the label for the entry to be used next should getty receives X a break. There is a default speed entry built into getty which X is used if this field is not specified. X X `Type' describes the terminal type attached to the line. The X default is "none". This version of getty does not recognize X any terminal types other than "none". X X `Linedisc' describes the line discipline to be used when X communicating with the terminal. The default is "LDISC0". This X version of getty does not recognize any line disciplines other X than "LDISC0". X X The program options are: X X -P When you are debugging a new terminal line, you may not X want getty to exit immediately on errors. If there is an X error in the invocation of getty, for example, init will X respawn gettys as fast as they die. Init will eventually X catch on, but why go through the hassle? If you specify the X -P option, getty will pause just before exiting. It will X also change its arguments so that a ps will show it as X "badgetty". When paused, getty will have closed the X terminal line. Once you have fixed the cause of the error, X you can kill the getty which will cause it to exit cleanly. X X -T This version of getty assumes that a succeeding open means X that there is a user on the other end. Accordingly, the X timeout, if specified, starts when the open returns. If the X open succeeds immediately, regardless of the presence of a X connection, you will want the timeout to start when the X first character is recieved. The -T option does that. X X -h Normally, getty hangs up the line immediately after the X open succeeds. On certain lines, notably dial up lines X where the open succeeds only when there is a carrier, this X is a definite mistake. -h will prevent the hang up. X X -s This causes the getty to display the system name right X after it displays the /etc/issue file. X X -l If this is specified, getty writes a record of everything X that happens to the log file. Getty creates the log file X with modes 660, you will want to make sure that it remains X unreadable by anyone other than the super-user, as it may X contain things like passwords entered at the wrong prompt. X Getty tries to write each log message with one system call, X so you should be able to use one log file for all gettys. X Each line in the log file contains the terminal name, X process id of the getty, the date, and a message. X X You will almost certainly want to truncate this file X periodically. X X -t This specifies the length of time that getty will wait for X a complete login argument. If it doesn't get one by this X time, it just exits. Getty starts its timer when the open X succeeds unless the -T option is specified, in which case X it starts it when the first character is read. X X -i This specifies an alternate to the /etc/issue file, in case X you don't want do use the standard one or there is no X standard one and you want one for a specific line. Note X that specifying a nonexistent file will simply result in no X message being printed out. /dev/null is a good choice for X an empty message. X X Getty -c is used for checking out a definition file. If you X don't specify a file name, /etc/gettydefs is used. It is a X good idea to run getty -c on a just-edited definition file to X see if anything is amiss. X X The initial sequence of operations performed by getty are: X X 1) Open the terminal line, set its owner, group, and modes. X 2) Place accounting entries in /etc/utmp and /etc/wtmp. X 3) Hang up the line unless -h was specified. X 4) Start the timeout, unless -T was specified. X X If getty can't get the specified speed entry, it gets the X first one from the /etc/gettydefs file. If it can't get to the X file, it uses a default that is built into the program. This X default is for a terminal at 2400 baud. X X Then, for each speed entry that is tried, it does these steps: X X 1) Set terminal modes as specified in the /etc/gettydefs file. X Note that most of these options are ignored. In particular, X the fields in c_iflag, other than ICRNL and IGNPAR are X ignored; not specifying a character size gets you eight X bits; CREAD and HUPCL in c_cflag are always set; and X c_lflag is cleared. X X 2) Write the message from /etc/issue and the system name, if X requested. X X 3) Get the login arguments. If a break is read, get a new X speed entry and try again. If -T was specified, start the X timeout when the first character is received. X X When the login arguments are read, the terminal modes are set X up as specified in the current /etc/gettydefs entry; however, X they may be modified by getty. If the input terminator is a X return, translation of returns to and from newlines is X enabled. If the login arguments contain at least one upper X case letter but no lower case letters, case translation is X enabled and the login arguments are made all lower case. X X The arguments are then broken up into words and these become X the arguments to login. Words are separated by white space. If X you want to put white space into an argument, use one of the \ X escapes described below. X X Getty recognizes a number of special characters when reading X the login arguments. They are: X X ^H causes a backspace. The character is removed from the input X buffer and a backspace-space-backspace is written to the X terminal to remove the character from the display. X X # removes one character from the input buffer. There is no X attempt to remove the character from the terminal display. X X ^D causes getty to exit. X X Any of ^C, ^U, DEL, ^|, or @ causes the current input to be X discarded. The user is prompted again with the login prompt X but not the /etc/issue message. X X ^J and ^M terminate the input. X X \ is an escape character. A NUL still causes a speed change; X however, other characters' interpretations are changed. The X standard C escape sequences do as expected. \E translates to X an escape character. \s is translated to a space; however, X unlike a space, it does not separate login arguments. X X Control characters are not echoed as control characters, but X as either ^letter or \octal. X X If the input buffer overflows, getty will exit. This buffer X can hold 255 characters. X XINSTALLATION X X The following installation instructions are for relatively X standard systems; if yours isn't, you'll have to use your own X judgement. The main thing left out is what you do if you have X put things in an unusual places or want to do unusual things X with the getty. It is also assumed that you are replacing an X existing getty, and so there are no instructions on how to set X up a terminal, etc. X X The steps are: X X 1) Edit the getty source to meet your requirements. X 2) Edit the Makefile. X 3) Run `make' to compile the getty. X 4) Run `make install' to put it where it belongs. X 5) Update /etc/inittab. X 6) Update /etc/gettydefs. X X There are a number of changes you might want to make in the X getty source; these are summarized below: X X BREAK_DELAY (40 ms) X X Many systems respond poorly when receiving a break; they X generate lots of garbage and normal terminal flushing doesn't X get rid of it. To deal with that, the getty flushes the buffer X itself, by reading characters from the terminal till none X appear after a certain delay. As configured, the program waits X 40ms after the last character received before concluding that X the break garbage has gone away. If your system translates a X break into exactly one character, you might want to make this X 10ms; if your system is particularly noisy, you might want to X make it longer. This parameter is specified in units of 10 X milliseconds. X X CONSOLE (/dev/console) X X Error message go to this device; your console may have a X different name. X X DFLT_SPEED (2400) X X If you want a different default speed in the getty, change X this. Along with this change, you might want to change the X default gettydefs entry or the definition of SANE; the first X is controlled by the Default_def variable, the second by the X MODE_[IOCL]SANE variables. X X LOGCMD (/bin/login) X X This is the file containing the program that getty is to run X when it has read the login arguments. Yours may be in X /etc/login. X X The one change you might want to make to the Makefile is to X specify where the getty should be installed. Note that many X systems have an init that does strange things with getty; that X means that you can't put the getty in a directory which has X `getty' as a component, nor can you use a name other than X `getty' for it. The macro to change is GETTYBIN. X X To compile the getty, type `make'. To install it, become root, X and type `make install'. X X You may want to modify your /etc/inittab or whatever your init X uses to control the programs it runs. What you'd want to X change is the command that starts the getty. In particular, X you may want to add a -T option, to specify timeout after the X first character read; -s, to display the system name; or -l X <filename>, to enable getty logging. X X Finally, you may want to edit your existing /etc/gettydefs X file, or you may need to create one if your system didn't use X one before. If you need to create one, you will have to hunt X up the gettydefs manual page. If you want to use your old X gettydefs, odds are it will work fine. The one thing that X might break is the interpretation of SANE: the one in getty is X unlikely to be identical with yours. X XFILES X X /bin/login This is called when the arguments have been read. X /dev The terminal file is found in this directory. X /dev/console Error messages are written here. X /etc/gettydefs The getty parameters are read from here. X /etc/issue This is the initial connection message. X /etc/utmp The entry in this file for the terminal is updated. X /etc/wtmp An accounting record is appended to this file. X X The /etc/gettydefs is interpreted somewhat differently than is X described in gettydefs(4). In particular, all the backslash X escapes described for input work in it. Also, !<mode> is X recognized to turn off modes; this is useful to get SANE minus X some particular mode. X XSEE ALSO X X gettydefs(4) init(1) ioctl(2) login(1) termio(7) utmp(4) X XBUGS X X None known. But if you do find any, let me, T. William Wells, X bill at twwells.com, know. *-*-END-of-getty.8-*-* echo x - Makefile sed 's/^X//' >Makefile <<'*-*-END-of-Makefile-*-*' XGETTYBIN = /etc/bin XGETTY = $(GETTYBIN)/getty XOGETTY = $(GETTYBIN)/getty.old XCC = gcc XCFLAGS = -O XLDCC = cc XLFLAGS = XLDLIB = -lc_s X X# Builds getty. X Xgetty : getty.o X $(LDCC) $(LFLAGS) getty.o $(LDLIB) X mv a.out $@ X X# Installs getty. Makes a copy of the old one, if there is no copy already X# made. You may want to get rid of the copy after all is going well. X Xinstall : X if [ ! -r $(OGETTY) ]; then mv $(GETTY) $(OGETTY); fi X cp getty $(GETTY) X strip $(GETTY) X chown root $(GETTY) X chgrp root $(GETTY) X chmod 770 $(GETTY) X X# Lints getty. X Xlint.out : getty X lint getty.c >lint.out 2>&1 X X# Makes a shar for distribution of the getty. X XGETTYSHAR = README getty.8 Makefile getty.c Xgetty.shar : $(GETTYSHAR) X shar $(GETTYSHAR) >shar.tmp X mv shar.tmp $@ X X# Deletes unneeded files in the getty source directory. X Xclean : X rm -f *.out *.o getty *-*-END-of-Makefile-*-* echo x - getty.c sed 's/^X//' >getty.c <<'*-*-END-of-getty.c-*-*' X#include <sys/types.h> X#include <sys/stat.h> X#include <sys/utsname.h> X#include <ctype.h> X#include <errno.h> X#include <fcntl.h> X#include <signal.h> X#include <stdio.h> X#include <string.h> X#include <termio.h> X#include <time.h> X#include <utmp.h> X X/* Copyright 1989 By T. William Wells. All Rights Reserved. X X You may distribute this code and its derivatives so long as you do not X charge for them; you may charge a fee sufficient to cover distribution X costs. You may not include it in a product to be sold. You may not use it X as an inducement to buy. X X You may not modify this copyright notice; you may only add to the X modification log that follows this copyright notice. X X You may modify the code. If you modify the code and distribute it, you must X update the modification log to say who you are and when you made the X change. */ X X/* Send bug reports to T. William Wells, bill at twwells.com. X X Modification log: X X Version 0.1, written by T. William Wells, released March 19, 1989. X Version 0.2, modified by T. William Wells, released June 25, 1989. X Problems fixed: X Some comments with problems were improved. X The echo of ^<letter> was screwed up because another buffer X was too short; a null overwrote the '^'. X Breaks were not handled correctly all the time, causing the X program to rapidly cycle through speeds. X When signals were received, sometimes the log messages were X not displayed with their time stamps. X The log file remained open after the exec. X The B19200 and B38400 labels aren't defined for all systems, X requiring the references to them to be #ifdef'ed. X (Jay Maynard <splut!jay>) X The setpgrp that used to be there was wrong; it made getty X not work if getty were called from a front end that X had already opened the terminals. (Marc Boucher X <marc at clik.qc.ca>) X X Changes: X \E can be used to input the escape character; \E is also X displayed for the escape. X \s can be used to input the space character; \s is also X displayed for a space. X IGNPAR is no longer ignored as one of the initial modes. X Added a -s option to display the system name. (Jay Maynard X <splut!jay>) X SANE is saner: includes TAB3. X Added ! to gettydefs; turns off a mode. X Version 1.0, modified by T. William Wells, released January 1, 1990. X Changes: X Option -i can be used to specify an alternate to the X /etc/issue file. X*/ X X/* getty - the program to handle initial terminal connections to the system. X It sets up the speed, terminal flags, and line discipline. It then waits X for some arguments and calls login with them. X X getty [-P] [-T] [-h] [-s] [-l logfile] [-t timeout] [-i issue_file] X line [speed [type [linedisc]]] X getty -c [file] X X -P When error exiting, set our name to badgetty, close the line, and pause. X One makes the getty exit by sending it a signal. X X -T Do the timeout from after the first character read. This is appropriate X for lines where the open does not wait for a carrier. X X -h Don't hang up the line when initializing it. X X -l Report getty behavior to the log file. X X -s Display the system name. X X -t If timeout seconds elapse with no input, hang up the line. Timeout is X normally from when the open returns, but the -T option changes that. X X -i Specify alternate to /etc/issue. X X Line is the device name as found in /dev. X X Speed is the label of the entry in the definition file which is to be used X to initialize the line. X X Type is the terminal type name. X X Linedisc is the line discipline name. X X -c Check the specified file for validity. An interpretation of the file is X printed so that it can be checked for correctness. */ X Xextern unsigned alarm(); Xextern void endutent(); Xextern void exit(); Xextern struct utmp *getutent(); Xextern unsigned short getegid(); Xextern unsigned short geteuid(); Xextern char *optarg; Xextern int opterr; Xextern int optind; Xextern struct utmp *pututline(); Xextern char *sys_errlist[]; Xextern int sys_nerr; Xextern time_t time(); X X#define BAD_NAME "badgetty" /* name shown when getty hangs due to error */ X#define BREAK_DELAY 4 /* VTIME for skipping break garbage */ X#define CONSOLE "/dev/console" /* msgs go here when parent is init */ X#define DFLT_SPEED B2400 /* speed for default entry */ X#define ESC_CHAR 0x1B /* character for \E escape */ X#define GETTYDEFS "/etc/gettydefs" /* default definition file */ X#define INTR_CHAR (0x1F&'C') /* other interrupt character */ X#define ISSUE "/etc/issue" /* file containing signon message */ X#define KILL_CHAR (0x1F&'U') /* other line kill character */ X#define LINE_LEN 256 /* length of line buffers, etc. */ X#define LOGIN_ARGV0 "login" /* command name of login */ X#define LOGIN_CMD "/bin/login" /* command to execute to do login */ X#define LOG_MODE 0660 /* file modes for log file */ X#define MAX_ARGS 32 /* max args to be passed to login */ X#define TTY_MODE 0660 /* terminal mode */ X Xtypedef unsigned char UCHAR; X X/* These are the standard UNIX fd's; here defined so that they can be found X with no difficulty. */ X X#define TTY_IN 0 /* fd for reading the terminal */ X#define TTY_OUT 1 /* fd for writing the terminal */ X#define TTY_ERR 2 /* fd for error writes to the terminal */ X X#define LOG_FD 10 /* fd to assign to the log file */ X X/* A kludge because of the missing LDISC0 in some system includes. */ X X#ifndef LDISC0 X#define LDISC0 0 X#endif X Xtypedef struct { /* contains one speed entry */ X char td_label[16]; /* label for this entry */ X struct termio td_initial; /* initial terminal flags */ X struct termio td_final; /* final terminal flags */ X int td_msglen; /* length of msg to prompt with */ X char td_logmsg[80]; /* message to prompt with */ X char td_nxtlbl[16]; /* next label to try */ X} TTYDEF; X Xtypedef struct { /* used to contain table of word -> value */ X char *w_text; /* input word */ X unsigned w_value; /* value for it */ X} WORD; X X/* These are the modes that are used when SANE is specified. */ X X#define MODE_ISANE (BRKINT | IGNPAR | ISTRIP | ICRNL | IXON) X#define MODE_OSANE (OPOST | ONLCR | TAB3) X#define MODE_CSANE (CS8 | CREAD | HUPCL) X#define MODE_LSANE (ISIG | ICANON | ECHO | ECHOE | ECHOK) X X/* This is the default terminal entry; it is used if none is available from X the definition file. */ X XTTYDEF Default_def = { X "default", /* fake speed name */ X X /* initial modes */ X X ICRNL, 0, DFLT_SPEED | MODE_CSANE, X 0, LDISC0, X { CINTR, CQUIT, CERASE, CKILL, CEOF }, X X /* final modes */ X X MODE_ISANE, MODE_OSANE, DFLT_SPEED | MODE_CSANE, X MODE_LSANE, LDISC0, X { CINTR, CQUIT, CERASE, CKILL, CEOF }, X X sizeof("LOGIN: ") - 1, "LOGIN: ", /* prompt */ X "default", /* next speed entry */ X}; X X/* These tables define the input words for setting modes. */ X XWORD W_imodes[] = { X "IGNBRK", IGNBRK, "BRKINT", BRKINT, "IGNPAR", IGNPAR, "PARMRK", PARMRK, X "INPCK", INPCK, "ISTRIP", ISTRIP, "INLCR", INLCR, "IGNCR", IGNCR, X "ICRNL", ICRNL, "IUCLC", IUCLC, "IXON", IXON, "IXANY", IXANY, X "IXOFF", IXOFF, X0, 0}; X XWORD W_omodes[] = { X "OPOST", OPOST, "OLCUC", OLCUC, "ONLCR", ONLCR, "OCRNL", OCRNL, X "ONOCR", ONOCR, "ONLRET", ONLRET, "OFILL", OFILL, "OFDEL", OFDEL, X "NL0", NL0, "NL1", NL1, "CR0", CR0, "CR1", CR1, X "CR2", CR2, "CR3", CR3, "TAB0", TAB0, "TAB1", TAB1, X "TAB2", TAB2, "TAB3", TAB3, "BS0", BS0, "BS1", BS1, X "VT0", VT0, "VT1", VT1, "FF0", FF0, "FF1", FF1, X0, 0}; X XWORD W_cmodes[] = { X "B0", B0, "B50", B50, "B75", B75, "B110", B110, X "B134", B134, "B150", B150, "B200", B200, "B300", B300, X "B600", B600, "B1200", B1200, "B1800", B1800, "B2400", B2400, X "B4800", B4800, "B9600", B9600, X#ifdef B19200 X "B19200", B19200, X#endif X#ifdef B38400 X "B38400", B38400, X#endif X "EXTA", EXTA, "EXTB", EXTB, "CS6", CS6, "CS7", CS7, X "CS8", CS8, "CSTOPB", CSTOPB, "CREAD", CREAD, "PARENB", PARENB, X "PARODD", PARODD, "HUPCL", HUPCL, "CLOCAL", CLOCAL, X0, 0}; X XWORD W_lmodes[] = { X "ISIG", ISIG, "ICANON", ICANON, "XCASE", XCASE, "ECHO", ECHO, X "ECHOE", ECHOE, "ECHOK", ECHOK, "ECHONL", ECHONL, "NOFLSH", NOFLSH, X0, 0}; X X/* These are the terminal types recognized by the program. */ X XWORD W_terminals[] = { X "none", TERM_NONE, X0, 0}; X X/* These are the line disciplines recognized by the program. */ X XWORD W_linedisc[] = { X "LDISC0", LDISC0, X0, 0}; X X/* Global variables. */ X Xchar **Argv; /* save for argv; used to change name in ps */ Xint Check_definitions; /* -c option specified */ Xchar *Definition_file; /* definition file to read from */ Xint Hang_up_on_init; /* do hang up after terminal opened, ! -h */ Xchar *Issue_file; /* file with message to print at connect */ Xint Line_discipline; /* line discipline from the command line */ XFILE *Log_file; /* file to log to, null if none */ Xint Our_pid; /* result of getpid() */ Xint Parent_is_init; /* set if getppid() returns 1 */ Xint Pause_on_exit; /* do a pause on an error exit */ Xchar *Program_name; /* base name of argv[0] */ Xint Save_signal; /* used for signal fiddling during logging */ Xint Show_sysname; /* -s: display the system name */ Xstruct utsname Sys_name; /* name of our system */ Xint Terminal_type; /* terminal type from command line */ Xunsigned Timeout_length; /* from command line, zero if no timeout */ Xint Tmout_after_first; /* -T: start timeout after first char read */ XTTYDEF Tty_def; /* current definition entry */ Xchar *Tty_line; /* terminal device name, from the cmd line */ X X/* Forward referenced functions. */ X Xvoid exit_on_signal(); Xint find_tty_def(); Xvoid flush_input(); Xvoid init_at_speed(); Xvoid init_terminal(); Xvoid parse_arguments(); Xvoid read_login_args(); X Xint Xmain(argc, argv) Xint argc; Xchar **argv; X{ X char next_label[LINE_LEN]; X X /* Random initialization. */ X X Our_pid = getpid(); X Parent_is_init = getppid() == 1; X Argv = argv; X uname(&Sys_name); X X /* Parse our arguments; the results go in globals. This does not X return if there is an argument error or if the -c option was X specified. */ X X parse_arguments(argc, argv); X X /* Initialize the terminal. Then cycle through the speed entries till X a successful read of the arguments occurs or an error occurs. */ X X init_terminal(); X while (1) { X init_at_speed(); X read_login_args(); X flush_input(); X strcpy(next_label, Tty_def.td_nxtlbl); X (void)find_tty_def(next_label); X } X} X X/* This gets called after logging is done to print deferred a signal log X message. */ X Xvoid Xlog_signal() X{ X int sig; /* signal that was deferred */ X X sig = Save_signal; X Save_signal = 0; X if (sig > 0) { X exit_on_signal(sig); X } X} X X/* Write to the log file. This routine prepends to each line in the log file X the terminal name, our pid, and a time stamp. */ X Xvoid Xlog_fputs(s) Xchar *s; /* string to write to the log file */ X{ X char *ptr; /* pointer into the string */ X time_t clock; /* current time */ X static int begin = 1; /* set to write the start of a line */ X X if (!Log_file) { X return; X } X Save_signal = -1; X while (*s) { X if (begin) { X if (*s == '\n') { X ++s; X continue; X } X clock = time((long *)0); X if (Tty_line) { X (void)fprintf(Log_file, "%s", Tty_line); X } else { X (void)fprintf(Log_file, "<none>"); X } X (void)fprintf(Log_file, " %d %.24s: ", X Our_pid, ctime(&clock)); X begin = 0; X } X if (!(ptr = strchr(s, '\n'))) { X (void)fputs(s, Log_file); X break; X } X ++ptr; X (void)fwrite(s, 1, ptr - s, Log_file); X (void)fflush(Log_file); X begin = 1; X s = ptr; X } X log_signal(); X} X X/* This is called when a timeout or other signal occurs. Unfortunately, a X signal can occur while logging. To deal with that, we don't really exit X when that occurs. Instead, the logger sets a variable which will be X interpreted by the signal handler to mean to defer the signal till after X the current output is done. There are lots of complex reasons why this must X be done; consider, for example, nonreentrancy of stdio calls. Anyway, we X don't want a recursive call to log_fputs and Save_signal is used both to X prevent this and to record the last signal that occured. Of course, this X might cause a signal to be not logged if two of them occured one right X after the other, but that can't be solved without major headaches. Note X the newline at the start of the exit message: that terminates the log X buffer if there was anything in it; otherwise, it does nothing. */ X Xvoid Xexit_on_signal(sig) Xint sig; /* signal number that was caught */ X{ X char buf[LINE_LEN]; X X if (Save_signal) { X Save_signal = sig; X return; X } X sprintf(buf, "\nexiting on signal %d\n", sig); X log_fputs(buf); X exit(1); X} X X/* Start the terminal timeout alarm. */ X Xvoid Xstart_timeout() X{ X if (Timeout_length) { X (void)signal(SIGALRM, exit_on_signal); X (void)alarm(Timeout_length); X Timeout_length = 0; X } X} X X/* Append text to the console output buffer. When this routine is called with X a null pointer, flush that buffer. The hope here is that writing the X message with one system call will get it out as one message. The message X will also be written to the log file. */ X Xvoid Xadd_to_msg(msg) Xchar *msg; /* string to add to error message */ X{ X register int tmp; X static int pos; /* index into msgbuf */ X static char msgbuf[LINE_LEN]; /* message buffer */ X X if (!msg) { X if (!pos) { X return; X } X msgbuf[pos++] = '\n'; X msgbuf[pos] = 0; X if (Parent_is_init) { X if ((tmp = open(CONSOLE, O_WRONLY)) >= 0) { X (void)write(tmp, msgbuf, (unsigned)pos); X (void)close(tmp); X } X } else { X (void)write(TTY_ERR, msgbuf, (unsigned)pos); X } X log_fputs(msgbuf); X pos = 0; X return; X } X tmp = strlen(msg); X if (tmp + pos >= sizeof(msgbuf) - 1) { X tmp = sizeof(msgbuf) - 2 - pos; X } X if (tmp) { X strncpy(msgbuf + pos, msg, tmp); X pos += tmp; X } X} X X/* Print an error message. The error message has two text sections. */ X Xvoid Xerror2(m1, m2) Xchar *m1; /* part one of the message */ Xchar *m2; /* part two of the message */ X{ X add_to_msg(Program_name); X add_to_msg(" on "); X add_to_msg(Tty_line ? Tty_line : "<none>"); X add_to_msg(": "); X add_to_msg(m1); X add_to_msg(m2); X add_to_msg("."); X add_to_msg((char *)0); X} X X/* Print an error message. The error message has one text section. */ X Xvoid Xerror1(msg) Xchar *msg; /* text to print */ X{ X error2(msg, ""); X} X X/* Print an error message for a failed system function. This requires that X errno be set correctly. The text string provided as input goes in text X like: "when (message) got error: (error message)". */ X Xvoid Xsys_emsg(msg) Xchar *msg; /* text to insert into the message */ X{ X char buf[LINE_LEN]; X X if (errno < sys_nerr) { X sprintf(buf, "when %s got error: ", msg); X error2(buf, sys_errlist[errno]); X } else { X sprintf(buf, "when %s got error number %d", msg, errno); X error1(buf); X } X} X X/* Print a string so that it is unambiguous when read and contains no control X characters. All nonprinting characters are displayed as some backslash X sequence, similar to the C escapes. Space is also printed this way. */ X Xvoid Xqprint(fp, buf, len) Xregister FILE *fp; /* file to write to */ Xregister UCHAR *buf; /* buffer to write from */ Xint len; /* number of characters in tbe buffer */ X{ X int cc; /* character from the write buffer */ X UCHAR *ebuf = buf + len; /* pointer to the end of the write buffer*/ X X for ( ; buf < ebuf; ) { X switch (cc = *buf++) { X case '\\': (void)fputs("\\\\",fp); break; X case '\n': (void)fputs("\\n", fp); break; X case '\t': (void)fputs("\\t", fp); break; X case '\v': (void)fputs("\\v", fp); break; X case '\b': (void)fputs("\\b", fp); break; X case '\r': (void)fputs("\\r", fp); break; X case '\f': (void)fputs("\\f", fp); break; X case ESC_CHAR: (void)fputs("\\E", fp); break; X case ' ': (void)fputs("\\s", fp); break; X default: X if (isprint(cc)) { X (void)putc(cc, fp); X } else { X (void)fprintf(fp, "\\%03o", cc); X } X break; X } X } X} X X/* Print a string to the log file using qprint. This eliminates control X characters and makes each space explicit. */ X Xvoid Xlog_qprint(msg, buf, len) Xchar *msg; /* text to print before the buffer */ XUCHAR *buf; /* buffer to print */ Xint len; /* number of characters in the buffer */ X{ X if (!Log_file) { X return; X } X log_fputs(msg); X Save_signal = -1; X qprint(Log_file, buf, len); X log_signal(); X log_fputs("\n"); X} X X/* If our parent is init, getty should not ever error exit; it should exec X another program or exit in order to have a new getty. However, when an X unrecoverable error occurs, something has to be done. What we'll do is set X the argument vector so that a ps will show the getty to have failed. Then X pause, and if an interrupt is received, exit. */ X Xvoid Xdo_exit(n) Xint n; /* exit code to return to caller */ X{ X add_to_msg((char *)0); X log_fputs("exiting\n"); X if (Pause_on_exit) { X (void)alarm(0); X strcpy(Argv[0], BAD_NAME); X (void)signal(SIGHUP, SIG_IGN); X (void)close(TTY_IN); X (void)close(TTY_OUT); X (void)close(TTY_ERR); X (void)pause(); X } X exit(n); X} X X/* Duplicates an fd. Checks for some errors, as unlikely as they may be. */ X Xvoid Xmy_dup2(fd, newfd) Xint fd; /* fd to duplicate */ Xint newfd; /* fd it is supposed to become */ X{ X int ret; X X if (close(newfd) < 0 && errno != EBADF) { X sys_emsg("closing an fd"); X do_exit(1); X } X if ((ret = fcntl(fd, F_DUPFD, newfd)) != newfd) { X if (ret < 0) { X sys_emsg("duping an fd"); X } else { X error1("dup didn't return expected fd"); X } X do_exit(1); X } X} X X/* An ugly: as init doesn't open any fd's for us, a regular open isn't going X to work because it will open one of the fd's we would use for the X terminal. All this BS exists so that the fd ends up not being one of the X first three. */ X Xvoid Xlog_open(name) Xchar *name; /* name of file to log to. */ X{ X int fd; X X if ((fd = open(name, O_WRONLY | O_APPEND | O_CREAT, LOG_MODE)) < 0) { X sys_emsg("opening log file"); X do_exit(1); X } X if (fd != LOG_FD) { X my_dup2(fd, LOG_FD); X (void)close(fd); X if (!(Log_file = fdopen(LOG_FD, "a"))) { X sys_emsg("fdopening log file"); X do_exit(1); X } X } X if (fcntl(LOG_FD, F_SETFD, 1) == -1) { X sys_emsg("setting close on exec"); X do_exit(1); X } X} X X/* Write text to the terminal. This logs the text, writes it to the terminal, X and checks for errors. */ X Xvoid Xtty_write(buf, len) Xchar *buf; /* text to write */ Xint len; /* number of characters to write */ X{ X int ret; /* return value from the write */ X char errbuf[LINE_LEN]; /* buffer for generating error message */ X X if (!len) { X return; X } X if (len < 0) { X len = strlen(buf); X } X log_qprint("write: ", (UCHAR *)buf, len); X if ((ret = write(TTY_OUT, buf, (unsigned)len)) < 0) { X sys_emsg("writing the terminal"); X do_exit(1); X } X if (ret != len) { X sprintf(errbuf, "%d bytes weren't written", len - ret); X error1(errbuf); X do_exit(1); X } X} X X/* Do an ioctl to the terminal. Make sure that it works. */ X Xvoid Xtty_ioctl(cmd, termio) Xint cmd; /* command to perform */ Xstruct termio *termio; /* termio structure to use */ X{ X if (ioctl(TTY_IN, cmd, termio) < 0) { X sys_emsg("doing ioctl for the terminal"); X do_exit(1); X } X} X X/* Scan through a keyword table and return the a pointer to the keyword entry. X If there is no matching entry, return null. */ X XWORD * Xfind_word(word, table) Xregister char *word; /* word to look for */ Xregister WORD *table; /* table to look into */ X{ X for ( ; table->w_text; ++table) { X if (strcmp(word, table->w_text) == 0) { X return (table); X } X } X return (0); X} X X/* Print a usage message and then exit. */ X Xvoid Xusage(msg) Xchar *msg; /* text to insert into the usage message */ X{ X /* This funny logging is done to prevent the entire usage message from X being written to the log file. */ X X log_fputs("usage error\n"); X log_fputs("exiting\n"); X Log_file = 0; X X /* Print the usage message and exit. */ X X add_to_msg(Program_name); X add_to_msg(": "); X add_to_msg(msg); X add_to_msg("\nusage: "); X add_to_msg(Program_name); X add_to_msg(" [-P] [-T] [-h] [-l logfile] [-t timeout]\n"); X add_to_msg((char *)0); X add_to_msg(" line [speed [type [linedisc]]]\n"); X add_to_msg((char *)0); X add_to_msg(" "); X add_to_msg(Program_name); X add_to_msg(" -c [file]"); X add_to_msg((char *)0); X do_exit(1); X} X X/* Parse our arguments. */ X Xvoid Xparse_arguments(argc, argv) Xint argc; Xregister char **argv; X{ X int nocheck; /* flag was set that isn't legal with -c */ X register WORD *wp; /* return value from find_word */ X char *ptr; /* pointer into argument */ X X /* Record the base part of the path name. */ X X if (Program_name = strrchr(argv[0], '/')) { X ++Program_name; X } else { X Program_name = argv[0]; X } X /* Interpret the options. */ X X nocheck = 0; X opterr = 0; X Definition_file = GETTYDEFS; X Hang_up_on_init = 1; X Issue_file = ISSUE; X while (1) { X switch (getopt(argc, argv, "PTchsi:l:t:")) { X default: usage("illegal option"); X case -1: break; X case 'P': /* Pause on exit. */ X Pause_on_exit = 1; X nocheck = 1; X continue; X case 'T': /* Start timeout after first character read. */ X Tmout_after_first = 1; X nocheck = 1; X continue; X case 'c': /* Check definition file. */ X Check_definitions = 1; X continue; X case 'h': /* Don't hang up on init. */ X Hang_up_on_init = 0; X nocheck = 1; X continue; X case 'l': /* Write messages to log file. */ X log_open(optarg); X nocheck = 1; X continue; X case 's': /* Show the system name. */ X Show_sysname = 1; X nocheck = 1; X continue; X case 't': /* Time out after specified interval. */ X for (ptr = optarg; *ptr; ) { X if (!isdigit(*ptr)) { X usage("illegal digit"); X } X Timeout_length *= 10; X Timeout_length += *ptr++ - '0'; X } X nocheck = 1; X continue; X case 'i': /* Specify alternate to /etc/issue. */ X Issue_file = optarg; X nocheck = 1; X continue; X } X break; X } X if (Check_definitions && nocheck) { X usage("improper combination of options"); X } X /* If the -c option was specified, call the find_tty_def routine to X parse the entire file and print it out. */ X X if (Check_definitions) { X if (optind < argc) { X Definition_file = argv[optind++]; X } X if (optind != argc) { X usage("too many arguments"); X } X if (Parent_is_init) { X error1("-c is not legal when called from init"); X do_exit(1); X } X (void)find_tty_def((char *)0); X do_exit(0); X } X if (optind == argc) { X usage("not enough arguments"); X } X /* Save the terminal line name */ X X Tty_line = argv[optind++]; X X /* If the speed was provided on the command line, get the entry from X the definition file for that speed. */ X X Tty_def = Default_def; X if (optind < argc) { X if (!find_tty_def(argv[optind])) { X (void)find_tty_def((char *)0); X } X ++optind; X } X /* Get the terminal type, if specified. */ X X Terminal_type = TERM_NONE; X if (optind < argc) { X if (!(wp = find_word(argv[optind], W_terminals))) { X error2("can't find terminal type ", argv[optind]); X } else { X Terminal_type = wp->w_value; X } X ++optind; X } X /* Get the line discipline. */ X X Line_discipline = LDISC0; X if (optind < argc) { X if (!(wp = find_word(argv[optind], W_linedisc))) { X error2("can't find line discipline ", argv[optind]); X } else { X Line_discipline = wp->w_value; X } X ++optind; X } X /* One final check: are all arguments used up? */ X X if (optind != argc) { X usage("too many arguments"); X } X} X X/* Interpret a quoted character. It returns a pointer to the character right X after the quoted character. Note that escaped nuls don't work; they are X treated as an end of input. Why? Because it would have been too much X trouble to distinguish an escaped nul from a newline at the end of the X input buffer. */ X Xchar * Xqchar(ptr, rc) Xregister char *ptr; /* pointer after the backslash */ Xregister UCHAR *rc; /* return the character value through here */ X{ X register int cc; /* character from the input */ X X /* Deal with the alpha escapes and backslash null. */ X X switch (cc = *ptr++) { X case 'n': *rc = '\n'; return (ptr); X case 't': *rc = '\t'; return (ptr); X case 'v': *rc = '\v'; return (ptr); X case 'b': *rc = '\b'; return (ptr); X case 'r': *rc = '\r'; return (ptr); X case 'f': *rc = '\f'; return (ptr); X case 'E': *rc = ESC_CHAR; return (ptr); X case 's': *rc = ' '; return (ptr); X case 0: *rc = 0; return (ptr - 1); X } X /* If nondigit, the quote does nothing. */ X X if (cc < '0' || cc > '7') { X *rc = cc; X return (ptr); X } X /* Interpret 1-3 digits. */ X X *rc = cc - '0'; X cc = *ptr; X if (cc < '0' || cc > '7') { X return (ptr); X } X *rc <<= 3; X *rc += cc - '0'; X cc = *++ptr; X if (cc < '0' || cc > '7') { X return (ptr); X } X *rc <<= 3; X *rc += cc - '0'; X return (ptr + 1); X} X X/* Extract a word from some text. It returns a pointer to the next word or the X end of the input. A failure to extract the word is signaled by returning X null. */ X Xchar * Xextract_word(ptr, obuf, size) Xregister char *ptr; /* buffer to extract from */ Xchar *obuf; /* output buffer */ Xint size; /* size of output buffer */ X{ X register int cc; /* character from the input */ X UCHAR qcc; /* non-register char, for qchar */ X X /* Find the start of the word. */ X X do { X if (!(cc = *ptr++) || cc == '#') { X return (0); X } X } while (isspace(cc)); X X /* Move characters to the output buffer. */ X X --size; X while (cc && !isspace(cc) && cc != '#') { X if (cc == '\\') { X ptr = qchar(ptr, &qcc); X cc = qcc; X } X if (size) { X *obuf++ = cc; X --size; X } X cc = *ptr++; X } X /* Terminate the buffer and return a pointer to the next word in the X input buffer. */ X X *obuf = 0; X --ptr; X while (isspace(*ptr)) { X ++ptr; X } X return (ptr); X} X X/* Extract the termio specifications from a definition line. Return the end X of the definition or null on error. */ X Xchar * Xget_tty_modes(ptr, termio) Xchar *ptr; /* definition text */ Xregister struct termio *termio; /* termio structure to initialize */ X{ X WORD *wp; /* return value from find_word */ X char word[LINE_LEN]; /* buffer for extracting words */ X X /* Clear the termio structure. */ X X termio->c_iflag = 0; X termio->c_oflag = 0; X termio->c_cflag = 0; X termio->c_lflag = 0; X X /* Extract the definition words and store the results in the termio X structure. */ X X while (isspace(*ptr)) { X ++ptr; X } X while (*ptr != '#') { X if (!(ptr = extract_word(ptr, word, sizeof(word)))) { X return (0); X } X if (strcmp(word, "SANE") == 0) { X termio->c_iflag |= MODE_ISANE; X termio->c_oflag |= MODE_OSANE; X termio->c_cflag |= MODE_CSANE; X termio->c_lflag |= MODE_LSANE; X } else if (word[0] != '!') { X if (wp = find_word(word, W_imodes)) { X termio->c_iflag |= wp->w_value; X } else if (wp = find_word(word, W_omodes)) { X termio->c_oflag |= wp->w_value; X } else if (wp = find_word(word, W_cmodes)) { X termio->c_cflag |= wp->w_value; X } else if (wp = find_word(word, W_lmodes)) { X termio->c_lflag |= wp->w_value; X } else if (Check_definitions) { X (void)printf("Undefined: %s\n", word); X } X } else { X if (wp = find_word(word + 1, W_imodes)) { X termio->c_iflag &= ~wp->w_value; X } else if (wp = find_word(word + 1, W_omodes)) { X termio->c_oflag &= ~wp->w_value; X } else if (wp = find_word(word + 1, W_cmodes)) { X termio->c_cflag &= ~wp->w_value; X } else if (wp = find_word(word + 1, W_lmodes)) { X termio->c_lflag &= ~wp->w_value; X } else if (Check_definitions) { X (void)printf("Undefined: %s\n", word); X } X } X } X return (ptr + 1); X} X X/* Look through the definition file for a definition with the requested label. X If the label is null, the first entry will be used. */ X Xint Xfind_tty_def(label) Xchar *label; /* label to look for */ X{ X register char *ptr; /* general character pointer */ X register int cc; /* current character */ X register FILE *fp; /* file pointer for definition file */ X register int field; /* <0 means no error, else field of error */ X register char *nptr; /* another character pointer */ X UCHAR qcc; /* argument for qchar, can't be register */ X char line[BUFSIZ]; /* definition input buffer */ X static char *fnames[] = { /* names of each input field */ X "label", "initial flags", "final flags", X "message", "next label", X }; X /* Open the definition file. */ X X if (!(fp = fopen(Definition_file, "r"))) { X sys_emsg("opening definition file"); X Tty_def = Default_def; X return (0); X } X while (1) { X /* Read one definition from the file; the definitions are X separated by blank lines. */ X X ptr = line; X *ptr++ = ' '; X while (1) { X if ((cc = getc(fp)) == EOF) { X if (ptr == line + 1) { X (void)fclose(fp); X Tty_def = Default_def; X return (0); X } X if (ptr[-1] == '\n') { X --ptr; X } X break; X } else if (cc == '\n' && ptr[-1] == '\n') { X --ptr; X break; X } X if (ptr == &line[sizeof(line)]) { X if (Check_definitions) { X (void)printf("Entry too long.\n"); X } X while (cc != EOF) { X if (cc == '\n') { X cc = getc(fp); X if (cc == '\n') { X break; X } X } else { X cc = getc(fp); X } X } X ptr = line + 1; X break; X } X *ptr++ = cc; X } X *ptr = 0; X X /* Ignore blank and comment lines. Lines that are too long X also get rejected here. */ X X if (!line[1] || line[1] == '#') { X continue; X } X if (Check_definitions) { X (void)printf("\n**** Next Entry ****\n%s\n\n", X line + 1); X } X /* Extract the label of the line. */ X X ptr = line + 1; X field = -1; X if (nptr = extract_word(ptr, Tty_def.td_label, X sizeof(Tty_def.td_label))) { X ptr = nptr; X if (*ptr != '#') { X field = 0; X } else { X ++ptr; X } X } else { X field = 0; X } X /* Extract the initial flags. */ X X if (field < 0) { X if (nptr = get_tty_modes(ptr, &Tty_def.td_initial)) { X ptr = nptr; X X /* Since not just any modes can be used by X getty, fix up the modes as necessary. */ X X Tty_def.td_initial.c_iflag &= ICRNL | IGNPAR; X if (!(Tty_def.td_initial.c_cflag & CSIZE)) { X Tty_def.td_initial.c_cflag |= CS8; X } X Tty_def.td_initial.c_cflag |= CREAD | HUPCL; X Tty_def.td_initial.c_lflag = 0; X } else { X field = 2; X } X } X /* Extract the final flags. */ X X if (field < 0) { X if (nptr = get_tty_modes(ptr, &Tty_def.td_final)) { X ptr = nptr; X } else { X field = 3; X } X } X /* Extract the login message. */ X X if (field < 0) { X for (nptr = Tty_def.td_logmsg; X nptr < &Tty_def.td_logmsg X [sizeof(Tty_def.td_logmsg)]; X *nptr++ = cc) { X cc = *ptr++; X if (!cc || cc == '#') { X break; X } X if (cc == '\\') { X ptr = qchar(ptr, &qcc); X cc = qcc; X } X } X Tty_def.td_msglen = nptr - Tty_def.td_logmsg; X if (cc != '#') { X field = 4; X } X } X /* And finally, extract the next label. */ X X if (field < 0) { X if (nptr = extract_word(ptr, Tty_def.td_nxtlbl, X sizeof(Tty_def.td_nxtlbl))) { X ptr = nptr; X if (*ptr) { X field = 5; X } X } else { X field = 5; X } X } X /* Display the definition if requested. */ X X if (Check_definitions) { X (void)printf("label: %s\n", Tty_def.td_label); X (void)printf( X"initial flags: iflag %6o oflag %6o cflag %6o lflag %6o\n", X Tty_def.td_initial.c_iflag, X Tty_def.td_initial.c_oflag, X Tty_def.td_initial.c_cflag, X Tty_def.td_initial.c_lflag); X (void)printf( X"final flags: iflag %6o oflag %6o cflag %6o lflag %6o\n", X Tty_def.td_final.c_iflag, X Tty_def.td_final.c_oflag, X Tty_def.td_final.c_cflag, X Tty_def.td_final.c_lflag); X (void)printf("message: "); X qprint(stdout, (UCHAR *)Tty_def.td_logmsg, X Tty_def.td_msglen); X (void)printf("\nnext label: %s\n", Tty_def.td_nxtlbl); X if (field >= 0) { X *++ptr = 0; X (void)printf( X"Error in the \"%s\" field\n%s<--error detected here\n", X fnames[field], line + 1); X } X X /* Else check if this is the definition wanted. */ X X } else if (field < 0 X && (!label || strcmp(label, Tty_def.td_label) == 0)) { X break; X } X } X (void)fclose(fp); X return (1); X} X X/* This routine is called to set up the terminal for our use. It does all the X signal handling, mode changes, file opening, accounting, etc. that is X needed before we actually use the terminal. */ X Xvoid Xinit_terminal() X{ X register struct utmp *uptr; /* used to scan the utmp file */ X int fd; /* fd for the terminal */ X FILE *fp; /* file pointer for wtmp file */ X X log_fputs("starting\n"); X X /* Ignore keyboard interrupt signals. Sighup and sigterm cause an X exit, however. */ X X (void)signal(SIGINT, SIG_IGN); X (void)signal(SIGQUIT, SIG_IGN); X (void)signal(SIGHUP, exit_on_signal); X (void)signal(SIGTERM, exit_on_signal); X X /* Change the owner and mode of the terminal line. They are to have X the effective user and group id of the program. Also, the terminal X modes are set to 660 to prevent "other" access to the terminal. */ X X if (chdir("/dev") < 0) { X sys_emsg("doing chdir to /dev"); X do_exit(1); X } X if (chown(Tty_line, (int)geteuid(), (int)getegid()) < 0) { X sys_emsg("changing owner of terminal"); X do_exit(1); X } X if (chmod(Tty_line, TTY_MODE) < 0) { X sys_emsg("changing mode of terminal"); X do_exit(1); X } X /* Open up the terminal and make our standard fd's point to the X terminal. From now on, all terminal I/O is done to the opened X terminal. */ X X if ((fd = open(Tty_line, O_RDWR)) < 0) { X sys_emsg("opening the terminal"); X do_exit(1); X } X if (fd != TTY_IN) { X my_dup2(fd, TTY_IN); X } X my_dup2(fd, TTY_OUT); X my_dup2(fd, TTY_ERR); X if (fd != TTY_IN) { X (void)close(fd); X } X /* Look for an entry in /etc/utmp for us. If one is found, modify the X fields in it appropriately, write it back to the file, and append X the modified entry to /etc/wtmp. */ X X while (uptr = getutent()) { X if (uptr->ut_type == INIT_PROCESS X && uptr->ut_pid == Our_pid) { X strncpy(uptr->ut_line, Tty_line, X sizeof(uptr->ut_line)); X strncpy(uptr->ut_user, "LOGIN", X sizeof(uptr->ut_user)); X uptr->ut_type = LOGIN_PROCESS; X uptr->ut_time = time((long *)0); X (void)pututline(uptr); X if (fp = fopen(WTMP_FILE, "a")) { X (void)fwrite(uptr, sizeof(*uptr), 1, fp); X (void)fclose(fp); X } X break; X } X } X endutent(); X X /* Unless the -h option was specified, hang up the line. */ X X if (Hang_up_on_init) { X struct termio termio; X X (void)signal(SIGHUP, SIG_IGN); X tty_ioctl(TCGETA, &termio); X termio.c_cflag &= ~CBAUD; X termio.c_cflag |= B0; X tty_ioctl(TCSETAF, &termio); X (void)signal(SIGHUP, exit_on_signal); X } X /* If requested, set up a timer. This will cause the getty to exit if X a login hasn't occured. */ X X if (!Tmout_after_first) { X start_timeout(); X } X} X X/* Change the modes of the line to correspond to the current initial flags. X Then write the connect message to the terminal. */ X Xvoid Xinit_at_speed() X{ X register char *ptr; /* pointer into connect message buffer */ X register int cc; /* character from the connect message file */ X FILE *fp; /* file pointer for the connect message */ X struct termio termio; /* used to set the terminal modes */ X char buffer[LINE_LEN]; /* buffer for the connect message */ X X /* Log the new speed. */ X X log_fputs("new speed label "); X log_fputs(Tty_def.td_label); X log_fputs("\n"); X X /* Set the terminal modes from the initial flags. */ X X tty_ioctl(TCGETA, &termio); X termio.c_iflag = Tty_def.td_initial.c_iflag; X termio.c_oflag = Tty_def.td_initial.c_oflag; X termio.c_cflag = Tty_def.td_initial.c_cflag; X termio.c_lflag = Tty_def.td_initial.c_lflag; X termio.c_line = Line_discipline; X termio.c_cc[VMIN] = 1; X termio.c_cc[VTIME] = 0; X tty_ioctl(TCSETAF, &termio); X X /* Write the connect message. */ X X tty_write("\r\n", -1); X if (fp = fopen(Issue_file, "r")) { X do { X ptr = buffer; X while (1) { X switch (cc = getc(fp)) { X case EOF: break; X case '\n': X *ptr++ = '\r'; X *ptr++ = '\n'; X break; X default: X *ptr++ = cc; X if (ptr X == buffer + sizeof(buffer) - 1) { X break; X } X continue; X } X break; X } X tty_write(buffer, ptr - buffer); X } while (cc != EOF); X (void)fclose(fp); X } X /* If requested, show the system name. */ X X if (Show_sysname) { X tty_write("\r\nSystem name: ", -1); X tty_write(Sys_name.nodename, strlen(Sys_name.nodename)); X tty_write("\r\n\n", -1); X } X} X X/* Getting the input buffer cleared after a break is nontrivial. This routine X handles the grunge. The basic problem with flushing the input is that we X can't use the ioctl to do it till we know that there isn't anything coming X in from the UART. But we don't know that unless we know how long the break X is. The compromise is this: after a break, read from the terminal until at X least BREAK_DELAY * 10 milliseconds pass without there being anything in X the input queue. This means that, immediately after a break, the program X may not be willing to accept a character. This should not prove to be a X serious problem since the time is very small, in the default 40ms. */ X Xvoid Xflush_input() X{ X UCHAR cbuf; /* character read from the terminal */ X struct termio termio; /* used for setting VTIME */ X X tty_ioctl(TCGETA, &termio); X termio.c_cc[VMIN] = 0; X termio.c_cc[VTIME] = BREAK_DELAY; X tty_ioctl(TCSETA, &termio); X while (1) { X switch (read(TTY_IN, (char *)&cbuf, 1)) { X case 0: break; X case 1: continue; X default: X sys_emsg("flushing the terminal"); X do_exit(1); X } X break; X } X termio.c_cc[VMIN] = 1; X termio.c_cc[VTIME] = 0; X tty_ioctl(TCSETA, &termio); X} X X/* Read a line from the user. This routine only returns if the user requests a X speed change. */ X Xvoid Xread_login_args() X{ X register char *wptr; /* pointer for storing into buffer */ X register int tmp; X register char *rptr; /* pointer for reading buffer */ X UCHAR cbuf; /* character read from the terminal */ X int upper; /* set if input has an upper case letter */ X int lower; /* set if input has a lower case letter */ X int esc; /* set if previous char was a \ */ X struct termio termio; /* used for setting the final modes */ X char *arglist[MAX_ARGS + 2]; /* argument list for login */ X char buffer[LINE_LEN]; /* input line */ X static char ctlbuf[2] = "^"; /* buffer for printing ^@ controls */ X static char backbuf[5] = "\\"; /* buffer for printing \xxx chars */ X X /* This loops till a valid login line is returned. */ X X wptr = buffer; X while (wptr == buffer) { X X /* Print the login prompt. */ X X tty_write(Tty_def.td_logmsg, Tty_def.td_msglen); X X /* Read the login argument line. */ X X upper = 0; X lower = 0; X esc = 0; X while (1) { X /* Read a character. We shouldn't ever get an error, X as all such should have been trapped somewhere. */ X X if (read(TTY_IN, (char *)&cbuf, 1) < 0) { X sys_emsg("reading the terminal"); X do_exit(1); X } X log_qprint("read: ", &cbuf, 1); X tmp = cbuf; X X /* If there is to be a timeout and it hasn't already X been started, start it now. This has the effect of X starting the timeout after the first character X read, if it wasn't started after the open. */ X X start_timeout(); X X /* This means a break from the user. */ X X if (!tmp) { X return; X } X /* Echo the character if it is printable. */ X X if (isprint(tmp)) { X tty_write((char *)&cbuf, 1); X } X /* If the previous character was a backslash, don't X interpret this character. Note, that to make this X work, we resort to a kludge. Since the following X switch uses tmp, we'll set tmp to space. That X forces the switch to put the character into the X buffer. Of course, the default code must then X reinitialize tmp from cbuf. */ X X if (esc) { X tmp = ' '; X esc = 0; X } X /* Process the character. */ X X switch (tmp) { X case '\b': /* backspace */ X if (wptr > buffer) { X --wptr; X tty_write("\b \b", -1); X if (!isprint(*wptr)) { X tty_write("\b \b", -1); X } X } X continue; X case CERASE: /* non-control char backspace */ X if (wptr > buffer) { X --wptr; X } X continue; X case CEOF: /* end of file */ X log_fputs("exiting because of EOF\n"); X exit(1); X case INTR_CHAR: /* control C, for interrupt */ X case KILL_CHAR: /* control U, line kill */ X case CINTR: /* interrupt */ X case CQUIT: /* quit */ X case CKILL: /* line kill */ X wptr = buffer; X break; X case '\n': case '\r': /* end of line characters */ X *wptr = 0; X break; X case '\\': /* escape character */ X esc = 1; X /* no break */ X default: X /* See note just above the switch. */ X X tmp = cbuf; X X /* If the character is not printing, it hasn't X been echoed. Now we'll print out those, but X we'll do it with printing characters. */ X X if (!isprint(tmp)) { X if (tmp < 0x20) { X ctlbuf[1] = tmp | '@'; X tty_write(ctlbuf, 2); X } else { X sprintf(backbuf + 1, "%03o", X tmp); X tty_write(backbuf, 4); X } X } X /* If this is the last position in the buffer X the buffer is full. This could be just the X user typing a lot, but is more likely the X line going bonkers. Anyway, we'll exit so X that the line gets hung up. */ X X if (wptr == buffer + sizeof(buffer) - 1) { X error1("input overflow"); X do_exit(1); X } X if (islower(tmp)) { X lower = 1; X } else if (isupper(tmp)) { X upper = 1; X } X *wptr++ = tmp; X continue; X } X break; X } X tty_write("\r\n", -1); X } X log_qprint("args: ", (UCHAR *)buffer, wptr - buffer); X X /* Since we now have a valid input line, turn off the timer. */ X X (void)alarm(0); X X /* Change the terminal modes to those specified in the final flags. */ X X termio.c_iflag = Tty_def.td_final.c_iflag; X termio.c_oflag = Tty_def.td_final.c_oflag; X termio.c_cflag = Tty_def.td_final.c_cflag; X termio.c_lflag = Tty_def.td_final.c_lflag; X termio.c_line = Line_discipline; X X /* Do one kludge: if a return was the line terminator, arrange that X returns are used for I/O instead of line feeds. */ X X if (tmp == '\r') { X termio.c_iflag |= ICRNL; X termio.c_oflag |= ONLCR; X } X /* Set up the terminal control characters. */ X X for (tmp = NCC; --tmp >= 0; ) { X termio.c_cc[tmp] = 0; X } X termio.c_cc[VINTR] = CINTR; X termio.c_cc[VQUIT] = CQUIT; X termio.c_cc[VERASE] = CERASE; X termio.c_cc[VKILL] = CKILL; X termio.c_cc[VEOF] = CEOF; X X /* Do the next kludge: if the input contained an upper case letter but X did not contain a lower case letter, arrange for case translation X on I/O. While we're at it, translate all upper case letters to X lower case. */ X X if (upper && !lower) { X termio.c_iflag |= IUCLC; X termio.c_oflag |= OLCUC; X termio.c_lflag |= XCASE; X for (wptr = buffer; *wptr; ++wptr) { X if (isupper(*wptr)) { X *wptr = tolower(*wptr); X } X } X } X /* Establish the new terminal modes. */ X X tty_ioctl(TCSETAW, &termio); X X /* Split the input line into arguments. */ X X arglist[0] = LOGIN_ARGV0; X rptr = wptr = buffer; X for (tmp = 0; tmp < MAX_ARGS; ++tmp) { X while (isspace(*rptr)) { X ++rptr; X } X if (!*rptr) { X break; X } X arglist[tmp + 1] = wptr; X while (*rptr) { X if (isspace(*rptr)) { X ++rptr; X break; X } X if (*rptr == '\\') { X rptr = qchar(rptr + 1, &cbuf); X *wptr++ = cbuf; X } else { X *wptr++ = *rptr++; X } X } X *wptr++ = 0; X } X arglist[tmp + 1] = 0; X log_fputs("execing login\n"); X X /* Run the login program. */ X X (void)execv(LOGIN_CMD, arglist); X sys_emsg("execing login program"); X do_exit(1); X} *-*-END-of-getty.c-*-* exit From erlkonig at walt.cc.utexas.edu Wed Jan 17 20:45:20 1990 From: erlkonig at walt.cc.utexas.edu (Christopher North-Keys) Date: 17 Jan 90 09:45:20 GMT Subject: new display module for gnuchess (tested on 1.53) References: <9001031450.AA05558@life.ai.mit.edu> Message-ID: <23282@ut-emx.UUCP> A slightly scary interface to gnuchess 1.53 Problems: There are probably too many display-related subcommands. It has not been tested on a significant range of terminals. There is no provision for a user-defined default state. The program uses just standout() to do reverse video, and terminals doing proper boldface on standout() will not show the coloured squares except in the mode shown below. The new X11R4 xterm is one example, when the termcap is corrected. The program should instead extract the specific termcap entry for reverse video. Good things: I haven't found any significant bugs in some time. Toggles: There are two primary toggles. "brv" toggles use of standout() on the board itself, whereas "prv" toggles use of standout() on the pieces. The command "rv" will toggle both at once. My personal preference is the display achieved by "brv" alone, but the new xterms only work well this way if the boldface font definition is good. Example display after the command: rv 8 ///// ///// ///// /////| =R= /=N=/ =B= /=Q=/ =K= /=B=/ =N= /=R=/| Computer ///// ///// ///// /////| 7//// ///// ///// ///// | /=P=/ =P= /=P=/ =P= /=P=/ =P= /=P=/ =P= | ///// ///// ///// ///// | 6 ///// ///// ///// /////| ///// ///// ///// /////| ///// ///// ///// /////| 5//// ///// ///// ///// | GNUchess display (Nov 89) ///// ///// ///// ///// | ///// ///// ///// ///// | 4 ///// ///// ///// /////| ///// ///// ///// /////| 1: WHITE ///// ///// ///// /////| 3//// ///// ///// ///// | ///// ///// ///// ///// | ///// ///// ///// ///// | 2 ///// ///// ///// /////| Your move is? [P] /[P]/ [P] /[P]/ [P] /[P]/ [P] /[P]/| ///// ///// ///// /////| 1//// ///// ///// ///// | /[R]/ [N] /[B]/ [Q] /[K]/ [B] /[N]/ [R] | Human 5: 0 rv ////a b////c d////e f////g h| There is also a toggle to show positional data, with updating. Although accidently undocumented, the command "p" produces the following: 8 0 / 9/ 20 / 0/ -10 / 30/ / 2/| =R= /=N=/ =B= /=Q=/ =K= /=B=/ /=R=/| Computer 4:59 ///// ///// ///// /////| 7 9/ 9 / 4/ 0 ///// 4 / 9/ 9 | /=P=/ =P= /=P=/ =P= ///// =P= /=P=/ =P= | ///// ///// ///// ///// | 6 ///// ///// / 32/ /////| ///// ///// /=N=/ /////| ///// ///// ///// /////| 5//// ///// / 6/ ///// | ///// ///// /=P=/ ///// | ///// ///// ///// ///// | 4 ///// ///// 2 ///// /////| ///// ///// [P] ///// /////| 3: WHITE ///// ///// ///// /////| 3//// / 32/ ///// ///// | ///// /[N]/ ///// ///// | My move is: g8f6 ///// ///// ///// ///// | 2 9 / 9/ 4 / 0/ / 4/ 9 / 9/| Your move is? p [P] /[P]/ [P] /[P]/ ] /[P]/ [P] /[P]/ ///// ///// ///// /////| 1 2/ / 20/ 12 /-10/ 30 / 10/ 0 | /[R]/ /[B]/ [Q] /[K]/ [B] /[N]/ [R] | Human 2:48 ////a b////c d////e f////g h| It is the desire for dynamic positional heuristic display that led to the contained code. My hopes that someone finds the bloody thing useful. ------------------------------------/\---------------------------------------- Seo: Harp[@Mcc.Com] / \/\ ^*^ Christopher North-Keys Tha mi gu trang a'cluich. / \ \ Assoc. Systems Analyst, MCC --------------------------------(disclaimer)---------------------------------- Make the following changes to the Makefile: ---------------- all : gnuchess gnuchessn gnuchessr gnuchessn: gnuchess.o nuxdsp.o $(NEW) $(CC) $(CFLAGS) -o gnuchessn gnuchess.o nuxdsp.o $(NEW) -lcurses -ltermlib ---------------- nuxdisply.tar.Z.uu: (uudecode, uncompress, tar xf ...) ------------------------------cut here----------------------- begin 644 nuxdsp.tar.Z M'YV0;NK@(3,'CHLQ !(J7,BPH<.'$"-*G$@1 (B+-VK4 &$11(R,,#A>'!FR MXT at 0-F3,@&'C(HT:,FC8F"$C1HT;(VO,C&&QHL^?0(,*'4JTJ-&C2),J7<IT MX at L5"BX&80(%21 0:=S0*2/'3)@Q94"8>2,'Q! D1:9,B0J"K90R=M+,2?/& MC0X0-%K(J-$"!PZV;(>\@9-'3IHS:.B 0#$DA<<<.&RP>(SCQN08D'& ,"*G M3- at I;\S0N1.F\^8W==R0"4.'KIO)2=R,<1%X<.'#B1>/<8S9[T4E;]"X 3&% M3A at W8KZN 7RQR1LR:<RD*4,&1!D\6]W,M5.&31X03M[8H9S#+!K#<^@,1L,5 M/%DZ:%HL*9-G#EN7,/#$!#'Z38LQ;["!6EG0%<1&&'DHD,!@K=4E%ED at S(%& M&-"Y<08(8APXQAH1QE%':678E\!U<!Q'!G4 at G!%&&V'-$09WD[$A%QV3F0A" M9^F1%9899;!6!XX at U#&7A2"0@,03312A((.N\?<&" 6&D6%8!<)QX'>A at 0 @ M616R%N*2<#3H1AAL@!!&'>JU4 <<J[5&9)9PO#&7F&1BY<98<K3!FFM at TEEF M>J49]J89&&K(X5PG*JCG'',X><89;.P(86?<R3%'&2W$=>*39J0VAICVL44% M&G*)E4:D6#5:HAR*97E66E/0=E%@:*F5*I0S&B8&FBAFQ1][(* Q6%CPL8:5 M8G><6J8880E91J=LL,#6KHI=D0051U9!!0A!.)$%"%<$(844W5*1A0L7A6<F MFL*6!6&!=.B*)EEL?056F(WB&*=V:8AQ:AIT?*>>F6[D49>D9<$7%H#:E>%A M&;*%"$*60F9U(<!L08 at G"'>PIW!9 $?(%7>-'O?=JJV-4<>!9<'Q8YR73ES6 M'62M4;)B9$;+5FJ1,AILBP at V.L>3OMYAF)MGH O"6SPF_*3"9M4Z!0A'0,Q5 MG5#4D6$:8[#%!-<0Q[PQM&6>:-RI<\C:UD5%5&JP&V&5>H8<QVU5'1Q<M2'7 M7 X.#"!AD[7Q7'3?V=@9O/)N12NLDU$[L1O>!:E:>U S#!VH4(8XAJZ]#J?P MXK96#3?=96:]]1@@? U6PTISJZ5M$Q,*7ZDRKAZS7&S-L2;,* X\(7<8>C;< M&6EPY_F3!M=AIH!$)@M?U+!&B#QJ;(UQ' AKN/'&'2 D7Y9AB-%1LFHWAKCO M7/[*V%J(2B>AF(2HL5$=LW::R99TJ([)8G5#/ %%%DEPPA&4%@3!O>ECO[+8 M'"93.=N +S?:2UD9ZD6^V34J at F #01N$I!CZP0%'(T.1 at W+V.CA,)VUL4<$+ M%,#"$61E#&RHPXE P(/T0.<-+D"##Q3 at 0MG$<(8\^%0>\);#'?80AC(,2PWK M\X)5K:B(/'SA#Y4X!R:VAD5ITV$4?9A$&E9Q#B_ 7QF@>,0I>I&)3FP#&:78 MQ2#^Z%)9-"(;@3B7,XR)#6OD(AWCI< \(G&&(K!C'<; 'D;E4 11-,.)".6$ M(ERA"4^P at I+*V$41"(X[A^0AQ*!C!A9>9RMR& XA2P,"%9RA#-FQ PI2L ,6 M/N5U7,J*EQKE/%(-)PP=^I!I-@:UL;!!0,DB$H at 6LX48L* &76!!,5DP at RXX M1H4\7&16/A.%*RRF!BF(YK.F29PH(&$Q,\CF"*0)-Q!0(0A"6,Q+Q$G.L%@A M"5+XPA!0, ?'+*9\E8K9#T!P at _\$J YM<,,6Z)F"+H#@+@"*84 '6D^#LG.; MY7QG/*5 T(N@ )]<T2<_6R"'[3&TH >]D4<)ZE!M2B>B4XC"%[" CS8\Z*4 MRFA8]IE2:Z[ (R!HP6)<&M*6.N:A)W5G2K^0!13DX:48M=1,N_G-F\8 at IXLY M:D^E"E1N6B%#RJGH14.P&!1(5)X5O>E7*5I/QY0 !#+XJ0)>.04/@4AHI($# MWJH#S7%"U)U;D@,9Z,D"/+! JEQ0$ I04-,4J,"K\ 1K65.P I^R8+ I18)A M4=#/L1*4L49-03;9ZE8 at V2@KH+PC" 1D/<S-(:YS+>4*[1I4$%@AKV1( E_] M"EC!$K::D_WJ/!?;6"L,E:4N3<%C;RO9PU8VL635;&^'6M2C:G:M*B!.9R7V M6:UP1;0=O0-<PR!7%-6UG:Z%+5G[^E?'!#8!D,7M875[6<RZ=+B1G>QQ)WK9 MY:JTN9K-I at +2(X=!*H8.;6 at 4@'=E!F,.N YFD$$K06O.O,ER*U/HD1P(N4H6 M$&$ZJVPE_%@% BC("6"N,<*!+M0#$,! P^UZWX1F"((2GWB_*8:E7AM5XAB@ M^#T1,HZE+N+B&W-8#N,Y28U;:5)NSL%Z;M"#6,P00PG1DPYD0 T=A'ODX]RA MR.7\(&B5K&6M7%E!"H at -B,F4!CV4894*V(."ZGA'PB;A" &D at H6GP\H(':;- M4WAS%*IPK3F7 at 94*R at K CBR'#"MH<X([D:'[P$(%% $/ !M"(>> 9C4G0'N( M?LZ9 3TBU033T"."-!U0 - ,YJ%%]YTF@\]H;+,80LX@$$76ID -I/)S7!V M at ISS?(0OO-D)G+8U&W"]YS[SVM=' #:MIR"L.S0A1"XZ)0I$$ 0QO&>?(@@V MDO4P[1+,000LJ">MH[,8_HZA#7#@JPCR$*)LM]C%CGETI"<-:F'C.LY^KK.] M>5UL.:?:U(VF at H/'!&$)4SB;EM[WF_%][%\'^\ZWYC>?=_UF9"M;05<L at Y1; MS)_^EH'6UH8/HB168J^PX5*T5GBN_4WG'=C9CA'7\\3SW<I3A]D-+J.#8-J@ M)]6@&;IL at 4)'P>(SJ#EKQP#BN8G0E01"]:B*&M3TK9Y@!",LIH'HYA7(&L66 MV;EA#19[W,3D>C"M"#@-+'*,C:#VP3?,;46WVGB6K/V&-3"0/</1TQK"TG5@ MG<"6=#A!U('7-V!9NS35L9'U?DF<[I3A4\[ASBJ=9"KRX5)?=;D4ND0%K*/S M9^"S_%6+#(X&#'T'8J ,NQ>&L!@/A6PN<;BC8YB%)[Y?!/5<"3LND]YS,C!= M=L :S+Y0#Z4W2"R"&@S#WD4?+ 9?L at QWA]C:1*:8*9PH3*4?F)D[NOF+0'/5 MM8YQW5F0!A8 & ZT9MZ%QJ 5%M!M*^8WL((5E!HVHVC#BFF#'6@]2E?#6M:T MMB0<4F*NIQ at E1R8HIR!6 at B#M46+"5W9TL&S-- at 5I8#9O\'R@)AH<]V()0&XH M '@@X ,F!@(F8 (@$ )/]QTE" )"\ 9U]V[@405,P 39=!*6E@!FP&1"@@9/ M%F5HPFD)D'$A46(9-UCJ5THI4&JTE@!D<@9B4&B YP,^@ ,L ((FF!]5QP(F M=RE :&Z$P5?ZQU\Q (3GQW%E =S,%U+Z(%6D'MFD >1=V8+9$PFH'_/=1(V MJ" )D !"=X%A8 at 1D$8>@MH<1%BF0)QYGEG0YQQ4LD%9+F !M:!AO*(AA&"_& M) ,L4(=V (0=2"B$=7W/(X*E1AR@&!\MT$IX.!*,MH<:2(1H=V8H<(0JD(2. MH5-"N(1GF(:Z%!9$B&ZHJ(I at 5FL0-VR\AF__YG(JUV\TIR =<RIA at 0(A@ (O MR =\ (%>(<C<8-]B&YT (AR((A=N&W=]FWA!H0+R&YEX8!D!S=:L80O6&*1 M2#B"N$ PD(EVN(:>^((KJ'\G6&* 5X.I" (WF #6=X;/TV-ZB(,&:&*_F(J, M%I!ML8<>J (T5F(GP 4P< *.405LXB479B (0FHL4(_&I(0L))&>:&[HIFYB M0 ;NU@/P=A]X.)!#P 9R, 6;(SR#F <V29E\)'G*)(D.9* !I&KV(GE%B_G MEFX+) (%^)+P9HUU$#)$Z''XF)03MI)-"3-T )4FYAA<R7$AP)57^619R90L M( +4 3!>.8I%<#DMB'B#Z($JB9:!] 9MZ1COV'%U\'%Z2)=*J95IR1YL =Y M^3.%.9<I&9AVB2=@<9B.R8LG&)EE69<LZ8)K<)@MN)=.((-,4)F,J6ZI$65M M28(F> 0K4 at 9#H!4A&)55H!IOH)A8N93J!C=W<)A.4 9W@)HL(IMF29M-*2/I M<9A?DQZ\N6F@>9;J%BG<P0:'68B/1P=, !?=X9N6V903(B&'F9UHP&1A0&(G MR)W>>0;)"9QIR2QG>)CH"0=BN9[E*9C4%DQ1=IN. 9-?:1['<4I!4)@3<@59 M,9_6&9I-*03RN3V'*6GY609"@$IAX)^P>0<!JIS8"5J'>03%4P9( %H1:IXB M$')HD)<RF8=[F >.G(T=H(E6H$A\H@%B7T;R**.=XB2]X#L2"-C^(A[&2]] MV9!X>)2 *:%I&5-*!:(0.9!"&C,E%@)'ZI<C6I,WF9,0LY,]Z9%R$93U.)0F M:91_N9A *@(20B%E0*0!.9!?.D-)6J9,NH=.BI.=$:6<.*5; 917(I0L4))% M&9 ^RJ4<>EH 0TABFHH#J8A:QW%O\#$CMP6""DJSEI T2GP.:*@JN at 6-JA6+ M.J*1R7%;F*8$68HORJ@#R)=^J:4H.9OPV8Q;<9C3!Z@)F:@-R#&DLA4N-ZD+ MB54;@J.?JJ,?]R 3)IF9RJ*<BI"BBI2_"9^TFIGU&9-%NJI^.*@E5JRQNHZ. MZJH HZDY:I6Z"A:8BH":VJ('R9 A"HRC.JQVV1G/5YHK>)RKJ1@^4&..\:T7 M,9"O&649!@+Q&IMWZI!;2JIV>4I=>:SW635T<)P;"I\NPAW/^2)E(+! ^*,< M6HH'.B$64 at 815AJ$1 0&R8,+JZ?P23>PV0:'>3GLD8XH\9YVF8*'F8)BF8(D MJVX,LQ7<^)RH)!C6Q8T#:Y=X< >>]K )B at 4%"J$9JZ\LZX(S!J)[&*A"2Q!B M"5MS\(AP^I-5.J=76J=$N81Y"K1-"2B60K0)0*8Z=J(A at +5+FY!-*Z<A&;5V M2K7Y*J[JMA7#Z:^EYJX"F9!T\%2NV)LF.:+LMY <R(H0@@)I\*)804,> 0.$ M>V)8L0(K ) 0^:X)F0!Q6)RC)JN-R(D)D+<@L (E1 at 5R 5:L07-!%6:R[ET ML 4RL*B+"ZY[2 <RP'%%>+=[^'Z2:;DO<'4RT )SRXEG4*AO@ 5%=4Y"T(@T MP(E=1@?<)@)Y6V(E(#\7 ;O(*S_ at EK?NYR6<Z*1%$"!N8&C!RK#P:9ANFTU% MFY#1 at 0(>-B<A-F)B.;X at 5A<B]IUOVI%Q^K1E.Y)2Z[I5J[9->2*[<@:'201O M8+'Y6[/J!F1::Z1!QF,G"&2/B*9BB< )";8+O']BZ[Y."Y)Y0*=GJX</"8PG MH2 U*6'/QBC?B9P*4 at 0'@H;4006OB (W&FB>&)F*&[=[R*HB*ZO/.GRL^:@A M>Z at R;+K at B@)V\ 85Z!@91VDF<& %]G P1XP+IVLL('!Y\F 22WKZ-HS$-G-. MK#<$%\44BP8 QT)O"3!QJ5<_]TIL$6&*L29F at B%O@'@@ #/IZP;H @73071F M8AJX=SBFQQ]#%'9L-\>V]R"_M#TH(@8" RRDM2=U at 2[>:!UXL")6 GW at 808S MP#'*TL8:$A:XE#VXT2K#D3O3)18ST'VJQ4()%V-AX'XL, ;A%@?\UVH1\G^5 MRL$VR:8ZR6EC"[\5;+93JR"YJQZ\BP*^.[DN-[S%VSKR]E]/HB=9D6VTULN[ MV[OHQ$QU1LS3-@(CT<&D='AZQ<R\K+N_',S!.\R"0KS3ACH7@: 1:V<G\FV< MYLR__!(L@ /3/,[%6P36U3)^3(*C]0:EY1IWP<U,R'&FRJ11IB WR&S;\\'1 M=F:X9)\##0+8]L5(<Q?2>JHA)0(2;3$47:P G0#N7%0W, /'5&?4:[WS6F5) M-H[@)FYI^VJR!H,G, (:J8<#N3'T% > FX:":P,T@(QQ at +C>^[TC2J)KK%=; MD(8&56+:\P4F]'BYFE!D<=1QD-0@ #=H0CJ/>)0\*<%DF\OR>\%[6+\NG=06 M.0:"1XVO_-+V>0)#H)%IC,,9%:EA4*F5RW&O%@-=T (G$ 8GX'(B^VJEJ]<Q MT-=IBP*HLZ[WN8*&+;CR;)J+41:(/8J*718\ +R'-1DBM,E1EH")0==@*AT M7;D!$M5(S7%A\(ATN05J;9%PX-;:3 923=4E at K./V!VWDY*J3=8@< )NX-I% M#=NE76*:'#ZU?7)Q@]NKO=MBX-N(%]L<YR_P at WX):=O'76ZY#=-RP-Q&'=PB M57?%?=O6G=PG$ ?:#=Q3S7$/ S'?7=WT=-UKO0;E[=S";3'K+9!JW-S<O=1- M#18N!]5R(-]57097328NI]5$0#=W(,=.?=- N(I](*VHTMXO'0(6Z0(:263" M^MI;0 ,&1>'88S&. 786\GRP/=!4'0,<Z($:;@,3/M\6$N(60^);4*PGSH'H M>L,Y96-4DYHU,(0,28H7VZD)(&:M069F5ARL06F<MJ90>KVVS-6X;,&[;'.$ MF6X()\M/VJ9.WLS>7%0R0(4WVL;T/&VO8BN\9R.ZHW1RD < _=$J+,WBO&73 M=@8Q(,FI^'QBT5%MD")/-3"2W.9=_N;A+.9R+@)W,LEWCHC8XP:;3'E_WLZ! M;DS8%.=:4;S^\22I:#WI at 2HB?B$C!^B^7%3&9 /S7.B7W@*8/A*:3@>HDM[# M\>F0'NIO?@.E7NG3MI:*@8>X?M_;'.O/_.;R3.GD[*7.0T at G8:*4_#PR#.J_ M;DPY4.O#_M G(<.6'#05'::^_LO&A.+07KS%BH?4?HZ-PM'9+NIU&N;4+ )+ M.A*OC2L4S.S:7J>.2.BVWJ&%6GK at OJR@E'QTX*?E_N8Q$$["7KP<&V5[/A(% M?X%E%A;G"._F'@.#GNZCF>HC,?&C%0;I,7C8SN6RONV33N_#KL GH1Z/@BH* M3.X<W^QU2NH#/VU !I$D#REAL>Z:HG$.CP(T@(D"#_+%RYS= >X0>TJC19W. M^>\YSP(1/^8BP*G'CDHBL\69 at WTW?_0?G^YAB8==- at 9I\,@@8 >ED0:([ 93 MCXDLS_/3!H)XJ#N/$B(XH_%CSP*TWO(=6AT!>3@(SNLN:?28&.QF;[Q'VR at C M$?.HHK1O_^QR[\ C[W8RGV.EP<XI_\Z8R.UR?ZDG<<<IDIH:[_C=+.M''P/H MKO3"F>LGH2(L0GF$!&TN<'+]^OA%U?GSGNX%&Q9X2/K$PBG.^/8!W^US[O2I M2/MY?H&F$BFXG_2%;IL!B;6*8?RTC_M5K_0%F(K7$3)E/@4WC^*-^/F%OG.+ M* ?_S&D>2.T._:I_UO=7@ 374 at 3,;!W&W?="P 1!, 1+4/WU* .OK_1/ *U: MT?WCEH_X;X E-M!@2>F5O_.7_J@;^W-_\$_^-:*=E^ZF4W.Z"\G+);$ !]@= MTI+(F T*,";H/HR&\;Y#HBD#^H^%+884% +W1-P @5P_:4[JF,$IM[\PW[U MSF)A'P at H 9M &, #$VO"H $9"!^,WORK?X5."IB("Z3_(I(' EE<H036NQ.8 M F/&"JPZ+G !;D#-=1P*PH<1$_Q!2D2*$"BLQ-.(48+#C at G6&0/X!%L at I^D, M9@!'8"Q:TXPB'+_J/Y/'P\F N(?E:)F;HC6WC()).9-D<Q#:'>"!/(B09)/^ MHR700"NQ-&X.G&U 0(B\R$ )0!W at AENA@53&Q5Q.26,#6TX!],%F\Q9T!QL0 M'_0$0'0&%B &-MTTH839!/]$"%'HE^K/G;D_,:84LKIIL at 46%2$D)(=PS<08 M,L "H(^5R /[;S&$I15TCAI0B9%A+^P&2:;")"<BD!Y*A-&L^14ZG*0C&N%* M8X4DS295+TPXB*I#B<$!+@<:_BXRD WEP#;,A'RK+*" 7\AQ=)PLE!%P8PO\ M0H,BBH:9=P!J<&L at -:$GA +>(2V<AR%(!%$A?Q@/ >(5P at -9*%-Q(@_$#NW3 M1D!K#;'$E >(&#GL4\ # 13Q.UA$6@>W1-2($H<L '&10TNH#4W:O5I<6BW= ME8 :T"C 3262 RLL6%U"=)@ F&'&*S%D8 FUP6<D$FE(B?DS^3 A@<21:!9* M(C<\B2<A at UT$1M,'20^28Q7% <&8 7JBHE)AC!DYN3#\X)@TD'*H6#%B8E<, MBN5 08B,O*+,Z3-A,8N-Q4HH M?AE3"&KR/K@)*@9M/^5HFI 2[G;U4VB)<7 M\:%0VT,@,0V4PW,XB)ABHWD":"+G@"/PXX$Z2J%J 3Y@/#4*$W2&%L4:V$A0 M3 at _JLKME /- at 4'*,= RF@'WXX)"HP^@$?4(-(K&$3,9M<2FLXS_+IA]A W8 M!#R at HI,+$) <O<05EN$\ QP 2V@"#M+!!# 30<WF^W7!3 ,&0Q2@&B,C:]1G M9 #!@<'B=>#" ,ZZ?"PB! T ]@82R-D/#(Z @:U@!Q 'I]=WT," .5ZZ FV MI1TY#7?T1,T1/)H&^U0>&UNZTWZ#:CV&B/9(:][C8_../D ^*I&<D@,*UW2< M-NBQYU RQC,T'(1^Y(\*PC\R1P I($,0""B0A,N>W$=]UQZ2!8-T07G'2T!( MXF at 4T6%;Y$K)\!D&NN0(!.M=>%AG)>8BE ;X+Q8P(M435IA,)K$)0025<(& MO)%@),*, >1% VHD7(!=.O(H\BC#Z,5*V*4@ RBL-]&%W^A*H at M;L%B@!(L1 M"V"1<7Z%L<A.;0SC/4D[$S&8SZ6 >J1!:. at 8N_%[I at _4Z [<94QVR>L %JB# M at .&2I8%?+89.>#[*0)0L RO at T<2+,/ GA1C>H3YN\A5MG(&!JZ25L?.092)+ M0C$S27I$V?=1A5,R*SJ]N at 6+9!$M at BJWJ"TZO<HVBC:EMTH 18 *:(]U=KGN M8HKS1$Y/!*&2D(#6IB0,&D,RZ09YH%BY-,Q'YO&3KRA08@>Z\2<=FR2TD&.( M/RA*-,&ZK)(>FI5FR!F&*UMI$5^81PQ"K\C'%:%85!<NQ"Q20M:!#OBX%Q.L M?!@0(X?*$HN@@"+6!@B,(])#8R#GO"*1A>)@P&$Q8C+ !0"8.? %T,0K I7M M$L'$ 'T98/IEQG$,LPL):(&R%"_])8N ;/?I2'H)CJ/"")<*N)'I*@6\ ,,F M+Q_F"JB7*D T "$#*#&W at I!#E:I2TYPHC,F:;DJ/6T)-JR;Q,YN!O8"1S8F9 MI(5F7CFMR&':0+BA-7ON)]*!%\#BD!'%='HZA<6I@#;@_3P1%1@"XRE%[J&@ MN1C^I,R*%P'B(.1,>?@6/1M4024($R7LK1-E->L"UL0C,&1F<DT&Y#5U"M(4 MFTMS2;;%/4<J'0/5?)7E1G"-HA.%-]TBVX1! #!M+2G'X.98G#!3?S&C<,X_ M at 1<AC9O at I$Y*A7 &.L/I(UV. 52<PDP!*;T20 9T0 F0 70/!+C$<K0<462N M5)&R[@;\P!^I,F,D")B1-9)E3AD>&>A4IQ24>T#R!0A)(FDD[0"2E)L) VJ MP473:!2 &2N;6J&C#)N=Z8&>9M0\G7L(>9Y-%_!\7HV)XSC24WE23T3T:F@< M]AP"U7,)9<^LF38WQ!:XGIGK%5U-[5D^U\",,Q1436ERRQ?W-+$8KPA;2;%Q M7 at KHF0#&)QZIGN=3_%$U_[D]2<;[5 Y4;6\1T/890*?5 %6?9I-];DWOB9#V M$ 4L$R5&?JJ?%% _L\+]!)ZFD at .1L#AYPE+8"K,Y;HZV6$4<0UNR(@;* RW MF."!&-K%% "3TW*5YM!$BM(PKX1GB%B#FK#1%,>="4-8A?$)$#WT60S/+E8= M$YP?8W P!L>DH:Q("/$ AG-SK^5HD94XT(@F%Z!9,\4N$(ZV_X;4O)>EN0B: M+BP4*QVPI9CC)F)\L E-#")JEI0:'T03G2K@$:H $7#17B<D%"YM# _@@1GW MVV*;0UE"@&)R^!P@](1ZQ!J at -6@4XX4%JS8HV0 ;14GT9,6,OX1$S:Z*H6!P M=U0$O(!1RD?_V4C at HZQD1#W+]3>0PI<GS2II2+/ 41\T:H27TCNEG"B1GHA% MBK;V4"-5/I!42TC2:W=)$T"Z\Z.B<S+ 4%*2/';5#ND>NB7/E(%<1$6R9GX MA,74#RJT$#9MFJB" PL4S;\Y-ZX@!SJ:-*4U3+*)MI5=!$55X11EC%,133F& M&X1%8<M-DUIC2/>]T at T!2K'-*/VGI51TXJ&.5D^/UCV]1)JEY>W3-=!/1><_ M):5]]"00U$"71;G$095F^K18-511^E #*A^5J)SFP1E 73D5%RJ#<PRZ5,H, MHH)J4=,0/DVH?6^@ B&6*L9<*D+=@#*5=LJZBEI3N:@Q"2<X%:0B4N. at 2/=* M2 VB"J")"@8NH>3 CRK4 Q at .3Z /= ##)<>X $]X :X'#W@%V^0.V5E)ZG6 M:#;+5DI %1%G;^.I\:6BYI/RY)7T:BQ%"-6(WGJV( ,2B6JM'2.;DX)^-@@ MIT;1##I%R=R%IW)3]$!"U4.Z=). FE.#@\C"5*VJ6Q6K:E6S"M1 P"L)%U+ M"020(T#11D6IZ"C^LIR4BB P!89 $D@"+>#Z;!+B TVV%F*]BF!U#R'6L7I6 M 2-%A2VRQ:76%!807W[68#&I<16MT=459%=GJ4I-I0E #ZG$,0!N^FH^62I_ M1_ $UI"RUP1/83VL>RBQ\E(%L8H4A%2EJCKNJO8 %( #5$!\V:I=%:W^,O)J M7G'+QV0!AG4)I3L^ -"88G)5 )YQ3HU&&C&>R$^5V71 417N5RTT8OSKJHL4 M61%3L@ VX'+:XO/TB%(U#4!6K, #>%I?3%PT+2&IT^GBMSB1-WVB at K&7)E=, MJK0<@U+]>X-(O4*SWR7YE*O22S95X/3YC"IQ)19#>!@/..#9=305"\RB&7/T MJTM%)804M()=A17X:U:&XD"* /P(2IH at PU-Z"?)Z7(2)*NN"V8]]KG<4K804 M'^E;C^RU4[),EBLXV?.8'H?#E#V)JXBZ\<\/N^#,0)UALV !!<S.M"47#BQ0 M'%$>2%V)A:"VM4 G#TS9F %[+P_*V=I:(&;;HYS1.T!/XO at OBF@;0&#CM#2 M at 8]99Y0B"%A%X0M]B8GU=08<@Q\<7W3 #5@!,M&7E!RM\:%.IHM]VF8H:DFM M'(H#*Y3#O%-+\THV2,;['0LC9Z"(1[,BIHFF=0V31SI8"L706H_C+U.K6[2+ MME46]E8_:5Q=05]+D][5(2A'.<T8H%NO0T"0T:G6WU877+,4D>K:5BHH, 2P M+12PCFX at 72$JO.9RR*VW[3#H5MV.@=)%:UC#&L"VK$'YK-M98R;HP!IXM_G6 M?<[;2A6^Q&EI\W"4E'0$-94X R1 at 6QFU,>35L@!9A5W5[!ZB9 at IL!0%76!M* M 6I$%9W!!J\J5E7;;$!MJXVX3;64;44,QVNUY*^M"QFH;]G%'Z<744)/.UR) MBSB47%8+<?M2AUTVK/#E7B_)90)"K+%=L<"+TZ0[:M at 9K"'Y29*9\-0 K/L' M,13(&(,*%^$M4(CZ 36H+J,C$IN)0X at 1@G$W&M^6Q&1LX)0\H3# -:I:H0I[ MNBJ-L04\!UJ>Q/5PA7:D<VR%4U(6\,1ZM!/0H9\1B5ZBY\@NY?%DNPA=#('. M,#%Q"3S<.]4A],6.L5-UB00\E!APXDI,AEHR?5#/FH.,< ,[M#$@IA7XV-, M%J%7,5Q>P^MY8:@/P'-Q K287KF+1M% :N 068)%"(XU]SJT MO]NA<":E1/ M=.$<3(/7#3N7MU%0#/8T,/9"2V +$X(-$(KJF7R^ _V@$">B. at P,02)CTP;= M60.6<H6 'R.0!)A $2 at EBF3<L"955G[40+A142E'1WT*%H29[%F\^ XJH/72 M&KP+-ZJ#*M0_+&!IP@'S at VZ*">&*9<(*!2 at 23#4LKE<@"0C=UP5\7W"C[K*- M8_!PG6D&2<T$$'8Y3@;^3'\IIZDH at 2;^="*IB'"+K<2LBDNA@'FA)GJ_)T*6 M1C8^^_UN)9\=2$&H ".N-$#5],\C$D9F:F) JA-QU%14:--J$A)UV*>0L(+^ MEBBZP8VK]5),_N)?Z&_=L;^\=Q;IB4 V!JBBF0D-9JD*AUTL[%Q^,+JAF/P7 M%N(8+9PS^-E at 20.4EB(M/#"<AOUOBBFR>ZCU0D9^5&)\411.GJXW]7*<L/N# M._!/!,0-=JC9-#70#ET.(\:J6,$15];#@FXJ:R^" UM #82V!"" 3Z9$$L%! M>*!E-3UD!M(F"U8D:!:I*@ &LX(!+2\$P",GFY!?\XM^<Z("J,,1(L8L30CF M3N$O8UR_Y,?]&!,Y@(FN;2J;/Y7+E=VU \P&3_ S2L$I I5T853LKP3/A0LT M.<V]:8EF[(QT0S_:;>!X!:$.#W>1>IMC&\<EI at A0'92Z!78P55/"T;C?M>!@ MTXY7 _F.!<I(RU')9R.UW'YH ,_XGH9VK8XUF!:"#AKU:CFAA/^N1.],3GF M N98'']C=6P$' ,\?H/S> EU!H <2DA-*A96KX;#P;0W,-/"U<B!0<7JF?!A M$X,'9L 0F %!P'*NOUV\@? #* !, 92\B"O-9(<E"C2R/8/J7D4K*2\X-+ MG@%%0";'#)KL8FPR3K8!_=%Q>L1K:]>NFTZIKGX-V]XU at W*5!]L2FK=5N71! M%:Q\(][MJ_E<79FP[2&FO!@XVQ: B9]-W/( 'M#8;HI;)L9QF=[*I%6TD0.R M"JNA $MAC=_R>WY#IBU.QJ3$#.B/,K %FD 0P )0( A@"_/K!)()?UC,C?DQ M1^;)7 0J<RLC)2K at _*A?Q3 &4 at YLW;_\(N_:81S3!@)0)Y*SZ*8'\"N(H4I$ MP)%($A88L2JE+Z284Q,#03?N,='B(,PL:WI /E;+YH8U*.#%/!E$*3=3$-H4 MVG!3$6 $NO%BYH(HK7AYF^8::E/3%WW-W9E%Y+:@EIQ'36]F$0QD,0?G_9E= ME9)R/L^03 0<A$D#T(XNP*LS?6\[3P;X_)T]4 MFP'CC>L'G(&6!8= '-J-Z M*#J#,&E#G:5QZ?$*SBCO:614$I#1*0BXKS@(I4U%19*62@ :<(0?VD-+0!,@ MPS(1T3U./8[3F $-W8([=(A^T2!: NJAD4"B,1ZK*W$"-!,=6-A&XZ3%'J+1 MG4[&F;A,%*01$8^&GRJ:17-H$2"B132X,0'.L\": *K[?LA"H:0U*QK);&A> MR*3E1P1LTA\:W,SHBP"E(6CR))];<TB7:1:Q/M&TVNS18YH$$5 JJ;G-/<\ MH!O"F6#IOJ73>DR'V&DW-PVE5U:DI+FTD[9'C+20<C<4L.>DD&6K,P;WO)48 M1JW/L%!%9IAC5+Y%I4A-U1(N at 4.<8:$%^!-M&]O0J8*X<0LIAO8W?/P#U')# M7FP>CB(CZ#V$N%#U5\94A=I%Q^@F[:5A]*$V <<)<FT!5-T%7, 9>#X^>D31 MZ& ](X9U:DI7Q5I 9B)FG1Z<-9NF5"Z@%"7K'TVFJ?7H(M8N8%6&B&F=FH0U MN,XXVSH!+.MRW:S!]7Z#/L":75=K<.W??*NWMM8XD at X4:_\&@T;1O:;78Y3C M>&H&NTICAJC^U\\:6_LW4YT 4+6H7HX+-$T+4 LYBJ+T=VJ6.^K0<$@Y\+#' MC at T+C:<H&)5B 7&*1^))(G)@3T8<.>, "CG-L:R@"GJA31LCX*"+#]Q0&D(' MVM"0MT '? ! R\XJC0#_1CR8&:W45]MEJG@*("S!;&EF<6%.OZPF,6-FQPR9 M)3,2H,R6.3PS9JJ]F:]V9ZY4A# T^Z*(]%6#<6D.-*S)BNHA9GM^9#,JH<T( M$DF at O^?2GB<,;V;._ $X1V7V/)Q34VXSSA@).;MG\XRWG?-WCMG3N3KGC]2$ MG<41DR9'E]D[8[CPI;7'LVZ>,.\9;VOM]3Q!ZG9I6<Z^673.9VCSG#U:I*M3 M^%DE0F[^[)K#UP>&0?^YY#1 at T(V>10!]HML'K=EL4P8='MX'PI+0>J at OAQ*& M[5V'UY;NT-6!<[Y.,@"1G]?&?J^RZKVBZ+ME!HQWBV;2R3M[+^_FO:UW= /= M"LG$>_?H(LT=<+0#90'DFSK at Z36@IXOW.#O>V'M[B[TF!C4++)5F#5;Z%:EH MZ[VD(^#K5%[*FW-R[X04L=7FD"[@YA-.CR@[;4 /N)F>G@"4QJEH/CU6#9=. MJVP6MD/@0X_X_3)U<%-J JZ26F3 90#A,:?^F$NH>K_OZRW Y[?S50$:KK3= ME-T /.LBX-*+)<96X]P-[('N-0\^" ';/@WL$5Y!1\3Z@\<^?%\';*>2POFW MH=;> 1R 0W'F/;\;5Q(WULCZBDOK*ZZMK;B\'ET_7%POD"N.KKTXBQ#6/_Q= MI[*//++EA"MVV;I;.C-HI0T\HLS-O@@YVV?P )[ML[7-<=#.Y.C\/#F?U-7V M8 V%7$Q;03CM6OR9RT+(G-J:V6IC;=.\%;60^<%P7JB"#>AX#+=ML]RVP#M@ MQ)9GV at U]1.GH-B2JKW2'KP4LNP,T*4]+MSM!Q_$%?69$P!4X&F''#[R 4YXV M4CGG-FBR/*')\5H^!(X#\C$:TPH$Z')>GOK:UH3FR&Z >.,@)YZ6FO?^7N%+ M^OBQPFH:Y-PNJTR7LB\@ 305#EK at MS8/CU'O>7ASB0'.K?F>5H<SUW#A\!UW MK2/0#N>?A"*'?_$M\,./-2*20N"0/U#,*^[/@<=!K#I :!\6F@&K$-WJWSHK M::5?.P9RKA7 at MSL'U6*!FG]4<0Z$*#H=@-\K$?"MQ- I(T'GZZ21R;L&2,#= MF*ZU."MD 5S\8K7T?1[&529,I^G%^F#6<(T.D=VY=S7%;UP""7-:/FV6>016 M?1SC:&0';O;@&DV]NKILH5XQ'\&1\3K#ZE ,T=<,M(#GHS:^C\KE,/L52W,< MA%W/BW5!+P, G=8L)+*>K\TZGCOH1F Y:CA]#8,ZG6.#%\<ASO)7QR""<&4, ML]&1 @6P=6 at -Q+6M):<1[]*([T^/J.', %6;Z_Q6G#IVCB-.]?42 at NQC?9^[ M:S_VE3,U7=?G9[Q=)VQ]7=C)0EEJ[+JMT]6B%I"^89MD[P(\;"FV18O=:2_7 M"F#@(0)196K'7JD<]BGB=[Q*6[F<EWTJ\VO\PE*<!F4;.8G%LDUMTI[E,KN> M*("P';80X8J,9F5/=:\TJ$L\;>@._4;#/(>:[BH;S>)>432'.Q*I^D$*9($P MT,X$B1"O:0K#K at DXQ9^2_9R=<R0,0"J _NI48T'5E/8%)'8RN#E!)T5C00 at P M_OEWP3[: WQB'Z(UAX5LHS\4B!"1>(?OAJ_O98$!H?%2!;;A[B1W>PR!']$9 MM((@@@/M9[_&6L6 XOGK)0<_"ET!FQ\MI*UB8WG?@"@ OYL5&D".6CP+V(U= M#)WI)_[4H/[3]A#OB)M!]ZS&_<>[39C.1$&@9P7YH*>@&)2# E [,\G7\B4/ M<E..X_[5!,K(WX$N9J&X0X;2"N*=$(9D *0 at 8GPF?0\IX .!%H N7-X\JXCS M5H at E(W0:;]Q"KMVN8$WI_G;Y-3.XP9 =$$-P?*A']RF?H-8B($3RT'TZEZ(2 M\[.__),W 380!Y(>0*AJ8Y;9+ ,T*\M'>@;=LD!]F*#T?CRE,>E+7^JY$:./ M6#Q+S$-Z13^=;Y:G0?5>OLFO^A%MZ\G F(_P+ 0Z?8H+*MYO:"UC?2B )AS. M^R at U;IX,J$?$K]YYA-;!XC)?_;@(&\%^LBUG7X^DH;3/ER.AVE-?7^$1LKT' MW?;_[MFS at .Q^2T-9N \)X][,K at 0-<N[;3;JO1^;]F-* UH&3K3VYG_?:WMXC M>W7/]XYI#>#W\)Y[7GMQ7^\UWWC_=>H^PQ]3&X#P_?UPB '/GMX'!'0_\$D2 MN#RF-Z#BQWNTTN\#OL-W<^K>\^%4'- Z< J>N_8V0>/?3VXO[W!J#FCY3^7E MDWN&O_$%OGU.^0Q0Z:$XG-_AZP>+ at _<-OSXG@/NM'N1 L?33]5/A9U##U4%[ M_HG"B\$(Y9.D?*_T[&][N*!<$-4"T5KSY6ND";B at P2:,+@:T?SHSW3!]*G<A MZI,,CE,TS0GX;/@<!R]B",8[3=U^S%A=<1]\2GVQZ7*J_OULAWK_G'ZK- H" M)EG at I[Y3O_#??:O/<5:"RU'\?C\LT("0(O=)#EZ@^I/_\)<8R[_W'2F/BJ0Q M8R,\_L&/DR6_R:?[A at OS@[MAVA)6_]PO,:W?[K_^&O/L+S_?/_W"-&;@!-OO M^7._X6=;'"<FQ/[?O_B'J68 at _B=*QQU_SV\3?+_I;_XQHSQ _T:L^_%^Y"_] MP!3[AP44Q_D%_^WW"*[?^XO-Y7_]\^>(I>T4L_,WBK[NLE&)_P0UQOX.*@CC M[M60.[#G7_Y+'7 &B'>JD-TQ@)4?=, UN\T<J\,3E:IM%R^UA4$;"5ZSD9X MA]'<,VV,'\/DJ7KZ&4L#DKDW%LD=X-9\*J(81O>I."L$63&AVYP K0U8PG', M-M&<_L3>;&4P36_C @HWC YQ(P-B!;@-7@/3+#<W((8@%P at +THUB-P.J@-B- M6\.>E!B.T31E!/* UHT/N-:0-T&@J[.W'8%2H$4"WP2!G<X5V,8(;&\ 4\/9 M>5<RUPT'J%U8&QA-M5>4'R)-6D&&+(%X#S_';_4[E%VFQH-==H74/::"]3=V M(%7C!%8NV-8CI26\6_=.7$.$B5M+"+EE;L5;G0LBV&$, >_6N86SR%MZV1YB M;^%;QH' Q6[U6_^6:9,)(BJ5H#&U.35<R=3#Y6KY+1-7_U-D:3AZ('^ ?F1; M44TKN #N9=!9T"4!PEQ$E]'U\'TST8QRI#E-0ZR0TQ5BG7>$$<!!N>AAK]=X MT(<5 at 2,*,BB(E1B$6.-BB%D'B%A$8JGT+8S8D $"/&(E!E>T#4YBC!H<8(GE M;9B8)O:#=6)%W"?FIYUD_T\)EI <)6U<R9:*V1RLF-G5HL%B59$"L, at 99JT$ M+J8*[6(^QOO at BUD:# ;[)8RY'\68,3%O,8#+&)N7 +QJT!A&1HW!-+L-H&$# M[1UB1%.@$6J$(T%&L!%T!!]!CR,2G 0E04!" V!\B,Y+$!/0 #> #: ZM038 MGDXP _0$&V%-:!/>A#AA3J at 3[H0\H48X O 0(,!%N$V@"AO#],-# (6" 6'P M0"@&C %O !E(!I2!94 9: :<@6= '(0&H\$P 8B,)F$/;" ;T 8_H37C634* M8U>I@#),7M,/6(@42 at VW N+0+_ *U8&O #40 at 5N2L1 R0$K!0Y!P*4 +TH(U MXSA8"]C"$Z M< O> K@@+I +NL:YD"[87>P"A/ NY IO8=,'%-H+!DF^X"OQ M"^D#P" PV%T%P\$0=S40#</#$#$H7X1"Q4 D8 S6C,8 (70,J$3(<BR(#$ & M=5$PA$FL M>P,I 2+H,<P#O(#!Q#S7 S+ \Z at S7#,^ALP(*+4!](#_4#,H<T M* U, ^5P>H4%TP_58#60#AV&UE [ (6J0]B ,(@%*T/9P*"@#6JA-=,V< 5O M0]S0*+P=UL7=X& P"DV"WV ;! Z#PQMB>!T.D"&U,$%8,]-/X\ LU061PVA" M.0 +EL,;TRBL,YM#O] YB!YK8?0 at .EP-I8-UV'9EAZS#2' 5_ U8 O!!.X - M#4.J !3J#F2'G/0DX%K!@_1!/!@/E$?RL#QT2\E.Z1$=#@W= _5 at S2 9B\[V MT"+^"#?")C,^5 >8!V;X+ZP/:<-%X#[D8O'#_! WW!) X=BUF/$/_@, (4 0 M$ ;$A5 ()@RVQ!FP0# ?%.)2Z'9)$)-A!4$J7!"%2 at 9A:W403U:($$)4!R,$ MX_$WG!#A(5#(?4T:"]*R<'8M#W# A)!:X3)=3USC(* G)?*H%2 $5F2]4 E M63-K(K0Q,U0R] /4H#VX 7,B!5,G at EMWXL9 !@ 48L#G\<3<$3<B4#@2; S. M0HI('%0!3L )T"AT7^I!@&!X80$M0,_B*8( >$ $9BE>!%3 DY I<EX' AT M2M0(9$!UT (0 =,/%? $/ %, .4!-02*AL0;\ (<B at 2!0? &K(IQD0D1*S8) MR=<(9*RA"V, ZM "/ $Y!:XH->B*O"((X )LB^*$#34$'$-=0R-Q!?0 7-VQ M. 08 >[/$3 %E!C38K4H+D(2DD0/@/$I "3$70 LGH<0V*0Q/.2+ at B(+<2_: MB_QBL!@D# 0%@0OP)) *("XZ+T at C$- 8U D, ;H8A"@+M8B3\*]F"($C&F# MJT at P&HL/H\*84[ !>B(<\3%F23*"&. O8HQVP<4X2$P:!F-5(Q 4BRTCPJ at P M*@@,H\/(,$:,$V-.43&BC"IC!/8D! 0;8\R8,#H2M0C(^$9(#"W )Y0WE(PG MX\HH* *,3J/ 2"P6C ?CT'@%+(R,@<T(,::+4P#%V#-.&F7!O=@R3HT<H\Q( M-#:-/B/4&(%U#0E S>@8W(Q<8RV".HB-78,"4"[>!5P=V^@V/HSG8MR84Z . M>2,+\3)2C7?!X&@0Z(U9X]NX-4J,7>/?.##"C'4CV6 at PW@62(^+8,"J.?2/C M*#>Z7:I!P5 at WNH74@C^#<9 28P"AH%.(C:4'W:CQY!"K(^I at .!X$G"/D" )@ M =W7UXCZ?%]^UA,P!%0!28*N(9DE 2=04*A\#(5A at 0@B-NH8&ANZ at 2/@BU%C MVH \KF+:@7'P2UQ2\9+MR"B4!2^ D" 'O "T#QA!-TX:H2(;<&BP)Q9C]C@' M;(_=(_>(,8Z/UJ/WA9E85MHC]YB:@!$EH_K8/$I at F D+ 4/T"':!@L!1[#D6 MX[WHR!F,C4:M48^U at L?9/@:#R&K_F%\VD'V XLU!)E<%+I7-0N81O6KHV&X# MD0D>$EFLYH]=9-)81A:\46@=698"KJ0V(EE/5I*!9$$9DJ4<J&3*($MVE,5D M&!U;EA_<9#F9%YC:B#<^64O30A8*+R11%D,:92]94E9#%F5.&4MP!?)/5%F) M49!=97Q-5E:5^8!IV5=FEI$N7-EN$T6695496K;;>&5Z"%O&+;$?;QE>LV_- M9779/D-&XF6 at 8&QW:2D(PEM/*$?.D71D'6E'WI%X9!ZI1^Z1?&0?Z4?^D8!D M("E(#I*$9$7 at 0M8JG@K&EJM<*@>(<>.K!#G "I[2T@@HYXFA\*?,),J*7-2J M."L>&P1"@DTKMHHBZ7(PDF*!<)>0$'?DDB1IDE&2Z at ZHAXB8*Z?):->:> 3M M2K(RHCQU=08N"?S)=JMDE\*O5"BHA,*RLEPM",O!PAT(DY-DE^*P="_X2<3B MZ%TL $Q3DO!X+,PD$B2R0&7))(=BLC"3*$N2HK)DD_!)JQ<FP"PZQZ<7Z at V3 M:4FO1Y](=,WD*1'K/2C19%I"^'0O&1;>\O<D+7\/TU*T02U'&_T"3MHE8,L MT\!T+6()V*)/$G)1SF;4X/R3:PO;<TE>2W,+ZY+"N"Z5"XZSMS16\)P9N!<5 M+O+<!G>ZP# CRN,R(T at C_4_F--18+IB+.;&Y="Y>9.C2N>AE'^4;.:*H+A*E MW<*)P"Z4'6LRN\A9M<OM\HCT2.$,)Z7T'"__&]W#O!25STO[\3LE)! >W"+6 ML)+<BT173V)20A>G=;[<@FX I]6^()2:43^Y4/:2#4L9D+_L+_V+6"D QI/J MCAT at 4(XH+\](D*0P,".* O-60C!Q)4$Y5QZ45$I7Z?]A,+3@!D,B>3#A':<Q M0IDP4)())=\I8&0!6+"!@3^=9(U2PWB2WY8.L[&YD:N(N13$@'-$C!'#&ZD< M^$9:Y"6L15-,$E/%H$6 at 1\&QQ=10$DT88U152=.'&1,DL">X1+OCQH@)<8P? M4S+8,??,(",P[#&#%[#PKDT?O at 0PH5LR'X<,;7D:E 77 at 2,3*4P&3H"=@Q<N M(-A*)I,#Y at 8. N(U3$@RX1<IHPOA&*>,')#*K#(,(2SCFN5_Z!#_9\@A>\G1 M!F3,B!J4AS(C]MAXOTO05^A8,^?,=X?WW#R*D-QCSK23+8**<O(%.O!,P=?U L88"_I0E27/HS at UY TPZ"D at I"0>-:$2*C'D-3WR5S$<WEH-%<! .-1Y716 CU end ------------------------------------/\---------------------------------------- Seo: Harp[@Mcc.Com] / \/\ ^*^ Christopher North-Keys Tha mi gu trang a'cluich. / \ \ Assoc. Systems Analyst, MCC --------------------------------(disclaimer)---------------------------------- From davidsen at crdos1.crd.ge.COM Thu Jan 11 02:51:05 1990 From: davidsen at crdos1.crd.ge.COM (Wm E Davidsen Jr) Date: 10 Jan 90 15:51:05 GMT Subject: bundle: a new working version Message-ID: <1994@crdos1.crd.ge.COM> Thanks to suggestions from several people I have added some new features to unbundle. It now splits into two processes and uses pipes to send data, giving double buffering. I also added an (optional) argument for the size of the input volume, for one person who has a driver which messes up on end of tape, and another who only wants to use the outer tracks of a floppy for critical backup. The prompts are now consistent, and the documentation is expanded and corrected. I think that's about all the enhancement this program can stand, but if someone has a thought for something *useful* I'll consider it. This will be posted to sources.misc in a few weeks unless someone finds problems. : #!/bin/sh # shar+ created from directory /u/local/src/bundle # 10:44 on Wed Jan 10, 1990 by local echo 'x - whats.new (text)' sed << 'E!O!F' 's/^X//' > whats.new X bundle change history 1.2 revised 1/10/90 X X01-10-90 X X Added input volume size limit to unbundle. This allows reading a fixed Xquantity of data from each volume. Ubdated the documentation to match Xall this. X X01-06-90 X X Added fork and pipe operations to unbundle. Speedup is very slight on Xthe test systems, but may be larger on selected hardware. X X01-02-90 X X Added fork and pipe operations to bundle to make it faster. E!O!F newsize=`wc -c < whats.new` if [ $newsize -ne 437 ] then echo "File whats.new was $newsize bytes, 437 expected" fi echo 'x - bundle.1 (text)' sed << 'E!O!F' 's/^X//' > bundle.1 X'\" Copyright 1986,87,90 by Bill Davidsen. This code may be used for X'\" personal or commercial purposes. It may be freely distributed X'\" in unmodified source form providing this notice is kept intact. X.TH bundle 1 "1990 release" X'\" bundle doc v1.5 (1/10/90) X.SH NAME X bundle \- buffer and copy \fIstdin\fR to a physical device X unbundle \- buffer and copy a physical device to \fIstdout\fR X.SH SYNOPSIS X\fBbundle\fR special dev_size buf_size X.br X\fBunbundle\fR special buf_size X.br X\fBunbundle\fP special dev_size buf_size X.SH DESCRIPTION XThese programs allow a physical device to be the head or end of a pipe, Xallows software which does not know about volumes to operate on Xmulti-volume sets, and improves the performance of programs such as X\fItar\fR and \fIcpio\fR. X.P X\fBSpecial\fR is the name of a raw device, such as /dev/rmt0. X\fBdev_size\fR is the size of a volume the device, given in bytes or Xkilobytes. When \fBdev_size\fR bytes have been written to the output Xdevice, the operator will be prompted for a media change. The dev_size Xis optional for unbundle, and is only used when a fixed quantity of data Xis written on a volume. This is sometimes done when (a) tape drivers Xdon't handle end of tape correctly, or (b) for best reliability on Xfloppy disk, using only the outer tracks. X.P X\fBBuf_size\fR is the size of the buffer for the write or read. For Xtape this should be the desired tape block size. For disk this should Xthe size of a cylinder. For disk output writing a cylinder at a time Xrather than odd sectors can reduce real time by a factor of three. X.SH EXAMPLES X # \fIwriting to 395k floppy volumes\fP X ls *.c | cpio -o | bundle /dev/rfp021 395k 5k X unbundle /dev/rfp021 5k | cpio -idm X.sp X # \fIwriting 4MB tape volumes\fP X tar cf - /usr/local | bundle /dev/rmt0 4000k 8k X unbundle /dev/rmt0 8k | tar cf - X.sp X # \fIusing only part of a floppy disk\fP X find . -depth -print | bundle /dev/rfd096 800k 15k X unbundle /dev/rfd096 800k 15k | cpio -icdm X.SH WARNINGS XThe volume promts are written to the controlling terminal. If other Xprograms running, such as \fBtar\fP or \fBcpio\fP produce output the Xterminal messages are mingles. Use of the \fBv\fP option with these Xprograms is often very confusing. \fIunbundle\fR normally reads to EOF Xon the input device. If the device does not handle EOF well there may Xbe errors. If the \fBdev_size\fR is not a multiple of the X\fBbuf_size\fR, bizarre errors may occur. X.SH FILES X/dev/\fBspecial\fR X.SH SEE ALSO Xtar, cpio. X.SH AUTHOR XBill Davidsen (davidsen at crdos1.crd.ge.com) X.SH COPYRIGHT XCopyright 1986,87,90 by Bill Davidsen, all rights reserved. This program Xmay be distributed in any manner providing that further distribution is Xnot restricted and the package is kept intact. Modified versions must Xinclude the original source and documentation. X'\" For more details, see man(7), as well as man(1), manroff(1), and mmt(1) E!O!F newsize=`wc -c < bundle.1` if [ $newsize -ne 2906 ] then echo "File bundle.1 was $newsize bytes, 2906 expected" fi echo 'x - bundle.c (text)' sed << 'E!O!F' 's/^X//' > bundle.c X/***************************************************************** X | Program name: bundle.c X |---------------------------------------------------------------- X | accept standard input and write to a device named on the command X | line. The total bytes on the device and the buffer size are X | given on the command line. When the device is full, prompt X | for a new medium in the device and continue. X | X | Command form: X | bundle device Dsize Bsize X |---------------------------------------------------------------- X | Author: Bill Davidsen, 8/16/86 X | Version 1.8 X | Last modified: 1/10/90 X |---------------------------------------------------------------- X | Copyright 1986,87 by Bill Davidsen. This code may be used for X | personal or commercial purposes. It may be freely distributed X | in source form providing this notice is kept intact. X *****************************************************************/ X X#include <stdio.h> X X#ifdef DEBUG X#define debug(f,v) fprintf(stderr, f, v) X#else X#define debug(f,v) X#endif X Xstatic char *SCCS = "@(#) bundle 1.8"; X Xmain (argc, argv) X int argc; X char *argv[]; X{ X char *buffer, /* i/o buffer */ X *malloc (); X register long left; /* room left in the buffer */ X long bufsize, devsize; /* buffer and device size */ X long devleft = 0; /* room left on device */ X int istat, /* stdin read status */ X ostat, /* device write status */ X dev, /* device name from open */ X MediaNum = 1; /* sequential media # */ X FILE *tty, *fopen (); X long getsize (); /* get size from argument */ X int pipex[2]; /* pipe for double buffering */ X int wklen; /* working pie read length */ X X /* validate arguments */ X if (argc != 4) X { /* invalid */ X printf ("Format:\n bundle device DevSize BufSize\n"); X printf ("Where size may be bytes (as 5120) or k (as 5k)\n"); X exit (1); X } X X devsize = getsize (argv[2]); X debug ("Device size %ld", devsize); X bufsize = getsize (argv[3]); X debug (", buffer size %ld\n", bufsize); X if (devsize < 1 || devsize < bufsize) X { /* invalid specification of size */ X printf ("Invalid buffer and/or device size\n"); X exit (1); X } X X /* open the terminal for prompt */ X tty = fopen ("/dev/tty", "r"); X if (tty == NULL) X { /* mystery failure */ X printf ("Unable to open /dev/tty for prompt\n"); X exit (1); X } X X /* open the buffer */ X buffer = malloc (bufsize); X debug ("Buffer allocated\n", 0); X if (buffer == NULL) X { /* can't mallocate */ X printf ("Can't allocate space for the buffer\n"); X exit (1); X } X X /* see if you can open the device */ X printf ("Mount volume #1 on %s and press RETURN: ", argv[1]); X while (getc (tty) != '\n'); X dev = open (argv[1], 1); X if (dev < 0) X { /* invalid name */ X printf ("Can't access device %s\n", argv[1]); X exit (1); X } X devleft = devsize; /* set media ready */ X debug ("Enter copy loop\n\n", 0); X X /* open the pipe */ X if (pipe(pipex)) { X fprintf(stderr, "Can't open pipe for double buffering\n"); X exit(1); X } X X if (fork() == 0) { X /* child - copy stdin to pipe */ X for (wklen = 0; X (istat = read(0, buffer+wklen, (int)(bufsize - wklen))) > 0 X || wklen; X ) { X if (istat > 0) wklen += istat; X debug("Child read %5d bytes\n", istat); X debug(" buffer has %d bytes\n", wklen); X X /* output the size read, then the data */ X if (istat <= 0 || wklen == bufsize) { X write(pipex[1], (char *)&wklen, sizeof(int)); X if (write(pipex[1], buffer, wklen) != wklen) { X fprintf(stderr, "Child can't write pipe!\n"); X exit(1); X } X else debug("Child wrote %d bytes\n", wklen); X wklen = 0; X } X } X X /* output a size of zero */ X istat = 0; X write(pipex[1], (char *)&istat, sizeof(int)); X } X else { X /* main copy loop */ X while (read(pipex[0], (char *)&istat, sizeof(int)), istat) { X /* show the size factor and read those bytes */ X debug ("Input read size %d\n", istat); X for (wklen = 0; wklen < istat; ) { X wklen += read(pipex[0], buffer+wklen, istat-wklen); X } X X if (devleft < istat) X { /* change media */ X close (dev); X printf ("\007Mount volume #%d on %s and press RETURN: ", X ++MediaNum, argv[1]); X while (getc (tty) != '\n'); X dev = open (argv[1], 1); X devleft = devsize; X } X X /* write the buffer */ X ostat = write (dev, buffer, bufsize); X debug ("Output write size %d\n", ostat); X X if (bufsize != ostat) X { /* error on write */ X printf ("Error on device write!\n"); X exit (1); X } X devleft -= ostat; X } X } X X exit(0); X} X X/***************************************************************** X | Procedure: getsize X |---------------------------------------------------------------- X | Convert the size string to bytes. If the last character is X | 'k', multiply by 1024 X ****************************************************************/ X Xlong Xgetsize (string) X char *string; X{ X register long len = strlen (string), X val = atol (string); X X if (string[len - 1] == 'k') X val *= 1024; X X return val; X} E!O!F newsize=`wc -c < bundle.c` if [ $newsize -ne 5387 ] then echo "File bundle.c was $newsize bytes, 5387 expected" fi echo 'x - unbundle.c (text)' sed << 'E!O!F' 's/^X//' > unbundle.c X/***************************************************************** X | Program: unbundle X | accept input from a device and write to stdout X |---------------------------------------------------------------- X | Arguments: X | 1) device name X | 2) block size in bytes or k X | Version: 1.9 X | Last modified: 1/10/90 X |---------------------------------------------------------------- X | Copyright 1986,87 by Bill Davidsen. This code may be used for X | personal or commercial purposes. It may be freely distributed X | in source form providing this notice is kept intact. X ****************************************************************/ X X#include <stdio.h> X#include <signal.h> X X/* define signal for BSD or USG */ X#ifndef SIGCHLD X#ifdef SIGCLD X#define SIGCHLD SIGCLD X#endif X#endif X X#ifdef DEBUG X#define debug(f,v) fprintf(stderr, f, v) X#else X#define debug(f,v) X#endif X Xextern wrapup(); X Xmain (argc, argv) X int argc; X char *argv[]; X{ X char *buf, *malloc (); X int bufsize, dn, mnum = 1, ch, readsize; X int pid; /* child process id */ X long vol_limit = 0; /* max volume size */ X long vol_size; /* read on this volume */ X static char *SCCSid = "@(#)unbundle 1.9"; X long getsize (); /* size of buffer */ X int pipes[2]; /* hold read and write pipes */ X X if (argc < 3 || argc > 4) X { /* bad calling sequence */ X fprintf (stderr, "%s: wrong # of arguments\n", argv[0]); X fprintf (stderr, "Calling seq:\n %s device [volsize] bufsize\n", X argv[0]); X exit (1); X } X X /* try to open the device */ X dn = open (argv[1], 0); X if (dn < 0) X { /* open failed */ X fprintf (stderr, "%s: can't open device %s\n", argv[0], argv[1]); X exit (1); X } X close (dn); /* so I can reopen */ X X /* open the pipe */ X if (pipe(pipes)) { X fprintf(stderr, "Can't create pipes (out of inodes?)\n"); X exit(1); X } X X /* allocate the buffer */ X if (argc == 4) { X /* have volume and buffer size */ X vol_limit = getsize(argv[2]); X bufsize = getsize(argv[3]); X } X else { X /* just the buffer size */ X bufsize = getsize (argv[2]); X } X debug("Volsize: %ld, ", vol_limit); X debug ("Bufsize: %d\n", bufsize); X X buf = malloc (bufsize); X if (buf == NULL) X { /* can't allocate the buffer */ X fprintf (stderr, "Can't allocate %d byte buffer\n", bufsize); X exit (1); X } X X /* here I split the process */ X pid = fork(); X if (pid) { X /* setup for signal when child done */ X signal(SIGCHLD, wrapup); X } X X for (;;) X { /* get a fresh mount and read it */ X if (pid) { X /* parent will read the input device */ X fprintf (stderr, "Mount input volume #%d on %s and press return: ", X mnum++, argv[1]); X read (0, &ch, 1); X dn = open (argv[1], 0); X X if (vol_limit) { X /* must read a limited amount from each volume */ X vol_size = 0; X while (vol_size < vol_limit) { X /* calculate max read size */ X readsize = vol_limit - vol_size; X if (readsize > bufsize) readsize = bufsize; X X /* now read the data and copy */ X readsize = read (dn, buf, bufsize); X if (readsize < 1) break; X write(pipes[1], buf, readsize); X vol_size += readsize; X } X } X else { X /* just copy the data */ X while (readsize = read (dn, buf, bufsize)) { X write (pipes[1], buf, readsize); X } X } X close (dn); X } X else { X /* child will do pipe => stdout */ X while ((readsize = read(pipes[0], buf, bufsize))) { X if (write(1, buf, readsize) < 1) break; X } X } X } X X /* return good status */ X exit(0); X} X X/* X | Procedure: getsize X |- X | Convert the size string to bytes. If the last character is X | 'k', multiply by 1024 X */ X Xlong Xgetsize (string) X char *string; X{ X register int len = strlen (string); X register long val = atol (string); X X if (string[len - 1] == 'k') X val *= 1024; X X return val; X} X X/* wrapup parent on signal */ X Xwrapup() { X exit(0); X} E!O!F newsize=`wc -c < unbundle.c` if [ $newsize -ne 3767 ] then echo "File unbundle.c was $newsize bytes, 3767 expected" fi echo 'x - Makefile (text)' sed << 'E!O!F' 's/^X//' > Makefile X# makefile for bundle items v1.11 1/10/90 X X# ================ this you might wnat to change X X# for compressed backup with date preservation uncomment one of these XBACKUP = zoo X#BACKUP = tar X X# ================ this is all you want to change! X X# distribution and source files XDIST = whats.new bundle.1 bundle.c unbundle.c Makefile XSCCS = s.bundle.c s.unbundle.c s.Makefile s.bundle.1 \ X s.whats.new XOTHER = buntest.c unbuntest.c X XRESULTS = bundle unbundle XTESTPROG = buntest unbuntest X X# if a library is needed for nap() XNAPLIB = -lx X X# which shar to use XSHAR = shar X X# makerule for SCCS which doesn't leave writable files on error X.c~.c: X get $? X X# start making here X Xall : $(RESULTS) $(TESTPROG) X Xtest : all buntest X Xbundle : bundle.o X $(CC) -o bundle bundle.o X Xunbundle : unbundle.o X $(CC) -o unbundle unbundle.o X Xbuntest : buntest.o X $(CC) -o buntest buntest.o $(NAPLIB) X Xunbuntest : unbuntest.o X $(CC) -o unbuntest unbuntest.o $(NAPLIB) X X# things with now reasonable makerules by default Xbundle.1 : X get s.bundle.1 X Xwhats.new : X get s.whats.new X X# shar for distribution Xshar : bundle.shar Xbundle.shar : $(DIST) X shar $(DIST) > bundle.shar X X# zoo backup - what the author uses Xzoo : check1 $(SCCS) $(OTHER) X zoo aunPP bundle.zoo $(SCCS) $(OTHER) X X# check for any files not in SCCS Xcheck1 : X ls p.* && echo "Modified versions!" && exit 1 || exit 0 X X# if you like backup via compressed tar files Xtar : check1 $(SCCS) $(OTHER) X tar cvf - $(SCCS) $(OTHER) | compress -v > bundle.tar.Z X X# cleanup all the files other than the shar, zoo, and executables Xclean : $(BACKUP) shar X @echo "Removing working files";\ X rm -f $(DIST) $(SCCS) $(OTHER) bundle.bak *.o buntest unbuntest E!O!F newsize=`wc -c < Makefile` if [ $newsize -ne 1690 ] then echo "File Makefile was $newsize bytes, 1690 expected" fi exit 0 -- bill davidsen (davidsen at crdos1.crd.GE.COM -or- uunet!crdgw1!crdos1!davidsen) "The world is filled with fools. They blindly follow their so-called 'reason' in the face of the church and common sense. Any fool can see that the world is flat!" - anon From maart at cs.vu.nl Sat Jan 6 07:08:05 1990 From: maart at cs.vu.nl (Maarten Litmaath) Date: 5 Jan 90 20:08:05 GMT Subject: fast which v3.0 Message-ID: <5051@solo9.cs.vu.nl> : This is a shar archive. Extract with sh, not csh. : This archive ends with exit, so do not worry about trailing junk. : --------------------------- cut here -------------------------- PATH=/bin:/usr/bin:/usr/ucb echo Extracting 'Makefile' sed 's/^X//' > 'Makefile' << '+ END-OF-FILE ''Makefile' X# Makefile for /usr/local/bin/which X Xwhich: which.c X cc -O which.c -o which X Xinstall: which X /bin/mv -f which /usr/local/bin X Xdoc: X nroff -man which.1 > which.man + END-OF-FILE Makefile chmod 'u=rw,g=r,o=r' 'Makefile' set `wc -c 'Makefile'` count=$1 case $count in 167) :;; *) echo 'Bad character count in ''Makefile' >&2 echo 'Count should be 167' >&2 esac echo Extracting 'which.1' sed 's/^X//' > 'which.1' << '+ END-OF-FILE ''which.1' X.TH WHICH 1 Sep\ 21\ 1989 X.SH NAME Xwhich \- give alias, function or path expansion of command X.SH SYNOPSIS X.B which X[ X.B \-i X] [ X.B \-a X] [ X.B \-\- X] [ X.I command X] X.SH DESCRIPTION X.I Which Xprovides the user with the full expansion of the X.I command Xargument, be it either an \fIalias\fR, a \fIshell function\fR Xor an executable file (default). To enable search for X.I aliases Xand \fIshell functions\fR Xthe user should supply the `\fI\-i\fR' X(= interactive) flag. In that case X.I which Xexpects as standard input the expansion of the \fIalias\fR Xor \fIshell function\fR. XIf the standard input is empty or the `\fI\-i\fR' flag has not been Xgiven, \fIwhich\fR will try to locate \fIcommand\fR Xin the user's \fIPATH\fR. XThe interactive mode is easily used by setting an X.I alias Xlike the following: X.ft B X.nf X X alias which alias !\\$ \\| /usr/local/bin/which \-i !\\* X X.fi X.ft R Xin \fIcsh\fR, or X.ft B X.nf X X alias which eval alias '\\"\\$$#\\" |' \\ X /usr/local/bin/which \-i '${1+"$@"}' X X.fi X.ft R Xin shells which are supersets of X.I sh Xand which know \fIaliases\fR. If your shell has \fIshell functions\fR, you Xcan use the following function: X.ft B X.nf X X which() X { X eval last=\\"\\$$#\\" X set | sed \-n "/^$last(){$/,/^}$/p" | X /usr/local/bin/which \-i ${1+"$@"} X } X X.fi X.ft R XIf the `\fI\-a\fR' (= all) flag is given, X.I which Xwill not stop after the first `match', but search for all occurrences of X.I command Xin the user's X.I PATH. XThe `\fI\-\-\fR' Xflag can be used to end the list of options: the next argument (if present) Xwill be taken as \fIcommand\fR, even if it starts with a `\-'. X\fIWhich [\-i] [\-a] [\-\-]\fR Xwithout further arguments prints the user's X.I PATH Xbroken up into its components, Xone per line. X.PP XThis new version of the X.I which Xcommand is not a X.I csh Xscript. XBeing an executable it is much faster, and not sourcing X.I .cshrc Xit gives a true picture of one's X.I aliases. X.SH EXAMPLE X.ft B X.nf X% alias Xwhich alias !$ | /usr/local/bin/which \-i !* X% which which Xwhich alias !$ | /usr/local/bin/which \-i !* X% which \-a which Xwhich alias !$ | /usr/local/bin/which \-i !* X/usr/local/bin/which X/usr/ucb/which X% X.fi X.ft R X.SH AUTHOR XMaarten Litmaath @ VU Informatika Amsterdam + END-OF-FILE which.1 chmod 'u=rw,g=r,o=r' 'which.1' set `wc -c 'which.1'` count=$1 case $count in 2205) :;; *) echo 'Bad character count in ''which.1' >&2 echo 'Count should be 2205' >&2 esac echo Extracting 'which.c' sed 's/^X//' > 'which.c' << '+ END-OF-FILE ''which.c' X/* X * which [-i] [-a] [--] [<command>] X * alias which alias !\$ \| /usr/local/bin/which -i !\* X * alias which 'eval alias \$$# | /usr/local/bin/which -i ${1+"$@"}' X * which() X * { X * eval last=\"\$$#\" X * set | sed -n "/^$last(){$/,/^}$/p" | X * /usr/local/bin/which -i ${1+"$@"} X * } X * X * author: Maarten Litmaath @ VU University Amsterdam (maart at cs.vu.nl) X * first change: X * Emile LeBlanc (leblanc%math.Berkeley.EDU at ucbvax.berkeley.edu) notes X * the access() system call considering everything executable for X * root (!), so we give root a special treatment X * 'which', 'which -i' and 'which -a' with no further arguments now X * return the PATH environment variable, split up into its components X * the aliases defined above are slightly different from the previous X * version - now it's the shell who's doing the alias checking X * second change: X * added support for shell functions and multiline aliases, added the X * `--' option, changed the source style X */ X X#include <sys/types.h> X#include <sys/stat.h> X#include <stdio.h> X X#define BUF_SIZE 512 X Xchar Version[] = X "@(#)which 3.0 89/09/21 Maarten Litmaath @ VU Informatika Amsterdam"; Xchar *Prog; X X Xvoid usage() X{ X fprintf(stderr, "Usage: %s [-i] [-a] [--] [<command>]\n", Prog); X exit(1); X} X X Xmain(argc, argv) Xint argc; Xregister char **argv; X{ X register char *path, *s; X char *save, *strcpy(), *getenv(), *fgets(), buf[BUF_SIZE]; X int all = 0, inter = 0, stop = 0, found = 0, uid; X struct stat st; X void usage(), convert(); X X X Prog = *argv++; X --argc; X X while (!stop && (s = *argv) && (*s == '-')) { X ++argv; X --argc; X ++s; X while (*s) X switch (*s++) { X case 'a': X all = 1; X break; X case 'i': X inter = 1; X break; X case '-': X stop = 1; X break; X default: X usage(); X } X } X X if (argc > 1) X usage(); X X if (inter && *argv) { X while (fgets(buf, sizeof buf, stdin)) { X if (!found) { X printf("%s", *argv); X found = 1; X } X printf("\t%s", buf); X } X if (found && !all) X exit(0); X } X X if (!(save = path = getenv("PATH"))) { X fprintf(stderr, "%s: no PATH in environment!\n", Prog); X exit(1); X } X X if (!*path) X save = path = "."; X X if (!*argv) { X convert(path, buf); X puts(buf); X exit(0); X } X X uid = getuid(); X X while (*path) { X s = buf; X while ((*s++ = *path) && *path++ != ':') X ; X if (*buf == ':') { X /* X * to deal with the dubious convention that a spurious X * colon is equivalent to a dot... X */ X *buf = '.'; X ++s; X } X (void) strcpy(s, *argv); X *--s = '/'; X if (stat(buf, &st) != 0 || (st.st_mode & S_IFMT) != S_IFREG) X continue; X X /* file exists and is regular */ X X if (uid == 0 ? !(st.st_mode & 0111) : access(buf, 1) != 0) X continue; X X /* file is executable */ X X *s = 0; X if (uid == 0 && stat(buf, &st) != 0) { X perror(buf); X continue; X } X X if (uid == 0 ? !(st.st_mode & 0444) : access(buf, 4) != 0) { X fprintf(stderr, X "%s: %s found in unreadable directory %s!\n", X Prog, *argv, buf); X continue; X } X X /* directory is readable */ X X *s = '/'; X puts(buf); X if (!all) X exit(0); X found = 1; X } X X if (found) X exit(0); X X convert(save, buf); X fprintf(stderr, "%s not found in\n%s\n", *argv, buf); X exit(1); X} X X Xvoid convert(path, buf) Xregister char *path, *buf; X{ X for (;;) { X while ((*buf++ = *path) && *path++ != ':') X ; X if (!*path) X break; X *buf++ = '\n'; X } X *buf = '\0'; /* to cope with a PATH ending in ':' */ X} + END-OF-FILE which.c chmod 'u=rw,g=r,o=r' 'which.c' set `wc -c 'which.c'` count=$1 case $count in 3392) :;; *) echo 'Bad character count in ''which.c' >&2 echo 'Count should be 3392' >&2 esac exit 0 -- 1755 EST, Dec 14, 1992: Henry Spencer is put on a one-way mission to the moon.| Maarten Litmaath @ VU Amsterdam: maart at cs.vu.nl, uunet!mcsun!botter!maart From jfh at rpp386.cactus.org Sun Jan 14 04:47:14 1990 From: jfh at rpp386.cactus.org (John F. Haugh II) Date: 13 Jan 90 17:47:14 GMT Subject: DBM Toolkit Redux Message-ID: <17643@rpp386.cactus.org> [ The preceding version of this thing was cancelled after someone noticed it didn't compile. This is what I get for adding "one last feature" at the last moment and then failing to recompile ... ] This is the beta-test release of my DBM command line toolkit. There are no man pages [ what do you expect, this is a beta release ]. You are expected to read the source code for answers ;-) There are several command line interface programs in here. They are: dbmstore - store a record under a key in a database dbmfetch - fetch a record with a key from a database dbmedit - fetch a record, call an editor, and write the record back. dbmdelete - remove a record using a key from a database dbmfirstkey - return the first key in the database, a logical rewind. dbmnextkey - return the key following the supplied key. dbmkeys - list all of the keys in the database. The general syntax is <command name> <database name> <database key> All of the commands, except dbmfirstkey, expect a key to be provided on the command line. Data is either output on standard output, or input from standard input. There are not options to read or write to or from files. Both data and keys may contain octal-escapes for non-printing characters. The DBM editor will edit dbm files which contain binary data. And here is the source code ... ---- cut here ---- #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # Makefile # dbmdelete.c # dbmstore.c # dbmfetch.c # dbmedit.sh # dbmkeys.c # dbmfrstkey.c # dbmnextkey.c # This archive created: Sat Jan 13 11:45:47 1990 # By: John F. Haugh II (River Parishes Programming, Austin TX) export PATH; PATH=/bin:/usr/bin:$PATH if test -f 'Makefile' then echo shar: "will not over-write existing file 'Makefile'" else cat << \SHAR_EOF > 'Makefile' # @(#)Makefile 1.2 01:23:12 1/12/90 # # Makefile for dbmtools # # Copyright John F. Haugh II # All rights reserved. # # This software may be copied for non-commercial uses. # Use at your own risk. # #CFLAGS = -g #LDFLAGS = -g CFLAGS = -O LDFLAGS = -s LIBS = -ldbm # The default Make rules can't get a .sh file, and neglect to make # the output read-only in the .c case .sh~.sh: $(GET) $(GFLAGS) -p $< > $*.sh chmod a-w $*.sh .c~.c: $(GET) $(GFLAGS) -p $< > $*.c chmod a-w $*.c FILES = Makefile dbmdelete.c dbmstore.c dbmfetch.c dbmedit.sh \ dbmkeys.c dbmfrstkey.c dbmnextkey.c EXECS = dbmdelete dbmstore dbmfetch dbmedit dbmkeys dbmfirstkey dbmnextkey all: $(EXECS) dbmdelete: dbmdelete.o cc -o dbmdelete $(LDFLAGS) dbmdelete.o $(LIBS) dbmstore: dbmstore.o cc -o dbmstore $(LDFLAGS) dbmstore.o $(LIBS) dbmfetch: dbmfetch.o cc -o dbmfetch $(LDFLAGS) dbmfetch.o $(LIBS) dbmedit: dbmedit.sh cp dbmedit.sh dbmedit chmod +rx dbmedit dbmkeys: dbmkeys.o cc -o dbmkeys $(LDFLAGS) dbmkeys.o $(LIBS) dbmfirstkey: dbmfrstkey.o cc -o dbmfirstkey $(LDFLAGS) dbmfrstkey.o $(LIBS) dbmnextkey: dbmnextkey.o cc -o dbmnextkey $(LDFLAGS) dbmnextkey.o $(LIBS) shar: dbmtools.sh dbmtools.sh: $(FILES) shar $(FILES) > dbmtools.sh clean: rm -f *.o a.out core clobber: clean rm -f $(EXECS) SHAR_EOF fi if test -f 'dbmdelete.c' then echo shar: "will not over-write existing file 'dbmdelete.c'" else cat << \SHAR_EOF > 'dbmdelete.c' /* * Copyright 1990 John F. Haugh II * All rights reserved. * * This software may be reproduced for non-commercial uses. * Use at your own risk. */ /* * @(#)dbmdelete.c 1.1 09:36:19 1/8/90 * * Name: dbmdelete * * Purpose: delete a record from a DBM file * * Description: * dbmdelete is a command line interface to the DBM library * and provides the ability to remove individual records. * * Return Values: * 0 if everything is OK, 1 for everything else */ #include <dbm.h> #include <stdio.h> main (argc, argv) int argc; char **argv; { datum key; /* * Check for proper number of arguments. The first argument is * the name of the database with no .dir or .pag. The second * argument is the literal key to search for, sorry, no binary * keys just yet. */ if (argc != 3) { fprintf (stderr, "usage: dbmdelete database key\n"); exit (1); } /* * Open the named database. It must already exist. */ if (dbminit (argv[1])) { perror (argv[1]); exit (1); } /* * All keys right now are character strings. Point at the * argument and provide its length. */ key.dptr = argv[2]; key.dsize = strlen (argv[2]); /* * Call the low-level DBM library routine to kill off * the record. Report an error if one occurs. */ if (delete (key)) { fprintf (stderr, "%s: can't delete\n", argv[2]); exit (1); } exit (0); } SHAR_EOF fi if test -f 'dbmstore.c' then echo shar: "will not over-write existing file 'dbmstore.c'" else cat << \SHAR_EOF > 'dbmstore.c' /* * Copyright 1990 John F. Haugh II * All rights reserved. * * This software may be reproduced for non-commercial uses. * Use at your own risk. */ /* * @(#)dbmstore.c 1.3 11:45:23 1/13/90 * * Name: dbmstore * * Purpose: store a new record, or update an existing record * * Description: * dbmstore reads a record full of data and stores it in the * database under the supplied key. The record can be either * a completely new record, or a pre-existing record. * * Return Values: * 0 for success, 1 for all errors. */ #include <dbm.h> #include <stdio.h> main (argc, argv) int argc; char **argv; { int c; int len; int i, j; datum value; datum key; char keybuf[BUFSIZ]; char buf[BUFSIZ]; /* * Check the argument. The first argument is the name of the * database, the second is the key to store the record under. * The key may have octal values for characters. */ if (argc != 3) { fprintf (stderr, "usage: dbmstore database key\n"); exit (1); } /* * Open the database, reporting any errors that are found. */ if (dbminit (argv[1])) { perror (argv[1]); exit (1); } /* * Unquote the key. The quoted text is in argv[2] and is * copied one character at a time into keybuf[]. A quoted * character begins with '\' and has three octal digits * following it. */ for (i = j = 0;i < strlen (argv[2]);i++) { if (argv[2][i] == '\\') { c = (((argv[2][i + 1] - '0') << 3) + ((argv[2][i + 2] - '0')) << 3) + (argv[2][i + 3] - '0'); i += 3; } else { c = argv[2][i]; } keybuf[j++] = c; } key.dptr = keybuf; key.dsize = j; /* * Unquotify the input stream. Read from stdin until * EOF is reached, converting any quoted characters as * we go ... */ for (len = 0;len < BUFSIZ && (c = getchar ()) != EOF;len++) { if (c == '\\') { c = ((getchar () - '0') << 6); c += ((getchar () - '0') << 3); c += (getchar () - '0'); } buf[len] = c; } value.dptr = buf; value.dsize = len; /* * Store the new record under the key. If there is an error * report it using the quotified key value to avoid confusion. */ if (store (key, value)) { fprintf (stderr, "%s: can't store\n", argv[2]); exit (1); } exit (0); } SHAR_EOF fi if test -f 'dbmfetch.c' then echo shar: "will not over-write existing file 'dbmfetch.c'" else cat << \SHAR_EOF > 'dbmfetch.c' /* * Copyright 1990 John F. Haugh II * All rights reserved. * * This software may be reproduced for non-commercial uses. * Use at your own risk. */ /* * @(#)dbmfetch.c 1.2 01:23:20 1/12/90 * * Name: dbmfetch * * Purpose: Retrieving a single record from a DBM database * * Description: * dbmfetch retrieves a single record from a DBM database * using the user supplied command line key. * * Return Values: * 0 if the key is found, 1 for all errors. */ #include <dbm.h> #include <stdio.h> #include <ctype.h> main (argc, argv) int argc; char **argv; { int i; datum value; datum key; /* * Count the arguments. First argument is a database name * without .dir or .pag. Second argument is the literal * key used to look up the record. */ if (argc != 3) { fprintf (stderr, "usage: dbmfetch database key\n"); exit (1); } /* * Open the database. It must already exist or an error * is reported. */ if (dbminit (argv[1])) { perror (argv[1]); exit (1); } /* * Initialize the key datum structure and use it to lookup * the desired record in the database. */ key.dptr = argv[2]; key.dsize = strlen (argv[2]); value = fetch (key); /* * See if a value was actually returned, if so, print out * the string itself. It is assumed the string is terminated * with a newline, so one isn't printed. */ if (value.dptr == 0) { fprintf (stderr, "%s: not found\n", argv[2]); exit (1); } for (i = 0;i < value.dsize;i++) { if (! isascii (value.dptr[i]) || (! isprint (value.dptr[i]) && ! isspace (value.dptr[i])) || value.dptr[i] == '\\') printf ("\\%03.3o", value.dptr[i] & 0377); else putchar (value.dptr[i]); } exit (0); } SHAR_EOF fi if test -f 'dbmedit.sh' then echo shar: "will not over-write existing file 'dbmedit.sh'" else cat << \SHAR_EOF > 'dbmedit.sh' # # @(#)dbmedit.sh 1.2 01:23:18 1/12/90 # # Edit a DBM entry # # Copyright 1990 John F. Haugh II # All rights reserved. # # This software may be copied for non-commercial uses. # Use at your own risk. # TEMP=/tmp/dbmedit$$ trap 'rm -f $TEMP ; exit $rc' 0 1 2 3 15 if [ "$EDITOR" = "" ] then EDITOR=/usr/bin/vi fi # # Check for proper number of arguments # if [ $# != 2 ] then echo usage: $0 database key 1>&2 rc=1 exit fi # # Check for the database existing # if [ ! -f $1.dir -o ! -f $1.pag ] then echo $0: The database $1 does not exist 1>&2 rc=1 exit fi # # Get the value from the database and shove the # user into their favorite editor. Ignore the # error return since the key may not exist just # yet and the user wants to create it. # dbmfetch $1 "$2" > $TEMP 2>&1 $EDITOR $TEMP rc=$? if [ $rc != 0 ] then echo $0: Error editing $1 record "$2" 1>&2 exit fi # # Store the value back into the database # dbmstore $1 "$2" < $TEMP rc=$? exit SHAR_EOF fi if test -f 'dbmkeys.c' then echo shar: "will not over-write existing file 'dbmkeys.c'" else cat << \SHAR_EOF > 'dbmkeys.c' /* * Copyright 1990 John F. Haugh II * All rights reserved. * * This software may be reproduced for non-commercial uses. * Use at your own risk. */ /* * @(#)dbmkeys.c 1.2 01:23:22 1/12/90 * * Name: dbmkeys * * Purpose: list all database keys * * Description: * dbmkeys outputs all of the keys in the database. This * can be used to select keys for some operation. * * Return Values: * 0 if no errors are detected, 1 otherwise. */ #include <dbm.h> #include <stdio.h> #include <ctype.h> main (argc, argv) int argc; char **argv; { int i; datum key; /* * Check the arguments. The name of the database must be * given and the database must already exist. */ if (argc != 2) { fprintf (stderr, "usage: dbmkeys database\n"); exit (1); } /* * Open the database and report and error if one occurs. */ if (dbminit (argv[1])) { perror (argv[1]); exit (1); } /* * Walk through the entire database printing out all of the * keys, quoting any special characters as we go. */ for (key = firstkey ();key.dptr != 0;key = nextkey (key)) { for (i = 0;i < key.dsize;i++) { if (! isascii (key.dptr[i]) || (! isprint (key.dptr[i]) && ! isspace (key.dptr[i])) || key.dptr[i] == '\\') printf ("\\%03.3o", key.dptr[i] & 0377); else putchar (key.dptr[i]); } putchar ('\n'); } exit (0); } SHAR_EOF fi if test -f 'dbmfrstkey.c' then echo shar: "will not over-write existing file 'dbmfrstkey.c'" else cat << \SHAR_EOF > 'dbmfrstkey.c' /* * Copyright 1990 John F. Haugh II * All rights reserved. * * This software may be reproduced for non-commercial uses. * Use at your own risk. */ /* * @(#)dbmfrstkey.c 1.2 01:23:21 1/12/90 * * Name: dbmfirstkey * * Purpose: return the first key in the database * * Description: * Returns the first key in a DBM database. This key may * later be used as input to dbmnextkey to return successive * keys from the database. * * Return Values: * 0 if the first key was found, 1 for all other errors. */ #include <dbm.h> #include <stdio.h> #include <ctype.h> main (argc, argv) int argc; char **argv; { int i; datum key; /* * Check the arguments. Must include the name of the database, * which must already exist. */ if (argc != 2) { fprintf (stderr, "usage: dbmfirstkey database\n"); exit (1); } /* * Initialize the database and return an error message if there * is some problem opening the database. */ if (dbminit (argv[1])) { perror (argv[1]); exit (1); } /* * Fetch the first key from the database and return it to the * user. Quote all non-printable characters while you're at it. */ key = firstkey (); for (i = 0;i < key.dsize;i++) { if (! isascii (key.dptr[i]) || (! isprint (key.dptr[i]) && ! isspace (key.dptr[i])) || key.dptr[i] == '\\') printf ("\\%03.3o", key.dptr[i] & 0377); else putchar (key.dptr[i]); } putchar ('\n'); exit (0); } SHAR_EOF fi if test -f 'dbmnextkey.c' then echo shar: "will not over-write existing file 'dbmnextkey.c'" else cat << \SHAR_EOF > 'dbmnextkey.c' /* * Copyright 1990 John F. Haugh II * All rights reserved. * * This software may be reproduced for non-commercial uses. * Use at your own risk. */ /* * @(#)dbmnextkey.c 1.3 11:45:21 1/13/90 * * Name: dbmnextkey * * Purpose: return the next key after the supplied argument * * Description: * dbmnextkey returns the next key in the database after the * supplied argument, or nothing if no key was found. This * can be used to walk through the database one key at a time. * * Return Values: * 0 for success, 1 for all errors */ #include <dbm.h> #include <stdio.h> #include <ctype.h> main (argc, argv) int argc; char **argv; { int i; int j; int c; datum next; datum key; char buf[BUFSIZ]; /* * Check the arguments. The first is the name of a database, * which must already exist. The second is the key to search * for. It may contain quoted characters. */ if (argc != 3) { fprintf (stderr, "usage: dbmfetch database key\n"); exit (1); } /* * Open the database and report any errors which may occur. */ if (dbminit (argv[1])) { perror (argv[1]); exit (1); } /* * Unquote the key. The quoted text is in argv[2] and is * copied one character at a time into buf[]. A quoted * character begins with '\' and has three octal digits * following it. */ for (i = j = 0;i < strlen (argv[2]);i++) { if (argv[2][i] == '\\') { c = (((argv[2][i + 1] - '0') << 3) + ((argv[2][i + 2] - '0')) << 3) + (argv[2][i + 3] - '0'); i += 3; } else { c = argv[2][i]; } buf[j++] = c; } /* * Initialize the key structure. The unquotified key is * now in buf[] and the length is in j. */ key.dptr = buf; key.dsize = j; /* * Get the next key from the database. If the data pointer * is null there are no more keys. */ next = nextkey (key); if (next.dptr == 0) exit (0); /* * Output the new quotified key. */ for (i = 0;i < next.dsize;i++) { if (! isascii (next.dptr[i]) || (! isprint (next.dptr[i]) && ! isspace (next.dptr[i])) || next.dptr[i] == '\\') printf ("\\%03.3o", next.dptr[i] & 0377); else putchar (next.dptr[i]); } exit (0); } SHAR_EOF fi exit 0 # End of shell archive -- John F. Haugh II UUCP: ...!cs.utexas.edu!rpp386!jfh Ma Bell: (512) 832-8832 Domain: jfh at rpp386.cactus.org