Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: version B 2.10.1 6/24/83; site mulga.OZ Path: utzoo!watmath!clyde!burl!hou3c!hocda!houxm!hogpc!houti!ariel!vax135!floyd!whuxle!mit-eddie!genrad!decvax!mulga!isaac From: isaac@mulga.UUCP Newsgroups: net.sources Subject: seebib - a replacement for lookbib Message-ID: <289@mulga.OZ> Date: Fri, 18-May-84 10:00:51 EDT Article-I.D.: mulga.289 Posted: Fri May 18 10:00:51 1984 Date-Received: Sat, 19-May-84 01:36:40 EDT Organization: Comp Sci, Melbourne Uni, Australia Lines: 1070 ---------------------- [going going goanna] The following is a shar archive of seebib. It is a much nicer and more powerful replacement for lookbib. It can function on a refer-type database either in the old format or the newer one. As well it works fine on "bib" databases although it assumes indxbib and hunt but not invert. This is version one: any comments, bugs etc would be appreciated. ---- UUCP: {decvax,vax135}!mulga!isaac Isaac Balbin Department of Computer Science University of Melbourne, Parkville 3052 Melbourne, AUSTRALIA. Cut Here: ------------------------------------/\---------------------------------------- echo x - Makefile cat > Makefile < seebib.c < #include #include FILE *pin,*pout; /* file pointers for i/o with hunt */ WINDOW *big,*small; /* top and bottom windows */ char A[MEDIUM]; /* author */ char B[MEDIUM]; /* book */ char C[MEDIUM]; /* city */ char D[SMALL]; /* date */ char E[MEDIUM]; /* editors */ char F[UNUSED]; /* footnote number */ char G[UNUSED]; /* government order number */ char H[SMALL]; /* header rubbish */ char I[MEDIUM]; /* institute */ char J[MEDIUM]; /* journal */ char K[MEDIUM]; /* extra key words */ char L[SMALL]; /* refer override label */ char M[UNUSED]; /* bell labs rubbish */ char N[TINY]; /* number */ char O[LARGE]; /* other */ char P[SMALL]; /* page number(s) */ char Q[MEDIUM]; /* Corporate or foreign author */ char R[MEDIUM]; /* research report */ char S[MEDIUM]; /* series title */ char T[MEDIUM]; /* title */ char U[UNUSED]; /* unused */ char V[TINY]; /* volume */ char W[UNUSED]; /* unused */ char X[LARGE]; /* abstract */ char Y[MEDIUM]; /* who owns the reference */ char Z[UNUSED]; /* unused */ struct { char *s; /* string */ char *p; /* prompt NOTE: SHOULD ALL BE THE SAME LENGTH*/ int l; /* max buffer length */ } refs[ALPHABET] = { &(A[0]), "Author(s): ", MEDIUM, &(B[0]), "Book : ", MEDIUM, &(C[0]), "City : ", MEDIUM, &(D[0]), "Date : ", SMALL, &(E[0]), "Editor(s): ", MEDIUM, &(F[0]), (char *)NULL, UNUSED, &(G[0]), (char *)NULL, UNUSED, &(H[0]), "Header : ", SMALL, &(I[0]), "Institute: ", MEDIUM, &(J[0]), "Journal : ", MEDIUM, &(K[0]), "Keywords : ", MEDIUM, &(L[0]), "Label : ", SMALL, &(M[0]), (char *)NULL, UNUSED, &(N[0]), "Number : ", TINY, &(O[0]), "Other : ", LARGE, &(P[0]), "Pages : ", SMALL, &(Q[0]), "Author(s): ", MEDIUM, &(R[0]), "Report : ", MEDIUM, &(S[0]), "Series : ", MEDIUM, &(T[0]), "Title : ", MEDIUM, &(U[0]), (char *)NULL, UNUSED, &(V[0]), "Volume : ", TINY, &(W[0]), (char *)NULL, UNUSED, &(X[0]), "Abstract : ", LARGE, &(Y[0]), "Owned-by : ", MEDIUM, &(Z[0]), (char *)NULL, UNUSED, }; long offsets[MAXREFS]; /* holds byte offset of ref in tmp file */ /* ** order holds the order in which we want to print out the entries ** ie 0 == A(uthor) is first, 19 == T(itle) is second etc */ int order[ALPHABET] = { 0,19,18,9,1,4,17,8,2,21,13,3,15,11,10,24,23,14,7,-1,-1,-1,-1,-1,-1,-1}; /*A T S J B E R I C V N D P L K Y X O H */ extern char *strcpy(),*strcat(),*rindex(); int nrefs = 0; /* running total of refs found */ int totrefs = 0; /* sum of refs found in first pass */ int number = 0; /* optional number before a command */ int prompt_length; /* the CONSTANT length of the prompt */ char temp[20]; /* holds temporary file name */ char mbuf[80]; /* buffer for messages */ char *huntv[5] = {"/usr/lib/refer/hunt","-l",HUNTMAX,0,NULL}; char bib_file[80]; /* name of bib_file */ char bib_buf[80]; /* buffer for new bib files */ char user[40]; /* holds name of user output file */ bool tty = TRUE; /* true if terminal has cursor movement */ bool Terse_flag = FALSE; /* terse mode flag */ bool Safe_flag = FALSE; /* only allows q to skip past last ref */ FILE *userf; /* file pointer for user file */ FILE *tmpf; /* holds result of hunt search */ main( argc, argv ) int argc; char **argv; { FILE *fopen(); char s[MEDIUM], *sprintf(),*get_key_word(); register char *c; int die(); bool finished = FALSE; while(--argc > 0 && (*++argv)[0] == '-') switch(*(argv[0] + 1)) { case 't': Terse_flag = TRUE; break; case 's': Safe_flag = TRUE; break; default: usage(); } if ( argc > 1 ) usage(); else if ( argc == 1 ) strcpy(bib_file, *argv); else strcpy(bib_file,"bib"); /* set up default */ sprintf(temp,"/tmp/see%06d",getpid()); sprintf(s, "%s.ia", bib_file); if ( access(s, 0) == -1 ) { fprintf(stderr, "Index file %s not found\n", s); exit(1); } huntv[3] = &(bib_file[0]); signal(SIGINT,die); initscr(); if ( strlen(CM) == 0 ) { fprintf(stderr, "Visual mode needs terminal with cursor motion capability\n"); fprintf(stderr,"Using non-visual (open) mode...\n\n"); tty = FALSE; Safe_flag = TRUE; } clear(); signal(SIGINT,die); fflush(stdin); addstr("Instructions? (y/n) "); crmode(); refresh(); if ( getchar() == 'y') instruct(); clear(); refresh(); if ( tty ) { big = newwin(LINES-2,COLS,0,0); small = newwin(1,COLS,LINES-1,0); } /* only one screen needed */ else big = small = stdscr; wstandout(small); get_prompt_length(); while ( ! finished ) { if ( tty ) { wclear(big); wrefresh(big); } wclear(small); do_prompt(); if ( get_key_word(s) != NULL ) { for( c = &(s[0]); isspace(*c); c++ ) ; if ( strcmp(c,"?\n") == 0 ) { instruct(); clear(); refresh(); continue; } if ( c[0] == '<' ) { if ( sscanf(c,"<%s",bib_buf) == -1 ) /* trick */ print_bib_file(); else if ( access(strcat(bib_buf,".ia"),0) == -1) { message(sprintf(mbuf, "Index file %s not found", bib_buf)); wclear(small); sleep(SLEEP); } else { *rindex(bib_buf,'.') = '\0'; strcpy(bib_file,bib_buf); print_bib_file(); } continue; } if ( strlen(c) > 3 ) { /* key words <=2 + \n are out */ message("Searching database ..."); noecho(); wclear(small); if ( strncmp(c,"$all",4) != 0 ) { popen2(huntv,&pin,&pout); map_lower(c); fprintf(pout,"%s",c); fclose(pout); process_lines(); pclose2(pin,pout); } else { /* just use "cat" instead of "hunt"*/ if ( (pin = fopen(bib_file,"r"))!= NULL) { process_lines(); fclose(pin); } } echo(); } } else { finished = TRUE; } } die(); } map_lower(s) /* map string s to lower case */ register char *s; { for ( ; *s; ++s) if ( isupper(*s) ) *s = tolower(*s); } char map_upper(s) /* map character s to upper case */ register char s; { if ( islower(s) ) s = toupper(s); return(s); } instruct() { register int c; noecho(); mvaddstr(2,0,"Type key words (eg Author and Date) after the prompt."); mvaddstr(3,0,"References with those key words are shown if they exist"); mvaddstr(4,0,"if nothing matches you are given another prompt."); mvaddstr(5,0,"To quit seebib, press CTRL-d after the > prompt."); mvaddstr(6,0,"NOTE: key words <=2 characters long are ignored,"); mvaddstr(7,0,"and only the first 6 characters are significant."); mvaddstr(8,0,"the special key word \"$all\" lists every reference."); mvaddstr(9,0,"Cntrl L will redraw the screen."); mvaddstr(10,0,"Cntrl T toggles between terse and verbose mode."); mvaddstr(11,0,"It is possible to save the results of a search by"); mvaddstr(12,0,"following the keywords with '> filename'"); mvaddstr(13,0,"You can change bib files by typing '< bib_file' in"); mvaddstr(14,0,"in response to the prompt."); mvaddstr(15,0,"'<' on its own will indicate the name of the bib_file."); mvaddstr(LINES-1,0,"Press to continue to quit"); refresh(); while( (c = getchar()) != ' ' ) if ( c == 'q' ) die(); else write(fileno(stdout),"\07",1); echo(); } die() { signal(SIGINT,SIG_IGN); unlink(temp); echo(); clear(); refresh(); nocrmode(); if ( tty ) mvcur(0,COLS-1,LINES-1,0); else wmove(small,0,0); endwin(); exit(0); } static char info[LARGE]; static bool fname; /* true if redirect to filename */ process_lines() { char map_upper(); register char *cc; register char *pos; register int newline; register int i; int type; int icount = 0; init_refs(); nrefs = 0; totrefs = 0; newline = 1; if ( fname && ((userf = fopen(user,"a")) == NULL) ) { message(sprintf(mbuf,"Can't open %s",user)); fname = FALSE; sleep(SLEEP); message("Searching database ..."); } if ( !Terse_flag) { if ( (tmpf = fopen(temp,"w")) == NULL ) return; while( fgets(info,LARGE,pin) != NULL ) { if ( info[0] == '.' && (info[1] == '['||info[1] == ']')) continue; icount++; if (*info == '\n') newline = 1; else if ( *info == '%' && newline) { newline = 0; offsets[++totrefs] = ftell(tmpf); } fputs(info,tmpf); if ( fname ) fputs(info,userf); } putc('\n',tmpf);/* need blank line to make loop homogeneous */ fclose(tmpf); if ( fname ) fclose(userf); /* * Read refs again, displaying them ... */ if ( (tmpf = fopen(temp,"r")) == NULL ) return; } else tmpf = pin; while( fgets(info,LARGE,tmpf) != NULL ) { if ( info[0] == '.' && (info[1] == '['||info[1] == ']') ) continue; if ( Terse_flag && fname ) fputs(info,userf); if ( *info != '\n' ) { icount++; *rindex(info,'\n') = '\0'; pos = info; if ( info[0] == '%' ) { for(pos +=3;isspace(*pos);pos++) ; type = map_upper(info[1]); } /*ignore unused */ if ( refs[ord(type)].p == (char *)NULL ) continue; cc = refs[ord(type)].s; i = refs[ord(type)].l - strlen(cc); if ( i > 2 ) { if ( type != 'A' && type != 'E' ) { addblank(cc); if ( *cc != '\0' ) i--; } else { addcomma(cc); if ( *cc != '\0' ) i -= 2; } if ( i < strlen(pos) ) { pos[i - 2] = '>'; pos[i - 1] = '\0'; } strcat(cc,pos); } } else print_refs(); } if (*T || *B || *A) print_refs(); if (Terse_flag && fname) fclose(userf); if ( icount == 0 ) { message("No match"); sleep(SLEEP); } } char *get_key_word(s) register char *s; { char *save = s; fname = FALSE; if ( tty ) noecho(); while( (*s = getchar()) != '\n') { if (*s == cntrl('t')) { wstandout(small); if ( Terse_flag ) { message("Exiting terse mode"); Terse_flag = FALSE; } else { message("Entering terse mode"); Terse_flag = TRUE; } if ( !tty ) sleep(SLEEP); do_prompt(); continue; } if (*s == cntrl('d')) return(NULL); if (*s == cntrl('l')) { clearok(curscr,TRUE); if ( tty ) touchwin(big); touchwin(small); if ( tty ) wrefresh(big); wrefresh(small); continue; } if ( *s == _tty.sg_kill ) { s = save; break; } if (*s == _tty.sg_erase || *s == '\b') { if ( s == save ) write(fileno(stdout),"\07",1); else { if ( BS ) waddstr(small,"\b \b"); else { s = save; break; } s--; } } else { if ( !(isprint(*s) || *s == ' ') ) *s = '?'; waddch(small,*s++); } if ( tty ) wrefresh(small); } *++s = '\0'; echo(); wstandout(small); parse(save); return(save); } parse(s) register char *s; { char key[MEDIUM]; if ( (sscanf(s,"%[^>]>%s",key,user)) == 2 ) fname = TRUE; strcpy(s,key); } init_refs() { register int i; for( i = 0; i < ALPHABET; i++ ) refs[i].s[0] = '\0'; } static int cury; display() { register int i,j; cury = 0; for( i = 0; i < ALPHABET; i++) { j = order[i]; if ( j != -1 && refs[j].s[0] != '\0') { preamble(refs[j].p); exhume(refs[j].s); } } wrefresh(big); init_refs(); } getint(pn) register int *pn; { register int c; *pn = 0; while ( (c = getchar()) >= '0' && c <= '9' ) *pn = 10 * *pn + c - '0'; return(c); } any_more() { int more = ' '; wstandout(small); do { if ( ! Terse_flag ) mvwaddstr(small,0,0, " to continue, <-> to back up, to quit"); else mvwaddstr(small,0,0, " to continue, to quit"); wrefresh(small); clearerr(stdin); if (!Terse_flag) more = getint(&number); else more = getchar(); } while ( ferror(stdin) != 0 ); wstandend(small); return(more); } exhume(s) register char *s; { register char *c; c = s; while ( strlen(c) > COLS - prompt_length ) { c = &(s[COLS - prompt_length]); while(*c != ' ') c--; *c = '\0'; if ( cury > big->_maxy ) break; else waddstr(big,s); wmove(big,cury++,prompt_length); s = ++c; } if ( cury <= big->_maxy ) waddstr(big,s); else message("Ref. too long - truncated"); } put_out(n) register int n; { wstandout(small); if ( Terse_flag ) message(sprintf(mbuf,"Reference %d",n)); else message(sprintf(mbuf,"Reference %d of %d",n,totrefs)); } print_refs() { bool finished = FALSE; if ( !*T && !*B && !*A ) return; put_out(++nrefs); display(); while ( ! finished ) { switch( any_more() ) { case 'q': if ( Terse_flag ) fclose(tmpf); else fseek(tmpf,0L,2); finished = TRUE; break; case cntrl('l'): if ( !tty ) { fseek(tmpf,offsets[nrefs],0); wclear(big); nrefs--; finished = TRUE; break; } clearok(curscr,TRUE); if ( tty ) touchwin(big); touchwin(small); if ( tty ) wrefresh(big); wrefresh(small); break; case '-': if ( !Terse_flag && nrefs > 1 ) { if ( number > 1 ) nrefs -= number-1; if ( nrefs > 1 ) { nrefs--; fseek(tmpf, offsets[nrefs],0); nrefs--; } else { nrefs = 0; fseek(tmpf,0L,0); } wclear(big); finished = TRUE; } else write(fileno(stdout),"\07",1); break; case ' ': wclear(big); if (!Terse_flag) { if ( nrefs == totrefs && Safe_flag ) { write(fileno(stdout),"\07",1); break; } else { if ( number > 0 ) { nrefs += number; if ( nrefs > totrefs ) nrefs = totrefs; fseek(tmpf,offsets[nrefs],0); nrefs--; } } } if ( nrefs == totrefs && Safe_flag ) { write(fileno(stdout),"\07",1); break; } else finished = TRUE; break; default: write(fileno(stdout),"\07",1); break; } } } usage() { fprintf(stderr,"Usage: seebib [-t] [-s] [database]\n"); exit(0); } print_bib_file() { wstandout(small); message(sprintf(mbuf,"Processing Bib File '%s'",bib_file)); wstandend(small); sleep(SLEEP); wclear(small); } do_prompt() { wstandout(small); mvwaddstr(small,0,0,"key(s)[? for help]> "); wrefresh(small); wstandend(small); } message(s) register char *s; { wclear(small); if ( tty ) wmove(small,0,COLS - strlen(s) -1); else wmove(small,0,0); waddstr(small,s); wrefresh(small); } get_prompt_length() { register int i; for ( i=0; i < ALPHABET; i++) if( (prompt_length = strlen(refs[i].p)) > 0 ) break; } !EOF! echo x - popen2.c cat > popen2.c < # define newfd(old,new) if (old != new) {dup2(old,new);close(old);} static int child_pid; /* ** Two way popen: allows one to read and write to process "cmdv[0]" ** via File pointers pin and pout ** ** David Price ** Isaac Balbin */ popen2(cmdv,pinptr,poutptr) char *cmdv[]; FILE **pinptr,**poutptr; { int parentw[2], /* parent (caller) write file descriptor */ childw[2]; /* child (called) write file descriptor */ fflush(stdout); /* clear toilet first */ if ( pipe(parentw) < 0 || pipe(childw) < 0 ) { perror("popen2: No pipe"); exit(1); } if( (child_pid = fork()) == 0 ) { /* child */ close(parentw[1]); close(childw[0]); newfd(parentw[0],0); newfd(childw[1],1); execv(cmdv[0], cmdv); perror(cmdv[0]); exit(1); } if( child_pid < 0 ) { /* parent */ perror("popen2: Fork fails"); exit(1); } close(parentw[0]); close(childw[1]); *pinptr = fdopen(childw[0], "r"); *poutptr = fdopen(parentw[1], "w"); if (*pinptr == NULL || *poutptr == NULL) perror("Bad fdopen"); } pclose2(pin,pout) FILE *pin, *pout; { fclose(pin); fclose(pout); } !EOF! echo x - seebib.1 cat > seebib.1 <" prompt): .TP .I keyword(s) In response to the prompt, the user types key words which seek to identify the reference(s) required. Backspace and kill characters behave as would be expected whilst unprintable characters are echoed as question marks. .br A sample would be .sp 2 \fBkey(s)[? for help]>\fP balbin stuart 1983 .sp 2 In this case only references which are identified by .I all the aforementioned keywords are listed. The minimum size of a key word is 3 characters and only the first 6 characters are significant. It is possible to redirect the results of a search to filename by typing a ">" followed by a filename. An example would be :- .sp 2 \fBkey(s)[? for help]>\fP logic > results .sp 2 In verbose mode all the references matched will be output to the file. In terse mode only those references actually viewed on the screen will be output to the file. If the file already exists then the resultant output will be appended to that file otherwise it will be created. .IP \fI$all\fP This special key word is used to list every reference in the bibliographic database. .IP "< [bib_file]" It is possible to interrogate a new bibliography whilst within seebib by giving the new file name after the <. Typing < on its own will print the name of the current bibliography file. .IP "?" If this is typed in response to the prompt (followed by a newline) then the help information is displayed. .IP ^T This key can be used to toggle between terse and verbose modes. In verbose mode two passes of the bibliography are made so that there is an indication of how many references are available matching a particular keyword (or group of key words). .IP ^D Used to terminate a session. .PP In Line commands during output phase of the search: .IP [integer] By hitting the space bar, the next reference matching the keywords is displayed. If the is preceded by an integer then that many references will be skipped. .IP [integer]<-> Allows the user to back up to the previous reference. This is enabled only for the verbose mode of .I seebib. If the <-> is preceded by an integer then that many references will be backed up. .IP Pressing this key causes the current search to be aborted and the screen to be cleared. .IP ^L Redraws the screen when necessary. .SH AUTHOR Isaac Balbin .br Department of Computer Science, .br University of Melbourne, Parkville 3052, Australia. .br UUCP: ...{decvax,vax135}!mulga!isaac .SH ACKNOWLEDGEMENTS David Price (Univ. of Melb), Baron Grey (UCLA) and John Shepherd (Univ. of Melb). .SH FILES .DT /etc/termcap Terminal data base /tmp/seeXXXX temporary file .SH "SEE ALSO" refer(1), indxbib(1), hunt(1), mkey(1), inv(1). .SH DIAGNOSTICS .DT Messages indicating that a search is being undertaken or that the mode has switched from terse to verbose are indicated on the lower window. Any errors from .I hunt are simply written to .I stderr. If a reference entry is too long and will overflow a buffer, it is truncated and an '>' appears at the last character position on the screen. If all a references entries are too long to fit on one screen (very unlikely) then only as much as can be shown will be; an error message is printed. .SH CAVEATS The special key word "$all" works properly only when the references are in one file. Essentially providing "$all" is not the function of a program which really only formats .I hunt output. Of course, .I seebib still works properly for any other key words even though the bibliography is in multiple files. It is fairly easy to modify seebib so that "$all" works on multiple files but we decided against it. .SH BUGS .DT If .I hunt sends out some error message (eg the user does has not used indxbib properly) the screen will need to be redrawn using ^L. !EOF!