Pristine Ack-5.5
[Ack-5.5.git] / lang / cem / libcc.ansi / misc / termcap.c
1 /*
2  *      termcap.c       1.1     20/7/87         agc     Joypace Ltd
3  *
4  *      Copyright Joypace Ltd, London, UK, 1987. All rights reserved.
5  *      This file may be freely distributed provided that this notice
6  *      remains attached.
7  *
8  *      A public domain implementation of the termcap(3) routines.
9  *
10  *      Made fully functional by Ceriel J.H. Jacobs.
11  *
12  * BUGS:
13  *      - does not check termcap entry sizes
14  *      - not fully tested
15  */
16 /* $Id: termcap.c,v 1.3 1994/06/24 11:45:47 ceriel Exp $ */
17
18 #include        <stdio.h>
19 #include        <stdlib.h>
20 #include        <string.h>
21
22 #define CAPABLEN        2
23
24 #define ISSPACE(c)      ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == '\n')
25 #define ISDIGIT(x)      ((x) >= '0' && (x) <= '9')
26
27 short   ospeed;         /* output speed */
28 char    PC;             /* padding character */
29 char    *BC;            /* back cursor movement */
30 char    *UP;            /* up cursor movement */
31
32 static const char       *capab;         /* the capability itself */
33 static int      check_for_tc(void);
34 static int      match_name(const char *buf, const char *name);
35
36 /*
37  *      tgetent - get the termcap entry for terminal name, and put it
38  *      in bp (which must be an array of 1024 chars). Returns 1 if
39  *      termcap entry found, 0 if not found, and -1 if file not found.
40  */
41 int
42 tgetent(char *bp, const char *name)
43 {
44         FILE    *fp;
45         char    *file;
46         char    *cp;
47         char    buf[1024];
48
49         capab = bp;
50         if ((file = getenv("TERMCAP")) != (char *) NULL) {
51                 if (*file != '/' &&
52                     (cp = getenv("TERM")) != NULL && strcmp(name, cp) == 0) {
53                         (void) strcpy(bp, file);
54                         return(1);
55                 }
56                 else file = "/etc/termcap";
57         } else
58                 file = "/etc/termcap";
59         if ((fp = fopen(file, "r")) == (FILE *) NULL)
60                 return(-1); 
61         while (fgets(buf, 1024, fp) != NULL) {
62                 if (buf[0] == '#') continue;
63                 while (*(cp = &buf[strlen(buf) - 2]) == '\\')
64                         if (fgets(cp, 1024, fp) == NULL)
65                                 return (0);
66                 if (match_name(buf, name)) {
67                         strcpy(bp, buf);
68                         fclose(fp);
69                         return(check_for_tc());
70                 }
71         }
72         fclose(fp);
73         return(0);
74 }
75
76 /*
77  *      Compare the terminal name with each termcap entry name; Return 1 if a
78  *      match is found.
79  */
80 static int
81 match_name(const char *buf, const char *name)
82 {
83         register const char *tp = buf;
84         register const char *np;
85
86         for (;;) {
87                 for (np = name; *np && *tp == *np; np++, tp++) { }
88                 if (*np == 0 && (*tp == '|' || *tp == ':' || *tp == 0))
89                         return(1);
90                 while (*tp != 0 && *tp != '|' && *tp != ':') tp++;
91                 if (*tp++ != '|') return (0);
92         }
93 }
94
95 /*
96  *      Handle tc= definitions recursively.
97  */
98 static int
99 check_for_tc(void)
100 {
101         static int      count = 0;
102         const char      *savcapab = capab;
103         char            buf[1024];
104         char            terminalname[128];
105         register char   *p = (char *)capab + strlen(capab) - 2, *q;
106
107         while (*p != ':')
108                 if (--p < (char *)capab)
109                         return(0);      /* no : in termcap entry */
110         if (p[1] != 't' || p[2] != 'c')
111                 return(1);
112         if (count > 16) return(0);      /* recursion in tc= definitions */
113         count++;
114         strcpy(terminalname, &p[4]);
115         q = terminalname;
116         while (*q && *q != ':') q++;
117         *q = 0;
118         if (tgetent(buf, terminalname) != 1) {
119                 --count;
120                 return(0);
121         }
122         --count;
123         for (q = buf; *q && *q != ':'; q++) { }
124         strcpy(p, q);
125         capab = savcapab;
126         return(1);
127 }
128
129 /*
130  *      tgetnum - get the numeric terminal capability corresponding
131  *      to id. Returns the value, -1 if invalid.
132  */
133 int
134 tgetnum(const char *id)
135 {
136         const char      *cp;
137         int     ret;
138
139         if ((cp = capab) == NULL || id == NULL)
140                 return(-1);
141         while (*++cp != ':')
142                 ;
143         while (*cp) {
144                 cp++;
145                 while (ISSPACE(*cp))
146                         cp++;
147                 if (strncmp(cp, id, CAPABLEN) == 0) {
148                         while (*cp && *cp != ':' && *cp != '#')
149                                 cp++;
150                         if (*cp != '#')
151                                 return(-1);
152                         for (ret = 0, cp++ ; *cp && ISDIGIT(*cp) ; cp++)
153                                 ret = ret * 10 + *cp - '0';
154                         return(ret);
155                 }
156                 while (*cp && *cp != ':')
157                         cp++;
158         }
159         return(-1);
160 }
161
162 /*
163  *      tgetflag - get the boolean flag corresponding to id. Returns -1
164  *      if invalid, 0 if the flag is not in termcap entry, or 1 if it is
165  *      present.
166  */
167 int
168 tgetflag(const char *id)
169 {
170         const char      *cp;
171
172         if ((cp = capab) == NULL || id == NULL)
173                 return(-1);
174         while (*++cp != ':')
175                 ;
176         while (*cp) {
177                 cp++;
178                 while (ISSPACE(*cp))
179                         cp++;
180                 if (strncmp(cp, id, CAPABLEN) == 0)
181                         return(1);
182                 while (*cp && *cp != ':')
183                         cp++;
184         }
185         return(0);
186 }
187
188 /*
189  *      tgetstr - get the string capability corresponding to id and place
190  *      it in area (advancing area at same time). Expand escape sequences
191  *      etc. Returns the string, or NULL if it can't do it.
192  */
193 char *
194 tgetstr(const char *id, char ** const area)
195 {
196         const char      *cp;
197         char    *ret;
198         int     i;
199
200         if ((cp = capab) == NULL || id == NULL)
201                 return(NULL);
202         while (*++cp != ':')
203                 ;
204         while (*cp) {
205                 cp++;
206                 while (ISSPACE(*cp))
207                         cp++;
208                 if (strncmp(cp, id, CAPABLEN) == 0) {
209                         while (*cp && *cp != ':' && *cp != '=')
210                                 cp++;
211                         if (*cp != '=')
212                                 return(NULL);
213                         for (ret = *area, cp++; *cp && *cp != ':' ; (*area)++, cp++)
214                                 switch(*cp) {
215                                 case '^' :
216                                         **area = *++cp - 'A' + 1;
217                                         break;
218                                 case '\\' :
219                                         switch(*++cp) {
220                                         case 'E' :
221                                                 **area = '\033';
222                                                 break;
223                                         case 'n' :
224                                                 **area = '\n';
225                                                 break;
226                                         case 'r' :
227                                                 **area = '\r';
228                                                 break;
229                                         case 't' :
230                                                 **area = '\t';
231                                                 break;
232                                         case 'b' :
233                                                 **area = '\b';
234                                                 break;
235                                         case 'f' :
236                                                 **area = '\f';
237                                                 break;
238                                         case '0' :
239                                         case '1' :
240                                         case '2' :
241                                         case '3' :
242                                                 for (i=0 ; *cp && ISDIGIT(*cp) ; cp++)
243                                                         i = i * 8 + *cp - '0';
244                                                 **area = i;
245                                                 cp--;
246                                                 break;
247                                         case '^' :
248                                         case '\\' :
249                                                 **area = *cp;
250                                                 break;
251                                         }
252                                         break;
253                                 default :
254                                         **area = *cp;
255                                 }
256                         *(*area)++ = '\0';
257                         return(ret);
258                 }
259                 while (*cp && *cp != ':')
260                         cp++;
261         }
262         return(NULL);
263 }
264
265 /*
266  *      tgoto - given the cursor motion string cm, make up the string
267  *      for the cursor to go to (destcol, destline), and return the string.
268  *      Returns "OOPS" if something's gone wrong, or the string otherwise.
269  */
270 char *
271 tgoto(const char *cm, int destcol, int destline)
272 {
273         register char   *rp;
274         static char     ret[24];
275         char            added[16];
276         int             *dp = &destline;
277         int             numval;
278         int             swapped = 0;
279
280         added[0] = 0;
281         for (rp = ret ; *cm ; cm++) {
282                 if (*cm == '%') {
283                         switch(*++cm) {
284                         case '>' :
285                                 if (dp == NULL)
286                                         return("OOPS");
287                                 cm++;
288                                 if (*dp > *cm++) {
289                                         *dp += *cm;
290                                 }
291                                 break;
292                         case '+' :
293                         case '.' :
294                                 if (dp == NULL)
295                                         return("OOPS");
296                                 if (*cm == '+') *dp = *dp + *++cm;
297                                 for (;;) {
298                                     switch(*dp) {
299                                     case 0:
300                                     case 04:
301                                     case '\t':
302                                     case '\n':
303                                         /* filter these out */
304                                         if (dp == &destcol || swapped || UP) {
305                                                 strcat(added, dp == &destcol || swapped ?
306                                                         (BC ? BC : "\b") :
307                                                         UP);
308                                                 (*dp)++;
309                                                 continue;
310                                         }
311                                     }
312                                     break;
313                                 }
314                                 *rp++ = *dp;
315                                 dp = (dp == &destline) ? &destcol : NULL;
316                                 break;
317
318                         case 'r' : {
319                                 int tmp = destline;
320
321                                 destline = destcol;
322                                 destcol = tmp;
323                                 swapped = 1 - swapped;
324                                 break;
325                         }
326                         case 'n' :
327                                 destcol ^= 0140;
328                                 destline ^= 0140;
329                                 break;
330
331                         case '%' :
332                                 *rp++ = '%';
333                                 break;
334
335                         case 'i' :
336                                 destcol++;
337                                 destline++;
338                                 break;
339
340                         case 'B' :
341                                 if (dp == NULL)
342                                         return("OOPS");
343                                 *dp = 16 * (*dp / 10) + *dp % 10;
344                                 break;
345
346                         case 'D' :
347                                 if (dp == NULL)
348                                         return("OOPS");
349                                 *dp = *dp - 2 * (*dp % 16);
350                                 break;
351
352                         case 'd' :
353                         case '2' :
354                         case '3' :
355                                 if (dp == NULL)
356                                         return("OOPS");
357                                 numval = *dp;
358                                 dp = (dp == &destline) ? &destcol : NULL;
359                                 if (numval >= 100) {
360                                         *rp++ = '0' + numval / 100;
361                                 }
362                                 else if (*cm == '3') {
363                                         *rp++ = ' ';
364                                 }
365                                 if (numval >= 10) {
366                                         *rp++ = '0' + ((numval%100)/10);
367                                 }
368                                 else if (*cm == '3' || *cm == '2') {
369                                         *rp++ = ' ';
370                                 }
371                                 *rp++ = '0' + (numval%10);
372                                 break;
373                         default :
374                                 return("OOPS");
375                         }
376                 }
377                 else *rp++ = *cm;
378         }
379         *rp = '\0';
380         strcpy(rp, added);
381         return(ret);
382 }
383
384 static int tens_of_ms_p_char[] = {      /* index as returned by gtty */
385                                         /* assume 10 bits per char */
386         0, 2000, 1333, 909, 743, 666, 500, 333, 166, 83, 55, 41, 20, 10, 5, 2
387 };
388 /*
389  *      tputs - put the string cp out onto the terminal, using the function
390  *      outc. Also handle padding.
391  */
392 int
393 tputs(register const char *cp, int affcnt, int (*outc)(int))
394 {
395         int delay = 0;
396         if (cp == NULL)
397                 return(1);
398         while (ISDIGIT(*cp)) {
399                 delay = delay * 10 + (*cp++ - '0');
400         }
401         delay *= 10;
402         if (*cp == '.') {
403                 cp++;
404                 if (ISDIGIT(*cp)) {
405                         delay += *cp++ - '0';
406                 }
407                 while (ISDIGIT(*cp)) cp++;
408         }
409         if (*cp == '*') {
410                 delay *= affcnt;
411                 cp++;
412         }
413         while (*cp)
414                 (*outc)(*cp++);
415         if (delay != 0 &&
416             ospeed > 0 &&
417             ospeed < (sizeof tens_of_ms_p_char / sizeof tens_of_ms_p_char[0])) {
418                 delay = (delay + tens_of_ms_p_char[ospeed] - 1) / 
419                                   tens_of_ms_p_char[ospeed];
420                 while (delay--) (*outc)(PC);
421         }
422         return(1);
423 }
424
425 /*
426  *      That's all, folks...
427  */