Annotation of OpenXM_contrib/gnuplot/help.c, Revision 1.1
1.1 ! maekawa 1: #ifndef lint
! 2: static char *RCSid = "$Id: help.c,v 1.29 1998/04/14 00:15:36 drd Exp $";
! 3: #endif
! 4:
! 5: /* GNUPLOT - help.c */
! 6:
! 7: /*[
! 8: * Copyright 1986 - 1993, 1998 Thomas Williams, Colin Kelley
! 9: *
! 10: * Permission to use, copy, and distribute this software and its
! 11: * documentation for any purpose with or without fee is hereby granted,
! 12: * provided that the above copyright notice appear in all copies and
! 13: * that both that copyright notice and this permission notice appear
! 14: * in supporting documentation.
! 15: *
! 16: * Permission to modify the software is granted, but not the right to
! 17: * distribute the complete modified source code. Modifications are to
! 18: * be distributed as patches to the released version. Permission to
! 19: * distribute binaries produced by compiling modified sources is granted,
! 20: * provided you
! 21: * 1. distribute the corresponding source modifications from the
! 22: * released version in the form of a patch file along with the binaries,
! 23: * 2. add special version identification to distinguish your version
! 24: * in addition to the base release version number,
! 25: * 3. provide your name and address as the primary contact for the
! 26: * support of your modified version, and
! 27: * 4. retain our contact information in regard to use of the base
! 28: * software.
! 29: * Permission to distribute the released version of the source code along
! 30: * with corresponding source modifications in the form of a patch file is
! 31: * granted with same provisions 2 through 4 for binary distributions.
! 32: *
! 33: * This software is provided "as is" without express or implied warranty
! 34: * to the extent permitted by applicable law.
! 35: ]*/
! 36:
! 37: #include "plot.h"
! 38:
! 39: #define SAME 0 /* for strcmp() */
! 40:
! 41: #include "help.h" /* values passed back */
! 42:
! 43: void int_error __PROTO((char str[], int t_num));
! 44:
! 45: #if defined(__EMX__) || defined(DJGPP) || defined(DOS386)
! 46: /* we have plenty of memory under __EMX__ or DJGPP */
! 47: # ifdef MSDOS
! 48: # undef MSDOS
! 49: # endif
! 50: #endif
! 51:
! 52: /*
! 53: ** help -- help subsystem that understands defined keywords
! 54: **
! 55: ** Looks for the desired keyword in the help file at runtime, so you
! 56: ** can give extra help or supply local customizations by merely editing
! 57: ** the help file.
! 58: **
! 59: ** The original (single-file) idea and algorithm is by John D. Johnson,
! 60: ** Hewlett-Packard Company. Thanx and a tip of the Hatlo hat!
! 61: **
! 62: ** Much extension by David Kotz for use in gnutex, and then in gnuplot.
! 63: ** Added output paging support, both unix and builtin. Rewrote completely
! 64: ** to read helpfile into memory, avoiding reread of help file. 12/89.
! 65: **
! 66: ** Modified by Russell Lang to avoid reading completely into memory
! 67: ** if MSDOS defined. This uses much less memory. 6/91
! 68: **
! 69: ** The help file looks like this (the question marks are really in column 1):
! 70: **
! 71: ** ?topic
! 72: ** This line is printed when the user wants help on "topic".
! 73: ** ?keyword
! 74: ** ?Keyword
! 75: ** ?KEYWORD
! 76: ** These lines will be printed on the screen if the user wanted
! 77: ** help on "keyword", "Keyword", or "KEYWORD". No casefolding is
! 78: ** done on the keywords.
! 79: ** ?subject
! 80: ** ?alias
! 81: ** This line is printed for help on "subject" and "alias".
! 82: ** ?
! 83: ** ??
! 84: ** Since there is a null keyword for this line, this section
! 85: ** is printed when the user wants general help (when a help
! 86: ** keyword isn't given). A command summary is usually here.
! 87: ** Notice that the null keyword is equivalent to a "?" keyword
! 88: ** here, because of the '?' and '??' topic lines above.
! 89: ** If multiple keywords are given, the first is considered the
! 90: ** 'primary' keyword. This affects a listing of available topics.
! 91: ** ?last-subject
! 92: ** Note that help sections are terminated by the start of the next
! 93: ** '?' entry or by EOF. So you can't have a leading '?' on a line
! 94: ** of any help section. You can re-define the magic character to
! 95: ** recognize in column 1, though, if '?' is too useful. (Try ^A.)
! 96: */
! 97:
! 98: #define KEYFLAG '?' /* leading char in help file topic lines */
! 99:
! 100: /*
! 101: ** Calling sequence:
! 102: ** int result; # 0 == success
! 103: ** char *keyword; # topic to give help on
! 104: ** char *pathname; # path of help file
! 105: ** int subtopics; # set to TRUE if only subtopics to be listed
! 106: ** # returns TRUE if subtopics were found
! 107: ** result = help(keyword, pathname, &subtopics);
! 108: ** Sample:
! 109: ** cmd = "search\n";
! 110: ** helpfile = "/usr/local/lib/program/program.help";
! 111: ** subtopics = FALSE;
! 112: ** if (help(cmd, helpfile, &subtopics) != H_FOUND)
! 113: ** printf("Sorry, no help for %s", cmd);
! 114: **
! 115: **
! 116: ** Speed this up by replacing the stdio calls with open/close/read/write.
! 117: */
! 118: #ifdef WDLEN
! 119: # define PATHSIZE WDLEN
! 120: #else
! 121: # define PATHSIZE BUFSIZ
! 122: #endif
! 123:
! 124: typedef struct line_s LINEBUF;
! 125: struct line_s {
! 126: char *line; /* the text of this line */
! 127: LINEBUF *next; /* the next line */
! 128: };
! 129:
! 130: typedef struct linkey_s LINKEY;
! 131: struct linkey_s {
! 132: char *key; /* the name of this key */
! 133: long pos; /* ftell position */
! 134: LINEBUF *text; /* the text for this key */
! 135: TBOOLEAN primary; /* TRUE -> is a primary name for a text block */
! 136: LINKEY *next; /* the next key in linked list */
! 137: };
! 138:
! 139: typedef struct key_s KEY;
! 140: struct key_s {
! 141: char *key; /* the name of this key */
! 142: long pos; /* ftell position */
! 143: LINEBUF *text; /* the text for this key */
! 144: TBOOLEAN primary; /* TRUE -> is a primary name for a text block */
! 145: };
! 146: static LINKEY *keylist = NULL; /* linked list of keys */
! 147: static KEY *keys = NULL; /* array of keys */
! 148: static int keycount = 0; /* number of keys */
! 149: static FILE *helpfp = NULL;
! 150:
! 151: static int LoadHelp __PROTO((char *path));
! 152: static void sortkeys __PROTO((void));
! 153: static int keycomp __PROTO((struct key_s * a, struct key_s * b));
! 154: static LINEBUF *storeline __PROTO((char *text));
! 155: static LINKEY *storekey __PROTO((char *key));
! 156: static KEY *FindHelp __PROTO((char *keyword));
! 157: static TBOOLEAN Ambiguous __PROTO((struct key_s * key, int len));
! 158:
! 159: /* Help output */
! 160: static void PrintHelp __PROTO((struct key_s * key, int *subtopics));
! 161: static void ShowSubtopics __PROTO((struct key_s * key, int *subtopics));
! 162:
! 163: #if defined(PIPES)
! 164: static FILE *outfile; /* for unix pager, if any */
! 165: #endif
! 166: static int pagelines; /* count for builtin pager */
! 167: #define SCREENSIZE 24 /* lines on screen (most have at least 24) */
! 168:
! 169: /* help:
! 170: * print a help message
! 171: * also print available subtopics, if subtopics is TRUE
! 172: */
! 173: int help(keyword, path, subtopics)
! 174: char *keyword; /* on this topic */
! 175: char *path; /* from this file */
! 176: TBOOLEAN *subtopics; /* (in) - subtopics only? */
! 177: /* (out) - are there subtopics? */
! 178: {
! 179: static char oldpath[PATHSIZE] = ""; /* previous help file */
! 180: int status; /* result of LoadHelp */
! 181: KEY *key; /* key that matches keyword */
! 182:
! 183: /*
! 184: ** Load the help file if necessary (say, first time we enter this routine,
! 185: ** or if the help file changes from the last time we were called).
! 186: ** Also may occur if in-memory copy was freed.
! 187: ** Calling routine may access errno to determine cause of H_ERROR.
! 188: */
! 189: errno = 0;
! 190: if (strncmp(oldpath, path, PATHSIZE) != SAME)
! 191: FreeHelp();
! 192: if (keys == NULL) {
! 193: status = LoadHelp(path);
! 194: if (status == H_ERROR)
! 195: return (status);
! 196:
! 197: /* save the new path in oldpath */
! 198: safe_strncpy(oldpath, path, PATHSIZE);
! 199: }
! 200: /* look for the keyword in the help file */
! 201: key = FindHelp(keyword);
! 202: if (key != NULL) {
! 203: /* found the keyword: print help and return */
! 204: PrintHelp(key, subtopics);
! 205: status = H_FOUND;
! 206: } else {
! 207: status = H_NOTFOUND;
! 208: }
! 209:
! 210: return (status);
! 211: }
! 212:
! 213: /* we only read the file once, into memory
! 214: * except for MSDOS when we don't read all the file -
! 215: * just the keys and location of the text
! 216: */
! 217: static int LoadHelp(path)
! 218: char *path;
! 219: {
! 220: LINKEY *key; /* this key */
! 221: long pos = 0; /* ftell location within help file */
! 222: char buf[BUFSIZ]; /* line from help file */
! 223: LINEBUF *head; /* head of text list */
! 224: LINEBUF *firsthead = NULL;
! 225: TBOOLEAN primary; /* first ? line of a set is primary */
! 226: TBOOLEAN flag;
! 227:
! 228: if ((helpfp = fopen(path, "r")) == NULL) {
! 229: /* can't open help file, so error exit */
! 230: return (H_ERROR);
! 231: }
! 232: /*
! 233: ** The help file is open. Look in there for the keyword.
! 234: */
! 235: if (!fgets(buf, BUFSIZ - 1, helpfp) || *buf != KEYFLAG)
! 236: return (H_ERROR); /* it is probably not the .gih file */
! 237:
! 238: while (!feof(helpfp)) {
! 239: /*
! 240: ** Make an entry for each synonym keyword
! 241: */
! 242: primary = TRUE;
! 243: while (buf[0] == KEYFLAG) {
! 244: key = storekey(buf + 1); /* store this key */
! 245: key->primary = primary;
! 246: key->text = NULL; /* fill in with real value later */
! 247: key->pos = 0; /* fill in with real value later */
! 248: primary = FALSE;
! 249: pos = ftell(helpfp);
! 250: if (fgets(buf, BUFSIZ - 1, helpfp) == (char *) NULL)
! 251: break;
! 252: }
! 253: /*
! 254: ** Now store the text for this entry.
! 255: ** buf already contains the first line of text.
! 256: */
! 257: #ifndef MSDOS
! 258: firsthead = storeline(buf);
! 259: head = firsthead;
! 260: #endif
! 261: while ((fgets(buf, BUFSIZ - 1, helpfp) != (char *) NULL)
! 262: && (buf[0] != KEYFLAG)) {
! 263: #ifndef MSDOS
! 264: /* save text line */
! 265: head->next = storeline(buf);
! 266: head = head->next;
! 267: #endif
! 268: }
! 269: /* make each synonym key point to the same text */
! 270: do {
! 271: key->pos = pos;
! 272: key->text = firsthead;
! 273: flag = key->primary;
! 274: key = key->next;
! 275: } while (flag != TRUE && key != NULL);
! 276: }
! 277: #ifndef MSDOS
! 278: (void) fclose(helpfp);
! 279: #endif
! 280:
! 281: /* we sort the keys so we can use binary search later */
! 282: sortkeys();
! 283: return (H_FOUND); /* ok */
! 284: }
! 285:
! 286: /* make a new line buffer and save this string there */
! 287: static LINEBUF *
! 288: storeline(text)
! 289: char *text;
! 290: {
! 291: LINEBUF *new;
! 292:
! 293: new = (LINEBUF *) malloc(sizeof(LINEBUF));
! 294: if (new == NULL)
! 295: int_error("not enough memory to store help file", -1);
! 296: if (text != NULL) {
! 297: new->line = (char *) malloc((unsigned int) (strlen(text) + 1));
! 298: if (new->line == NULL)
! 299: int_error("not enough memory to store help file", -1);
! 300: (void) strcpy(new->line, text);
! 301: } else
! 302: new->line = NULL;
! 303:
! 304: new->next = NULL;
! 305:
! 306: return (new);
! 307: }
! 308:
! 309: /* Add this keyword to the keys list, with the given text */
! 310: static LINKEY *
! 311: storekey(key)
! 312: char *key;
! 313: {
! 314: LINKEY *new;
! 315:
! 316: key[strlen(key) - 1] = NUL; /* cut off \n */
! 317:
! 318: new = (LINKEY *) malloc(sizeof(LINKEY));
! 319: if (new == NULL)
! 320: int_error("not enough memory to store help file", -1);
! 321: new->key = (char *) malloc((unsigned int) (strlen(key) + 1));
! 322: if (new->key == NULL)
! 323: int_error("not enough memory to store help file", -1);
! 324: (void) strcpy(new->key, key);
! 325:
! 326: /* add to front of list */
! 327: new->next = keylist;
! 328: keylist = new;
! 329: keycount++;
! 330: return (new);
! 331: }
! 332:
! 333: /* we sort the keys so we can use binary search later */
! 334: /* We have a linked list of keys and the number.
! 335: * to sort them we need an array, so we reform them into an array,
! 336: * and then throw away the list.
! 337: */
! 338: static void sortkeys()
! 339: {
! 340: LINKEY *p, *n; /* pointers to linked list */
! 341: int i; /* index into key array */
! 342:
! 343: /* allocate the array */
! 344: keys = (KEY *) malloc((unsigned int) ((keycount + 1) * sizeof(KEY)));
! 345: if (keys == NULL)
! 346: int_error("not enough memory to store help file", -1);
! 347:
! 348: /* copy info from list to array, freeing list */
! 349: for (p = keylist, i = 0; p != NULL; p = n, i++) {
! 350: keys[i].key = p->key;
! 351: keys[i].pos = p->pos;
! 352: keys[i].text = p->text;
! 353: keys[i].primary = p->primary;
! 354: n = p->next;
! 355: free((char *) p);
! 356: }
! 357:
! 358: /* a null entry to terminate subtopic searches */
! 359: keys[keycount].key = NULL;
! 360: keys[keycount].pos = 0;
! 361: keys[keycount].text = NULL;
! 362:
! 363: /* sort the array */
! 364: /* note that it only moves objects of size (two pointers + long + int) */
! 365: /* it moves no strings */
! 366: qsort((char *) keys, keycount, sizeof(KEY), (sortfunc) keycomp);
! 367: }
! 368:
! 369: static int keycomp(a, b)
! 370: KEY *a, *b;
! 371: {
! 372: return (strcmp(a->key, b->key));
! 373: }
! 374:
! 375: /* Free the help file from memory. */
! 376: /* May be called externally if space is needed */
! 377: void FreeHelp()
! 378: {
! 379: int i; /* index into keys[] */
! 380: LINEBUF *t, *next;
! 381:
! 382: if (keys == NULL)
! 383: return;
! 384:
! 385: for (i = 0; i < keycount; i++) {
! 386: free((char *) keys[i].key);
! 387: if (keys[i].primary) /* only try to release text once! */
! 388: for (t = keys[i].text; t != NULL; t = next) {
! 389: free((char *) t->line);
! 390: next = t->next;
! 391: free((char *) t);
! 392: }
! 393: }
! 394: free((char *) keys);
! 395: keys = NULL;
! 396: keycount = 0;
! 397: #ifdef MSDOS
! 398: (void) fclose(helpfp);
! 399: #endif
! 400: }
! 401:
! 402: /* FindHelp:
! 403: * Find the key that matches the keyword.
! 404: * The keys[] array is sorted by key.
! 405: * We could use a binary search, but a linear search will aid our
! 406: * attempt to allow abbreviations. We search for the first thing that
! 407: * matches all the text we're given. If not an exact match, then
! 408: * it is an abbreviated match, and there must be no other abbreviated
! 409: * matches -- for if there are, the abbreviation is ambiguous.
! 410: * We print the ambiguous matches in that case, and return not found.
! 411: */
! 412: static KEY * /* NULL if not found */
! 413: FindHelp(keyword)
! 414: char *keyword; /* string we look for */
! 415: {
! 416: KEY *key;
! 417: int len = strlen(keyword);
! 418: int compare;
! 419:
! 420: for (key = keys, compare = 1; key->key != NULL && compare > 0; key++) {
! 421: compare = strncmp(keyword, key->key, len);
! 422: if (compare == 0) /* we have a match! */
! 423: if (!Ambiguous(key, len)) {
! 424: /* non-ambiguous abbreviation */
! 425: (void) strcpy(keyword, key->key); /* give back the full spelling */
! 426: return (key); /* found!! */
! 427: }
! 428: }
! 429:
! 430: /* not found, or ambiguous */
! 431: return (NULL);
! 432: }
! 433:
! 434: /* Ambiguous:
! 435: * Check the key for ambiguity up to the given length.
! 436: * It is ambiguous if it is not a complete string and there are other
! 437: * keys following it with the same leading substring.
! 438: */
! 439: static TBOOLEAN
! 440: Ambiguous(key, len)
! 441: KEY *key;
! 442: int len;
! 443: {
! 444: char *first;
! 445: char *prev;
! 446: TBOOLEAN status = FALSE; /* assume not ambiguous */
! 447: int compare;
! 448: int sublen;
! 449:
! 450: if (key->key[len] == NUL)
! 451: return (FALSE);
! 452:
! 453: for (prev = first = key->key, compare = 0, key++;
! 454: key->key != NULL && compare == 0; key++) {
! 455: compare = strncmp(first, key->key, len);
! 456: if (compare == 0) {
! 457: /* So this key matches the first one, up to len.
! 458: * But is it different enough from the previous one
! 459: * to bother printing it as a separate choice?
! 460: */
! 461: sublen = instring(prev + len, ' ');
! 462: if (strncmp(key->key, prev, len + sublen) != 0) {
! 463: /* yup, this is different up to the next space */
! 464: if (!status) {
! 465: /* first one we have printed is special */
! 466: fprintf(stderr,
! 467: "Ambiguous request '%.*s'; possible matches:\n",
! 468: len, first);
! 469: fprintf(stderr, "\t%s\n", prev);
! 470: status = TRUE;
! 471: }
! 472: fprintf(stderr, "\t%s\n", key->key);
! 473: prev = key->key;
! 474: }
! 475: }
! 476: }
! 477:
! 478: return (status);
! 479: }
! 480:
! 481: /* PrintHelp:
! 482: * print the text for key
! 483: */
! 484: static void PrintHelp(key, subtopics)
! 485: KEY *key;
! 486: TBOOLEAN *subtopics; /* (in) - subtopics only? */
! 487: /* (out) - are there subtopics? */
! 488: {
! 489: LINEBUF *t;
! 490: #ifdef MSDOS
! 491: char buf[BUFSIZ]; /* line from help file */
! 492: #endif
! 493:
! 494: StartOutput();
! 495:
! 496: if (subtopics == NULL || !*subtopics) {
! 497: #ifdef MSDOS
! 498: fseek(helpfp, key->pos, 0);
! 499: while ((fgets(buf, BUFSIZ - 1, helpfp) != (char *) NULL)
! 500: && (buf[0] != KEYFLAG)) {
! 501: OutLine(buf);
! 502: }
! 503: #else
! 504: for (t = key->text; t != NULL; t = t->next)
! 505: OutLine(t->line); /* print text line */
! 506: #endif
! 507: }
! 508: ShowSubtopics(key, subtopics);
! 509: OutLine("\n");
! 510:
! 511: EndOutput();
! 512: }
! 513:
! 514:
! 515: /* ShowSubtopics:
! 516: * Print a list of subtopic names
! 517: */
! 518: #define PER_LINE 4
! 519:
! 520: static void ShowSubtopics(key, subtopics)
! 521: KEY *key; /* the topic */
! 522: TBOOLEAN *subtopics; /* (out) are there any subtopics */
! 523: {
! 524: int subt = 0; /* printed any subtopics yet? */
! 525: KEY *subkey; /* subtopic key */
! 526: int len; /* length of key name */
! 527: char line[BUFSIZ]; /* subtopic output line */
! 528: char *start; /* position of subname in key name */
! 529: int sublen; /* length of subname */
! 530: int pos = 0;
! 531: int spacelen = 0; /* Moved from inside for() loop */
! 532: char *prev = NULL; /* the last thing we put on the list */
! 533:
! 534: *line = NUL;
! 535: len = strlen(key->key);
! 536:
! 537: for (subkey = key + 1; subkey->key != NULL; subkey++) {
! 538: int ispacelen = 0;
! 539: if (strncmp(subkey->key, key->key, len) == 0) {
! 540: /* find this subtopic name */
! 541: start = subkey->key + len;
! 542: if (len > 0) {
! 543: if (*start == ' ')
! 544: start++; /* skip space */
! 545: else
! 546: break; /* not the same topic after all */
! 547: } else {
! 548: /* here we are looking for main topics */
! 549: if (!subkey->primary)
! 550: continue; /* not a main topic */
! 551: }
! 552: sublen = instring(start, ' ');
! 553: if (prev == NULL || strncmp(start, prev, sublen) != 0) {
! 554: if (subt == 0) {
! 555: subt++;
! 556: if (len)
! 557: (void) sprintf(line, "\nSubtopics available for %s:\n",
! 558: key->key);
! 559: else
! 560: (void) sprintf(line, "\nHelp topics available:\n");
! 561: OutLine(line);
! 562: *line = NUL;
! 563: pos = 0;
! 564: }
! 565: if (pos == PER_LINE) {
! 566: (void) strcat(line, "\n");
! 567: OutLine(line);
! 568: *line = NUL;
! 569: pos = 0;
! 570: }
! 571: /* adapted by DvdSchaaf */
! 572: {
! 573: #define FIRSTCOL 6
! 574: #define COLLENGTH 15
! 575:
! 576: if (pos == 0)
! 577: spacelen = FIRSTCOL;
! 578: for (ispacelen = 0;
! 579: ispacelen < spacelen; ispacelen++)
! 580: (void) strcat(line, " ");
! 581: /* commented out *
! 582: (void) strcat(line, "\t");
! 583: */
! 584: (void) strncat(line, start, sublen);
! 585: spacelen = COLLENGTH - sublen;
! 586: if (spacelen <= 0)
! 587: spacelen = 1;
! 588: }
! 589: pos++;
! 590: prev = start;
! 591: }
! 592: } else {
! 593: /* new topic */
! 594: break;
! 595: }
! 596: }
! 597:
! 598: /* put out the last line */
! 599: if (subt > 0 && pos > 0) {
! 600: (void) strcat(line, "\n");
! 601: OutLine(line);
! 602: }
! 603: /*
! 604: if (subt == 0) {
! 605: OutLine("\n");
! 606: OutLine("No subtopics available\n");
! 607: }
! 608: */
! 609:
! 610: if (subtopics)
! 611: *subtopics = (subt != 0);
! 612: }
! 613:
! 614:
! 615: /* StartOutput:
! 616: * Open a file pointer to a pipe to user's $PAGER, if there is one,
! 617: * otherwise use our own pager.
! 618: */
! 619: void StartOutput()
! 620: {
! 621: #if defined(PIPES)
! 622: char *pager_name = getenv("PAGER");
! 623:
! 624: if (pager_name != NULL && *pager_name != NUL)
! 625: if ((outfile = popen(pager_name, "w")) != (FILE *) NULL)
! 626: return; /* success */
! 627: outfile = stderr;
! 628: /* fall through to built-in pager */
! 629: #endif
! 630:
! 631: /* built-in pager */
! 632: pagelines = 0;
! 633: }
! 634:
! 635: #if defined(ATARI) || defined(MTOS)
! 636: # ifndef READLINE
! 637: # error cannot compile atari versions without -DREADLINE
! 638: # endif
! 639: #endif
! 640:
! 641: /* write a line of help output */
! 642: /* line should contain only one \n, at the end */
! 643: void OutLine(line)
! 644: char *line;
! 645: {
! 646: int c; /* dummy input char */
! 647: #if defined(PIPES)
! 648: if (outfile != stderr) {
! 649: fputs(line, outfile);
! 650: return;
! 651: }
! 652: #endif
! 653:
! 654: /* built-in dumb pager */
! 655: /* leave room for prompt line */
! 656: if (pagelines >= SCREENSIZE - 2) {
! 657: fputs("Press return for more: ", stderr);
! 658: #if defined(ATARI) || defined(MTOS)
! 659: do
! 660: c = tos_getch();
! 661: while (c != '\x04' && c != '\r' && c != '\n');
! 662: #else
! 663: do
! 664: c = getchar();
! 665: while (c != EOF && c != '\n');
! 666: #endif
! 667: pagelines = 0;
! 668: }
! 669: fputs(line, stderr);
! 670: pagelines++;
! 671: }
! 672:
! 673: void EndOutput()
! 674: {
! 675: #if defined(PIPES)
! 676: if (outfile != stderr)
! 677: (void) pclose(outfile);
! 678: #endif
! 679: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>