1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
3*0Sstevel@tonic-gate * Use is subject to license terms.
4*0Sstevel@tonic-gate */
5*0Sstevel@tonic-gate
6*0Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
7*0Sstevel@tonic-gate /* All Rights Reserved */
8*0Sstevel@tonic-gate
9*0Sstevel@tonic-gate /*
10*0Sstevel@tonic-gate * Copyright (c) 1980 Regents of the University of California.
11*0Sstevel@tonic-gate * All rights reserved. The Berkeley software License Agreement
12*0Sstevel@tonic-gate * specifies the terms and conditions for redistribution.
13*0Sstevel@tonic-gate */
14*0Sstevel@tonic-gate
15*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
16*0Sstevel@tonic-gate
17*0Sstevel@tonic-gate /*LINTLIBRARY*/
18*0Sstevel@tonic-gate
19*0Sstevel@tonic-gate #if 0
20*0Sstevel@tonic-gate static char
21*0Sstevel@tonic-gate sccsid[] = "@(#)termcap.c 1.11 88/02/08 SMI"; /* from UCB 5.1 6/5/85 */
22*0Sstevel@tonic-gate #endif
23*0Sstevel@tonic-gate
24*0Sstevel@tonic-gate #define BUFSIZ 1024
25*0Sstevel@tonic-gate #define MAXHOP 32 /* max number of tc= indirections */
26*0Sstevel@tonic-gate #define E_TERMCAP "/etc/termcap"
27*0Sstevel@tonic-gate
28*0Sstevel@tonic-gate #include <sys/types.h>
29*0Sstevel@tonic-gate #include <unistd.h>
30*0Sstevel@tonic-gate #include <stdlib.h>
31*0Sstevel@tonic-gate #include <stddef.h>
32*0Sstevel@tonic-gate #include <string.h>
33*0Sstevel@tonic-gate #include <strings.h>
34*0Sstevel@tonic-gate #include <ctype.h>
35*0Sstevel@tonic-gate
36*0Sstevel@tonic-gate /*
37*0Sstevel@tonic-gate * termcap - routines for dealing with the terminal capability data base
38*0Sstevel@tonic-gate *
39*0Sstevel@tonic-gate * BUG: Should use a "last" pointer in tbuf, so that searching
40*0Sstevel@tonic-gate * for capabilities alphabetically would not be a n**2/2
41*0Sstevel@tonic-gate * process when large numbers of capabilities are given.
42*0Sstevel@tonic-gate * Note: If we add a last pointer now we will screw up the
43*0Sstevel@tonic-gate * tc capability. We really should compile termcap.
44*0Sstevel@tonic-gate *
45*0Sstevel@tonic-gate * Essentially all the work here is scanning and decoding escapes
46*0Sstevel@tonic-gate * in string capabilities. We don't use stdio because the editor
47*0Sstevel@tonic-gate * doesn't, and because living w/o it is not hard.
48*0Sstevel@tonic-gate */
49*0Sstevel@tonic-gate
50*0Sstevel@tonic-gate static char *tbuf;
51*0Sstevel@tonic-gate static int hopcount; /* detect infinite loops in termcap, init 0 */
52*0Sstevel@tonic-gate
53*0Sstevel@tonic-gate /* forward declarations */
54*0Sstevel@tonic-gate static char *tdecode(char *, char **);
55*0Sstevel@tonic-gate static void tngetsize(char *);
56*0Sstevel@tonic-gate static char *tskip(char *bp);
57*0Sstevel@tonic-gate static char *appendsmalldec(char *, int);
58*0Sstevel@tonic-gate int tnamatch(char *);
59*0Sstevel@tonic-gate int tnchktc(void);
60*0Sstevel@tonic-gate
61*0Sstevel@tonic-gate /*
62*0Sstevel@tonic-gate * Get an entry for terminal name in buffer bp,
63*0Sstevel@tonic-gate * from the termcap file. Parse is very rudimentary;
64*0Sstevel@tonic-gate * we just notice escaped newlines.
65*0Sstevel@tonic-gate */
66*0Sstevel@tonic-gate
67*0Sstevel@tonic-gate int
tgetent(char * bp,char * name)68*0Sstevel@tonic-gate tgetent(char *bp, char *name)
69*0Sstevel@tonic-gate {
70*0Sstevel@tonic-gate char *cp;
71*0Sstevel@tonic-gate int c;
72*0Sstevel@tonic-gate int i = 0;
73*0Sstevel@tonic-gate ssize_t cnt = 0;
74*0Sstevel@tonic-gate char ibuf[BUFSIZ];
75*0Sstevel@tonic-gate int tf;
76*0Sstevel@tonic-gate
77*0Sstevel@tonic-gate tbuf = bp;
78*0Sstevel@tonic-gate tf = -1;
79*0Sstevel@tonic-gate #ifndef V6
80*0Sstevel@tonic-gate cp = getenv("TERMCAP");
81*0Sstevel@tonic-gate /*
82*0Sstevel@tonic-gate * TERMCAP can have one of two things in it. It can be the
83*0Sstevel@tonic-gate * name of a file to use instead of /etc/termcap. In this
84*0Sstevel@tonic-gate * case it better start with a "/". Or it can be an entry to
85*0Sstevel@tonic-gate * use so we don't have to read the file. In this case it
86*0Sstevel@tonic-gate * has to already have the newlines crunched out.
87*0Sstevel@tonic-gate */
88*0Sstevel@tonic-gate if (cp && *cp) {
89*0Sstevel@tonic-gate if (*cp == '/') {
90*0Sstevel@tonic-gate tf = open(cp, 0);
91*0Sstevel@tonic-gate } else {
92*0Sstevel@tonic-gate tbuf = cp;
93*0Sstevel@tonic-gate c = tnamatch(name);
94*0Sstevel@tonic-gate tbuf = bp;
95*0Sstevel@tonic-gate if (c) {
96*0Sstevel@tonic-gate (void) strcpy(bp, cp);
97*0Sstevel@tonic-gate return (tnchktc());
98*0Sstevel@tonic-gate }
99*0Sstevel@tonic-gate }
100*0Sstevel@tonic-gate }
101*0Sstevel@tonic-gate if (tf < 0)
102*0Sstevel@tonic-gate tf = open(E_TERMCAP, 0);
103*0Sstevel@tonic-gate #else
104*0Sstevel@tonic-gate tf = open(E_TERMCAP, 0);
105*0Sstevel@tonic-gate #endif
106*0Sstevel@tonic-gate if (tf < 0)
107*0Sstevel@tonic-gate return (-1);
108*0Sstevel@tonic-gate for (;;) {
109*0Sstevel@tonic-gate cp = bp;
110*0Sstevel@tonic-gate for (;;) {
111*0Sstevel@tonic-gate if (i == cnt) {
112*0Sstevel@tonic-gate cnt = read(tf, ibuf, BUFSIZ);
113*0Sstevel@tonic-gate if (cnt <= 0) {
114*0Sstevel@tonic-gate (void) close(tf);
115*0Sstevel@tonic-gate return (0);
116*0Sstevel@tonic-gate }
117*0Sstevel@tonic-gate i = 0;
118*0Sstevel@tonic-gate }
119*0Sstevel@tonic-gate c = ibuf[i++];
120*0Sstevel@tonic-gate if (c == '\n') {
121*0Sstevel@tonic-gate if (cp > bp && cp[-1] == '\\') {
122*0Sstevel@tonic-gate cp--;
123*0Sstevel@tonic-gate continue;
124*0Sstevel@tonic-gate }
125*0Sstevel@tonic-gate break;
126*0Sstevel@tonic-gate }
127*0Sstevel@tonic-gate if (cp >= bp+BUFSIZ) {
128*0Sstevel@tonic-gate (void) write(2, "Termcap entry too long\n", 23);
129*0Sstevel@tonic-gate break;
130*0Sstevel@tonic-gate } else
131*0Sstevel@tonic-gate *cp++ = (char) c;
132*0Sstevel@tonic-gate }
133*0Sstevel@tonic-gate *cp = 0;
134*0Sstevel@tonic-gate
135*0Sstevel@tonic-gate /*
136*0Sstevel@tonic-gate * The real work for the match.
137*0Sstevel@tonic-gate */
138*0Sstevel@tonic-gate if (tnamatch(name)) {
139*0Sstevel@tonic-gate (void) close(tf);
140*0Sstevel@tonic-gate return (tnchktc());
141*0Sstevel@tonic-gate }
142*0Sstevel@tonic-gate }
143*0Sstevel@tonic-gate }
144*0Sstevel@tonic-gate
145*0Sstevel@tonic-gate /*
146*0Sstevel@tonic-gate * tnchktc: check the last entry, see if it's tc=xxx. If so,
147*0Sstevel@tonic-gate * recursively find xxx and append that entry (minus the names)
148*0Sstevel@tonic-gate * to take the place of the tc=xxx entry. This allows termcap
149*0Sstevel@tonic-gate * entries to say "like an HP2621 but doesn't turn on the labels".
150*0Sstevel@tonic-gate * Note that this works because of the left to right scan.
151*0Sstevel@tonic-gate */
152*0Sstevel@tonic-gate
153*0Sstevel@tonic-gate int
tnchktc(void)154*0Sstevel@tonic-gate tnchktc(void)
155*0Sstevel@tonic-gate {
156*0Sstevel@tonic-gate char *p, *q;
157*0Sstevel@tonic-gate char tcname[16]; /* name of similar terminal */
158*0Sstevel@tonic-gate char tcbuf[BUFSIZ];
159*0Sstevel@tonic-gate char *holdtbuf = tbuf;
160*0Sstevel@tonic-gate ptrdiff_t l;
161*0Sstevel@tonic-gate
162*0Sstevel@tonic-gate p = tbuf + strlen(tbuf) - 2; /* before the last colon */
163*0Sstevel@tonic-gate while (*--p != ':')
164*0Sstevel@tonic-gate if (p < tbuf) {
165*0Sstevel@tonic-gate (void) write(2, "Bad termcap entry\n", 18);
166*0Sstevel@tonic-gate return (0);
167*0Sstevel@tonic-gate }
168*0Sstevel@tonic-gate p++;
169*0Sstevel@tonic-gate /* p now points to beginning of last field */
170*0Sstevel@tonic-gate if (p[0] != 't' || p[1] != 'c') {
171*0Sstevel@tonic-gate tngetsize(tbuf);
172*0Sstevel@tonic-gate return (1);
173*0Sstevel@tonic-gate }
174*0Sstevel@tonic-gate (void) strcpy(tcname, p+3);
175*0Sstevel@tonic-gate q = tcname;
176*0Sstevel@tonic-gate while (*q && *q != ':')
177*0Sstevel@tonic-gate q++;
178*0Sstevel@tonic-gate *q = 0;
179*0Sstevel@tonic-gate if (++hopcount > MAXHOP) {
180*0Sstevel@tonic-gate (void) write(2, "Infinite tc= loop\n", 18);
181*0Sstevel@tonic-gate return (0);
182*0Sstevel@tonic-gate }
183*0Sstevel@tonic-gate if (tgetent(tcbuf, tcname) != 1) {
184*0Sstevel@tonic-gate hopcount = 0; /* unwind recursion */
185*0Sstevel@tonic-gate return (0);
186*0Sstevel@tonic-gate }
187*0Sstevel@tonic-gate for (q = tcbuf; *q != ':'; q++)
188*0Sstevel@tonic-gate ;
189*0Sstevel@tonic-gate l = p - holdtbuf + strlen(q);
190*0Sstevel@tonic-gate if (l > BUFSIZ) {
191*0Sstevel@tonic-gate (void) write(2, "Termcap entry too long\n", 23);
192*0Sstevel@tonic-gate q[BUFSIZ - (p-tbuf)] = 0;
193*0Sstevel@tonic-gate }
194*0Sstevel@tonic-gate (void) strcpy(p, q+1);
195*0Sstevel@tonic-gate tbuf = holdtbuf;
196*0Sstevel@tonic-gate hopcount = 0; /* unwind recursion */
197*0Sstevel@tonic-gate tngetsize(tbuf);
198*0Sstevel@tonic-gate return (1);
199*0Sstevel@tonic-gate }
200*0Sstevel@tonic-gate
201*0Sstevel@tonic-gate /*
202*0Sstevel@tonic-gate * Tnamatch deals with name matching. The first field of the termcap
203*0Sstevel@tonic-gate * entry is a sequence of names separated by |'s, so we compare
204*0Sstevel@tonic-gate * against each such name. The normal : terminator after the last
205*0Sstevel@tonic-gate * name (before the first field) stops us.
206*0Sstevel@tonic-gate */
207*0Sstevel@tonic-gate
208*0Sstevel@tonic-gate int
tnamatch(char * np)209*0Sstevel@tonic-gate tnamatch(char *np)
210*0Sstevel@tonic-gate {
211*0Sstevel@tonic-gate char *Np, *Bp;
212*0Sstevel@tonic-gate
213*0Sstevel@tonic-gate Bp = tbuf;
214*0Sstevel@tonic-gate if (*Bp == '#')
215*0Sstevel@tonic-gate return (0);
216*0Sstevel@tonic-gate for (;;) {
217*0Sstevel@tonic-gate for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
218*0Sstevel@tonic-gate continue;
219*0Sstevel@tonic-gate if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
220*0Sstevel@tonic-gate return (1);
221*0Sstevel@tonic-gate while (*Bp && *Bp != ':' && *Bp != '|')
222*0Sstevel@tonic-gate Bp++;
223*0Sstevel@tonic-gate if (*Bp == 0 || *Bp == ':')
224*0Sstevel@tonic-gate return (0);
225*0Sstevel@tonic-gate Bp++;
226*0Sstevel@tonic-gate }
227*0Sstevel@tonic-gate }
228*0Sstevel@tonic-gate
229*0Sstevel@tonic-gate /*
230*0Sstevel@tonic-gate * Skip to the next field. Notice that this is very dumb, not
231*0Sstevel@tonic-gate * knowing about \: escapes or any such. If necessary, :'s can be put
232*0Sstevel@tonic-gate * into the termcap file in octal.
233*0Sstevel@tonic-gate */
234*0Sstevel@tonic-gate
235*0Sstevel@tonic-gate static char *
tskip(char * bp)236*0Sstevel@tonic-gate tskip(char *bp)
237*0Sstevel@tonic-gate {
238*0Sstevel@tonic-gate
239*0Sstevel@tonic-gate while (*bp && *bp != ':')
240*0Sstevel@tonic-gate bp++;
241*0Sstevel@tonic-gate if (*bp == ':') {
242*0Sstevel@tonic-gate do {
243*0Sstevel@tonic-gate bp++;
244*0Sstevel@tonic-gate while (isspace(*bp))
245*0Sstevel@tonic-gate bp++;
246*0Sstevel@tonic-gate } while (*bp == ':');
247*0Sstevel@tonic-gate }
248*0Sstevel@tonic-gate return (bp);
249*0Sstevel@tonic-gate }
250*0Sstevel@tonic-gate
251*0Sstevel@tonic-gate /*
252*0Sstevel@tonic-gate * Return the (numeric) option id.
253*0Sstevel@tonic-gate * Numeric options look like
254*0Sstevel@tonic-gate * li#80
255*0Sstevel@tonic-gate * i.e. the option string is separated from the numeric value by
256*0Sstevel@tonic-gate * a # character. If the option is not found we return -1.
257*0Sstevel@tonic-gate * Note that we handle octal numbers beginning with 0.
258*0Sstevel@tonic-gate */
259*0Sstevel@tonic-gate
260*0Sstevel@tonic-gate int
tgetnum(char * id)261*0Sstevel@tonic-gate tgetnum(char *id)
262*0Sstevel@tonic-gate {
263*0Sstevel@tonic-gate int i, base;
264*0Sstevel@tonic-gate char *bp = tbuf;
265*0Sstevel@tonic-gate
266*0Sstevel@tonic-gate for (;;) {
267*0Sstevel@tonic-gate bp = tskip(bp);
268*0Sstevel@tonic-gate if (*bp == 0)
269*0Sstevel@tonic-gate return (-1);
270*0Sstevel@tonic-gate if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
271*0Sstevel@tonic-gate continue;
272*0Sstevel@tonic-gate if (*bp == '@')
273*0Sstevel@tonic-gate return (-1);
274*0Sstevel@tonic-gate if (*bp != '#')
275*0Sstevel@tonic-gate continue;
276*0Sstevel@tonic-gate bp++;
277*0Sstevel@tonic-gate base = 10;
278*0Sstevel@tonic-gate if (*bp == '0')
279*0Sstevel@tonic-gate base = 8;
280*0Sstevel@tonic-gate i = 0;
281*0Sstevel@tonic-gate while (isdigit(*bp))
282*0Sstevel@tonic-gate i *= base, i += *bp++ - '0';
283*0Sstevel@tonic-gate return (i);
284*0Sstevel@tonic-gate }
285*0Sstevel@tonic-gate }
286*0Sstevel@tonic-gate
287*0Sstevel@tonic-gate /*
288*0Sstevel@tonic-gate * Handle a flag option.
289*0Sstevel@tonic-gate * Flag options are given "naked", i.e. followed by a : or the end
290*0Sstevel@tonic-gate * of the buffer. Return 1 if we find the option, or 0 if it is
291*0Sstevel@tonic-gate * not given.
292*0Sstevel@tonic-gate */
293*0Sstevel@tonic-gate
294*0Sstevel@tonic-gate int
tgetflag(char * id)295*0Sstevel@tonic-gate tgetflag(char *id)
296*0Sstevel@tonic-gate {
297*0Sstevel@tonic-gate char *bp = tbuf;
298*0Sstevel@tonic-gate
299*0Sstevel@tonic-gate for (;;) {
300*0Sstevel@tonic-gate bp = tskip(bp);
301*0Sstevel@tonic-gate if (!*bp)
302*0Sstevel@tonic-gate return (0);
303*0Sstevel@tonic-gate if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
304*0Sstevel@tonic-gate if (!*bp || *bp == ':')
305*0Sstevel@tonic-gate return (1);
306*0Sstevel@tonic-gate else if (*bp == '@')
307*0Sstevel@tonic-gate return (0);
308*0Sstevel@tonic-gate }
309*0Sstevel@tonic-gate }
310*0Sstevel@tonic-gate }
311*0Sstevel@tonic-gate
312*0Sstevel@tonic-gate /*
313*0Sstevel@tonic-gate * Get a string valued option.
314*0Sstevel@tonic-gate * These are given as
315*0Sstevel@tonic-gate * cl=^Z
316*0Sstevel@tonic-gate * Much decoding is done on the strings, and the strings are
317*0Sstevel@tonic-gate * placed in area, which is a ref parameter which is updated.
318*0Sstevel@tonic-gate * No checking on area overflow.
319*0Sstevel@tonic-gate */
320*0Sstevel@tonic-gate
321*0Sstevel@tonic-gate char *
tgetstr(char * id,char ** area)322*0Sstevel@tonic-gate tgetstr(char *id, char **area)
323*0Sstevel@tonic-gate {
324*0Sstevel@tonic-gate char *bp = tbuf;
325*0Sstevel@tonic-gate
326*0Sstevel@tonic-gate for (;;) {
327*0Sstevel@tonic-gate bp = tskip(bp);
328*0Sstevel@tonic-gate if (!*bp)
329*0Sstevel@tonic-gate return (0);
330*0Sstevel@tonic-gate if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
331*0Sstevel@tonic-gate continue;
332*0Sstevel@tonic-gate if (*bp == '@')
333*0Sstevel@tonic-gate return (0);
334*0Sstevel@tonic-gate if (*bp != '=')
335*0Sstevel@tonic-gate continue;
336*0Sstevel@tonic-gate bp++;
337*0Sstevel@tonic-gate return (tdecode(bp, area));
338*0Sstevel@tonic-gate }
339*0Sstevel@tonic-gate }
340*0Sstevel@tonic-gate
341*0Sstevel@tonic-gate /*
342*0Sstevel@tonic-gate * Tdecode does the grung work to decode the
343*0Sstevel@tonic-gate * string capability escapes.
344*0Sstevel@tonic-gate */
345*0Sstevel@tonic-gate
346*0Sstevel@tonic-gate static char *
tdecode(char * str,char ** area)347*0Sstevel@tonic-gate tdecode(char *str, char **area)
348*0Sstevel@tonic-gate {
349*0Sstevel@tonic-gate char *cp;
350*0Sstevel@tonic-gate int c;
351*0Sstevel@tonic-gate char *dp;
352*0Sstevel@tonic-gate int i;
353*0Sstevel@tonic-gate
354*0Sstevel@tonic-gate cp = *area;
355*0Sstevel@tonic-gate while (((c = *str++) != 0) && c != ':') {
356*0Sstevel@tonic-gate switch (c) {
357*0Sstevel@tonic-gate
358*0Sstevel@tonic-gate case '^':
359*0Sstevel@tonic-gate c = *str++ & 037;
360*0Sstevel@tonic-gate break;
361*0Sstevel@tonic-gate
362*0Sstevel@tonic-gate case '\\':
363*0Sstevel@tonic-gate dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
364*0Sstevel@tonic-gate c = *str++;
365*0Sstevel@tonic-gate nextc:
366*0Sstevel@tonic-gate if (*dp++ == c) {
367*0Sstevel@tonic-gate c = *dp++;
368*0Sstevel@tonic-gate break;
369*0Sstevel@tonic-gate }
370*0Sstevel@tonic-gate dp++;
371*0Sstevel@tonic-gate if (*dp)
372*0Sstevel@tonic-gate goto nextc;
373*0Sstevel@tonic-gate if (isdigit(c)) {
374*0Sstevel@tonic-gate c -= '0', i = 2;
375*0Sstevel@tonic-gate do
376*0Sstevel@tonic-gate c <<= 3, c |= *str++ - '0';
377*0Sstevel@tonic-gate while (--i && isdigit(*str));
378*0Sstevel@tonic-gate }
379*0Sstevel@tonic-gate break;
380*0Sstevel@tonic-gate }
381*0Sstevel@tonic-gate *cp++ = (char) c;
382*0Sstevel@tonic-gate }
383*0Sstevel@tonic-gate *cp++ = 0;
384*0Sstevel@tonic-gate str = *area;
385*0Sstevel@tonic-gate *area = cp;
386*0Sstevel@tonic-gate return (str);
387*0Sstevel@tonic-gate }
388*0Sstevel@tonic-gate
389*0Sstevel@tonic-gate #include <sys/ioctl.h>
390*0Sstevel@tonic-gate
391*0Sstevel@tonic-gate static void
tngetsize(char * bp)392*0Sstevel@tonic-gate tngetsize(char *bp)
393*0Sstevel@tonic-gate {
394*0Sstevel@tonic-gate struct winsize ws;
395*0Sstevel@tonic-gate char *np, *cp;
396*0Sstevel@tonic-gate
397*0Sstevel@tonic-gate if (ioctl(1, TIOCGWINSZ, (char *)&ws) < 0)
398*0Sstevel@tonic-gate return;
399*0Sstevel@tonic-gate if (ws.ws_row == 0 || ws.ws_col == 0 ||
400*0Sstevel@tonic-gate ws.ws_row > 999 || ws.ws_col > 999)
401*0Sstevel@tonic-gate return;
402*0Sstevel@tonic-gate cp = index(bp, ':'); /* find start of description */
403*0Sstevel@tonic-gate bp = rindex(bp, 0); /* find end of description */
404*0Sstevel@tonic-gate np = bp + 15; /* allow enough room for stuff below */
405*0Sstevel@tonic-gate while (bp >= cp) /* move description right 15 chars */
406*0Sstevel@tonic-gate *np-- = *bp--;
407*0Sstevel@tonic-gate bp++; /* bp now points to where ':' used to be */
408*0Sstevel@tonic-gate *bp++ = ':';
409*0Sstevel@tonic-gate *bp++ = 'l';
410*0Sstevel@tonic-gate *bp++ = 'i';
411*0Sstevel@tonic-gate *bp++ = '#';
412*0Sstevel@tonic-gate bp = appendsmalldec(bp, ws.ws_row);
413*0Sstevel@tonic-gate *bp++ = ':';
414*0Sstevel@tonic-gate *bp++ = 'c';
415*0Sstevel@tonic-gate *bp++ = 'o';
416*0Sstevel@tonic-gate *bp++ = '#';
417*0Sstevel@tonic-gate bp = appendsmalldec(bp, ws.ws_col);
418*0Sstevel@tonic-gate *bp++ = ':';
419*0Sstevel@tonic-gate while (bp <= np) /* space fill to start of orig description */
420*0Sstevel@tonic-gate *bp++ = ' ';
421*0Sstevel@tonic-gate }
422*0Sstevel@tonic-gate
423*0Sstevel@tonic-gate static char *
appendsmalldec(char * bp,int val)424*0Sstevel@tonic-gate appendsmalldec(char *bp, int val)
425*0Sstevel@tonic-gate {
426*0Sstevel@tonic-gate int i;
427*0Sstevel@tonic-gate
428*0Sstevel@tonic-gate if ((i = val / 100) != 0) {
429*0Sstevel@tonic-gate *bp++ = '0' + i;
430*0Sstevel@tonic-gate val %= 100;
431*0Sstevel@tonic-gate if (0 == val / 10)
432*0Sstevel@tonic-gate *bp++ = '0'; /* place holder because next test fails */
433*0Sstevel@tonic-gate }
434*0Sstevel@tonic-gate if ((i = val / 10) != 0)
435*0Sstevel@tonic-gate *bp++ = '0' + i;
436*0Sstevel@tonic-gate *bp++ = '0' + val % 10;
437*0Sstevel@tonic-gate return (bp);
438*0Sstevel@tonic-gate }
439