1 /* vi:set ts=8 sts=4 sw=4: */
3 * The following software is (C) 1984 Peter da Silva, the Mad Australian, in
4 * the public domain. It may be re-distributed for any purpose with the
5 * inclusion of this notice.
8 /* Modified by Bram Moolenaar for use with VIM - Vi Improved. */
9 /* A few bugs removed by Olaf 'Rhialto' Seibert. */
11 /* TERMLIB: Terminal independent database. */
14 #include "termlib.pro"
16 #if !defined(AMIGA) && !defined(VMS) && !defined(MACOS) && !defined(RISCOS)
20 static int getent
__ARGS((char *, char *, FILE *, int));
21 static int nextent
__ARGS((char *, FILE *, int));
22 static int _match
__ARGS((char *, char *));
23 static char *_addfmt
__ARGS((char *, char *, int));
24 static char *_find
__ARGS((char *, char *));
27 * Global variables for termlib
30 char *tent
; /* Pointer to terminal entry, set by tgetent */
31 char PC
= 0; /* Pad character, default NULL */
32 char *UP
= 0, *BC
= 0; /* Pointers to UP and BC strings from database */
33 short ospeed
; /* Baud rate (1-16, 1=300, 16=19200), as in stty */
38 * Purpose: Get termcap entry for <term> into buffer at <tbuf>.
40 * Calling conventions: char tbuf[TBUFSZ+], term=canonical name for terminal.
42 * Returned values: 1 = success, -1 = can't open file,
43 * 0 = can't find terminal.
46 * - Should probably supply static buffer.
47 * - Uses environment variables "TERM" and "TERMCAP". If TERM = term (that is,
48 * if the argument matches the environment) then it looks at TERMCAP.
49 * - If TERMCAP begins with a slash, then it assumes this is the file to
50 * search rather than /etc/termcap.
51 * - If TERMCAP does not begin with a slash, and it matches TERM, then this is
53 * - This could be simplified considerably for non-UNIX systems.
58 # define TERMCAPFILE "s:termcap"
61 # define TERMCAPFILE "VIMRUNTIME:termcap"
63 # define TERMCAPFILE "/etc/termcap"
70 char *tbuf
; /* Buffer to hold termcap entry, TBUFSZ bytes max */
71 char *term
; /* Name of terminal */
73 char tcbuf
[32]; /* Temp buffer to handle */
74 char *tcptr
= tcbuf
; /* extended entries */
75 char *tcap
= TERMCAPFILE
; /* Default termcap file */
81 if ((tmp
= (char *)mch_getenv((char_u
*)"TERMCAP")) != NULL
)
83 if (*tmp
== '/') /* TERMCAP = name of termcap file */
87 /* Convert /usr/share/lib/termcap to usr:share/lib/termcap */
89 tmp
= strchr(tcap
, '/');
94 else /* TERMCAP = termcap entry itself */
96 int tlen
= strlen(term
);
98 while (*tmp
&& *tmp
!= ':') /* Check if TERM matches */
104 nexttmp
= _find(tmp
, ":|"); /* Rhialto */
105 if (tmp
+tlen
== nexttmp
&& _match(tmp
, term
) == tlen
)
116 if (!(termcap
= mch_fopen(tcap
, "r")))
123 while (getent(tbuf
+ len
, term
, termcap
, TBUFSZ
- len
))
125 tcptr
= tcbuf
; /* Rhialto */
126 if ((term
= tgetstr("tc", &tcptr
))) /* extended entry */
134 tent
= tbuf
; /* reset it back to the beginning */
143 getent(tbuf
, term
, termcap
, buflen
)
149 int tlen
= strlen(term
);
151 while (nextent(tbuf
, termcap
, buflen
)) /* For each possible entry */
154 while (*tptr
&& *tptr
!= ':') /* : terminates name field */
158 while (*tptr
== '|') /* | separates names */
160 nexttptr
= _find(tptr
, ":|"); /* Rhialto */
161 if (tptr
+ tlen
== nexttptr
&&
162 _match(tptr
, term
) == tlen
) /* FOUND! */
167 else /* Look for next name */
175 nextent(tbuf
, termcap
, buflen
) /* Read 1 entry from TERMCAP file */
180 char *lbuf
= tbuf
; /* lbuf=line buffer */
181 /* read lines straight into buffer */
183 while (lbuf
< tbuf
+buflen
&& /* There's room and */
184 fgets(lbuf
, (int)(tbuf
+buflen
-lbuf
), termcap
)) /* another line */
186 int llen
= strlen(lbuf
);
188 if (*lbuf
== '#') /* eat comments */
190 if (lbuf
[-1] == ':' && /* and whitespace */
194 mch_memmove(lbuf
, lbuf
+ 2, strlen(lbuf
+ 2) + 1);
197 if (lbuf
[llen
-2] == '\\') /* and continuations */
201 lbuf
[llen
-1]=0; /* no continuation, return */
206 return 0; /* ran into end of file */
212 * Purpose: returns flag true or false as to the existence of a given entry.
213 * used with 'bs', 'am', etc...
215 * Calling conventions: id is the 2 character capability id.
217 * Returned values: 1 for success, 0 for failure.
224 char buf
[256], *ptr
= buf
;
226 return tgetstr(id
, &ptr
) ? 1 : 0;
232 * Purpose: get numeric value such as 'li' or 'co' from termcap.
234 * Calling conventions: id = 2 character id.
236 * Returned values: -1 for failure, else numerical value.
246 if (tgetstr(id
, &ptr
))
255 * Purpose: get terminal capability string from database.
257 * Calling conventions: id is the two character capability id.
258 * (*buf) points into a hold buffer for the
259 * id. the capability is copied into the buffer
260 * and (*buf) is advanced to point to the next
261 * free byte in the buffer.
263 * Returned values: 0 = no such entry, otherwise returns original
264 * (*buf) (now a pointer to the string).
267 * It also decodes certain escape sequences in the buffer.
268 * they should be obvious from the code:
270 * \n, \r, \t, \f, \b match the 'c' escapes.
271 * ^x matches control-x (^@...^_).
272 * \nnn matches nnn octal.
273 * \x, where x is anything else, matches x. I differ
274 * from the standard library here, in that I allow ^: to match
283 int len
= strlen(id
);
289 tmp
= _find(tmp
, ":"); /* For each field */
290 while (*tmp
== ':') /* skip empty fields */
295 if (_match(id
, tmp
) == len
) {
296 tmp
+= len
; /* find '=' '@' or '#' */
297 if (*tmp
== '@') /* :xx@: entry for tc */
298 return 0; /* deleted entry */
300 while (*++tmp
&& *tmp
!= ':') { /* not at end of field */
302 case '\\': /* Expand escapes here */
304 case 0: /* ignore backslashes */
305 tmp
--; /* at end of entry */
306 break; /* shouldn't happen */
337 /* get up to three digits */
338 for (i
= 0; i
< 3 && VIM_ISDIGIT(*tmp
); ++i
)
339 **buf
= **buf
* 8 + *tmp
++ - '0';
343 default: /* \x, for all other x */
347 case '^': /* control characters */
349 *(*buf
)++ = Ctrl_chr(*tmp
);
366 * Purpose: decode cm cursor motion string.
368 * Calling conventions: cm is cursor motion string. line, col, are the
369 * desired destination.
371 * Returned values: a string pointing to the decoded string, or "OOPS" if it
375 * The accepted escapes are:
376 * %d as in printf, 0 origin.
377 * %2, %3 like %02d, %03d in printf.
379 * %+x adds <x> to value, then %.
380 * %>xy if value>x, adds y. No output.
381 * %i increments line& col, no output.
382 * %r reverses order of line&col. No output.
383 * %% prints as a single %.
384 * %n exclusive or row & col with 0140.
386 * %D reverse coding (x-2*(x%16)), no output.
391 char *cm
; /* cm string, from termcap */
392 int col
, /* column, x position */
393 line
; /* line, y position */
395 char gx
, gy
, /* x, y */
396 *ptr
, /* pointer in 'cm' */
397 reverse
= 0, /* reverse flag */
398 *bufp
, /* pointer in returned string */
399 addup
= 0, /* add upline */
400 addbak
= 0, /* add backup */
402 static char buffer
[32];
405 return "OOPS"; /* Kludge, but standard */
411 if ((c
= *ptr
++) != '%') { /* normal char */
413 } else { /* % escape */
415 case 'd': /* decimal */
416 bufp
= _addfmt(bufp
, "%d", line
);
419 case '2': /* 2 digit decimal */
420 bufp
= _addfmt(bufp
, "%02d", line
);
423 case '3': /* 3 digit decimal */
424 bufp
= _addfmt(bufp
, "%03d", line
);
427 case '>': /* %>xy: if >x, add y */
430 if (col
>gx
) col
+= gy
;
431 if (line
>gx
) line
+= gy
;
433 case '+': /* %+c: add c */
435 case '.': /* print x/y */
436 if (line
== '\t' || /* these are */
437 line
== '\n' || /* chars that */
438 line
== '\004' || /* UNIX hates */
440 line
++; /* so go to next pos */
441 if (reverse
== (line
== col
))
442 addup
=1; /* and mark UP */
444 addbak
=1; /* or BC */
449 case 'r': /* r: reverse */
455 case 'i': /* increment (1-origin screen) */
459 case '%': /* %%=% literally */
462 case 'n': /* magic DM2500 code */
466 case 'B': /* bcd encoding */
467 line
= line
/10<<4+line
%10;
468 col
= col
/10<<4+col
%10;
470 case 'D': /* magic Delta Data code */
471 line
= line
-2*(line
&15);
472 col
= col
-2*(col
&15);
474 default: /* Unknown escape */
480 if (addup
) /* add upline */
483 while (VIM_ISDIGIT(*ptr
) || *ptr
== '.')
491 if (addbak
) /* add backspace */
494 while (VIM_ISDIGIT(*ptr
) || *ptr
== '.')
512 * Purpose: decode padding information
514 * Calling conventions: cp = string to be padded, affcnt = # of items affected
515 * (lines, characters, whatever), outc = routine to output 1 character.
517 * Returned values: none
520 * cp has padding information ahead of it, in the form
521 * nnnTEXT or nnn*TEXT. nnn is the number of milliseconds to delay,
522 * and may be a decimal (nnn.mmm). If the asterisk is given, then
523 * the delay is multiplied by afcnt. The delay is produced by outputting
524 * a number of nulls (or other padding char) after printing the
532 600, 1200, 1800, 2400,
533 4800, 9600, 19200, 19200 };
536 tputs(cp
, affcnt
, outc
)
537 char *cp
; /* string to print */
538 int affcnt
; /* Number of lines affected */
539 void (*outc
) __ARGS((unsigned int));/* routine to output 1 character */
541 long frac
, /* 10^(#digits after decimal point) */
542 counter
, /* digits */
543 atol
__ARGS((const char *));
545 if (VIM_ISDIGIT(*cp
)) {
548 while (VIM_ISDIGIT(*cp
))
549 counter
= counter
* 10L + (long)(*cp
++ - '0');
551 while (VIM_ISDIGIT(*++cp
)) {
552 counter
= counter
* 10L + (long)(*cp
++ - '0');
555 if (*cp
!='*') { /* multiply by affected lines */
556 if (affcnt
>1) affcnt
= 1;
561 /* Calculate number of characters for padding counter/frac ms delay */
563 counter
= (counter
* _bauds
[ospeed
] * (long)affcnt
) / frac
;
565 while (*cp
) /* output string */
568 while (counter
--) /* followed by pad characters */
580 * Purpose: Utility routines for TERMLIB functions.
584 _match(s1
, s2
) /* returns length of text common to s1 and s2 */
589 while (s1
[i
] && s1
[i
] == s2
[i
])
596 * finds next c in s that's a member of set, returns pointer
606 while (*ptr
&& *s
!= *ptr
)
617 * add val to buf according to format fmt
620 _addfmt(buf
, fmt
, val
)
624 sprintf(buf
, fmt
, val
);