/*======================================================================= /* /* REDUCE help interface /* /* Author: H. Melenk, ZIB-Berlin, Nov. 1992 /* /* /*======================================================================= /* /* interface: Help file must have been compiled by /* GNU Texinfo system /* /* compile: UNIX: cc help.c -DUNIX -o help /* DOS: cl -DMSC -DANSI help.c /* (for Microsoft C, ansi.sys screen control) /* or cl -DMSC help.c /* (for Microsoft C, bare screen usage) /* /* /* call(Unix): help -f helpfile /* or help -f helpfile topic /* where <topic> is an initial help topic. /* /*=======================================================================*/ #include <stdio.h> #include <setjmp.h> #if defined MSC #include <string.h> #include <dos.h> #endif #ifndef SEEK_SET #define SEEK_SET 0 #endif FILE * helpfile; #define PAGE 0x1f #define EOL 0x0a #define MAX_NODE 1000 #define MAX_TABLE 1000 #define NAME_LENGTH 50 char tag[30]; char Node[NAME_LENGTH],Next[NAME_LENGTH],Prev[NAME_LENGTH],Up[NAME_LENGTH]; int node_count; char * node_name[MAX_NODE]; long node_adr[MAX_NODE]; long table[MAX_TABLE]; int table_count; long top_node,act_node; int bp; char buffer[100]; char out_buffer[100]; long read_number(); long find_node(); #if defined MSC int strncasecmp(char * u, char * v,int n); int display(long); int video=0; int fg_color,bg_color; #endif jmp_buf more_base; main(argc,argv) char * argv[]; int argc; { int i; char cmd; char*search_node; long ll; #if defined UNIX printf(" UNIX "); #endif #if defined MSC #if defined ANSI { union REGS regs; regs.h.ah = 0x1a; /* read display code */ regs.h.al = 0; int86(0x10, ®s, ®s); video=(regs.h.bl==2) || (regs.h.bl==4) || (regs.h.bl==6) || (regs.h.bl==8) || (regs.h.bl>=0x0c); regs.h.ah = 0x08; /* read actual color */ regs.h.bh = 0; int86(0x10, ®s, ®s); fg_color=regs.h.ah & 0xf; bg_color=(regs.h.ah>>4) & 0x7; regs.h.ah = 5; /* set video page */ regs.h.al = 1; /* page number */ int86(0x10, ®s, ®s); } #endif printf(" DOS "); #endif printf(" REDUCE help system \n"); if(argc<2 || strcmp(argv[1],"-f")) wrong_call(argc,argv); #if defined MSC helpfile = fopen(argv[2],"r+b"); #else helpfile = fopen(argv[2],"r"); #endif if(!helpfile) {printf("cannot open help file >%s<\n",argv[2]); my_exit(1);}; /* find table of contents */ find_TOC(); top_node = find_node("Top"); if(!top_node) { printf("Top node not found\n"); my_exit(1);}; act_node=top_node; if(argc>3) { ll=find_matching_nodes(argv[3],strlen(argv[3])); if(ll) goto next_command; else printf("**** no item matching >%s<\n",argv[3]); }; loop: display(act_node); next_command: cmd = command(); if(cmd == 'q' || cmd == 'Q' || cmd == 'x' || cmd == 'X') my_exit(0); else if(cmd == '+' || cmd == 'n' || cmd == 'N') { if(Next[0]) {search_node=Next; goto search;}; goto loop;} else if(cmd == '-' || cmd == 'p' || cmd == 'P') { if(Prev[0]) {search_node=Prev; goto search;}; goto loop;} else if(cmd == 't' || cmd == 'T') { act_node=top_node; goto loop;} else if(cmd == 'U' || cmd == 'u' || cmd == 'U') { if(liter(Up[0])) {search_node=Up; goto search;}; goto loop;} goto loop; search: ll = find_node(search_node); if(ll) {act_node=ll; goto loop;}; /* printf("\n ****** node >%s< not found\n",search_node); /* */ goto loop; } my_exit(n) int n; { #if defined ANSI if(n) getch(); { union REGS regs; more_putc(0x1b); more_putc('['); more_putc('0'); more_putc(';'); more_putc('4'); more_putc('0'+bg_color); more_putc(';'); more_putc('3'); more_putc('0'+fg_color); more_putc('m'); regs.h.ah = 5; /* set video page */ regs.h.al = 0; /* page number */ int86(0x10, ®s, ®s); } #endif exit(n); } command() { char c; int n; long ll; loop: printf("\n Enter: "); printfhighlight("+ - u t s q ?"); if(table_count>0) printf(" or a reference number\n"); nextchar: n=0; #if defined MSC c=getch(); putchar(c); /* input without return */ #else c=getchar(); #endif if(digit(c)) goto number; if(c == ' ' || c == EOL) goto nextchar; if (c == '+' || c == '-' || c == 'u' || c == 'U' || c == 't' || c == 'T' || c == 'q' || c == 'Q' || c == 'x' || c == 'X' ) return(c); if (c == '?' || c== 'h' || c == 'H') goto help; if (c == 's' || c== 'S') goto find; goto loop; number: n= 10*n+(c-'0'); c=getchar(); if(digit(c)) goto number; if(0<n && n<=table_count) {act_node = table[n]; return('d');} /* search item entered from terminal */ find: bp =0; while((c=getchar()) != EOL) if(c!=' ' || bp>0) buffer[bp++]=c; buffer[bp] = 0; ll=find_matching_nodes(buffer,bp); if(!ll) printf("**** no item matching >%s<\n",buffer); goto loop; help: printf("\n Enter command terminated by Return Key:\n"); printf(" + browse forwards to next topic on same level.\n"); printf(" - browse backwards on same level.\n"); printf(" u return to next upper level (directory).\n"); printf(" t return to top directory.\n"); printf(" nnn (nnn a number): \n"); printf(" select the nnn-th topic from menu or context,\n"); printf(" don't enclose number in sqare brackets.\n"); printf(" s cccc (cccc sequence of characters): \n"); printf(" search topics which match the character sequence:\n"); printf(" not case sensitive, no wildcard;\n"); printf(" result is a selection menu.\n"); printf(" q quit help.\n"); goto loop; } display(adr) long adr; { char c; int i; int state; long ll; char * bv; /* printf("display node: %ld\n",adr); /* */ if(seek_char(adr)) {printf("cannot find file position %lx\n",adr); my_exit(1);}; Next[0]=0; Prev[0]=0; Up[0]=0; loop: read_tag(); if(!strcmp(tag,"File:")) {read_string(tag); goto loop;} else if(!strcmp(tag,"Node:")) {read_string(Node); goto loop;} else if(!strcmp(tag,"Next:")) {read_string(Next); goto loop;} else if(!strcmp(tag,"Prev:")) {read_string(Prev); goto loop;} else if(!strcmp(tag,"Up:")) read_string(Up); else {printf("\n *** unknown node tag:>%s<",tag); /*exit(1);*/}; if(setjmp(more_base)) goto done; more_open(); for(i=0;i<71;i++) more_putc('='); more_putc(EOL); state = 0; bp=0; table_count=0; while((c=read_char()) != PAGE) { more_putc(c); /* look for menu and note entries */ if(c == '*' && state==0) state=2; else if(c == ':' && state==2) state=4; else if(c == ':' && state==4) { /* menu entry found */ buffer[bp]=0; /* printf("menu entry: >%s<\n",buffer); */ bv = buffer; if(!strncmp(bv,"note ",5)) bv=bv+5; ll = find_node(bv); if(ll && table_count<MAX_TABLE) { table_count++; table[table_count]=ll; sprintf(out_buffer,"[%d]",table_count); highlight_on(); for(i=0;out_buffer[i];i++) more_putc(out_buffer[i]); highlight_off(); state=0; bp=0; }; } else if(state==2 && bp<NAME_LENGTH && (liter(c) || digit(c) || c==' ')) {if(c!=' ' || bp>0) buffer[bp++]=c;} else { if(c=='*') state=2; else state=0; bp=0; }; }; done: more_close(); } FILE * pfeife = NULL; int use_pipe = 0, more_line_count; more_open() { FILE * loc; more_line_count=0; pfeife = stdout; use_pipe = 0; #if defined UNIX loc = popen("more","w"); if(loc) { pfeife = loc; use_pipe = 1;} #endif #if defined ANSI more_putc(0x1b); more_putc('['); more_putc('3'); more_putc('7'); more_putc(';'); more_putc('4'); more_putc('4'); more_putc('m'); more_putc(0x1b); more_putc('['); more_putc('2'); more_putc('J'); #endif } more_putc(c) char c; { int i; char d=0; if(use_pipe) putc(c,pfeife); else { putchar(c); if(c==EOL) { if(more_line_count++ >= 22) {more_line_count=0; #if defined MSC highlight_on(); printf("--More--"); highlight_off(); d = getch(); for (i=0;i<30;i++) putchar(8); #else printf("--More--\n"); d = getchar(); #endif if(d == 'q' || d == 'Q') longjmp(more_base,1); }} } } more_close() { #if defined UNIX if(use_pipe) pclose(pfeife); #endif use_pipe=0; } long find_node(s) char * s; { int i; i=0; while(i<node_count && (s[0] !=node_name[i][0] ||strcmp(s,node_name[i]))) { i++; /* printf("%d(%d) suchen: >%s< >%s< \n",i,node_count,s,node_name[i]); */ } if(i<node_count) return(node_adr[i]); printf("node not found: >%s< \n",s); return(0); } find_matching_nodes (s,lth) char * s; int lth; { int i=0,j=0,k=1; char * t; /* printf("find_node_case >%s< %d\n",s,lth); */ more_open(); while(i<node_count && (t=node_name[i])) { k=1; while (t[0] && (k=strncasecmp(s,t,lth))) t++; /* { printf(">%s< >%s< %x\n",s,t,k);t++;};*/ if(!k && j<MAX_TABLE) { j++; table[j]=node_adr[i]; t=node_name[i]; while(*t) more_putc(*t++); sprintf(out_buffer,"[%d]",j); highlight_on(); t=out_buffer; while(*t) more_putc(*t++); highlight_off(); more_putc(EOL); } i++; } more_close(); if(j) table_count=j; return (j); } find_TOC() { node_count=0; loop1: skip_char(PAGE); skip_char(EOL); read_tag(); /* printf("tag: %s\n",tag); /* */ if(strcmp(tag,"TagTable:")) goto loop1; skip_char(EOL); loop2: read_tag(); /* printf("tag(Node?): %s\n",tag); /* */ if(strcmp(tag,"Node:")) return(0); read_string(buffer); node_name[node_count] = (char*)malloc(strlen(buffer)+1); if(!node_name[node_count]) {printf("ran out of memory\n"); my_exit(1);}; strcpy(node_name[node_count],buffer); node_adr[node_count]=read_number(); /* printf("node %s %d\n",node_name[node_count], node_adr[node_count]); /* */ node_count++; if (node_count > MAX_NODE) {printf("too many nodes found\n"); my_exit(1);}; goto loop2; } read_tag() { char c; int i; i=0; while((c=read_char()) && i<30 && (digit(c) || liter(c) || c==' ' || (i==0 && c==EOL))) if(c!=EOL && c!=' ')tag[i++]=c; if(c==':') tag[i++]=c; tag[i]=0; return(0); } liter(c) char c; { return( (c>='a' && c<='z') || (c>='A' && c<='Z') || c == '_');} digit(c) char c; { return(c>='0' && c<='9');} read_string(s) char * s; { char c; int i; i=0; while((c=read_char()) && (digit(c) || liter(c) || c==':' || c==' ' || c=='.' || c=='(' || c==')' || c=='!' || c=='_' || c=='-'|| c=='?' || c=='*')) { s[i++]=c; if(i==1 && c==' ')i--;} s[i]=0; return(0); } long read_number() { char c; long n; n=0; while((c=read_char()) && digit(c)) n = n*10 + (c-'0'); return(n); } /* buffered file io */ int b_ptr=0,b_size=-1; #define BUFFLEN 2048 char buffo[BUFFLEN]; read_char() { char c; if(b_ptr<b_size) return(buffo[b_ptr++]); if(feof(helpfile)) {printf("unexpected EOF found in help file\n"); my_exit(1);}; b_size = fread(buffo,1,BUFFLEN,helpfile); b_ptr=1; return(buffo[0]); } skip_char(u) char u; { char c; loop: if(read_char()==u) return(0); goto loop; } seek_char(adr) long adr; { b_size=-2; return(fseek(helpfile,adr,SEEK_SET)); } /* error handlers */ wrong_call(argc,argv) char * argv[]; int argc; { int i; for(i=0;i<argc;i++) printf("%s\n",argv[i]); printf("usage: help -f <file> [ <topic> ]\n "); my_exit(1); } #if defined MSC /* Microsoft C does not support strncasecmp */ strncasecmp(char * u, char * v,int n) { char cu,cv; int r=1; while(r && (n-- > 0)) { cu = *u++; cv = *v++; if('a' <= cu) cu = cu-32; if('a' <= cv) cv = cv-32; r = (cu == cv); } return(!r); } #endif printfhighlight(s) char * s; { while(*s) {if(*s !=' ' && *s != EOL) { highlight_on(); putchar(' '); putchar(*s); putchar(' '); highlight_off(); } else putchar(*s); s++; } } highlight_on() { #if defined ANSI if(video) { putchar(0x1b); putchar('['); putchar('4'); putchar('3'); putchar('m'); } else { putchar(0x1b); putchar('['); putchar('5'); putchar('m'); } #endif } highlight_off() { #if defined ANSI more_putc(0x1b); more_putc('['); more_putc('0'); more_putc(';'); more_putc('4'); more_putc('4'); more_putc('m'); #endif }