|
|
1.1.1.2 root 1: /* more.c - Unix-style "more" paging output for PGP.
2: PGP: Pretty Good(tm) Privacy - public key cryptography for the masses.
3:
4: (c) Copyright 1990-1992 by Philip Zimmermann. All rights reserved.
5: The author assumes no liability for damages resulting from the use
6: of this software, even if the damage results from defects in this
7: software. No warranty is expressed or implied.
8:
9: All the source code Philip Zimmermann wrote for PGP is available for
10: free under the "Copyleft" General Public License from the Free
11: Software Foundation. A copy of that license agreement is included in
12: the source release package of PGP. Code developed by others for PGP
13: is also freely available. Other code that has been incorporated into
14: PGP from other sources was either originally published in the public
15: domain or was used with permission from the various authors. See the
16: PGP User's Guide for more complete information about licensing,
17: patent restrictions on certain algorithms, trademarks, copyrights,
18: and export controls.
19: */
20:
21: #include <ctype.h>
22: #include <stdio.h>
23: #include <stdlib.h>
24: #include <string.h>
25: #ifdef UNIX
26: #include <sys/types.h>
1.1.1.3 ! root 27: #include "system.h"
1.1.1.2 root 28: #endif
29: #ifdef sco
30: #include <sys/stream.h>
31: #include <sys/ptem.h>
1.1.1.3 ! root 32: FILE *popen();
1.1.1.2 root 33: #endif
34: #include "mpilib.h"
35: #include "language.h"
36: #include "fileio.h"
37: #include "pgp.h"
1.1.1.3 ! root 38: #include "more.h"
! 39: #include "charset.h"
1.1.1.2 root 40:
41: #ifdef MSDOS
1.1.1.3 ! root 42: #include <conio.h>
1.1.1.2 root 43: #define DEFAULT_LINES 25 /* MSDOS actually has a 25-line screen */
44: #else
45: #define DEFAULT_LINES 24
46: #endif /* MSDOS */
47: #define DEFAULT_COLUMNS 80
48:
1.1.1.3 ! root 49: static int screen_lines = DEFAULT_LINES, screen_columns = DEFAULT_COLUMNS;
1.1.1.2 root 50:
51: #define TAB 0x09 /* ASCII tab char */
52: #define CR '\r' /* Carriage return char */
53: #define LF '\n' /* Linefeed */
54:
55: /* Get the screen size for 'more'. The environment variables $LINES and
56: $COLUMNS will be used if they exist. If not, then the TIOCGWINSZ call to
57: ioctl() is used (if it is defined). If not, then the TIOCGSIZE call to
58: ioctl() is used (if it is defined). If not, then the WIOCGETD call to
59: ioctl() is used (if it is defined). If not, then get the info from
60: terminfo/termcap (if it is there). Otherwise, assume we have a 24x80
61: model 33.
62:
63: That was for Unix.
64:
65: For DOS, just assume 24x80. */
66:
67: #ifdef UNIX
68: /* Try to access terminfo through the termcap-interface in the curses library
69: (which requires linking with -lcurses) or use termcap directly (which
70: requires linking with -ltermcap) */
71:
72: #ifndef USE_TERMCAP
73: #ifdef USE_TERMINFO
74: #define USE_TERMCAP
75: #endif
76: #ifdef USE_CURSES
77: #define USE_TERMCAP
78: #endif
79: #endif
80:
81: #ifdef USE_TERMCAP
82: #define TERMBUFSIZ 1024
83: #define UNKNOWN_TERM "unknown"
84: #define DUMB_TERMBUF "dumb:co#80:hc:"
85:
86: extern int tgetent(), tgetnum();
87: #endif
88:
89: /* Try to get TIOCGWINSZ from termios.h, then from sys/ioctl.h */
90: #ifndef NOTERMIO
91: #ifdef SVR2
92: #include <termio.h>
93: #else
94: #include <termios.h>
95: #endif /* SVR2 */
96: #endif
97:
98: #ifndef SVR2
99: #ifndef TIOCGWINSZ
100: #ifndef TIOCGSIZE
101: #ifndef WIOCGETD
102: #include <sys/ioctl.h>
103: #endif /* not WIOCGETD */
104: #endif /* not TIOCGSIZE */
105: #endif /* not TIOCGWINSZ */
106:
107: /* If we still dont have TIOCGWINSZ (or TIOCGSIZE) try for WIOCGETD */
108: #ifndef TIOCGWINSZ
109: #ifndef TIOCGSIZE
110: #ifndef WIOCGETD
111: #include <sgtty.h>
112: #endif /* not WIOCGETD */
113: #endif /* not TIOCGSIZE */
114: #endif /* not TIOCGWINSZ */
115: #endif /* not SVR2 */
116: #endif /* UNIX */
117:
118: static void getScreenSize(void) /* Rot bilong kargo */
119: /* Return the screen size */
120: {
121: char *envLines, *envColumns;
122: long rowTemp = 0, colTemp = 0;
123: #ifdef UNIX
124: #ifdef USE_TERMCAP
125: char termBuffer[TERMBUFSIZ], *termInfo;
126: #endif
127: #ifdef TIOCGWINSZ
128: struct winsize windowInfo;
129: #else
130: #ifdef TIOCGSIZE
131: struct ttysize windowInfo;
132: #else
133: #ifdef WIOCGETD
134: struct uwdata windowInfo;
135: #endif /* WIOCGETD */
136: #endif /* TIOCGSIZE */
137: #endif /* TIOCGWINSZ */
138:
139: /* Make sure that we're outputting to a terminal */
140: if (!isatty(fileno(stderr)))
141: {
142: screen_lines = DEFAULT_LINES;
143: screen_columns = DEFAULT_COLUMNS;
144: return;
145: }
146: screen_lines = screen_columns = 0;
147: #endif /* UNIX */
148:
149: /* LINES & COLUMNS environment variables override everything else */
150: envLines = getenv("LINES");
151: if (envLines != NULL && (rowTemp = atol(envLines)) > 0 )
152: screen_lines = (int)rowTemp;
153:
154: envColumns = getenv("COLUMNS");
155: if (envColumns != NULL && (colTemp = atol(envColumns)) > 0 )
156: screen_columns = (int)colTemp;
157:
158: #ifdef UNIX
159: #ifdef TIOCGWINSZ
160: /* See what ioctl() has to say (overrides terminfo & termcap) */
161: if ((!screen_lines || !screen_columns) && ioctl(fileno(stderr),TIOCGWINSZ,&windowInfo) != -1)
162: { if (!screen_lines && windowInfo.ws_row > 0)
163: screen_lines = (int)windowInfo.ws_row;
164:
165: if (!screen_columns && windowInfo.ws_col > 0 )
166: screen_columns = (int)windowInfo.ws_col;
167: }
168: #else
169: #ifdef TIOCGSIZE
170: /* See what ioctl() has to say (overrides terminfo & termcap) */
171: if ((!screen_lines || !screen_columns) && ioctl(fileno(stderr),TIOCGSIZE,&windowInfo) != -1)
172: { if (!screen_lines && windowInfo.ts_lines > 0)
173: screen_lines = (int)windowInfo.ts_lines;
174:
175: if (!screen_columns && windowInfo.ts_cols > 0)
176: screen_columns = (int)windowInfo.ts_cols;
177: }
178: #else
179: #ifdef WIOCGETD
180: /* See what ioctl() has to say (overrides terminfo & termcap) */
181: if ((!screen_lines || !screen_columns) && ioctl(fileno(stderr),WIOCGETD,&windowInfo) != -1)
182: { if (!screen_lines && windowInfo.uw_height > 0)
183: screen_lines = (int)(windowInfo.uw_height / windowInfo.uw_vs);
184:
185: if (!screen_columns && windowInfo.uw_width > 0)
186: screen_columns = (int)(windowInfo.uw_width / windowInfo.uw_hs);
187: } /* You are in a twisty maze of standards, all different */
188: #endif
189: #endif
190: #endif
191:
192: #ifdef USE_TERMCAP
193: /* See what terminfo/termcap has to say */
194: if (!screen_lines || !screen_columns)
195: { if ((termInfo = getenv("TERM")) == (char *)NULL)
196: termInfo = UNKNOWN_TERM;
197:
198: if ((tgetent(termBuffer, termInfo) <= 0))
199: strcpy(termBuffer,DUMB_TERMBUF);
200:
201: if (!screen_lines && (rowTemp = tgetnum("li")) > 0)
202: screen_lines = (int)rowTemp;
203:
204: if (!screen_columns && (colTemp = tgetnum("co")) > 0)
205: screen_columns = (int)colTemp;
206: }
207: #endif
208: if (screen_lines == 0) /* nothing worked, use defaults */
209: screen_lines = DEFAULT_LINES;
210: if (screen_columns == 0)
211: screen_columns = DEFAULT_COLUMNS;
212: #endif /* UNIX */
213: }
214:
215: /* Certain systems need to go into a "break" mode */
216: #ifdef UNIX
217: #define NEEDBREAK
218: #endif
219: #ifdef AMIGA
220: #define NEEDBREAK
221: #endif
222: #ifdef ATARI
223: #define reverse_attr() printf("\033p")
224: #define norm_attr() printf("\033q")
225: #else
226: #define reverse_attr()
227: #define norm_attr()
228: #endif
229:
230:
231: #ifdef VMS
232: char pager[80] = "Type/Page"; /* default pager for VMS */
233: #else /* not VMS */
234: char pager[80] = "";
235: #endif /* not VMS */
236:
237:
238: int more_file(char *fileName)
239: /* Blort a file to the screen with page breaks, intelligent handling of line
240: terminators, truncation of overly long lines, and zapping of illegal
241: chars */
242: {
243: FILE *inFile;
244: int lines = 0,ch,i,chars = 0, c;
245: long fileLen;
246: char cmd[MAX_PATH];
247: char buf[16];
248: int lineno;
249: char *p;
250:
251: if ((inFile = fopen(fileName,FOPRBIN)) == NULL)
252: /* Can't see how this could fail since we just created the file */
253: return(-1);
254:
255: fread(buf, 1, 16, inFile);
1.1.1.3 ! root 256: if (compressSignature( (byte *) buf) >= 0)
1.1.1.2 root 257: { fprintf(pgpout, PSTR("\n\007File '%s' is not a text file; cannot display.\n"),
258: fileName);
259: return(-1);
260: }
261:
262: /* PAGER set in config.txt overrides environment variable,
263: set PAGER in config.txt to 'pgp' to use builtin pager */
264: if (pager[0] == '\0')
265: {
266: if ((p = getenv("PAGER")) != NULL)
267: strncpy(pager, p, sizeof(pager) - 1);
268: }
1.1.1.3 ! root 269: if (strcmp(pager, "cat") == 0)
! 270: { fclose(inFile);
! 271: writePhantomOutput(fileName);
! 272: return 0;
! 273: }
! 274:
! 275: /* Use built-in pager if PAGER is not set or if this is for your eyes only,
! 276: this currently doesn't work, the _CONSOLE filename isn't used as the real
! 277: filename anymore */
1.1.1.2 root 278: if ((strcmp(fileName,CONSOLE_FILENAME) != 0)
279: && (strlen(pager) != 0) && strcmp("pgp", pager))
280: {
281: fclose(inFile);
282: #ifdef UNIX
283: if (strchr(fileName, '\'') != NULL)
284: return(-1);
285: sprintf(cmd, "%s '%s'", pager, fileName);
286: #else
287: sprintf(cmd, "%s %s", pager, fileName);
288: #ifdef MSDOS
289: for (p = cmd; *p; ++p)
290: if (*p == '/')
291: *p = '\\';
292: #endif
293: #endif
1.1.1.3 ! root 294: fflush(pgpout);
1.1.1.2 root 295: return(system(cmd));
296: }
297:
298: #ifdef UNIX
299: if (!isatty(fileno(stdout)))
300: { fclose(inFile);
301: writePhantomOutput(fileName);
302: return 0;
303: }
304: #endif /* UNIX */
305:
306: getScreenSize();
307:
308: /* Get file length */
309: fseek(inFile,0L,SEEK_END);
310: fileLen = ftell(inFile);
311: rewind(inFile);
312: lineno = 1;
313:
314: #ifdef NEEDBREAK
315: ttycbreak();
316: #endif
317: putchar('\n');
318: while (TRUE)
319: { ch = getc(inFile);
320: if (ch == LF)
321: { lines++;
322: putchar('\n');
323: chars = 0;
324: ++lineno;
325: }
326: else
327: if (ch == CR)
328: { lines++;
329: putchar('\n');
330: chars = 0;
331: ++lineno;
332:
333: /* Skip following LF if there is one */
334: if ((ch = getc(inFile)) != LF && ch != EOF)
335: ungetc(ch,inFile);
336: }
337: else
338: if (((unsigned char) ch >= ' ' && ch != EOF) || ch == TAB)
339: { /* Legal char or tab, print it */
340: putchar(ch);
341: chars += (ch == TAB) ? 8 : 1;
342: }
343:
344: /* If we've reach the max.no of columns we can handle, skip the
345: rest of the line */
346: if (chars == screen_columns - 1)
347: { chars = 0;
1.1.1.3 ! root 348: while ((ch = getc(inFile)) != CR && ch != LF && ch != EOF )
! 349: ;
1.1.1.2 root 350: if (ch != EOF)
351: ungetc(ch,inFile);
352: }
353:
354: /* If we've reached the max.no of rows we can handle, wait for the
355: user to hit a key */
356: while (ch == EOF || lines == screen_lines - 1)
357: { /* Print prompt at end of screen */
358: reverse_attr();
359: if (ch == EOF)
360: printf(PSTR("\nDone...hit any key\r"));
361: else
362: printf(PSTR("More -- %d%% -- Hit space for next screen, Enter for new line, 'Q' to quit --\r"),
363: ( 100 * ftell( inFile ) ) / fileLen );
364: norm_attr();
365: fflush(stdout);
366: c = getch();
367: c = to_upper(c);
368:
369: /* Blank out prompt */
370: for (i=0; i<79; i++)
371: putchar(' ');
372: putchar('\r');
373: fflush(stdout);
374: if (c == 'B' && lineno > screen_lines) /* go Back a page */
375: { int seek_line = lineno - 2*screen_lines + 3;
376: lineno = 1;
377: rewind(inFile);
378: if (seek_line > 1)
379: { printf("...skipping\n");
380: while ((ch = getc(inFile)) != EOF)
381: if (ch == '\n')
382: if (++lineno == seek_line)
383: break;
384: }
385: ch = '\0';
386: lines = 0;
387: }
388: else
389: { if (c == 'Q' || ch == EOF)
390: goto done;
391: if (c == ' ' || c == '\n' || c == '\r' || c == 'J')
392: lines -= (c == ' ') ? screen_lines - 2 : 1; /* Do n more lines */
393: }
394: }
395: }
396: done:
397: #ifdef NEEDBREAK
398: ttynorm();
399: #endif
400: fclose(inFile);
401: return(0);
402: } /* more_file */
403:
404:
405: /*
406: * open_more() and close_more() redirect pgpout to the pager.
407: *
408: */
409:
410: static char *mfile = NULL;
411: static boolean piping = FALSE;
412: static FILE *savepgpout;
413:
414:
415: int
1.1.1.3 ! root 416: open_more(void)
1.1.1.2 root 417: {
1.1.1.3 ! root 418: #ifdef UNIX
1.1.1.2 root 419: char *p;
1.1.1.3 ! root 420: #endif
1.1.1.2 root 421:
422: if (mfile || piping)
423: close_more();
424:
425: savepgpout = pgpout;
426: #ifdef UNIX
1.1.1.3 ! root 427: fflush(pgpout);
1.1.1.2 root 428: if (pager[0] == '\0')
429: {
430: if ((p = getenv("PAGER")) != NULL)
431: strncpy(pager, p, sizeof(pager) - 1);
432: }
433: /* Use built-in pager if PAGER is not set or set to "pgp" */
434: if ((strlen(pager) != 0) && strcmp("pgp", pager))
435: {
436: if ((pgpout = popen(pager, "w")) != NULL)
437: { piping = TRUE;
438: return 0;
439: }
440: perror("popen");
441: pgpout = savepgpout;
442: }
443: #endif
444: if ((mfile = tempfile(TMP_TMPDIR|TMP_WIPE)) == NULL)
445: return -1;
446: if ((pgpout = fopen(mfile, FOPWTXT)) == NULL)
447: {
448: pgpout = savepgpout;
449: rmtemp(mfile);
450: return -1;
451: }
452: /* user will not see anything until close_more() is called */
453: fprintf(savepgpout,PSTR("Just a moment..."));
454: fflush(savepgpout);
455: return 0;
456: }
457:
458: int
1.1.1.3 ! root 459: close_more(void)
1.1.1.2 root 460: {
461: if (!mfile && !piping)
462: return 0;
463:
464: #ifdef UNIX
465: if (piping)
466: pclose(pgpout);
467: else
468: #endif
469: fclose(pgpout);
470: pgpout = savepgpout;
471: if (mfile)
472: {
473: fprintf(pgpout,"\n");
474: more_file(mfile);
475: rmtemp(mfile);
476: mfile = NULL;
477: }
478: piping = FALSE;
479: return 0;
480: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.