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