blob: 42eccf5e90c2b5321f69d5db0671128001fb2662 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet: */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002/*
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.
6 */
7
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +01008// Modified by Bram Moolenaar for use with VIM - Vi Improved.
9// A few bugs removed by Olaf 'Rhialto' Seibert.
Bram Moolenaar071d4272004-06-13 20:20:40 +000010
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +010011// TERMLIB: Terminal independent database.
Bram Moolenaar071d4272004-06-13 20:20:40 +000012
13#include "vim.h"
14#include "termlib.pro"
15
Bram Moolenaard0573012017-10-28 21:11:06 +020016#if !defined(AMIGA) && !defined(VMS)
Bram Moolenaar071d4272004-06-13 20:20:40 +000017# include <sgtty.h>
18#endif
19
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010020static int getent(char *, char *, FILE *, int);
21static int nextent(char *, FILE *, int);
22static int _match(char *, char *);
23static char *_addfmt(char *, char *, int);
24static char *_find(char *, char *);
Bram Moolenaar071d4272004-06-13 20:20:40 +000025
26/*
27 * Global variables for termlib
28 */
29
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +010030char *tent; // Pointer to terminal entry, set by tgetent
31char PC = 0; // Pad character, default NULL
32char *UP = 0, *BC = 0; // Pointers to UP and BC strings from database
33short ospeed; // Baud rate (1-16, 1=300, 16=19200), as in stty
Bram Moolenaar071d4272004-06-13 20:20:40 +000034
35/*
36 * Module: tgetent
37 *
38 * Purpose: Get termcap entry for <term> into buffer at <tbuf>.
39 *
40 * Calling conventions: char tbuf[TBUFSZ+], term=canonical name for terminal.
41 *
42 * Returned values: 1 = success, -1 = can't open file,
43 * 0 = can't find terminal.
44 *
45 * Notes:
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
52 * used as the entry.
53 * - This could be simplified considerably for non-UNIX systems.
54 */
55
56#ifndef TERMCAPFILE
57# ifdef AMIGA
58# define TERMCAPFILE "s:termcap"
59# else
60# ifdef VMS
61# define TERMCAPFILE "VIMRUNTIME:termcap"
62# else
63# define TERMCAPFILE "/etc/termcap"
64# endif
65# endif
66#endif
67
68 int
Bram Moolenaar764b23c2016-01-30 21:10:09 +010069tgetent(
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +010070 char *tbuf, // Buffer to hold termcap entry, TBUFSZ bytes max
71 char *term) // Name of terminal
Bram Moolenaar071d4272004-06-13 20:20:40 +000072{
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +010073 char tcbuf[32]; // Temp buffer to handle
74 char *tcptr = tcbuf; // extended entries
75 char *tcap = TERMCAPFILE; // Default termcap file
Bram Moolenaar071d4272004-06-13 20:20:40 +000076 char *tmp;
77 FILE *termcap;
78 int retval = 0;
79 int len;
80
81 if ((tmp = (char *)mch_getenv((char_u *)"TERMCAP")) != NULL)
82 {
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +010083 if (*tmp == '/') // TERMCAP = name of termcap file
Bram Moolenaar071d4272004-06-13 20:20:40 +000084 {
85 tcap = tmp ;
86#if defined(AMIGA)
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +010087 // Convert /usr/share/lib/termcap to usr:share/lib/termcap
Bram Moolenaar071d4272004-06-13 20:20:40 +000088 tcap++;
89 tmp = strchr(tcap, '/');
90 if (tmp)
91 *tmp = ':';
92#endif
93 }
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +010094 else // TERMCAP = termcap entry itself
Bram Moolenaar071d4272004-06-13 20:20:40 +000095 {
96 int tlen = strlen(term);
97
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +010098 while (*tmp && *tmp != ':') // Check if TERM matches
Bram Moolenaar071d4272004-06-13 20:20:40 +000099 {
100 char *nexttmp;
101
102 while (*tmp == '|')
103 tmp++;
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100104 nexttmp = _find(tmp, ":|"); // Rhialto
Bram Moolenaar071d4272004-06-13 20:20:40 +0000105 if (tmp+tlen == nexttmp && _match(tmp, term) == tlen)
106 {
107 strcpy(tbuf, tmp);
108 tent = tbuf;
109 return 1;
110 }
111 else
112 tmp = nexttmp;
113 }
114 }
115 }
116 if (!(termcap = mch_fopen(tcap, "r")))
117 {
118 strcpy(tbuf, tcap);
119 return -1;
120 }
121
122 len = 0;
123 while (getent(tbuf + len, term, termcap, TBUFSZ - len))
124 {
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100125 tcptr = tcbuf; // Rhialto
126 if ((term = tgetstr("tc", &tcptr))) // extended entry
Bram Moolenaar071d4272004-06-13 20:20:40 +0000127 {
128 rewind(termcap);
129 len = strlen(tbuf);
130 }
131 else
132 {
133 retval = 1;
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100134 tent = tbuf; // reset it back to the beginning
Bram Moolenaar071d4272004-06-13 20:20:40 +0000135 break;
136 }
137 }
138 fclose(termcap);
139 return retval;
140}
141
142 static int
Bram Moolenaar2f6271b2016-02-29 21:20:48 +0100143getent(char *tbuf, char *term, FILE *termcap, int buflen)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000144{
145 char *tptr;
146 int tlen = strlen(term);
147
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100148 while (nextent(tbuf, termcap, buflen)) // For each possible entry
Bram Moolenaar071d4272004-06-13 20:20:40 +0000149 {
150 tptr = tbuf;
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100151 while (*tptr && *tptr != ':') // : terminates name field
Bram Moolenaar071d4272004-06-13 20:20:40 +0000152 {
153 char *nexttptr;
154
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100155 while (*tptr == '|') // | separates names
Bram Moolenaar071d4272004-06-13 20:20:40 +0000156 tptr++;
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100157 nexttptr = _find(tptr, ":|"); // Rhialto
Bram Moolenaar071d4272004-06-13 20:20:40 +0000158 if (tptr + tlen == nexttptr &&
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100159 _match(tptr, term) == tlen) // FOUND!
Bram Moolenaar071d4272004-06-13 20:20:40 +0000160 {
161 tent = tbuf;
162 return 1;
163 }
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100164 else // Look for next name
Bram Moolenaar071d4272004-06-13 20:20:40 +0000165 tptr = nexttptr;
166 }
167 }
168 return 0;
169}
170
Bram Moolenaar764b23c2016-01-30 21:10:09 +0100171/*
172 * Read 1 entry from TERMCAP file.
173 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000174 static int
Bram Moolenaar764b23c2016-01-30 21:10:09 +0100175nextent(char *tbuf, FILE *termcap, int buflen)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000176{
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100177 char *lbuf = tbuf; // lbuf=line buffer
178 // read lines straight into buffer
Bram Moolenaar071d4272004-06-13 20:20:40 +0000179
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100180 while (lbuf < tbuf+buflen && // There's room and
181 fgets(lbuf, (int)(tbuf+buflen-lbuf), termcap)) // another line
Bram Moolenaar071d4272004-06-13 20:20:40 +0000182 {
183 int llen = strlen(lbuf);
184
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100185 if (*lbuf == '#') // eat comments
Bram Moolenaar071d4272004-06-13 20:20:40 +0000186 continue;
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100187 if (lbuf[-1] == ':' && // and whitespace
Bram Moolenaar071d4272004-06-13 20:20:40 +0000188 lbuf[0] == '\t' &&
189 lbuf[1] == ':')
190 {
Bram Moolenaar446cb832008-06-24 21:56:24 +0000191 STRMOVE(lbuf, lbuf + 2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000192 llen -= 2;
193 }
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100194 if (lbuf[llen-2] == '\\') // and continuations
Bram Moolenaar071d4272004-06-13 20:20:40 +0000195 lbuf += llen-2;
196 else
197 {
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100198 lbuf[llen-1]=0; // no continuation, return
Bram Moolenaar071d4272004-06-13 20:20:40 +0000199 return 1;
200 }
201 }
202
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100203 return 0; // ran into end of file
Bram Moolenaar071d4272004-06-13 20:20:40 +0000204}
205
206/*
207 * Module: tgetflag
208 *
209 * Purpose: returns flag true or false as to the existence of a given entry.
210 * used with 'bs', 'am', etc...
211 *
212 * Calling conventions: id is the 2 character capability id.
213 *
214 * Returned values: 1 for success, 0 for failure.
215 */
216
217 int
Bram Moolenaar764b23c2016-01-30 21:10:09 +0100218tgetflag(char *id)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000219{
220 char buf[256], *ptr = buf;
221
222 return tgetstr(id, &ptr) ? 1 : 0;
223}
224
225/*
226 * Module: tgetnum
227 *
228 * Purpose: get numeric value such as 'li' or 'co' from termcap.
229 *
230 * Calling conventions: id = 2 character id.
231 *
232 * Returned values: -1 for failure, else numerical value.
233 */
234
235 int
Bram Moolenaar764b23c2016-01-30 21:10:09 +0100236tgetnum(char *id)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000237{
238 char *ptr, buf[256];
239 ptr = buf;
240
241 if (tgetstr(id, &ptr))
242 return atoi(buf);
243 else
244 return 0;
245}
246
247/*
248 * Module: tgetstr
249 *
250 * Purpose: get terminal capability string from database.
251 *
252 * Calling conventions: id is the two character capability id.
253 * (*buf) points into a hold buffer for the
254 * id. the capability is copied into the buffer
255 * and (*buf) is advanced to point to the next
256 * free byte in the buffer.
257 *
258 * Returned values: 0 = no such entry, otherwise returns original
259 * (*buf) (now a pointer to the string).
260 *
261 * Notes
262 * It also decodes certain escape sequences in the buffer.
263 * they should be obvious from the code:
264 * \E = escape.
265 * \n, \r, \t, \f, \b match the 'c' escapes.
266 * ^x matches control-x (^@...^_).
267 * \nnn matches nnn octal.
268 * \x, where x is anything else, matches x. I differ
269 * from the standard library here, in that I allow ^: to match
270 * :.
271 *
272 */
273
274 char *
Bram Moolenaar764b23c2016-01-30 21:10:09 +0100275tgetstr(char *id, char **buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000276{
277 int len = strlen(id);
278 char *tmp=tent;
279 char *hold;
280 int i;
281
Hirohito Higashia4a00a72025-05-08 22:58:31 +0200282 do
283 {
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100284 tmp = _find(tmp, ":"); // For each field
285 while (*tmp == ':') // skip empty fields
Bram Moolenaar071d4272004-06-13 20:20:40 +0000286 tmp++;
287 if (!*tmp)
288 break;
289
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000290 if (_match(id, tmp) == len)
291 {
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100292 tmp += len; // find '=' '@' or '#'
293 if (*tmp == '@') // :xx@: entry for tc
294 return 0; // deleted entry
Bram Moolenaar071d4272004-06-13 20:20:40 +0000295 hold= *buf;
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000296 while (*++tmp && *tmp != ':') // not at end of field
297 {
298 switch(*tmp)
299 {
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100300 case '\\': // Expand escapes here
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000301 switch(*++tmp)
302 {
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100303 case 0: // ignore backslashes
304 tmp--; // at end of entry
305 break; // shouldn't happen
Bram Moolenaar071d4272004-06-13 20:20:40 +0000306 case 'e':
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100307 case 'E': // ESC
Bram Moolenaar071d4272004-06-13 20:20:40 +0000308 *(*buf)++ = ESC;
309 break;
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100310 case 'n': // \n
Bram Moolenaar071d4272004-06-13 20:20:40 +0000311 *(*buf)++ = '\n';
312 break;
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100313 case 'r': // \r
Bram Moolenaar071d4272004-06-13 20:20:40 +0000314 *(*buf)++ = '\r';
315 break;
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100316 case 't': // \t
Bram Moolenaar071d4272004-06-13 20:20:40 +0000317 *(*buf)++ = '\t';
318 break;
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100319 case 'b': // \b
Bram Moolenaar071d4272004-06-13 20:20:40 +0000320 *(*buf)++ = '\b';
321 break;
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100322 case 'f': // \f
Bram Moolenaar071d4272004-06-13 20:20:40 +0000323 *(*buf)++ = '\f';
324 break;
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100325 case '0': // \nnn
Bram Moolenaar071d4272004-06-13 20:20:40 +0000326 case '1':
327 case '2':
328 case '3':
329 case '4':
330 case '5':
331 case '6':
332 case '7':
333 case '8':
334 case '9':
335 **buf = 0;
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100336 // get up to three digits
Bram Moolenaar071d4272004-06-13 20:20:40 +0000337 for (i = 0; i < 3 && VIM_ISDIGIT(*tmp); ++i)
338 **buf = **buf * 8 + *tmp++ - '0';
339 (*buf)++;
340 tmp--;
341 break;
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100342 default: // \x, for all other x
Bram Moolenaar071d4272004-06-13 20:20:40 +0000343 *(*buf)++= *tmp;
344 }
345 break;
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100346 case '^': // control characters
Bram Moolenaar071d4272004-06-13 20:20:40 +0000347 ++tmp;
348 *(*buf)++ = Ctrl_chr(*tmp);
349 break;
350 default:
351 *(*buf)++ = *tmp;
352 }
353 }
354 *(*buf)++ = 0;
355 return hold;
356 }
357 } while (*tmp);
358
359 return 0;
360}
361
362/*
363 * Module: tgoto
364 *
365 * Purpose: decode cm cursor motion string.
366 *
367 * Calling conventions: cm is cursor motion string. line, col, are the
368 * desired destination.
369 *
370 * Returned values: a string pointing to the decoded string, or "OOPS" if it
371 * cannot be decoded.
372 *
373 * Notes
374 * The accepted escapes are:
375 * %d as in printf, 0 origin.
376 * %2, %3 like %02d, %03d in printf.
377 * %. like %c
378 * %+x adds <x> to value, then %.
379 * %>xy if value>x, adds y. No output.
380 * %i increments line& col, no output.
381 * %r reverses order of line&col. No output.
382 * %% prints as a single %.
383 * %n exclusive or row & col with 0140.
384 * %B BCD, no output.
385 * %D reverse coding (x-2*(x%16)), no output.
386 */
387
388 char *
Bram Moolenaar764b23c2016-01-30 21:10:09 +0100389tgoto(
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100390 char *cm, // cm string, from termcap
391 int col, // column, x position
392 int line) // line, y position
Bram Moolenaar071d4272004-06-13 20:20:40 +0000393{
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100394 char gx, gy, // x, y
395 *ptr, // pointer in 'cm'
396 reverse = 0, // reverse flag
397 *bufp, // pointer in returned string
398 addup = 0, // add upline
399 addbak = 0, // add backup
Bram Moolenaar071d4272004-06-13 20:20:40 +0000400 c;
401 static char buffer[32];
402
403 if (!cm)
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100404 return "OOPS"; // Kludge, but standard
Bram Moolenaar071d4272004-06-13 20:20:40 +0000405
406 bufp = buffer;
407 ptr = cm;
408
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000409 while (*ptr)
410 {
411 if ((c = *ptr++) != '%') // normal char
412 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000413 *bufp++ = c;
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000414 }
415 else
416 { // % escape
417 switch(c = *ptr++)
418 {
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100419 case 'd': // decimal
Bram Moolenaar071d4272004-06-13 20:20:40 +0000420 bufp = _addfmt(bufp, "%d", line);
421 line = col;
422 break;
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100423 case '2': // 2 digit decimal
Bram Moolenaar071d4272004-06-13 20:20:40 +0000424 bufp = _addfmt(bufp, "%02d", line);
425 line = col;
426 break;
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100427 case '3': // 3 digit decimal
Bram Moolenaar071d4272004-06-13 20:20:40 +0000428 bufp = _addfmt(bufp, "%03d", line);
429 line = col;
430 break;
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100431 case '>': // %>xy: if >x, add y
Bram Moolenaar071d4272004-06-13 20:20:40 +0000432 gx = *ptr++;
433 gy = *ptr++;
434 if (col>gx) col += gy;
435 if (line>gx) line += gy;
436 break;
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100437 case '+': // %+c: add c
Bram Moolenaar071d4272004-06-13 20:20:40 +0000438 line += *ptr++;
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100439 case '.': // print x/y
440 if (line == '\t' || // these are
441 line == '\n' || // chars that
442 line == '\004' || // UNIX hates
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000443 line == '\0')
444 {
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100445 line++; // so go to next pos
Bram Moolenaar071d4272004-06-13 20:20:40 +0000446 if (reverse == (line == col))
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100447 addup=1; // and mark UP
Bram Moolenaar071d4272004-06-13 20:20:40 +0000448 else
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100449 addbak=1; // or BC
Bram Moolenaar071d4272004-06-13 20:20:40 +0000450 }
451 *bufp++=line;
452 line = col;
453 break;
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100454 case 'r': // r: reverse
Bram Moolenaar071d4272004-06-13 20:20:40 +0000455 gx = line;
456 line = col;
457 col = gx;
458 reverse = 1;
459 break;
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100460 case 'i': // increment (1-origin screen)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000461 col++;
462 line++;
463 break;
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100464 case '%': // %%=% literally
Bram Moolenaar071d4272004-06-13 20:20:40 +0000465 *bufp++='%';
466 break;
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100467 case 'n': // magic DM2500 code
Bram Moolenaar071d4272004-06-13 20:20:40 +0000468 line ^= 0140;
469 col ^= 0140;
470 break;
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100471 case 'B': // bcd encoding
Bram Moolenaar071d4272004-06-13 20:20:40 +0000472 line = line/10<<4+line%10;
473 col = col/10<<4+col%10;
474 break;
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100475 case 'D': // magic Delta Data code
Bram Moolenaar071d4272004-06-13 20:20:40 +0000476 line = line-2*(line&15);
477 col = col-2*(col&15);
478 break;
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100479 default: // Unknown escape
Bram Moolenaar071d4272004-06-13 20:20:40 +0000480 return "OOPS";
481 }
482 }
483 }
484
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100485 if (addup) // add upline
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000486 if (UP)
487 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000488 ptr=UP;
489 while (VIM_ISDIGIT(*ptr) || *ptr == '.')
490 ptr++;
491 if (*ptr == '*')
492 ptr++;
493 while (*ptr)
494 *bufp++ = *ptr++;
495 }
496
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100497 if (addbak) // add backspace
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000498 if (BC)
499 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000500 ptr=BC;
501 while (VIM_ISDIGIT(*ptr) || *ptr == '.')
502 ptr++;
503 if (*ptr == '*')
504 ptr++;
505 while (*ptr)
506 *bufp++ = *ptr++;
507 }
508 else
509 *bufp++='\b';
510
511 *bufp = 0;
512
513 return(buffer);
514}
515
516/*
517 * Module: tputs
518 *
519 * Purpose: decode padding information
520 *
521 * Calling conventions: cp = string to be padded, affcnt = # of items affected
522 * (lines, characters, whatever), outc = routine to output 1 character.
523 *
524 * Returned values: none
525 *
526 * Notes
527 * cp has padding information ahead of it, in the form
528 * nnnTEXT or nnn*TEXT. nnn is the number of milliseconds to delay,
529 * and may be a decimal (nnn.mmm). If the asterisk is given, then
530 * the delay is multiplied by afcnt. The delay is produced by outputting
531 * a number of nulls (or other padding char) after printing the
532 * TEXT.
533 *
534 */
535
536long _bauds[16]={
537 0, 50, 75, 110,
538 134, 150, 200, 300,
539 600, 1200, 1800, 2400,
540 4800, 9600, 19200, 19200 };
541
542 int
Bram Moolenaar764b23c2016-01-30 21:10:09 +0100543tputs(
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100544 char *cp, // string to print
545 int affcnt, // Number of lines affected
546 void (*outc)(unsigned int)) // routine to output 1 character
Bram Moolenaar071d4272004-06-13 20:20:40 +0000547{
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100548 long frac, // 10^(#digits after decimal point)
549 counter, // digits
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100550 atol(const char *);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000551
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000552 if (VIM_ISDIGIT(*cp))
553 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000554 counter = 0;
555 frac = 1000;
556 while (VIM_ISDIGIT(*cp))
557 counter = counter * 10L + (long)(*cp++ - '0');
558 if (*cp == '.')
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000559 while (VIM_ISDIGIT(*++cp))
560 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000561 counter = counter * 10L + (long)(*cp++ - '0');
562 frac = frac * 10;
563 }
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000564 if (*cp!='*') // multiply by affected lines
565 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000566 if (affcnt>1) affcnt = 1;
567 }
568 else
569 cp++;
570
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100571 // Calculate number of characters for padding counter/frac ms delay
Bram Moolenaar071d4272004-06-13 20:20:40 +0000572 if (ospeed)
573 counter = (counter * _bauds[ospeed] * (long)affcnt) / frac;
574
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100575 while (*cp) // output string
Bram Moolenaar071d4272004-06-13 20:20:40 +0000576 (*outc)(*cp++);
577 if (ospeed)
Bram Moolenaar0d6f5d92019-12-05 21:33:15 +0100578 while (counter--) // followed by pad characters
Bram Moolenaar071d4272004-06-13 20:20:40 +0000579 (*outc)(PC);
580 }
581 else
582 while (*cp)
583 (*outc)(*cp++);
584 return 0;
585}
586
587/*
588 * Module: tutil.c
589 *
590 * Purpose: Utility routines for TERMLIB functions.
Bram Moolenaar764b23c2016-01-30 21:10:09 +0100591 * Returns length of text common to s1 and s2.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000592 */
593 static int
Bram Moolenaar764b23c2016-01-30 21:10:09 +0100594_match(char *s1, char *s2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000595{
596 int i = 0;
597
598 while (s1[i] && s1[i] == s2[i])
599 i++;
600
601 return i;
602}
603
604/*
605 * finds next c in s that's a member of set, returns pointer
606 */
607 static char *
Bram Moolenaar764b23c2016-01-30 21:10:09 +0100608_find(char *s, char *set)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000609{
Yegappan Lakshmanan59b26232021-06-05 20:59:22 +0200610 for (; *s; s++)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000611 {
612 char *ptr = set;
613
614 while (*ptr && *s != *ptr)
615 ptr++;
616
617 if (*ptr)
618 return s;
619 }
620
621 return s;
622}
623
624/*
625 * add val to buf according to format fmt
626 */
627 static char *
Bram Moolenaar764b23c2016-01-30 21:10:09 +0100628_addfmt(char *buf, char *fmt, int val)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000629{
630 sprintf(buf, fmt, val);
631 while (*buf)
632 buf++;
633 return buf;
634}