| 1 | /* Work-alike for termcap, plus extra features.
|
|---|
| 2 | Copyright (C) 1985, 86, 93, 94, 95 Free Software Foundation, Inc.
|
|---|
| 3 |
|
|---|
| 4 | This program is free software; you can redistribute it and/or modify
|
|---|
| 5 | it under the terms of the GNU General Public License as published by
|
|---|
| 6 | the Free Software Foundation; either version 2, or (at your option)
|
|---|
| 7 | any later version.
|
|---|
| 8 |
|
|---|
| 9 | This program is distributed in the hope that it will be useful,
|
|---|
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|---|
| 12 | GNU General Public License for more details.
|
|---|
| 13 |
|
|---|
| 14 | You should have received a copy of the GNU General Public License
|
|---|
| 15 | along with this program; see the file COPYING. If not, write to
|
|---|
| 16 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|---|
| 17 |
|
|---|
| 18 | /* Modified for emx by Eberhard Mattes, Nov 1995 */
|
|---|
| 19 |
|
|---|
| 20 | /* Emacs config.h may rename various library functions such as malloc. */
|
|---|
| 21 | #ifdef HAVE_CONFIG_H
|
|---|
| 22 |
|
|---|
| 23 | #include <config.h>
|
|---|
| 24 |
|
|---|
| 25 | /* Get the O_* definitions for open et al. */
|
|---|
| 26 | #include <sys/file.h>
|
|---|
| 27 | #ifdef USG5
|
|---|
| 28 | #include <fcntl.h>
|
|---|
| 29 | #endif
|
|---|
| 30 |
|
|---|
| 31 | #else /* not HAVE_CONFIG_H */
|
|---|
| 32 |
|
|---|
| 33 | #ifdef STDC_HEADERS
|
|---|
| 34 | #include <stdlib.h>
|
|---|
| 35 | #include <string.h>
|
|---|
| 36 | #else
|
|---|
| 37 | char *getenv ();
|
|---|
| 38 | char *malloc ();
|
|---|
| 39 | char *realloc ();
|
|---|
| 40 | #endif
|
|---|
| 41 |
|
|---|
| 42 | /* Do this after the include, in case string.h prototypes bcopy. */
|
|---|
| 43 | #if (defined(HAVE_STRING_H) || defined(STDC_HEADERS)) && !defined(bcopy)
|
|---|
| 44 | #define bcopy(s, d, n) memcpy ((d), (s), (n))
|
|---|
| 45 | #endif
|
|---|
| 46 |
|
|---|
| 47 | #ifdef HAVE_UNISTD_H
|
|---|
| 48 | #include <unistd.h>
|
|---|
| 49 | #endif
|
|---|
| 50 | #ifdef _POSIX_VERSION
|
|---|
| 51 | #include <fcntl.h>
|
|---|
| 52 | #endif
|
|---|
| 53 |
|
|---|
| 54 | #endif /* not HAVE_CONFIG_H */
|
|---|
| 55 |
|
|---|
| 56 | #ifndef NULL
|
|---|
| 57 | #define NULL (char *) 0
|
|---|
| 58 | #endif
|
|---|
| 59 |
|
|---|
| 60 | #ifndef O_RDONLY
|
|---|
| 61 | #define O_RDONLY 0
|
|---|
| 62 | #endif
|
|---|
| 63 |
|
|---|
| 64 | /* BUFSIZE is the initial size allocated for the buffer
|
|---|
| 65 | for reading the termcap file.
|
|---|
| 66 | It is not a limit.
|
|---|
| 67 | Make it large normally for speed.
|
|---|
| 68 | Make it variable when debugging, so can exercise
|
|---|
| 69 | increasing the space dynamically. */
|
|---|
| 70 |
|
|---|
| 71 | #ifndef BUFSIZE
|
|---|
| 72 | #ifdef DEBUG
|
|---|
| 73 | #define BUFSIZE bufsize
|
|---|
| 74 |
|
|---|
| 75 | int bufsize = 128;
|
|---|
| 76 | #else
|
|---|
| 77 | #define BUFSIZE 2048
|
|---|
| 78 | #endif
|
|---|
| 79 | #endif
|
|---|
| 80 |
|
|---|
| 81 | #ifndef TERMCAP_FILE
|
|---|
| 82 | #define TERMCAP_FILE "/etc/termcap"
|
|---|
| 83 | #endif
|
|---|
| 84 |
|
|---|
| 85 | #ifndef emacs
|
|---|
| 86 | static void
|
|---|
| 87 | memory_out ()
|
|---|
| 88 | {
|
|---|
| 89 | write (2, "virtual memory exhausted\n", 25);
|
|---|
| 90 | exit (1);
|
|---|
| 91 | }
|
|---|
| 92 |
|
|---|
| 93 | static char *
|
|---|
| 94 | xmalloc (size)
|
|---|
| 95 | unsigned size;
|
|---|
| 96 | {
|
|---|
| 97 | register char *tem = malloc (size);
|
|---|
| 98 |
|
|---|
| 99 | if (!tem)
|
|---|
| 100 | memory_out ();
|
|---|
| 101 | return tem;
|
|---|
| 102 | }
|
|---|
| 103 |
|
|---|
| 104 | static char *
|
|---|
| 105 | xrealloc (ptr, size)
|
|---|
| 106 | char *ptr;
|
|---|
| 107 | unsigned size;
|
|---|
| 108 | {
|
|---|
| 109 | register char *tem = realloc (ptr, size);
|
|---|
| 110 |
|
|---|
| 111 | if (!tem)
|
|---|
| 112 | memory_out ();
|
|---|
| 113 | return tem;
|
|---|
| 114 | }
|
|---|
| 115 | #endif /* not emacs */
|
|---|
| 116 | |
|---|
| 117 |
|
|---|
| 118 | /* Looking up capabilities in the entry already found. */
|
|---|
| 119 |
|
|---|
| 120 | /* The pointer to the data made by tgetent is left here
|
|---|
| 121 | for tgetnum, tgetflag and tgetstr to find. */
|
|---|
| 122 | static char *term_entry;
|
|---|
| 123 |
|
|---|
| 124 | static char *tgetst1 (const char *ptr, char **area);
|
|---|
| 125 |
|
|---|
| 126 |
|
|---|
| 127 | /* Search entry BP for capability CAP.
|
|---|
| 128 | Return a pointer to the capability (in BP) if found,
|
|---|
| 129 | 0 if not found. */
|
|---|
| 130 |
|
|---|
| 131 | static const char *
|
|---|
| 132 | find_capability (bp, cap)
|
|---|
| 133 | register const char *bp, *cap;
|
|---|
| 134 | {
|
|---|
| 135 | for (; *bp; bp++)
|
|---|
| 136 | if (bp[0] == ':'
|
|---|
| 137 | && bp[1] == cap[0]
|
|---|
| 138 | && bp[2] == cap[1])
|
|---|
| 139 | return &bp[4];
|
|---|
| 140 | return NULL;
|
|---|
| 141 | }
|
|---|
| 142 |
|
|---|
| 143 | int
|
|---|
| 144 | tgetnum (cap)
|
|---|
| 145 | const char *cap;
|
|---|
| 146 | {
|
|---|
| 147 | register const char *ptr = find_capability (term_entry, cap);
|
|---|
| 148 | if (!ptr || ptr[-1] != '#')
|
|---|
| 149 | return -1;
|
|---|
| 150 | return atoi (ptr);
|
|---|
| 151 | }
|
|---|
| 152 |
|
|---|
| 153 | int
|
|---|
| 154 | tgetflag (cap)
|
|---|
| 155 | const char *cap;
|
|---|
| 156 | {
|
|---|
| 157 | register const char *ptr = find_capability (term_entry, cap);
|
|---|
| 158 | return ptr && ptr[-1] == ':';
|
|---|
| 159 | }
|
|---|
| 160 |
|
|---|
| 161 | /* Look up a string-valued capability CAP.
|
|---|
| 162 | If AREA is non-null, it points to a pointer to a block in which
|
|---|
| 163 | to store the string. That pointer is advanced over the space used.
|
|---|
| 164 | If AREA is null, space is allocated with `malloc'. */
|
|---|
| 165 |
|
|---|
| 166 | char *
|
|---|
| 167 | tgetstr (cap, area)
|
|---|
| 168 | const char *cap;
|
|---|
| 169 | char **area;
|
|---|
| 170 | {
|
|---|
| 171 | register const char *ptr = find_capability (term_entry, cap);
|
|---|
| 172 | if (!ptr || (ptr[-1] != '=' && ptr[-1] != '~'))
|
|---|
| 173 | return NULL;
|
|---|
| 174 | return tgetst1 (ptr, area);
|
|---|
| 175 | }
|
|---|
| 176 |
|
|---|
| 177 | /* Table, indexed by a character in range 0100 to 0140 with 0100 subtracted,
|
|---|
| 178 | gives meaning of character following \, or a space if no special meaning.
|
|---|
| 179 | Eight characters per line within the string. */
|
|---|
| 180 |
|
|---|
| 181 | static char esctab[]
|
|---|
| 182 | = " \007\010 \033\014 \
|
|---|
| 183 | \012 \
|
|---|
| 184 | \015 \011 \013 \
|
|---|
| 185 | ";
|
|---|
| 186 |
|
|---|
| 187 | /* PTR points to a string value inside a termcap entry.
|
|---|
| 188 | Copy that value, processing \ and ^ abbreviations,
|
|---|
| 189 | into the block that *AREA points to,
|
|---|
| 190 | or to newly allocated storage if AREA is NULL.
|
|---|
| 191 | Return the address to which we copied the value,
|
|---|
| 192 | or NULL if PTR is NULL. */
|
|---|
| 193 |
|
|---|
| 194 | static char *
|
|---|
| 195 | tgetst1 (ptr, area)
|
|---|
| 196 | const char *ptr;
|
|---|
| 197 | char **area;
|
|---|
| 198 | {
|
|---|
| 199 | register const char *p;
|
|---|
| 200 | register char *r;
|
|---|
| 201 | register int c;
|
|---|
| 202 | register int size;
|
|---|
| 203 | char *ret;
|
|---|
| 204 | register int c1;
|
|---|
| 205 |
|
|---|
| 206 | if (!ptr)
|
|---|
| 207 | return NULL;
|
|---|
| 208 |
|
|---|
| 209 | /* `ret' gets address of where to store the string. */
|
|---|
| 210 | if (!area)
|
|---|
| 211 | {
|
|---|
| 212 | /* Compute size of block needed (may overestimate). */
|
|---|
| 213 | p = ptr;
|
|---|
| 214 | while ((c = *p++) && c != ':' && c != '\n')
|
|---|
| 215 | ;
|
|---|
| 216 | ret = (char *) xmalloc (p - ptr + 1);
|
|---|
| 217 | }
|
|---|
| 218 | else
|
|---|
| 219 | ret = *area;
|
|---|
| 220 |
|
|---|
| 221 | /* Copy the string value, stopping at null or colon.
|
|---|
| 222 | Also process ^ and \ abbreviations. */
|
|---|
| 223 | p = ptr;
|
|---|
| 224 | r = ret;
|
|---|
| 225 | while ((c = *p++) && c != ':' && c != '\n')
|
|---|
| 226 | {
|
|---|
| 227 | if (c == '^')
|
|---|
| 228 | {
|
|---|
| 229 | c = *p++;
|
|---|
| 230 | if (c == '?')
|
|---|
| 231 | c = 0177;
|
|---|
| 232 | else
|
|---|
| 233 | c &= 037;
|
|---|
| 234 | }
|
|---|
| 235 | else if (c == '\\')
|
|---|
| 236 | {
|
|---|
| 237 | c = *p++;
|
|---|
| 238 | if (c >= '0' && c <= '7')
|
|---|
| 239 | {
|
|---|
| 240 | c -= '0';
|
|---|
| 241 | size = 0;
|
|---|
| 242 |
|
|---|
| 243 | while (++size < 3 && (c1 = *p) >= '0' && c1 <= '7')
|
|---|
| 244 | {
|
|---|
| 245 | c *= 8;
|
|---|
| 246 | c += c1 - '0';
|
|---|
| 247 | p++;
|
|---|
| 248 | }
|
|---|
| 249 | }
|
|---|
| 250 | else if (c >= 0100 && c < 0200)
|
|---|
| 251 | {
|
|---|
| 252 | c1 = esctab[(c & ~040) - 0100];
|
|---|
| 253 | if (c1 != ' ')
|
|---|
| 254 | c = c1;
|
|---|
| 255 | }
|
|---|
| 256 | }
|
|---|
| 257 | *r++ = c;
|
|---|
| 258 | }
|
|---|
| 259 | *r = '\0';
|
|---|
| 260 | /* Update *AREA. */
|
|---|
| 261 | if (area)
|
|---|
| 262 | *area = r + 1;
|
|---|
| 263 | return ret;
|
|---|
| 264 | }
|
|---|
| 265 | |
|---|
| 266 |
|
|---|
| 267 | /* Outputting a string with padding. */
|
|---|
| 268 |
|
|---|
| 269 | short ospeed;
|
|---|
| 270 | /* If OSPEED is 0, we use this as the actual baud rate. */
|
|---|
| 271 | int tputs_baud_rate;
|
|---|
| 272 | char PC;
|
|---|
| 273 |
|
|---|
| 274 | /* Actual baud rate if positive;
|
|---|
| 275 | - baud rate / 100 if negative. */
|
|---|
| 276 |
|
|---|
| 277 | static int speeds[] =
|
|---|
| 278 | {
|
|---|
| 279 | #ifdef VMS
|
|---|
| 280 | 0, 50, 75, 110, 134, 150, -3, -6, -12, -18,
|
|---|
| 281 | -20, -24, -36, -48, -72, -96, -192
|
|---|
| 282 | #else /* not VMS */
|
|---|
| 283 | 0, 50, 75, 110, 135, 150, -2, -3, -6, -12,
|
|---|
| 284 | -18, -24, -48, -96, -192, -288, -384, -576, -1152
|
|---|
| 285 | #endif /* not VMS */
|
|---|
| 286 | };
|
|---|
| 287 |
|
|---|
| 288 | void
|
|---|
| 289 | tputs (str, nlines, outfun)
|
|---|
| 290 | register const char *str;
|
|---|
| 291 | int nlines;
|
|---|
| 292 | register int (*outfun) ();
|
|---|
| 293 | {
|
|---|
| 294 | register int padcount = 0;
|
|---|
| 295 | register int speed;
|
|---|
| 296 |
|
|---|
| 297 | #ifdef emacs
|
|---|
| 298 | extern baud_rate;
|
|---|
| 299 | speed = baud_rate;
|
|---|
| 300 | /* For quite high speeds, convert to the smaller
|
|---|
| 301 | units to avoid overflow. */
|
|---|
| 302 | if (speed > 10000)
|
|---|
| 303 | speed = - speed / 100;
|
|---|
| 304 | #else
|
|---|
| 305 | if (ospeed == 0)
|
|---|
| 306 | speed = tputs_baud_rate;
|
|---|
| 307 | else
|
|---|
| 308 | speed = speeds[ospeed];
|
|---|
| 309 | #endif
|
|---|
| 310 |
|
|---|
| 311 | if (!str)
|
|---|
| 312 | return;
|
|---|
| 313 |
|
|---|
| 314 | while (*str >= '0' && *str <= '9')
|
|---|
| 315 | {
|
|---|
| 316 | padcount += *str++ - '0';
|
|---|
| 317 | padcount *= 10;
|
|---|
| 318 | }
|
|---|
| 319 | if (*str == '.')
|
|---|
| 320 | {
|
|---|
| 321 | str++;
|
|---|
| 322 | padcount += *str++ - '0';
|
|---|
| 323 | }
|
|---|
| 324 | if (*str == '*')
|
|---|
| 325 | {
|
|---|
| 326 | str++;
|
|---|
| 327 | padcount *= nlines;
|
|---|
| 328 | }
|
|---|
| 329 | while (*str)
|
|---|
| 330 | (*outfun) (*str++);
|
|---|
| 331 |
|
|---|
| 332 | /* PADCOUNT is now in units of tenths of msec.
|
|---|
| 333 | SPEED is measured in characters per 10 seconds
|
|---|
| 334 | or in characters per .1 seconds (if negative).
|
|---|
| 335 | We use the smaller units for larger speeds to avoid overflow. */
|
|---|
| 336 | padcount *= speed;
|
|---|
| 337 | padcount += 500;
|
|---|
| 338 | padcount /= 1000;
|
|---|
| 339 | if (speed < 0)
|
|---|
| 340 | padcount = -padcount;
|
|---|
| 341 | else
|
|---|
| 342 | {
|
|---|
| 343 | padcount += 50;
|
|---|
| 344 | padcount /= 100;
|
|---|
| 345 | }
|
|---|
| 346 |
|
|---|
| 347 | while (padcount-- > 0)
|
|---|
| 348 | (*outfun) (PC);
|
|---|
| 349 | }
|
|---|
| 350 | |
|---|
| 351 |
|
|---|
| 352 | /* Finding the termcap entry in the termcap data base. */
|
|---|
| 353 |
|
|---|
| 354 | struct buffer
|
|---|
| 355 | {
|
|---|
| 356 | char *beg;
|
|---|
| 357 | int size;
|
|---|
| 358 | char *ptr;
|
|---|
| 359 | int ateof;
|
|---|
| 360 | int full;
|
|---|
| 361 | };
|
|---|
| 362 |
|
|---|
| 363 | /* Forward declarations of static functions. */
|
|---|
| 364 |
|
|---|
| 365 | static int scan_file (char *str, int fd, struct buffer *bufp);
|
|---|
| 366 | static char *gobble_line (int fd, struct buffer *bufp, char *append_end);
|
|---|
| 367 | static int compare_contin (const char *str1, const char *str2);
|
|---|
| 368 | static int name_match (char *line, char *name);
|
|---|
| 369 |
|
|---|
| 370 | #ifdef EMX
|
|---|
| 371 |
|
|---|
| 372 | #define valid_filename_p(fn) \
|
|---|
| 373 | (*(fn) == '/' || *(fn) == '\\' || _fngetdrive (fn))
|
|---|
| 374 |
|
|---|
| 375 | #else /* not EMX */
|
|---|
| 376 | #ifdef VMS
|
|---|
| 377 |
|
|---|
| 378 | #include <rmsdef.h>
|
|---|
| 379 | #include <fab.h>
|
|---|
| 380 | #include <nam.h>
|
|---|
| 381 |
|
|---|
| 382 | static int
|
|---|
| 383 | valid_filename_p (fn)
|
|---|
| 384 | char *fn;
|
|---|
| 385 | {
|
|---|
| 386 | struct FAB fab = cc$rms_fab;
|
|---|
| 387 | struct NAM nam = cc$rms_nam;
|
|---|
| 388 | char esa[NAM$C_MAXRSS];
|
|---|
| 389 |
|
|---|
| 390 | fab.fab$l_fna = fn;
|
|---|
| 391 | fab.fab$b_fns = strlen(fn);
|
|---|
| 392 | fab.fab$l_nam = &nam;
|
|---|
| 393 | fab.fab$l_fop = FAB$M_NAM;
|
|---|
| 394 |
|
|---|
| 395 | nam.nam$l_esa = esa;
|
|---|
| 396 | nam.nam$b_ess = sizeof esa;
|
|---|
| 397 |
|
|---|
| 398 | return SYS$PARSE(&fab, 0, 0) == RMS$_NORMAL;
|
|---|
| 399 | }
|
|---|
| 400 |
|
|---|
| 401 | #else /* !VMS */
|
|---|
| 402 |
|
|---|
| 403 | #ifdef MSDOS /* MW, May 1993 */
|
|---|
| 404 | static int
|
|---|
| 405 | valid_filename_p (fn)
|
|---|
| 406 | char *fn;
|
|---|
| 407 | {
|
|---|
| 408 | return *fn == '/' || fn[1] == ':';
|
|---|
| 409 | }
|
|---|
| 410 | #else
|
|---|
| 411 | #define valid_filename_p(fn) (*(fn) == '/')
|
|---|
| 412 | #endif
|
|---|
| 413 |
|
|---|
| 414 | #endif /* !VMS */
|
|---|
| 415 | #endif /* not EMX */
|
|---|
| 416 |
|
|---|
| 417 | /* Find the termcap entry data for terminal type NAME
|
|---|
| 418 | and store it in the block that BP points to.
|
|---|
| 419 | Record its address for future use.
|
|---|
| 420 |
|
|---|
| 421 | If BP is null, space is dynamically allocated.
|
|---|
| 422 |
|
|---|
| 423 | Return -1 if there is some difficulty accessing the data base
|
|---|
| 424 | of terminal types,
|
|---|
| 425 | 0 if the data base is accessible but the type NAME is not defined
|
|---|
| 426 | in it, and some other value otherwise. */
|
|---|
| 427 |
|
|---|
| 428 | int
|
|---|
| 429 | tgetent (bp, name)
|
|---|
| 430 | char *bp; const char *name;
|
|---|
| 431 | {
|
|---|
| 432 | register char *termcap_name;
|
|---|
| 433 | register int fd;
|
|---|
| 434 | struct buffer buf;
|
|---|
| 435 | register char *bp1;
|
|---|
| 436 | char *bp2;
|
|---|
| 437 | char *term;
|
|---|
| 438 | int malloc_size = 0;
|
|---|
| 439 | register int c;
|
|---|
| 440 | char *tcenv = NULL; /* TERMCAP value, if it contains :tc=. */
|
|---|
| 441 | char *indirect = NULL; /* Terminal type in :tc= in TERMCAP value. */
|
|---|
| 442 | int filep;
|
|---|
| 443 |
|
|---|
| 444 | #ifdef INTERNAL_TERMINAL
|
|---|
| 445 | /* For the internal terminal we don't want to read any termcap file,
|
|---|
| 446 | so fake it. */
|
|---|
| 447 | if (!strcmp (name, "internal"))
|
|---|
| 448 | {
|
|---|
| 449 | term = INTERNAL_TERMINAL;
|
|---|
| 450 | if (!bp)
|
|---|
| 451 | {
|
|---|
| 452 | malloc_size = 1 + strlen (term);
|
|---|
| 453 | bp = (char *) xmalloc (malloc_size);
|
|---|
| 454 | }
|
|---|
| 455 | strcpy (bp, term);
|
|---|
| 456 | goto ret;
|
|---|
| 457 | }
|
|---|
| 458 | #endif /* INTERNAL_TERMINAL */
|
|---|
| 459 |
|
|---|
| 460 | /* For compatibility with programs like `less' that want to
|
|---|
| 461 | put data in the termcap buffer themselves as a fallback. */
|
|---|
| 462 | if (bp)
|
|---|
| 463 | term_entry = bp;
|
|---|
| 464 |
|
|---|
| 465 | termcap_name = getenv ("TERMCAP");
|
|---|
| 466 | if (termcap_name && *termcap_name == '\0')
|
|---|
| 467 | termcap_name = NULL;
|
|---|
| 468 | #if defined (MSDOS) && !defined (TEST)
|
|---|
| 469 | if (termcap_name && (*termcap_name == '\\'
|
|---|
| 470 | || *termcap_name == '/'
|
|---|
| 471 | || termcap_name[1] == ':'))
|
|---|
| 472 | dostounix_filename(termcap_name);
|
|---|
| 473 | #endif
|
|---|
| 474 |
|
|---|
| 475 | filep = termcap_name && valid_filename_p (termcap_name);
|
|---|
| 476 |
|
|---|
| 477 | /* If termcap_name is non-null and starts with / (in the un*x case, that is),
|
|---|
| 478 | it is a file name to use instead of /etc/termcap.
|
|---|
| 479 | If it is non-null and does not start with /,
|
|---|
| 480 | it is the entry itself, but only if
|
|---|
| 481 | the name the caller requested matches the TERM variable. */
|
|---|
| 482 |
|
|---|
| 483 | if (termcap_name && !filep && !strcmp (name, getenv ("TERM")))
|
|---|
| 484 | {
|
|---|
| 485 | indirect = tgetst1 (find_capability (termcap_name, "tc"), (char **) 0);
|
|---|
| 486 | if (!indirect)
|
|---|
| 487 | {
|
|---|
| 488 | if (!bp)
|
|---|
| 489 | bp = termcap_name;
|
|---|
| 490 | else
|
|---|
| 491 | strcpy (bp, termcap_name);
|
|---|
| 492 | goto ret;
|
|---|
| 493 | }
|
|---|
| 494 | else
|
|---|
| 495 | { /* It has tc=. Need to read /etc/termcap. */
|
|---|
| 496 | tcenv = termcap_name;
|
|---|
| 497 | termcap_name = NULL;
|
|---|
| 498 | }
|
|---|
| 499 | }
|
|---|
| 500 |
|
|---|
| 501 | if (!termcap_name || !filep)
|
|---|
| 502 | termcap_name = TERMCAP_FILE;
|
|---|
| 503 |
|
|---|
| 504 | /* Here we know we must search a file and termcap_name has its name. */
|
|---|
| 505 |
|
|---|
| 506 | #if defined (MSDOS) || defined (EMX)
|
|---|
| 507 | fd = open (termcap_name, O_RDONLY|O_TEXT, 0);
|
|---|
| 508 | #else
|
|---|
| 509 | fd = open (termcap_name, O_RDONLY, 0);
|
|---|
| 510 | #endif
|
|---|
| 511 | if (fd < 0)
|
|---|
| 512 | return -1;
|
|---|
| 513 |
|
|---|
| 514 | buf.size = BUFSIZE;
|
|---|
| 515 | /* Add 1 to size to ensure room for terminating null. */
|
|---|
| 516 | buf.beg = (char *) xmalloc (buf.size + 1);
|
|---|
| 517 | term = indirect ? indirect : (char *)name;
|
|---|
| 518 |
|
|---|
| 519 | if (!bp)
|
|---|
| 520 | {
|
|---|
| 521 | malloc_size = indirect ? strlen (tcenv) + 1 : buf.size;
|
|---|
| 522 | bp = (char *) xmalloc (malloc_size);
|
|---|
| 523 | }
|
|---|
| 524 | bp1 = bp;
|
|---|
| 525 |
|
|---|
| 526 | if (indirect)
|
|---|
| 527 | /* Copy the data from the environment variable. */
|
|---|
| 528 | {
|
|---|
| 529 | strcpy (bp, tcenv);
|
|---|
| 530 | bp1 += strlen (tcenv);
|
|---|
| 531 | }
|
|---|
| 532 |
|
|---|
| 533 | while (term)
|
|---|
| 534 | {
|
|---|
| 535 | /* Scan the file, reading it via buf, till find start of main entry. */
|
|---|
| 536 | if (scan_file (term, fd, &buf) == 0)
|
|---|
| 537 | {
|
|---|
| 538 | close (fd);
|
|---|
| 539 | free (buf.beg);
|
|---|
| 540 | if (malloc_size)
|
|---|
| 541 | free (bp);
|
|---|
| 542 | return 0;
|
|---|
| 543 | }
|
|---|
| 544 |
|
|---|
| 545 | /* Free old `term' if appropriate. */
|
|---|
| 546 | if (term != name)
|
|---|
| 547 | free (term);
|
|---|
| 548 |
|
|---|
| 549 | /* If BP is malloc'd by us, make sure it is big enough. */
|
|---|
| 550 | if (malloc_size)
|
|---|
| 551 | {
|
|---|
| 552 | malloc_size = bp1 - bp + buf.size;
|
|---|
| 553 | termcap_name = (char *) xrealloc (bp, malloc_size);
|
|---|
| 554 | bp1 += termcap_name - bp;
|
|---|
| 555 | bp = termcap_name;
|
|---|
| 556 | }
|
|---|
| 557 |
|
|---|
| 558 | bp2 = bp1;
|
|---|
| 559 |
|
|---|
| 560 | /* Copy the line of the entry from buf into bp. */
|
|---|
| 561 | termcap_name = buf.ptr;
|
|---|
| 562 | while ((*bp1++ = c = *termcap_name++) && c != '\n')
|
|---|
| 563 | /* Drop out any \ newline sequence. */
|
|---|
| 564 | if (c == '\\' && *termcap_name == '\n')
|
|---|
| 565 | {
|
|---|
| 566 | bp1--;
|
|---|
| 567 | termcap_name++;
|
|---|
| 568 | }
|
|---|
| 569 | *bp1 = '\0';
|
|---|
| 570 |
|
|---|
| 571 | /* Does this entry refer to another terminal type's entry?
|
|---|
| 572 | If something is found, copy it into heap and null-terminate it. */
|
|---|
| 573 | term = tgetst1 (find_capability (bp2, "tc"), (char **) 0);
|
|---|
| 574 | }
|
|---|
| 575 |
|
|---|
| 576 | close (fd);
|
|---|
| 577 | free (buf.beg);
|
|---|
| 578 |
|
|---|
| 579 | if (malloc_size)
|
|---|
| 580 | bp = (char *) xrealloc (bp, bp1 - bp + 1);
|
|---|
| 581 |
|
|---|
| 582 | ret:
|
|---|
| 583 | term_entry = bp;
|
|---|
| 584 | return 1;
|
|---|
| 585 | }
|
|---|
| 586 |
|
|---|
| 587 | /* Given file open on FD and buffer BUFP,
|
|---|
| 588 | scan the file from the beginning until a line is found
|
|---|
| 589 | that starts the entry for terminal type STR.
|
|---|
| 590 | Return 1 if successful, with that line in BUFP,
|
|---|
| 591 | or 0 if no entry is found in the file. */
|
|---|
| 592 |
|
|---|
| 593 | static int
|
|---|
| 594 | scan_file (str, fd, bufp)
|
|---|
| 595 | char *str;
|
|---|
| 596 | int fd;
|
|---|
| 597 | register struct buffer *bufp;
|
|---|
| 598 | {
|
|---|
| 599 | register char *end;
|
|---|
| 600 |
|
|---|
| 601 | bufp->ptr = bufp->beg;
|
|---|
| 602 | bufp->full = 0;
|
|---|
| 603 | bufp->ateof = 0;
|
|---|
| 604 | *bufp->ptr = '\0';
|
|---|
| 605 |
|
|---|
| 606 | lseek (fd, 0L, 0);
|
|---|
| 607 |
|
|---|
| 608 | while (!bufp->ateof)
|
|---|
| 609 | {
|
|---|
| 610 | /* Read a line into the buffer. */
|
|---|
| 611 | end = NULL;
|
|---|
| 612 | do
|
|---|
| 613 | {
|
|---|
| 614 | /* if it is continued, append another line to it,
|
|---|
| 615 | until a non-continued line ends. */
|
|---|
| 616 | end = gobble_line (fd, bufp, end);
|
|---|
| 617 | }
|
|---|
| 618 | while (!bufp->ateof && end[-2] == '\\');
|
|---|
| 619 |
|
|---|
| 620 | if (*bufp->ptr != '#'
|
|---|
| 621 | && name_match (bufp->ptr, str))
|
|---|
| 622 | return 1;
|
|---|
| 623 |
|
|---|
| 624 | /* Discard the line just processed. */
|
|---|
| 625 | bufp->ptr = end;
|
|---|
| 626 | }
|
|---|
| 627 | return 0;
|
|---|
| 628 | }
|
|---|
| 629 |
|
|---|
| 630 | /* Return nonzero if NAME is one of the names specified
|
|---|
| 631 | by termcap entry LINE. */
|
|---|
| 632 |
|
|---|
| 633 | static int
|
|---|
| 634 | name_match (line, name)
|
|---|
| 635 | char *line, *name;
|
|---|
| 636 | {
|
|---|
| 637 | register char *tem;
|
|---|
| 638 |
|
|---|
| 639 | if (!compare_contin (line, name))
|
|---|
| 640 | return 1;
|
|---|
| 641 | /* This line starts an entry. Is it the right one? */
|
|---|
| 642 | for (tem = line; *tem && *tem != '\n' && *tem != ':'; tem++)
|
|---|
| 643 | if (*tem == '|' && !compare_contin (tem + 1, name))
|
|---|
| 644 | return 1;
|
|---|
| 645 |
|
|---|
| 646 | return 0;
|
|---|
| 647 | }
|
|---|
| 648 |
|
|---|
| 649 | static int
|
|---|
| 650 | compare_contin (str1, str2)
|
|---|
| 651 | register const char *str1, *str2;
|
|---|
| 652 | {
|
|---|
| 653 | register int c1, c2;
|
|---|
| 654 | while (1)
|
|---|
| 655 | {
|
|---|
| 656 | c1 = *str1++;
|
|---|
| 657 | c2 = *str2++;
|
|---|
| 658 | while (c1 == '\\' && *str1 == '\n')
|
|---|
| 659 | {
|
|---|
| 660 | str1++;
|
|---|
| 661 | while ((c1 = *str1++) == ' ' || c1 == '\t');
|
|---|
| 662 | }
|
|---|
| 663 | if (c2 == '\0')
|
|---|
| 664 | {
|
|---|
| 665 | /* End of type being looked up. */
|
|---|
| 666 | if (c1 == '|' || c1 == ':')
|
|---|
| 667 | /* If end of name in data base, we win. */
|
|---|
| 668 | return 0;
|
|---|
| 669 | else
|
|---|
| 670 | return 1;
|
|---|
| 671 | }
|
|---|
| 672 | else if (c1 != c2)
|
|---|
| 673 | return 1;
|
|---|
| 674 | }
|
|---|
| 675 | }
|
|---|
| 676 |
|
|---|
| 677 | /* Make sure that the buffer <- BUFP contains a full line
|
|---|
| 678 | of the file open on FD, starting at the place BUFP->ptr
|
|---|
| 679 | points to. Can read more of the file, discard stuff before
|
|---|
| 680 | BUFP->ptr, or make the buffer bigger.
|
|---|
| 681 |
|
|---|
| 682 | Return the pointer to after the newline ending the line,
|
|---|
| 683 | or to the end of the file, if there is no newline to end it.
|
|---|
| 684 |
|
|---|
| 685 | Can also merge on continuation lines. If APPEND_END is
|
|---|
| 686 | non-null, it points past the newline of a line that is
|
|---|
| 687 | continued; we add another line onto it and regard the whole
|
|---|
| 688 | thing as one line. The caller decides when a line is continued. */
|
|---|
| 689 |
|
|---|
| 690 | static char *
|
|---|
| 691 | gobble_line (fd, bufp, append_end)
|
|---|
| 692 | int fd;
|
|---|
| 693 | register struct buffer *bufp;
|
|---|
| 694 | char *append_end;
|
|---|
| 695 | {
|
|---|
| 696 | register char *end;
|
|---|
| 697 | register int nread;
|
|---|
| 698 | register char *buf = bufp->beg;
|
|---|
| 699 | register char *tem;
|
|---|
| 700 |
|
|---|
| 701 | if (!append_end)
|
|---|
| 702 | append_end = bufp->ptr;
|
|---|
| 703 |
|
|---|
| 704 | while (1)
|
|---|
| 705 | {
|
|---|
| 706 | end = append_end;
|
|---|
| 707 | while (*end && *end != '\n') end++;
|
|---|
| 708 | if (*end)
|
|---|
| 709 | break;
|
|---|
| 710 | if (bufp->ateof)
|
|---|
| 711 | return buf + bufp->full;
|
|---|
| 712 | if (bufp->ptr == buf)
|
|---|
| 713 | {
|
|---|
| 714 | if (bufp->full == bufp->size)
|
|---|
| 715 | {
|
|---|
| 716 | bufp->size *= 2;
|
|---|
| 717 | /* Add 1 to size to ensure room for terminating null. */
|
|---|
| 718 | tem = (char *) xrealloc (buf, bufp->size + 1);
|
|---|
| 719 | bufp->ptr = (bufp->ptr - buf) + tem;
|
|---|
| 720 | append_end = (append_end - buf) + tem;
|
|---|
| 721 | bufp->beg = buf = tem;
|
|---|
| 722 | }
|
|---|
| 723 | }
|
|---|
| 724 | else
|
|---|
| 725 | {
|
|---|
| 726 | append_end -= bufp->ptr - buf;
|
|---|
| 727 | bcopy (bufp->ptr, buf, bufp->full -= bufp->ptr - buf);
|
|---|
| 728 | bufp->ptr = buf;
|
|---|
| 729 | }
|
|---|
| 730 | if (!(nread = read (fd, buf + bufp->full, bufp->size - bufp->full)))
|
|---|
| 731 | bufp->ateof = 1;
|
|---|
| 732 | bufp->full += nread;
|
|---|
| 733 | buf[bufp->full] = '\0';
|
|---|
| 734 | }
|
|---|
| 735 | return end + 1;
|
|---|
| 736 | }
|
|---|
| 737 | |
|---|
| 738 |
|
|---|
| 739 | #ifdef TEST
|
|---|
| 740 |
|
|---|
| 741 | #ifdef NULL
|
|---|
| 742 | #undef NULL
|
|---|
| 743 | #endif
|
|---|
| 744 |
|
|---|
| 745 | #include <stdio.h>
|
|---|
| 746 |
|
|---|
| 747 | main (argc, argv)
|
|---|
| 748 | int argc;
|
|---|
| 749 | char **argv;
|
|---|
| 750 | {
|
|---|
| 751 | char *term;
|
|---|
| 752 | char *buf;
|
|---|
| 753 |
|
|---|
| 754 | term = argv[1];
|
|---|
| 755 | printf ("TERM: %s\n", term);
|
|---|
| 756 |
|
|---|
| 757 | buf = (char *) tgetent (0, term);
|
|---|
| 758 | if ((int) buf <= 0)
|
|---|
| 759 | {
|
|---|
| 760 | printf ("No entry.\n");
|
|---|
| 761 | return 0;
|
|---|
| 762 | }
|
|---|
| 763 |
|
|---|
| 764 | printf ("Entry: %s\n", buf);
|
|---|
| 765 |
|
|---|
| 766 | tprint ("cm");
|
|---|
| 767 | tprint ("AL");
|
|---|
| 768 |
|
|---|
| 769 | printf ("co: %d\n", tgetnum ("co"));
|
|---|
| 770 | printf ("am: %d\n", tgetflag ("am"));
|
|---|
| 771 | }
|
|---|
| 772 |
|
|---|
| 773 | tprint (cap)
|
|---|
| 774 | char *cap;
|
|---|
| 775 | {
|
|---|
| 776 | char *x = tgetstr (cap, 0);
|
|---|
| 777 | register char *y;
|
|---|
| 778 |
|
|---|
| 779 | printf ("%s: ", cap);
|
|---|
| 780 | if (x)
|
|---|
| 781 | {
|
|---|
| 782 | for (y = x; *y; y++)
|
|---|
| 783 | if (*y <= ' ' || *y == 0177)
|
|---|
| 784 | printf ("\\%0o", *y);
|
|---|
| 785 | else
|
|---|
| 786 | putchar (*y);
|
|---|
| 787 | free (x);
|
|---|
| 788 | }
|
|---|
| 789 | else
|
|---|
| 790 | printf ("none");
|
|---|
| 791 | putchar ('\n');
|
|---|
| 792 | }
|
|---|
| 793 |
|
|---|
| 794 | #endif /* TEST */
|
|---|
| 795 |
|
|---|