Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!watmath!clyde!cbatt!cbosgd!ucbvax!sdcsvax!noscvax!sloane From: sloane@noscvax.UUCP (Gary K. Sloane) Newsgroups: net.sources Subject: DISPLIB - a screen pkg for BSD/C programmers Message-ID: <595@noscvax.UUCP> Date: Thu, 7-Aug-86 13:38:04 EDT Article-I.D.: noscvax.595 Posted: Thu Aug 7 13:38:04 1986 Date-Received: Sat, 9-Aug-86 08:43:07 EDT Organization: Computer Sciences Corporation, San Diego Lines: 1780 Keywords: termcap curses Here is the source for a (simple) display library ala curses, and some documentation. This was originally posted to USENET a long time ago, and I have hacked it into something different but useful. Thanks to the original (unknown) author. It was written for 4.Xbsd systems, and provides fairly good functionality at extremely low prices. Not very sophisticated, but if you wanna write some nice looking applciations with a minimum of hassle and overhead, this one's for you. A good example of termcap, cbreak, and execl for beginners. Includes a "main menu program" as a sample applciation. Unshar this with /bin/sh. ----------------------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: # README # Makefile # displib.h # libdisp.c # test.c # This archive created: Thu Aug 7 10:31:46 1986 # By: Gary K. Sloane (Computer Sciences Corporation, San Diego) export PATH; PATH=/bin:/usr/bin:$PATH if test -f 'README' then echo shar: "will not over-write existing file 'README'" else cat << \SHAR_EOF > 'README' # # README file for DISPLIB # # Donated into the public domain for any use whatever by anyone. # Please retain this header. # # This display library is a seriously modified version of a # display library posted to USENET several years ago. Many thanks. # # * **************************************************************** * # * Gary K. Sloane/Computer Sciences Corporation/San Diego, CA 92110 * # * DDD: (619) 225-8401 * # * MILNET: sloane@nosc.ARPA * # * UUCP: [ihnp4,akgua,decvax,dcdwest,ucbvax]!sdcsvax!noscvax!sloane * # * **************************************************************** * # Here is a SIMPLE display library, similar to curses, that lets you do full screen applications and onscreen editing from C. There is no warranty, express or implied. There is (alas!) no real documentation, so here are some pointers: CAVEATS -------- 1. This is ONLY tested on a Berkeley 4.[123] system. 2. This library does NOT support screen refresh (like ctrl-L in curses) since it does not map the screen into memory. 3. This library does NOT do windowing. DESCRIPTION ----------- Displib is an object archive of C language functions that allow C application programmers to write full-screen applications. It is kind of like a stripped down version of curses. It includes not only most of the primitives you would expect, but also a set of functions to standardize screens within an application. abb - see if input is a valid abbreviation of target bell - ring the bell on the terminal clear - clear the entire CRT screen cleod - clear from current cursor position to end of CRT screen cleol - clear from current cursor position to end of line clmsg - clear the 'message' area of the screen (see below) clrfield - clear a field clscr - clear the 'main' area of the screen (see below) date2ymd - convert a mm/dd/yy date string to a yymmdd date string editdate - edit a date onscreen in cbreak mode edits - edit a string onscreen in cbreak mode extract - extract delimited fields from a string gotoxy - move the cursor to a specified row and column home - move the cursor to the home (upper left corner) position initscrn - clear the CRT screen and draw the 'title', 'main', and 'message' areas inverse - go into inverse video mode (see normal) msg - display a message to the 'message' area normal - go to normal video mode (see inverse) power - exponentiation putpad - put out a termcap string with padding reload - overlay the current program (called by edits and editdate) stoi - convert string to positive integer terminit - initialize the displib data structures and check the tty description from termcap termreset - put the terminal back in normal (echo, cooked) mode termset - put the terminal in funny (-echo, cbreak) mode tmsg - go to the 'message' area today - build today's date ttyset - set various modes in the tty driver The screen (if you use initscrn, tmsg, clmsg, clscr, or msg) is set up in a "standard" form, in which the top 3 lines (the title area) is reserved for system and screen titles, the bottom 3 lines (the message area) is used for help, error messages, and other stuff, and the central part of the screen (the main area) is used for the actual application. The test.c program uses "standard" screen format. TODO ----- 1. extract the archive via sh, NOT csh. 2. type "% make all" 3. type "% test" to run a small demo (includes a date edit) USING IT --------- 1. every program that will make calls to displib needs the following: #include "displib.h" 2. every program that will use displib should call terminit() and termset() *before any other displib routines*. 3. every program should call termreset() before exiting to restore the tty to its normal (cooked with echo) state. SHAR_EOF fi if test -f 'Makefile' then echo shar: "will not over-write existing file 'Makefile'" else cat << \SHAR_EOF > 'Makefile' # # MAKEFILE FOR THE DISPLAY LIBRARY "DISPLIB" # # Donated into the public domain for any use whatever by anyone. # Please retain this header. # # This display library is a seriously modified version of a # display library posted to USENET several years ago. Many thanks. # # * **************************************************************** * # * Gary K. Sloane/Computer Sciences Corporation/San Diego, CA 92110 * # * DDD: (619) 225-8401 * # * MILNET: sloane@nosc.ARPA * # * UUCP: [ihnp4,akgua,decvax,dcdwest,ucbvax]!sdcsvax!noscvax!sloane * # * **************************************************************** * # # where should the archive be installed? DESTDIR = . # where is the displib.h include file IDIR = . # flags to cc and ld CFLAGS = -O all: libdisp.a test libdisp.a: libdisp.o ar cru libdisp.a libdisp.o ranlib libdisp.a test: test.o libdisp.a cc -o test test.o libdisp.a -ltermlib .c.o: ${CC} -I${IDIR} ${CFLAGS} -c $*.c -ld -x -r $*.o mv a.out $*.o SHAR_EOF fi if test -f 'displib.h' then echo shar: "will not over-write existing file 'displib.h'" else cat << \SHAR_EOF > 'displib.h' /* The include file for DISPLIB This version is for 4.[123]bsd UNIXs using termcap. Donated into the public domain for any use whatever by anyone. Please retain this header. This display library is a seriously modified version of a display library posted to USENET several years ago. Many thanks. * **************************************************************** * * Gary K. Sloane/Computer Sciences Corporation/San Diego, CA 92110 * * DDD: (619) 225-8401 * * MILNET: sloane@nosc.ARPA * * UUCP: [ihnp4,akgua,decvax,dcdwest,ucbvax]!sdcsvax!noscvax!sloane * * **************************************************************** * */ #ifndef DISPLIB #define DISPLIB /******************************************************************************/ /* DISPLIB terminal definition structure used by all display library routines */ /* and external termcap variables. */ /******************************************************************************/ typedef struct termdef { char tcapbuf[512]; /* array where following pointers point to */ char *BL; /* audible bell */ char *CD; /* clear to end of display */ char *CE; /* clear to end of line */ char *CL; /* clear display */ char *CM; /* cursor motion string */ char *IS; /* initialize terminal */ char PC; /* pad character */ char *SE; /* end standout mode */ char *SO; /* start standout mode */ char *TE; /* initialize CM mode */ char *TI; /* terminate CM mode */ int scrlen; /* screen length */ int scrwid; /* screen width -1 */ int curline; /* current line */ int curcol; /* current column */ } TERMDEF; /* displib functions that return something */ char *date2ymd(); int stoi(); int power(); /* termcap(3x) definitions */ char *tgoto(), *tgetstr(); extern char *UP; /* cursor up for tgoto() */ extern char *BC; /* backspace for tgoto() */ extern char PC; /* pad character for tputs() */ extern short ospeed; /* tty speed for tputs() */ /* tty control structure defined in terminit.c */ extern TERMDEF termctrl; /* #defines for error() modes */ #define BEEP 0 #define NOBEEP 1 /* defines for the edits and editdate routines */ #define NORMAL 0 #define COLON 1 #define INVERSE 2 #endif DISPLIB SHAR_EOF fi if test -f 'libdisp.c' then echo shar: "will not over-write existing file 'libdisp.c'" else cat << \SHAR_EOF > 'libdisp.c' /* DISPLIB - a display library for CRT-based applications. This version is for 4.[123]bsd UNIXs using termcap. Donated into the public domain for any use whatever by anyone. Please retain this header. This display library is a seriously modified version of a display library posted to USENET several years ago. Many thanks. * **************************************************************** * * Gary K. Sloane/Computer Sciences Corporation/San Diego, CA 92110 * * DDD: (619) 225-8401 * * MILNET: sloane@nosc.ARPA * * UUCP: [ihnp4,akgua,decvax,dcdwest,ucbvax]!sdcsvax!noscvax!sloane * * **************************************************************** * */ #include #include #include #include #include #include #include #include #include #include #include #include "displib.h" #define makelower(c) isupper(c)?tolower(c):(c) /* pointer to environment for getenv() */ extern char **environ; /* defined here, referenced as an extern elsewhere */ TERMDEF termctrl; /************************************************************************/ /* routine to get terminal capabilities, validate & initialize terminal */ /************************************************************************/ /* *** must be called before using any other displib routines *** */ /************************************************************************/ terminit() { struct sgttyb ttystate; char tbuf[1024], *ap, *pcptr, *getenv(), *term; /* this must be run from a terminal... */ if(isatty(fileno(stdout)) == 0) { fprintf(stderr, "** This program must be run from a tty**\n"); exit(0); } /* read the current tty state from the driver */ if(ioctl(1, (int)TIOCGETP, (char *)&ttystate) != 0) { fprintf(stderr, "** Error: Cannot get tty state **\n");; exit(0); } /* set the tty speed in the external variable ospeed for tputs() */ /* an interesting note: UNIX only knows the speed of the device */ /* that's actually connected to the driver. So if you have modems */ /* or some other link (like a data concentrator) in between, UNIX */ /* will pad for the speed of the device connected to the port, */ /* NOT the speed of the terminal (which is what you want...) */ ospeed = ttystate.sg_ospeed; /* clear the XTABS bit in the sg_flags */ /* so that tab chars (^I) are NOT expanded */ /* since some terminals use them for other */ /* than tabs. (see tgoto.c in termcap) */ ttystate.sg_flags &= ~XTABS; /* write the sg_flags back to the tty */ if(ioctl(1, (int)TIOCSETP, (char *)&ttystate) != 0) { fprintf(stderr, "** Cannot set tty state **\n");; exit(0); } /* delay long enough for TIOCSETP to do it's thing */ sleep(2); /* get terminal type and termcap entry */ term = getenv("TERM"); if(term == (char *)NULL) { fprintf(stderr, "** No TERM variable in environment **\n"); exit(0); } switch(tgetent(tbuf, term)) { case -1: { fprintf(stderr, "** Cannot open termcap data file **\n"); exit(0); } case 0: { fprintf(stderr, "** %s: Unknown terminal type **\n", term); exit(0); } } /* make sure it's not a hard-copy terminal */ if(tgetnum("hc") != -1) { fprintf(stderr, "** You cannot run this program from a hard copy terminal **\n"); exit(0); } /* get terminal attributes and capabilities */ ap = termctrl.tcapbuf; termctrl.BL = tgetstr("bl", &ap); termctrl.CD = tgetstr("cd", &ap); termctrl.CE = tgetstr("ce", &ap); termctrl.CL = tgetstr("cl", &ap); termctrl.CM = tgetstr("cm", &ap); termctrl.IS = tgetstr("is", &ap); termctrl.SE = tgetstr("se", &ap); termctrl.SO = tgetstr("so", &ap); termctrl.TE = tgetstr("te", &ap); termctrl.TI = tgetstr("ti", &ap); termctrl.scrlen = tgetnum("li"); termctrl.scrwid = tgetnum("co"); /* make sure terminal has required capabilities */ if( (termctrl.CM == 0) || (termctrl.CL == 0) ) { fprintf(stderr, "** Terminal must have clear and cursor movement capabilities **\n"); exit(0); } if( (termctrl.scrlen <= 0) || (termctrl.scrwid <= 0) ) { fprintf(stderr, "** Termcap entry must show screen size **\n"); exit(0); } /* define the upline and alternate backspace string for tgoto() */ UP = tgetstr("up", &ap); if(tgetflag("bs") == 0) BC = tgetstr("bc", &ap); else BC = (char *)NULL; /* get the (correct) pad character for tputs() */ /* some networks may discard NULs... */ if((pcptr = tgetstr("pc", &ap)) != (char *)NULL) PC = *pcptr; /* specified in termcap */ else PC = '\000'; /* use a NUL if not specified */ /* send initialization string if defined */ if(termctrl.IS != 0) putpad(termctrl.IS); } /**************************************************************************/ /* Check an Input String to see if it is a Valid Abbreviation of a Target */ /* Ignoring Case - returns 0 if it is an ok abbreviation, -1 if not */ /**************************************************************************/ int abb(input, target) char *input, *target; { char *malloc(); char *tarptr = target; char *tptr, *tptr1; char *inptr = malloc((unsigned int)strlen(target)+1); /* reject - user *must* enter something... */ if( (strlen(input) == 0) || (strlen(input) > strlen(target)) ) return(-1); /* convert input to lower case for the comparison */ for(tptr=input, tptr1=inptr; *tptr!='\0'; ++tptr, ++tptr1) *tptr1= makelower(*tptr); *tptr1 = '\0'; /* we allow one character abbreviations in this program */ if(*inptr == *tarptr) return(abbrev(inptr, tarptr)); else return(-1); } static abbrev(inptr, tarptr) char *inptr, *tarptr; { for(++inptr, ++tarptr; *tarptr != '\0'; ++inptr, ++tarptr) { if(*inptr == '\0') return(0); if(*inptr != *tarptr) return(-1); } if(*inptr == '\0') return(0); else return(-1); } /*************/ /* Ring Bell */ /*************/ bell() { /* If bell is defined, put it out */ if(termctrl.BL != 0) putpad(termctrl.BL); /* If not, put out ASCII ctrl-G */ else putchar('\007'); } /***************************/ /* routine to clear screen */ /***************************/ clear() { putpad(termctrl.CL); return; } /**************************************/ /* routine to clear to end of display */ /**************************************/ cleod() { int lin, col; /* if terminal has CD, do it */ if (termctrl.CD != 0) putpad(termctrl.CD); /* if it doesn't have CD, fake it */ else { /* save cursor position */ lin = termctrl.curline; col = termctrl.curcol; /* clear rest of current line */ cleol(); /* clear rest of screen */ while (termctrl.curline < termctrl.scrlen) { gotoxy(0, ++termctrl.curline); cleol(); } /* return to correct position */ gotoxy(col,lin); } return; } /***********************************/ /* routine to clear to end of line */ /***********************************/ cleol() { int i; /* if terminal has CE, do it */ if (termctrl.CE != 0) putpad(termctrl.CE); /* if terminal doesn't have CE, fake it */ else { for(i=termctrl.curcol; itm_mon += 1; /* months go 0-11 */ date[0] = dt->tm_mon / 10 + '0'; date[1] = dt->tm_mon % 10 + '0'; date[2] = '/'; date[3] = dt->tm_mday / 10 + '0'; date[4] = dt->tm_mday % 10 + '0'; date[5] = '/'; date[6] = dt->tm_year / 10 + '0'; date[7] = dt->tm_year % 10 + '0'; date[8] = '\0'; } /*********************************************************/ /* set tty modes ala stty(1) - arguments are: */ /* raw - turn on raw mode */ /* cbreak - turn on cbreak mode */ /* cooked - turn off raw and cbreak mode */ /* echo - cause echo (full duplex) */ /* -echo - turn off echo (half duplex) */ /* lcase - map upper case into lower case */ /* -lcase - don't map upper case to lower case */ /*********************************************************/ ttyset(cmd) char *cmd; { struct sgttyb ttystate; /* read the current status from the driver */ if(ioctl(1, (int)TIOCGETP, (char *)&ttystate) != 0) { printf("***ERROR: ioctl TIOCGETP failure in function ttyset()...\n"); exit(0); } /* set raw mode */ if(strcmp(cmd, "raw") == 0) { ttystate.sg_flags &= ~CBREAK; ttystate.sg_flags |= RAW; } /* set cbreak mode */ else if(strcmp(cmd, "cbreak") == 0) { ttystate.sg_flags &= ~RAW; ttystate.sg_flags |= CBREAK; } /* set cooked mode */ else if(strcmp(cmd, "cooked") == 0) ttystate.sg_flags &= ~(RAW+CBREAK); /* set echo on */ else if(strcmp(cmd, "echo") == 0) ttystate.sg_flags |= ECHO; /* set echo off */ else if(strcmp(cmd, "-echo") == 0) ttystate.sg_flags &= ~ECHO; /* map upper to lower case on input */ else if(strcmp(cmd, "lcase") == 0) ttystate.sg_flags |= LCASE; /* differentiate between upper and lower case */ else if(strcmp(cmd, "-lcase") == 0) ttystate.sg_flags &= ~LCASE; /* bad argument given */ else { printf("***ERROR: bad argument to ttyset()...\n"); exit(0); } /* write out the changes to the driver */ if(ioctl(1, (int)TIOCSETP, (char *)&ttystate) != 0) { printf("***ERROR: ioctl TIOCSETP failure in function ttyset()...\n"); exit(0); } return; } /**************************/ /* Enter or Edit a String */ /**************************/ /*VARARGS4*/ edits(string, len, flag, pgm, a1, a2, a3, a4, a5) char *pgm, *string; int flag, len; { register int cnt; int initline, initcol, dline, dcol, i; int mode = FREAD; char *sptr, c; /* save cursor positions and string for ctrl-u */ initline = termctrl.curline; initcol = termctrl.curcol; /* highlight the ':' if requested */ if(flag == COLON) { gotoxy(initcol-2, initline); inverse(); printf(":"); normal(); } /* highlight the entire field if requested */ if(flag == INVERSE) { inverse(); printf("%s", string); for(i=strlen(string); i= len) || (c == ':')) bell(); else { *sptr++ = c; putchar(c); ++termctrl.curcol; ++cnt; } break; } } } /*******************************************/ /* Enter or Edit a Date in mm/dd/yy Format */ /*******************************************/ /*VARARGS7*/ editdate(edate, flag, empty, oldate, date, pgm, a1, a2, a3, a4, a5) char *edate, *date, *pgm; int flag, empty, oldate; { int cnt, cd, chcnt=0, scnt=0, erflg=0; char *sptr, c; int initline, initcol, dline, dcol, i, j; int mode = FREAD; /* save cursor positions and string for ctrl-u */ initline = termctrl.curline; initcol = termctrl.curcol; /* highlight the ':' if requested */ if(flag == COLON) { gotoxy(initcol-2, initline); inverse(); printf(":"); normal(); } /* highlight the entire field if requested */ if(flag == INVERSE) { inverse(); printf("%s", edate); for(j=strlen(edate); j<8; j++) putchar(' '); } /* set up for enter or edit */ cnt = strlen(edate); for(sptr = edate; *sptr != '\0'; sptr++) if(*sptr == '/') scnt++; cnt = strlen(edate); sptr = edate + cnt; chcnt = cntdate(edate, sptr); gotoxy(initcol+cnt,initline); /* flush the type ahead buffer */ if(ioctl(0, (int)TIOCFLUSH, (char *)&mode) != 0) { printf("*** ERROR: Bad call to ioctl in editdate()... ***"); exit(0); } /* go into raw mode */ ttyset("raw"); /* accept characters and process them */ for(;;) { c=getc(stdin); if(erflg) { erflg = 0; clmsg(); } switch(c) { /* Delete entered - abort the program? */ case '\177': dline = termctrl.curline; dcol = termctrl.curcol; bell(); gotoxy(25,21); inverse(); printf(" Restart(y/n)? "); gotoxy(40,21); c = getc(stdin); putchar(c); normal(); if(c != 'y') { gotoxy(25,21); printf("------------------"); gotoxy(dcol, dline); if(flag == INVERSE) inverse(); break; } /* go into cbreak mode and restart the program */ ttyset("cbreak"); if(*pgm != '\0') reload(pgm, a1, a2, a3, a4, a5); termreset(); exit(0); /* ctrl-u entered */ case '\025': gotoxy(initcol,initline); for(i=0; i 2) { msg("Format to enter a date is MM/DD/YY...", BEEP,0); erflg++; break; } else ++scnt; chcnt = -1; } /* If it's not a '/', is the month, day, or year too long? */ else { if(chcnt > 1) { msg("Format to enter a date is MM/DD/YY...", BEEP,0); erflg++; break; } } /* everything's ok, put it on the date and bump the ctrs */ ++chcnt; *sptr++ = c; putchar(c); ++termctrl.curcol; ++cnt; break; } } } static cntdate(edate,sptr) char *edate, *sptr; { char *tptr; int chcnt; /* find out how many characters in previous field */ tptr = sptr; chcnt = 0; while (--tptr != (edate-1)) { if(*tptr == '/') break; else chcnt++; } return(chcnt); } static chkdate(edate, date, oldate) char *edate, *date; int oldate; { char *malloc(); char *testdate = malloc(10); char *emonth = malloc(3); char *eday = malloc(3); char *eyear = malloc(3); int i, eimonth, eiday; /* make a copy of edate to play around with */ (void)strcpy(testdate,edate); /* replace each '/' with ':' in testdate */ for(i = 0; i < strlen(testdate); i++) if (*(edate + i) == '/') *(testdate + i) = ':'; /* add a ":" on testdate for extract */ (void)strcat(testdate,":"); /* get month, day, and year into fields */ extract(emonth,testdate,1,':'); extract(eday,testdate,2,':'); extract(eyear,testdate,3,':'); /* make month, day, and year integers */ eimonth = stoi(emonth); eiday = stoi(eday); /* check for valid month entered */ if ( (eimonth > 12) || eimonth == 0) return(2); /* check for valid day entered */ if (eiday == 0) return(3); /* is the day valid for the entered month? */ switch(eimonth) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: if (eiday > 31) return(3); else break; case 4: case 6: case 9: case 11: if (eiday > 30) return(3); else break; case 2: if (eiday > 29) return(3); else break; } /* make sure that the entered date is after today's date */ if((oldate!= 0) && (strcmp(date2ymd(edate),date2ymd(date)) <= 0)) return(4); /* it's a good date */ return(1); } /********************************************/ /* convert a MM/DD/YY date to a YYMMDD date */ /********************************************/ char *date2ymd(date) char *date; { char tdate[10], mo[3], dy[3], yr[3]; static char ymddate[7]; /* extract the yr, mo, and dy from the date */ sprintf(tdate, "%s/", date); extract(yr, tdate, 3, '/'); extract(mo, tdate, 1, '/'); extract(dy, tdate, 2, '/'); /* build the YYMMDD date */ if(strlen(yr) == 2) (void)strcpy(ymddate, yr); else sprintf(ymddate, "0%s", yr); if(strlen(mo) == 1) (void)strcat(ymddate, "0"); (void)strcat(ymddate, mo); if(strlen(dy) == 1) (void)strcat(ymddate, "0"); (void)strcat(ymddate, dy); /* return the YYMMDD date */ return(ymddate); } /***********************************************************************/ /* Given a String With delimiter Separated Fields, and Given the */ /* Position of the Field You Want, Extract that Field */ /***********************************************************************/ extract(fieldnam,bufr,fieldnum, delim) char delim, *bufr, *fieldnam; int fieldnum; { int fieldcnt = 1; char *tptr, *fptr; tptr = bufr; /* move pointer to first address of desired field */ while (fieldcnt < fieldnum) { if( (*tptr == '\0') || (*tptr == delim) ) ++fieldcnt; ++tptr; } /* put a null at end of desired field and return field */ fptr = fieldnam; for(;;) { if( (*tptr == '\0') || (*tptr == delim) ) break; *fptr = *tptr; ++fptr; ++tptr; } *fptr = '\0'; } /*************************************************/ /* reload the program on an abort (DEL entered) */ /* called by edits and editdate */ /*************************************************/ /*VARARGS1*/ reload(prog, a1, a2, a3, a4, a5) char *prog; { int s; /* close all descriptors except stdin, stdout, stderr */ for(s = 3; s < NOFILE; s++) (void) close(s); /* overlay the caller with a 'new' program */ execl(prog, prog, a1, a2, a3, a4, a5); /* if the execl fails... */ perror("execl failed:"); exit(-1); } /*****************************************************************/ /* This function returns a positive integer from a string */ /* If the string contains invalid character(s) it returns a -1. */ /* If the string converts to a negative number it returns a -2. */ /*****************************************************************/ int stoi(string) char *string; { register int index; int exp, numchars, newint, placeint[64]; /* declare the integers */ int neg = 0; /* 1 if number is negative */ /*count number of characters and convert each to integer value*/ for(index=0, numchars=0; *(string+index)!='\0'; ++index,++numchars) { /* it must be a numeric */ if (*(string+index) >= '0' && *(string+index) <= '9') placeint[numchars] = *(string+index) - '0'; else if ( (index == 0) && (*(string+index) == '-') ) neg = 1; else return(-1); } /* return -2 if number is negative */ if (neg == 1) return(-2); /* make sure there's some characters to convert */ if(numchars==0)return(-1); /* convert integers in placeint to an integer by multiplying them */ /* by their corresponding place values */ newint = 0; for(exp = 0,index=numchars-1; index > -1;exp++,index--) newint += power(10, exp) * placeint[index]; return(newint); } /***********************/ /* raise x to the n-th */ /***********************/ int power(x,n) int x, n; { int p; for(p=1; n>0; --n) p *= x; return(p); } SHAR_EOF fi if test -f 'test.c' then echo shar: "will not over-write existing file 'test.c'" else cat << \SHAR_EOF > 'test.c' /* DISPLIB sample routine. Compile with the Makefile, or manually by: % cc -o test test.c libdisp.a -ltermlib This version is for 4.[123]bsd UNIXs using termcap. Donated into the public domain for any use whatever by anyone. Please retain this header. This display library is a seriously modified version of a display library posted to USENET several years ago. Many thanks. * **************************************************************** * * Gary K. Sloane/Computer Sciences Corporation/San Diego, CA 92110 * * DDD: (619) 225-8401 * * MILNET: sloane@nosc.ARPA * * UUCP: [ihnp4,akgua,decvax,dcdwest,ucbvax]!sdcsvax!noscvax!sloane * * **************************************************************** * */ #include #include #include #include #include #include #include "displib.h" /* what is the system title for initscrn() */ #define SYSNAME "DISPLIB DEMONSTRATION PROGRAM" static char Restart[128]; static char date[9]; main() { char *pgm = "test"; int choice; char sel[5], filename[31]; /* set program to exec on Restart (see edits and editdate) */ (void)sprintf(Restart, "%s/%s", "", "test"); /* Set up terminal type and validate terminal */ terminit(); /* Put terminal in CBREAK mode with no ECHO */ termset(pgm); /* get today's date */ today(date); /* Display the menu */ menu(); /* Get the menu choice and validate it */ for(;;) { tmsg(1); printf("Enter a choice from the menu above, or or "); gotoxy(28,20); cleol(); *sel = '\0'; edits(sel,4, 0, Restart, 0); if(abb(sel,"exit") == 0) { msg("Thank you...", NOBEEP, 2, 0); clear(); termreset(); exit(0); } /* convert choice to an int */ else choice = stoi(sel); /* validate range of choice */ if ( (*sel == '\0') || (choice < 1) || (choice > 4) ) bell(); else { switch(choice) { case 1: load(1, "/usr/ucb/mail", 0); break; case 2: load(2, "/usr/local/rn", 0); break; case 3: tmsg(1); printf("Enter the filename you wish to edit..."); gotoxy(15,16); printf("Filename:"); gotoxy(25,16); *filename = '\0'; edits(filename, 30, 0, Restart, 0); load(3, "/usr/ucb/vi", filename, 0); break; /* doesn't exist yet case 4: load(4, "/usr/sloane/sureBud"); break; */ default: msg("Option %d is not yet implemented...",BEEP,2,choice,0); clmsg(); break; } } } } /********************/ /* Display the Menu */ /********************/ static menu() { int pix=8; /* Display the ATRARI main menu */ initscrn("Main Menu", SYSNAME); gotoxy(15,pix); inverse(); printf("THE OPTIONS"); normal(); gotoxy(18,++pix); printf(" 1. Electronic MAIL"); gotoxy(18,++pix); printf(" 2. Read News with RN"); gotoxy(18,++pix); printf(" 3. Use VI"); gotoxy(18, ++pix); printf(" 4. Expert System: Translate COBOL to Fast-C"); gotoxy(15,20); printf("Your choice? "); } /******************/ /* Load a Program */ /******************/ static load(opt, prog, a1, a2, a3, a4, a5, a6) int opt; char *prog; { int s; char errmsg[128]; union wait *status; char *pgm = "test/load"; status = (union wait *)alloca(sizeof(status)); tmsg(1); printf("Now loading option %d...", opt); (void)fflush(stdout); clear(); termreset(); /* child */ if(vfork() == 0) { for(s=3; s<=NOFILE; s++) (void)close(s); execl(prog, prog, a1, a2, a3, a4, a5, a6); (void)sprintf(errmsg, "\nERROR: execl failed: %s", prog); perror(errmsg); exit(-1); } /* parent */ else { (void)wait(status); termset(pgm); if(status->w_retcode!= 0) { termreset(); exit((int)status->w_retcode); } menu(); } } SHAR_EOF fi exit 0 # End of shell archive