home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware 1 2 the Maxx
/
sw_1.zip
/
sw_1
/
OS2
/
BEAV132X.ZIP
/
TERMCAP.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-01-06
|
29KB
|
1,298 lines
/************************************************************************
* *
* 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 OS2
# define DEFAULT_FILE "termcap.dat"
# else
# define DEFAULT_FILE "/etc/termcap" /* default termcap filename */
# endif
char *_tcpbuf; /* Place to remember buffer pointer */
# ifdef OS2
# 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 OS2
{
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 OS2
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 OS2
do_padding(ptime,outc);
# endif
}
}
# ifndef OS2
/*
* 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