home *** CD-ROM | disk | FTP | other *** search
- /************************************************************************
- * *
- * Copyright (c) 1982, Fred Fish *
- * All Rights Reserved *
- * *
- * This software and/or documentation is released for public *
- * distribution for personal, non-commercial use only. *
- * Limited rights to use, modify, and redistribute are hereby *
- * granted for non-commercial purposes, provided that all *
- * copyright notices remain intact and all changes are clearly *
- * documented. The author makes no warranty of any kind with *
- * respect to this product and explicitly disclaims any implied *
- * warranties of merchantability or fitness for any particular *
- * purpose. *
- * *
- ************************************************************************
- */
-
- #include <stdlib.h>
- #include <ctype.h>
- #include <stdio.h>
- #include <string.h>
-
- #include "termcap.h"
-
- static char *fgetlr(char *bp, int bpsize, FILE *fp);
- static FILE *find_file(char *bp);
- static gotcha(char *bp, char *name);
- static char *decode(char *bp, char **area);
- static char *do_esc(char *out, char *in);
- static void process(void);
-
- #define TRUE 1
- #define FALSE 0
- #define BUFSIZE 1024 /* Assumed size of external buffer */
-
- #define NO_FILE -1 /* Returned if can't open file */
- #define NO_ENTRY 0 /* Returned if can't find entry */
- #define SUCCESS 1 /* Returned if entry found ok */
- #define TRUNCATED 2 /* Returned if entry found but trunc */
-
- # ifdef DGK
- # define DEFAULT_ROOT "termcap.cnf" /* name without path component */
- FILE *fopenp();
- # endif
-
- # ifdef MSDOS
- # define DEFAULT_FILE "termcap.dat"
- # else
- # define DEFAULT_FILE "/etc/termcap" /* default termcap filename */
- # endif
-
- char *_tcpbuf; /* Place to remember buffer pointer */
-
- # ifdef MSDOS
- # define index strchr
- # endif
-
-
- /*
- * LIBRARY FUNCTION
- *
- * fgetlr get logical record from a file
- *
- * KEY WORDS
- *
- * fgetlr
- * string functions
- *
- * SYNOPSIS
- *
- * char *fgetlr(bp,bpsize,fp)
- * char *bp;
- * int bpsize;
- * FILE *fp;
- *
- * DESCRIPTION
- *
- * Reads the next logical record from stream "fp" into buffer "bp"
- * until next unescaped newline, "bpsize" minus one characters
- * have been read, end of file, or read error.
- * The last character read is followed by a NULL.
- *
- * A logical record may span several physical records by having
- * each newline escaped with the standard C escape character
- * (backslash).
- *
- * This is particularly useful for things like the termcap
- * file, where a single entry is too long for one physical
- * line, yet needs to be treated as a single record.
- *
- * Returns its first argument unless an end of file or read
- * error occurs prior to any characters being read.
- *
- * BUGS
- *
- * The only way to know if read was terminated due to buffer size
- * limitation is to test for a newline before the terminating
- * null.
- *
- */
-
- /*
- * PSEUDO CODE
- *
- * Begin fgetlr
- * If read fails then
- * Return NULL.
- * Else
- * Find out how many characters were read.
- * Initialize pointer to terminating null.
- * If last char read was newline then
- * If newline was escaped then
- * Replace backslash with the newline.
- * Replace newline with null.
- * Read and append more.
- * End if
- * End if
- * Return buffer pointer.
- * End if
- * End fgetlr
- *
- */
-
- static char *fgetlr(bp,bpsize,fp)
- char *bp;
- int bpsize;
- FILE *fp;
- {
- int numch;
- char *cp;
-
- if (fgets(bp,bpsize,fp) == NULL) {
- return(NULL);
- } else {
- numch = strlen(bp);
- cp = &bp[numch];
- if (*--cp == '\n') {
- if (numch > 1 && *--cp == '\\') {
- *cp++ = '\n';
- *cp = 0;
- fgetlr(cp,bpsize-numch+1,fp);
- }
- }
- return(bp);
- }
- }
-
-
- #ifndef isdigit
- /*
- * LIBRARY FUNCTION
- *
- * isdigit test character for numeric property
- *
- * SYNOPSIS
- *
- * int isdigit(ch)
- * char ch;
- *
- * DESCRIPTION
- *
- * Returns TRUE or FALSE depending upon whether the specified
- * character is a numeric character or not.
- *
- * BUGS
- *
- * May fail on machines in which native character set is not ASCII.
- *
- */
-
- int isdigit(ch)
- char ch;
- {
- if (ch > '9' || ch < '0') {
- return(FALSE);
- } else {
- return(TRUE);
- }
- }
- #endif
-
-
- /*
- * LIBRARY FUNCTION
- *
- * tgetent load buffer with entry for specified terminal
- *
- * KEY WORDS
- *
- * termcap functions
- * utility routines
- *
- * SYNOPSIS
- *
- * int tgetent(bp,name)
- * char *bp;
- * char *name;
- *
- * DESCRIPTION
- *
- * Extracts the entry for terminal <name> from the termcap file
- * and places it in the character buffer <bp>. It is currently
- * assumed that bp is at least 1024 characters. If the entry in
- * the termcap file is larger than 1023 characters the excess
- * characters will be discarded and appropriate status will
- * be returned.
- *
- * Also note that since bp is used by other termcap
- * routines, the storage associated with the termcap entry
- * cannot be freed until all termcap calls are completed.
- *
- * Tgetent can be directed to look in a file other than
- * the default (/etc/termcap) by defining an environment
- * variable called TERMCAP to be the pathname of the desired
- * termcap file. This is useful for debugging new entries.
- * NOTE: the pathname MUST begin with a '/' character.
- *
- * Also, if the string assigned to TERMCAP does not begin with
- * a '/' and if the environment variable TERM matches <name> then
- * the string assigned to TERMCAP is copied to buffer <bp>
- * instead of reading a termcap file.
- *
- * RETURNS
- *
- * -1 if the termcap file cannot be opened
- * 0 if no entry in termcap file matches <name>
- * 1 if extraction is successful with no errors
- * 2 if extraction is successful but entry truncated
- *
- * SEE ALSO
- *
- * tgetnum extract numeric type capability
- * tgetflag test boolean type capability
- * tgetstr get string value of capability
- *
- * AUTHOR
- *
- * Fred Fish
- *
- */
-
- /*
- * PSEUDO CODE
- *
- * Begin tgetent
- * Erase any previous buffer contents.
- * Remember the buffer pointer.
- * If termcap file is not found then
- * If buffer was filled anyway then
- * Return SUCCESS.
- * Else
- * Return NO_FILE.
- * End if
- * Else
- * While records left to process
- * If this is entry is what we want then
- * Close the termcap file.
- * If entry was truncated then
- * Return TRUNCATED status
- * Else
- * Return SUCCESS status.
- * End if
- * End if
- * End while
- * Return NO_ENTRY status.
- * End if
- * End tgetent
- *
- */
-
- int tgetent(bp,name)
- char *bp; /* Pointer to buffer (1024 char min) */
- char *name; /* Pointer to terminal entry to find */
- {
- FILE *fp;
-
- *bp = 0;
- _tcpbuf = bp;
- if ((fp = find_file(bp)) == NULL) {
- if (*bp != 0) {
- return(SUCCESS);
- } else {
- return(NO_FILE);
- }
- } else {
- while (fgetlr(bp,BUFSIZE,fp)) {
- if (gotcha(bp,name)) {
- fclose(fp);
- if (bp[strlen(bp)-1] != '\n') {
- return(TRUNCATED);
- } else {
- return(SUCCESS);
- }
- }
- }
- return(NO_ENTRY);
- }
- }
-
- /*
- * INTERNAL FUNCTION
- *
- * find_file find the termcap file and open it if possible
- *
- * KEY WORDS
- *
- * internal functions
- * find_file
- *
- * SYNOPSIS
- *
- * static FILE *find_file(bp)
- * char *bp;
- *
- * DESCRIPTION
- *
- * Attempts to locate and open the termcap file. Also handles
- * using the environment TERMCAP string as the actual buffer
- * (that's why bp has to be an input parameter).
- *
- * If TERMCAP is defined an begins with a '/' character then
- * it is taken to be the pathname of the termcap file and
- * an attempt is made to open it. If this fails then
- * the default termcap file is used instead.
- *
- * If TERMCAP is defined but does not begin with a '/' then
- * it is assumed to be the actual buffer contents provided
- * that <name> matches the environment variable TERM.
- *
- * BUGS
- *
- * There is currently no way to be sure which termcap
- * file was opened since the default will always be
- * tried.
- *
- */
-
- /*
- * PSEUDO CODE
- *
- * Begin find_file
- * If there is a TERMCAP environment string then
- * If the string is not null then
- * If the string is a pathname then
- * If that file is opened successfully then
- * Return its pointer.
- * End if
- * Else
- * If there is a TERM environment string then
- * If TERM matches <name> then
- * Copy TERMCAP string to buffer.
- * Return NULL for no file.
- * End if
- * End if
- * End if
- * End if
- * End if
- * Open default termcap file and return results.
- * End find_file
- *
- */
-
- static FILE *find_file(bp)
- char *bp;
- {
- FILE *fp;
- char *cp, *ncp;
-
- if ((cp = getenv("TERMCAP")) != NULL) {
- if (*cp != 0) {
- if (*cp == '/' || *cp == '\\') {
- if ((fp = fopen(cp,"r")) != NULL) {
- return(fp);
- }
- } else {
- if ((ncp = getenv("TERM")) != NULL) {
- if (strcmp(cp,ncp) == 0) {
- strcpy(bp,cp);
- return((FILE *)NULL);
- }
- }
- }
- }
- }
- # ifdef DGK
- /* Try current directory, then /etc/termcap, then along the path
- */
- if (fp = fopen(DEFAULT_ROOT, "r"))
- return fp;
- else if (fp = fopen(DEFAULT_FILE, "r"))
- return fp;
- else
- return fopenp(DEFAULT_ROOT, "r", NULL);
- # else
- # ifdef MSDOS
- {
- char path[128];
-
- _searchenv(DEFAULT_FILE, "INIT", path);
- if ( path[0] == 0 )
- _searchenv(DEFAULT_FILE, "PATH", path);
-
- return(fopen(path,"r"));
- }
- # else
- return(fopen(DEFAULT_FILE,"r"));
- # endif
- # endif
- }
-
- /*
- * INTERNAL FUNCTION
- *
- * gotcha test to see if entry is for specified terminal
- *
- * SYNOPSIS
- *
- * gotcha(bp,name)
- * char *bp;
- * char *name;
- *
- * DESCRIPTION
- *
- * Tests to see if the entry in buffer bp matches the terminal
- * specified by name. Returns TRUE if match is detected, FALSE
- * otherwise.
- *
- */
-
- /*
- * PSEUDO CODE
- *
- * Begin gotcha
- * If buffer character is comment character then
- * Return FALSE since remainder is comment
- * Else
- * Initialize name scan pointer.
- * Compare name and buffer until end or mismatch.
- * If valid terminators for both name and buffer strings
- * Return TRUE since a match was found.
- * Else
- * Find next non-name character in buffer.
- * If not an alternate name separater character
- * Return FALSE since no more names to check.
- * Else
- * Test next name and return results.
- * End if
- * End if
- * End if
- * End gotcha
- *
- */
-
- static int gotcha(bp,name)
- char *bp;
- char *name;
- {
- char *np;
-
- if (*bp == '#') {
- return(FALSE);
- } else {
- np = name;
- while (*np == *bp && *np != 0) {np++; bp++;}
- if (*np == 0 && (*bp == 0 || *bp == '|' || *bp == ':')) {
- return(TRUE);
- } else {
- while (*bp != 0 && *bp != ':' && *bp != '|') {bp++;}
- if (*bp != '|') {
- return(FALSE);
- } else {
- return(gotcha(++bp,name));
- }
- }
- }
- }
-
-
- /*
- * LIBRARY FUNCTION
- *
- * tgetflag extract boolean termcap capability
- *
- * KEY WORDS
- *
- * termcap
- *
- * SYNOPSIS
- *
- * tgetflag(id)
- * char *id;
- *
- * DESCRIPTION
- *
- * Returns TRUE if specified id is present in terminal
- * entry, FALSE otherwise.
- *
- */
-
- /*
- * PSEUDO CODE
- *
- * Begin tgetflag
- * Initialize pointer to the termcap entry buffer.
- * While there is a field to process
- * Skip over the field separator character.
- * If this is the entry we want then
- * If entry is identifier only then
- * Return TRUE
- * Else
- * Return FALSE
- * End if
- * End if
- * End while
- * Return FALSE as default.
- * End tgetflag
- *
- */
-
- tgetflag(id)
- char *id;
- {
- char *bp;
-
- bp = _tcpbuf;
- while ((bp = index(bp,':')) != NULL) {
- bp++;
- if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
- if (*bp == 0 || *bp++ == ':') {
- return(TRUE);
- } else {
- return(FALSE);
- }
- }
- }
- return(FALSE);
- }
-
-
- /*
- * LIBRARY FUNCTION
- *
- * tgetnum extract numeric option from termcap entry
- *
- * KEY WORDS
- *
- * termcap
- * ce functions
- *
- * SYNOPSIS
- *
- * tgetnum(id)
- * char *id;
- *
- * DESCRIPTION
- *
- * Returns numeric value of capability <id>, or -1 if <id>
- * is not found. Knows about octal numbers, which
- * begin with 0.
- *
- */
-
- /*
- * PSEUDO CODE
- *
- * Begin tgetnum
- * Initialize pointer to the termcap entry buffer.
- * While there is a field to process
- * Skip over the field separator character.
- * If this is the entry we want then
- * If the entry is not a numeric then
- * Return failure value.
- * Else
- * Initialize value to zero.
- * If number begins with zero then
- * Set accumulation base to 8.
- * Else
- * Set accumulation base to 10.
- * End if
- * While there is a numeric character
- * Accumulate the value.
- * End while
- * Return value.
- * End if
- * End if
- * End while
- * Return failure value.
- * End tgetnum
- *
- */
-
- tgetnum(id)
- char *id;
- {
- int value, base;
- char *bp;
-
- bp = _tcpbuf;
- while ((bp = index(bp,':')) != NULL) {
- bp++;
- if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
- if (*bp != 0 && *bp++ != '#') {
- return(-1);
- } else {
- value = 0;
- if (*bp == '0') {
- base = 8;
- } else {
- base = 10;
- }
- while (isdigit(*bp)) {
- value *= base;
- value += (*bp++ - '0');
- }
- return(value);
- }
- }
- }
- return(-1);
- }
-
-
- /*
- * LIBRARY FUNCTION
- *
- * tgetstr extract string capability from termcap entry
- *
- * KEY WORDS
- *
- * termcap
- *
- * SYNOPSIS
- *
- * char *tgetstr(id,area)
- * char *id;
- * char **area;
- *
- * DESCRIPTION
- *
- * Gets the string capability for <id>, placing it in
- * the buffer at *area, and advancing *area to point
- * to next available storage.
- *
- * For example, if the following capabilities are
- * in the termcap file:
- *
- * ZZ=zzzz
- * YY=yyyyyy
- * WW=www
- *
- * then successive calls using YY, ZZ, and WW will
- * build the following buffer:
- *
- * yyyyyy0zzzz0www0
- *
- * The first call will return a pointer to yyyyyy, the
- * second will return a pointer to zzzz and the third
- * will return a pointer to www. Note that each
- * string is null terminated, as are all C strings.
- *
- * Characters preceded by the carot character (\136)
- * are mapped into the corresponding control character.
- * For example, the two character sequence ^A becomes
- * a single control-A (\001) character.
- *
- * The escape character is the normal C backslash and
- * the normal C escape sequences are recognized, along
- * with a special sequence for the ASCII escape character
- * (\033). The recognized sequences are:
- *
- * \E => '\033' (ASCII escape character)
- * \b => '\010' (ASCII backspace character)
- * \f => '\014' (ASCII form feed character)
- * \n => '\012' (ASCII newline/linefeed char)
- * \r => '\015' (ASCII carriage return char)
- * \t => '\011' (ASCII tab character)
- * \ddd => '\ddd' (arbitrary ASCII digit)
- * \x => 'x' (ordinary ASCII character)
- *
- */
-
- /*
- * PSEUDO CODE
- *
- * Begin tgetstr
- * Initialize pointer to the termcap entry buffer.
- * While there is a field to process
- * Skip over the field separator character.
- * If this is the entry we want then
- * If the entry is not a string then
- * Return NULL.
- * Else
- * Transfer string and rtn pointer.
- * End if
- * End if
- * End while
- * Return NULL
- * End tgetstr
- *
- */
-
- char *tgetstr(id,area)
- char *id;
- char **area;
- {
- char *bp;
- char *decode();
-
- bp = _tcpbuf;
- while ((bp = index(bp,':')) != NULL) {
- bp++;
- if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
- if (*bp != 0 && *bp++ != '=') {
- return(NULL);
- } else {
- return(decode(bp,area));
- }
- }
- }
- return(NULL);
- }
-
- /*
- * INTERNAL FUNCTION
- *
- * decode transfer string capability, decoding escapes
- *
- * SYNOPSIS
- *
- * static char *decode(bp,area)
- * char *bp;
- * char **area;
- *
- * DESCRIPTION
- *
- * Transfers the string capability, up to the next ':'
- * character, or null, to the buffer pointed to by
- * the pointer in *area. Note that the initial
- * value of *area and *area is updated to point
- * to the next available location after the null
- * terminating the transfered string.
- *
- * BUGS
- *
- * There is no overflow checking done on the destination
- * buffer, so it better be large enough to hold
- * all expected strings.
- *
- */
-
- /*
- * PSEUDO CODE
- *
- * Begin decode
- * Initialize the transfer pointer.
- * While there is an input character left to process
- * Switch on input character
- * Case ESCAPE:
- * Decode and xfer the escaped sequence.
- * Break
- * Case CONTROLIFY:
- * Controlify and xfer the next character.
- * Advance the buffer pointer.
- * Break
- * Default:
- * Xfer a normal character.
- * End switch
- * End while
- * Null terminate the output string.
- * Remember where the output string starts.
- * Update the output buffer pointer.
- * Return pointer to the output string.
- * End decode
- *
- */
-
- static char *decode(bp,area)
- char *bp;
- char **area;
- {
- char *cp, *bgn;
- char *do_esc();
-
- cp = *area;
- while (*bp != 0 && *bp != ':') {
- switch(*bp) {
- case '\\':
- bp = do_esc(cp++,++bp);
- break;
- case '^':
- *cp++ = (char) (*++bp & 037);
- bp++;
- break;
- default:
- *cp++ = *bp++;
- break;
- }
- }
- *cp++ = 0;
- bgn = *area;
- *area = cp;
- return(bgn);
- }
-
- /*
- * INTERNAL FUNCTION
- *
- * do_esc process an escaped sequence
- *
- * SYNOPSIS
- *
- * char *do_esc(out,in);
- * char *out;
- * char *in;
- *
- * DESCRIPTION
- *
- * Processes an escape sequence pointed to by
- * in, transfering it to location pointed to
- * by out, and updating the pointer to in.
- *
- */
-
- /*
- * PSEUDO CODE
- *
- * Begin do_esc
- * If the first character is not a NULL then
- * If is a digit then
- * Set value to zero.
- * For up to 3 digits
- * Accumulate the sum.
- * End for
- * Transfer the sum.
- * Else if character is in remap list then
- * Transfer the remapped character.
- * Advance the input pointer once.
- * Else
- * Simply transfer the character.
- * End if
- * End if
- * Return updated input pointer.
- * End do_esc
- *
- */
-
- static char *maplist = {
- "E\033b\bf\fn\nr\rt\t"
- };
-
- char *do_esc(out,in)
- char *out;
- char *in;
- {
- int count;
- char ch;
- char *cp;
-
- if (*in != 0) {
- if (isdigit(*in)) {
- ch = 0;
- for (count = 0; count < 3 && isdigit(*in); in++) {
- ch <<= 3;
- ch |= (*in - '0');
- }
- *out++ = ch;
- } else if ((cp = index(maplist,*in)) != NULL) {
- *out++ = *++cp;
- in++;
- } else {
- *out++ = *in++;
- }
- }
- return(in);
- }
-
-
- /*
- * LIBRARY FUNCTION
- *
- * tgoto expand cursor addressing string from cm capability
- *
- * KEY WORDS
- *
- * termcap
- *
- * SYNOPSIS
- *
- * char *tgoto(cm,destcol,destline)
- * char *cm;
- * int destcol;
- * int destline;
- *
- * DESCRIPTION
- *
- * Returns cursor addressing string, decoded from the cm
- * capability string, to move cursor to column destcol on
- * line destline.
- *
- * The following sequences uses one input argument, either
- * line or column, and place the appropriate substitution
- * in the output string:
- *
- * %d substitute decimal value (in ASCII)
- * %2 like %d but forces field width to 2
- * %3 like %d but forces field width to 3
- * %. like %c
- * %+x like %c but adds ASCII value of x
- *
- * The following sequences cause processing modifications
- * but do not "use up" one of the arguments. If they
- * act on an argument they act on the next one to
- * be converted.
- *
- * %>xy if next value to be converted is
- * greater than value of ASCII char x
- * then add value of ASCII char y.
- * %r reverse substitution of line
- * and column (line is substituted
- * first by default).
- * %i causes input values destcol and
- * destline to be incremented.
- * %% gives single % character in output.
- *
- * BUGS
- *
- * Does not implement some of the more arcane sequences for
- * radically weird terminals (specifically %n, %B, & %D).
- * If you have one of these you deserve whatever happens.
- *
- */
-
- #define MAXARGS 2
-
- static char *in; /* Internal copy of input string pointer */
- static char *out; /* Pointer to output array */
- static int args[MAXARGS]; /* Maximum number of args to convert */
- static int pcount; /* Count of args processed */
- static char output[64]; /* Converted string */
-
- /*
- * PSEUDO CODE
- *
- * Begin tgoto
- * If no string to process then
- * Return pointer to error string.
- * Else
- * Initialize pointer to input string.
- * Initialize pointer to result string.
- * First arg is line number by default.
- * Second arg is col number by default.
- * No arguments processed yet.
- * While there is another character to process
- * If character is a not a % character then
- * Simply copy to output.
- * Else
- * Process the control sequence.
- * End if
- * End while
- * Return pointer to static output string.
- * End if
- * End tgoto
- *
- */
-
- char *tgoto(cm,destcol,destline)
- char *cm;
- int destcol;
- int destline;
- {
- if (cm == NULL) {
- return("OOPS");
- } else {
- in = cm;
- out = output;
- args[0] = destline;
- args[1] = destcol;
- pcount = 0;
- while (*in != 0) {
- if (*in != '%') {
- *out++ = *in++;
- } else {
- process();
- }
- }
- *out++ = 0;
- return(output);
- }
- }
-
- /*
- * INTERNAL FUNCTION
- *
- * process process the conversion/command sequence
- *
- * SYNOPSIS
- *
- * static process()
- *
- * DESCRIPTION
- *
- * Processes the sequence beginning with the % character.
- * Directly manipulates the input string pointer, the
- * output string pointer, and the arguments. Leaves
- * the input string pointer pointing to the next character
- * to be processed, and the output string pointer pointing
- * to the next output location. If conversion of
- * one of the numeric arguments occurs, then the pcount
- * is incremented.
- *
- */
-
- /*
- * PSEUDO CODE
- *
- * Begin process
- * Skip over the % character.
- * Switch on next character after %
- * Case 'd':
- * Process %d type conversion (variable width).
- * Reinitialize output pointer.
- * Break;
- * Case '2':
- * Process %d type conversion (width 2).
- * Reinitialize output pointer.
- * Break;
- * Case '3':
- * Process %d type conversion (width 3).
- * Reinitialize output pointer.
- * Break;
- * Case '.'
- * Process %c type conversion.
- * Break;
- * Case '+':
- * Process %c type conversion with offset.
- * Break;
- * Case '>':
- * Process argument modification.
- * Break;
- * Case 'r':
- * Process argument reversal.
- * Break;
- * Case 'i':
- * Increment argument values.
- * Break;
- * Case '%':
- * Copy to output, incrementing pointers.
- * Break;
- * End switch
- * End process
- *
- */
-
- static void process()
- {
- int temp;
-
- in++;
- switch(*in++) {
- case 'd':
- sprintf(out,"%d",args[pcount++]);
- out = &output[strlen(output)];
- break;
- case '2':
- sprintf(out,"%02d",args[pcount++]);
- out = &output[strlen(output)];
- break;
- case '3':
- sprintf(out,"%03d",args[pcount++]);
- out = &output[strlen(output)];
- break;
- case '.':
- *out++ = (char) args[pcount++];
- break;
- case '+':
- *out++ = (char) args[pcount++] + *in++;
- break;
- case '>':
- if (args[pcount] > (int) *in++) {
- args[pcount] += *in++;
- } else {
- in++;
- }
- break;
- case 'r':
- temp = args[pcount];
- args[pcount] = args[pcount+1];
- args[pcount+1] = temp;
- break;
- case 'i':
- args[pcount]++;
- args[pcount+1]++;
- break;
- case '%':
- *out++ = '%';
- break;
- }
- }
-
-
- /*
- * LIBRARY FUNCTION
- *
- * tputs output string with appropriate padding
- *
- * KEY WORDS
- *
- * termcap
- *
- * SYNOPSIS
- *
- * tputs(cp,affcnt,outc)
- * char *cp;
- * int affcnt;
- * int (*outc)();
- *
- * DESCRIPTION
- *
- * Outputs string pointed to by cp, using function outc, and
- * following it with the appropriate number of padding characters.
- * Affcnt contains the number of lines affected, which is used
- * as a multiplier for the specified per line pad time. If
- * per line pad count is not applicable, affcnt should be 1,
- * NOT zero.
- *
- * The format of the string pointed to by cp is:
- *
- * [pad time][*]<string to send>
- *
- * where: pad time => time to delay in milliseconds
- * * => specifies that time is per line
- *
- * The pad character is assumed to reside in the external
- * variable "PC". Also, the external variable "ospeed"
- * should contain the output speed of the terminal as
- * encoded in /usr/include/sgtty.h (B0-B9600).
- *
- * BUGS
- *
- * Digit conversion is based on native character set
- * being ASCII.
- *
- */
-
- /*
- * Miscellaneous stuff
- */
-
-
- # ifndef MSDOS
- extern char PC; /* Pad character to use */
- extern char ospeed; /* Encoding of output speed */
-
- static int times[] = {
- 0, /* Tenths of ms per char 0 baud */
- 2000, /* Tenths of ms per char 50 baud */
- 1333, /* Tenths of ms per char 75 baud */
- 909, /* Tenths of ms per char 110 baud */
- 743, /* Tenths of ms per char 134 baud */
- 666, /* Tenths of ms per char 150 baud */
- 500, /* Tenths of ms per char 200 baud */
- 333, /* Tenths of ms per char 300 baud */
- 166, /* Tenths of ms per char 600 baud */
- 83, /* Tenths of ms per char 1200 baud */
- 55, /* Tenths of ms per char 1800 baud */
- 41, /* Tenths of ms per char 2400 baud */
- 20, /* Tenths of ms per char 4800 baud */
- 10 /* Tenths of ms per char 9600 baud */
- };
- # endif
-
- /*
- * PSEUDO CODE
- *
- * Begin tgoto
- * If string pointer is invalid then
- * Return without doing anything.
- * Else
- * For each pad digit (if any)
- * Do decimal left shift.
- * Accumulate the lower digit.
- * End for
- * Adjust scale to tenths of milliseconds
- * If there is a fractional field
- * Skip the decimal point.
- * If there is a valid tenths digit
- * Accumulate the tenths.
- * End if
- * Discard remaining digits.
- * End if
- * If per line is specified then
- * Adjust the pad time.
- * Discard the per line flag char.
- * End if
- * While there are any characters left
- * Send them out via output function.
- * End while
- * Transmit any padding required.
- * End if
- * End tgoto
- *
- */
-
- void tputs(cp,affcnt,outc)
- char *cp;
- int affcnt;
- int (*outc)(int);
- {
- int ptime; /* Pad time in tenths of milliseconds */
-
- if (cp == NULL || *cp == 0) {
- return;
- } else {
- for (ptime = 0; isdigit(*cp); cp++) {
- ptime *= 10;
- ptime += (*cp - '0');
- }
- ptime *= 10;
- if (*cp == '.') {
- cp++;
- if (isdigit(*cp)) {
- ptime += (*cp++ - '0');
- }
- while (isdigit(*cp)) {cp++;}
- }
- if (*cp == '*') {
- ptime *= affcnt;
- cp++;
- }
- while (*cp != 0) {
- (*outc)(*cp++);
- }
- # ifndef MSDOS
- do_padding(ptime,outc);
- # endif
- }
- }
-
- # ifndef MSDOS
- /*
- * FUNCTION
- *
- * do_padding transmit any pad characters required
- *
- * SYNOPSIS
- *
- * static do_padding(ptime,outc)
- * int ptime;
- * int (*outc)();
- *
- * DESCRIPTION
- *
- * Does any padding required as specified by ptime (in tenths
- * of milliseconds), the output speed given in the external
- * variable ospeed, and the pad character given in the
- * external variable PC.
- *
- */
-
- /*
- * PSEUDO CODE
- *
- * Begin do_padding
- * If there is a non-zero pad time then
- * If the external speed is in range then
- * Look up the delay per pad character.
- * Round pad time up by half a character.
- * Compute number of characters to send.
- * For each pad character to send
- * Transmit the pad character.
- * End for
- * End if
- * End if
- * End do_padding
- *
- */
-
- static do_padding(ptime,outc)
- int ptime;
- int (*outc)();
- {
- register int nchars;
- register int tpc;
-
- if (ptime != 0) {
- if (ospeed >= 0 && ospeed <= (sizeof(times)/ sizeof(int))) {
- tpc = times[ospeed];
- ptime += (tpc / 2);
- nchars = ptime / tpc;
- for ( ; nchars > 0; --nchars) {
- (*outc)(PC);
- }
- }
- }
- }
- # endif
-