info-vax@ucbvax.ARPA (08/22/85)
From: MANAGER%UMDHEP.BITNET@WISCVM.ARPA /*I got a lot of requests for the code, so here it is. Delete it immediately if you don't have VAX C2.0 on VMS4.1 or higher. I stress that I am working on it currently. Any fixes would be appreciated.--TSA*/ /*=============explode on the dotted line with your favorite nuke=========*/ /*==============I know you don't need to. It's for your own good==========*/ /* MORE emulates the function of the MORE utility of UNIX. It types text much like the TYPE command, but it pauses after each screen of data. This version is designed to work with 'CURSES'. Author: Thomas Bodoh U.S.G.S. / EROS data center Mundt Federal Building Sioux Falls, SD 57198 (605) 594-2271 (may change soon, try 594-6581) Hacker: Todd Aven Softwear Sweatshop High Energy Physics (University of Maryland) College Park, MD 20742 (301)454-3508 MANAGER%UMDHEP.BITNET@WISCVM.ARPA or MANAGER@UMDHEP (on bitnet). MORE pauses every n lines, where n is the terminal page length. When paused, the following commands can be typed in (commands increasing as UNIX capability is approached): <space> Advances 1 page <return> Advances 1 line d,D Advances half a page q,Q,^Z Quits the program MORE does not currently handle wildcarding, but may be changed at some future release. Other handy things which could be added are reverse and search functions. Hacker's note: my next project is to add the search and seek(direct access) functions. I am working from the man page of 4.2BSD for implementation. I doubt that I will add the editing, but I will add the multiple/wildcarded file specifications (using scanargs). I also plan to add the help command. Stay tuned to fa.info-vax for future releases.--Todd Aven */ /* ===== KNOWN BUGS ====== 1. Curses pads UNKNOWN type terminals with a screen of blanks at the end of the file. I have gotten in touch with Colorado Springs about this problem. It turns out that SMG$CONTROL_MODE should be able to prevent this, but I repeat SHOULD. (It doesn't work at present). I have another call in to CS. 2. Curses clears the screen at the beginning (initscr is the culprit). I personally would like for it not to do this. I may have to scrap curses for the time being and use vanilla SMG$ stuff. 3. The percentage read info is not exact. It counts the number of characters read and divides by the file-size obtained by stat(), but I don't know how stat() obtains its information. 4. The --More-- is supposed to come out in reverse-video on terminals that support it, but the setattr() function is not working. Another call is in to those vidiots at CS. */ #include stdio #include descrip #include iodef #include curses #include stat #define BUFSZ 256 int Pause; int LineLength; /* length of (tab expanded) line */ main(argc,argv) int argc; char *argv[]; { struct stat *statbuf; /* gets the filesize in bytes */ int inp; /* input file */ char buf[BUFSZ]; /* input buffer */ int sz; /* size of line read */ int nolines; /* number of lines left on the screen*/ int tlines; /* number of terminal lines this line needs */ short response; /* what the user typed */ double chars_read; /* number of characters read so far */ double file_size; /* size of file in bytes (includes header) */ float percent_read; /* percentage of file read */ float float_percent; /* intermediate result for percentage calc */ short ttchan; /* channel id for terminal */ short getchartt(); /* gets a single character from the terminal */ short ttopen(); /* opens TT: for getchartt */ unsigned long int scrmod,status; initscr(); if(COLS<5)COLS=72; nolines=LINES; /* def'd by initscr() to term page length*/ chars_read = 0; if (argc > 1) { stat(argv[1],statbuf); file_size=statbuf->st_size; inp = open(argv[1],0); } else { file_size=0.0; inp = dup(0); dup2(open("/dev/tty",0),0); } if (inp == -1) perror(argv[1]); else { ttchan = ttopen(); while ((sz = getline(inp,buf)) != 0) { chars_read += sz; /* COLS is defined by initscr() */ tlines = (LineLength + COLS-2) /COLS ; if (tlines == 0) tlines = 1; nolines -= tlines; if (nolines <= 0) { ask: setattr(_REVERSE); if(file_size>0.0) { float_percent = chars_read / file_size; percent_read = float_percent * 100; if (percent_read > 99.0) percent_read = 99.0; printf("--More--(%2.0f%%)",percent_read); } else printf("--More--"); clrattr(_REVERSE); response = getchartt(ttchan); write(1,"\r \r",24); if (response == ' ') nolines = LINES - tlines; else if (response == '\n') nolines = tlines; else if ((response & 0x5f) == 'D') nolines = (LINES-tlines)/2; else if ((response & 0x5f) == 'Q') exit(1); else if (response == '\032')/* ^Z */ exit(1); else { printf("\007"); goto ask; } } write(1,buf,sz); if (Pause) { nolines = 0; /* pause after this line */ Pause = 0; } } } } getline(fd,buf) int fd; char *buf; { register int linesz=0; register int c; LineLength = 1; while ((c=getcharacter(fd)) != -1 && c != '\n') { buf[linesz++] = c; if (c == '\t') LineLength = (LineLength + 8) & (~7); else if (c == '\f') { Pause = 1; buf[linesz-1] = '^'; buf[linesz++] = 'L'; } else LineLength++; } if (c != -1) buf[linesz++] = '\n'; return(linesz); } getcharacter(fd) int fd; { static char buf[512]; static int offset = 512; static int bufsz = 512; if (offset >= bufsz) { if ((bufsz=read(fd,buf,512)) == 0) return(-1); offset = 0; } return(buf[offset++]); } short getchartt(chan) short chan; { int status; short iosb[4]; char buf[1]; status = sys$qiow(0,chan,IO$_READLBLK | IO$M_NOECHO, iosb,0,0,buf,1,32767,0,0,0,0); if (status != 1) LIB$STOP(status); if (iosb[0] != 1) LIB$STOP(iosb[0]); if (buf[0] == '\r') buf[0] = '\n'; /* emulate UNIX */ return(buf[0]); } short ttopen() { short chan; register int status; struct dsc$descriptor dev_name; dev_name.dsc$w_length = 4; dev_name.dsc$a_pointer = "TT:"; dev_name.dsc$b_class = DSC$K_CLASS_S; dev_name.dsc$b_dtype = DSC$K_DTYPE_T; status = sys$assign(&dev_name,&chan,0,0,0); if (status != 1) LIB$STOP(status); return(chan); }