jchvr@ihlpg.UUCP (04/01/87)
sorry about that, but my last posting was not complete. here is the full source i hope. # ---- cut here ----- : To unbundle, sh this file echo Makefile 1>&2 cat >Makefile <<'@@@ Fin de Makefile' kbq: kb.o kbq.o fsindex.o sindex.o dir.o cc -o kbq kb.o fsindex.o dir.o kbq.o chmod +x kbq strip kbq ln kbq kbu ln kbq kbc ln kbq kbk ln kbq kbx kbq.o: kbq.c kb.h cc -O -c kbq.c kb.o: kbq.c kb.h cc -O -c kb.c @@@ Fin de Makefile echo dir.c 1>&2 cat >dir.c <<'@@@ Fin de dir.c' #include <stdio.h> #include <sys/types.h> #include <sys/dir.h> #include <sys/stat.h> /* dir - to execute a function for each file in a directory ** ** int dir(dirname,f,recursive,ignore) ** ** char *dirname; ** int (*f)(); ** int recursive; ** int ignore; ** ** For each file in dirname (except '.' and '..') the function f will ** be called with the name of the file as argument (eg. f(name)) ** When recursive = 0 then only 1 level of directory is done, ** all other values of recursive will make dir() do a recursive decent. ** ** When (*f)(name) returns to dir() with return code != 0 then dir ** aborts immediately with the return code from (*f)(name). ** Setting ignore != 0 will make dir() ignore errors from subdirectories ** in the case that recursive != 0. ** ** Return code values for dir() are: ** 0 all okay no error ** 1 directory does not exist ** 2 argument is not a directory ** 3 argument length too long to handle ** 4 cannot read directory file ** * return code from (*f)(name) ** ** The definition of f should be: ** ** int f(name) ** char *name; ** ** f should ALWAYS return an error code or 0 if all okay. */ #define BUFSIZE 512 int dir(dname,f,recursive,ignore) char *dname; /* name of directory to work on */ int (*f)(); /* function to call for every file in dir */ int recursive; /* if != 0 then recursive decent */ int ignore; /* if !=0 then ignore subdir in error */ { struct direct dirbuf; struct stat stbuf; char *nbp; char *nep; register int i; int fd; char fname[BUFSIZE]; int code; /* check if dname is a dir */ if (stat(dname, &stbuf) == -1) { #ifdef DEBUG fprintf(stderr,"dir(): can't find '%s'\n",dname); #endif return(1); } if ((stbuf.st_mode & S_IFMT) != S_IFDIR) { #ifdef DEBUG fprintf(stderr,"dir(): '%s' is not a directory\n",dname); #endif return(2); } /* check for length overflow: name = dname / fname */ if (strlen(dname) + 2 + DIRSIZ > BUFSIZE) { #ifdef DEBUG fprintf(stderr,"dir(): '%s' string too long\n",dname); #endif return(3); } if ((fd = open(dname,0)) == -1) { /* cannot open */ #ifdef DEBUG fprintf(stderr,"dir(): cannot open '%s'\n",dname); #endif return(4); } while (read(fd, (char *)&dirbuf, sizeof(dirbuf)) > 0) { if (dirbuf.d_ino == 0) { /* slot not in use */ continue; } if (strcmp(dirbuf.d_name, ".") == 0 || strcmp(dirbuf.d_name, "..") == 0) {/* skip . and .. */ continue; } /* construct fname */ strcpy(fname,dname); strcat(fname,"/"); strcat(fname,dirbuf.d_name); /* call function and check result */ code = (*f)(fname); if (code != 0) goto end; /* check if we need recursion */ if ( recursive == 0 ) continue; /* else see if this is a dir. */ if (stat(fname, &stbuf) == -1) { return(1); } if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { code = dir(fname,f,recursive,ignore); if (ignore != 0 ) continue; if (code != 0) goto end; } }/*while*/ code = 0; end: close(fd); return(code); }/*dir*/ @@@ Fin de dir.c echo fsindex.c 1>&2 cat >fsindex.c <<'@@@ Fin de fsindex.c' #include <stdio.h> #include <ctype.h> #define MIN(a,b) ( (a) < (b) ? (a) : (b) ) #define TSIZE 128 void initfsindex(s,t) register char *s; register int t[]; { register int i; register int slength; register int *p; slength = strlen(s); for ( i = 0 ; i < TSIZE ; i++ ) t[i] = slength; for ( i = 0 ; i < slength ; i++ ) { p = &t[s[i]]; *p = MIN( *p, slength-1-i ); } }/*initfsindex*/ /* fsindex: return pointer to where small starts in big, or NULL if ** not found. pos must be initialized by call to initfsindex */ char *fsindex(big,small,pos) char *big; char *small; int pos[]; { register char *pb; register char *ps; register char *lpb; /* start value for pb */ register char *pes; register char *peb; int slength; /* ABCD. DEFGH. where . means EOS ** 01234 012345 ** ^ ^ ^ ^ ** | | | | ** ps pes pb peb */ slength = strlen(small); if ( slength == 0 ) return(big); pes = &small[slength-1]; /* points to last char of small */ peb = &big[strlen(big)]; /* points to EOS in big */ lpb = &big[slength-1]; /* starting point for search */ l1: if ( lpb < peb ) { /* then not past end of big */ pb = lpb; /* set start for big */ ps = pes; /* set to end of small */ l2: if ( *pb != *ps ) { /* then not found so skip */ lpb++; /* skip one char */ lpb += ( *lpb < (char)TSIZE ? pos[*lpb] : slength ); goto l1; } if ( ps != small) { /* then not full small found yet */ ps--; pb--; goto l2; /* try previous char in small */ } else { return(pb); /* full small found at pb */ } } else { return(NULL); /* not found */ } }/*fsindex*/ /* sindex: returns pointer to start of small in big, or NULL if not found ** calls fsindex after initializing */ char *sindex(big,small) char big[]; char small[]; { int table[TSIZE]; initfsindex(small,table); return(fsindex(big,small,table)); }/*sindex*/ @@@ Fin de fsindex.c echo kb.c 1>&2 cat >kb.c <<'@@@ Fin de kb.c' /* kb.c to parse boolean expressions -*-update-version-*- ** HFVR VERSION=Wed Jan 7 07:51:33 1987 ** ** SYNTAX accepted: ** ------ --------- ** <query> ::= <term> { OR <term> }* ** ** <term> ::= <factor> { AND <factor> }* ** ** <factor> ::= <key> ** | NOT <factor> ** | ( <query> ) ** ** <key> ::= <anything except ( ) ! & | SP TAB \n \0 > and or not ~ ** ** alternative syntax for some keywords: ** ----------- ** NOT ! ~ not ** AND & && and ** OR | || or ** ( [ { < ** ) ] } > */ #include "kb.h" /* all types of symbols */ typedef enum { LPARENTsymbol, /* ( */ RPARENTsymbol, /* ) */ ORsymbol, /* | */ ANDsymbol, /* & */ NOTsymbol, /* ! */ EOFsymbol, /* '\0' */ KEYsymbol, /* rest */ } SYMBOL; /* symbol as parsed */ typedef struct { SYMBOL symbol; /* symbol type */ char key[SIZE]; /* spelling */ } ITEM; ITEM next; /* holds last symbol and spelling */ char *string1; /* ptr to start of string to parse */ char *string; /* ptr to rest of string to be parsed */ char lastchar; /* last char read */ int lastindex; /* index into string */ int count = 0; /* times true interpreter */ /* extern void initfsindex(); */ #define SETCODE(INS,ARG1,ARG2,ARG3,KEY1,CODESYM) \ { CODE *ptr; \ ptr = &(instruction[(INS)]); \ ptr->arg1 = setptr((ARG1)); \ ptr->arg2 = setptr((ARG2)); \ ptr->arg3 = setptr((ARG3)); \ ptr->count = 0; \ if ( strcmp(ptr->key,(KEY1)) != 0 ) { \ strcpy(ptr->key,(KEY1)); \ ptr->table = (KEYTAB *) malloc(sizeof(KEYTAB));\ initfsindex(ptr->key,ptr->table); \ }/*fi*/ \ ptr->code = (CODESYM); \ } #define MAXNROFCODES 100 CODE instruction[MAXNROFCODES]; #define NOPC -1 /* the novalue value for PC */ int PC; /* Program Counter */ /* return pointer to instruction.value, NULL if PC=NOPC */ BOOL *setptr(pc) int pc; { if ( pc != NOPC ) { return( &(instruction[pc].value) ); } else { return(NULL); } }/*setpc*/ /* print error message and exit */ void error(s) char s[]; { int i; fprintf(stderr,"\007kb: ERROR in query\n"); fprintf(stderr," query=%s\n",string1); fprintf(stderr," "); for (i = 1 ; i < lastindex ; i++) fprintf(stderr," "); fprintf(stderr,"^\n"); fprintf(stderr," %s\n",s); exit(1); }/*error*/ char *prcodesym(code) CODEsym code; { static char res[10]; switch(code) { case RFIcode : strcpy(res,"RFI"); break; case IFFcode : strcpy(res,"IFF"); break; case IFTcode : strcpy(res,"IFT"); break; case NOTcode : strcpy(res,"NOT"); break; case KEYcode : strcpy(res,"KEY"); break; case COPcode : strcpy(res,"COP"); break; case CITcode : strcpy(res,"CIT"); break; case CIFcode : strcpy(res,"CIF"); break; default : strcpy(res,"???"); break; } return(res); }/*prcodesym*/ /* generates 3-address code and returns PC of newly generated instruction */ int generate(code,key,PC1,PC2,PC3) CODEsym code; char key[]; int PC1; /* PC at which result for arg1 can be found */ int PC2; /* PC at which result for arg2 can be found */ int PC3; /* PC at which result for arg3 can be found */ { int temp; SETCODE(PC,PC1,PC2,PC3,key,code); temp = PC; PC++; return(temp); }/*generate */ /* read next character from string */ #define NEXTCHAR { lastchar = string[0]; \ if ( string[0] != '\0' ) { /* no skip past EOS */ \ string++; \ lastindex++; \ }} /* skip all white space characters */ void skipblanks() { while ( (lastchar == '\t') || (lastchar == '\n') || (lastchar == ' ' ) ) { NEXTCHAR; } }/*skipblanks*/ /* return TRUE if ch is NOT a special character (eg. not part of key) */ BOOL notspecial(ch) register char ch; { switch ( ch ) { case '(' : return(FALSE); break; case '[' : return(FALSE); break; case '{' : return(FALSE); break; case '<' : return(FALSE); break; case ')' : return(FALSE); break; case ']' : return(FALSE); break; case '}' : return(FALSE); break; case '>' : return(FALSE); break; case '|' : return(FALSE); break; case '&' : return(FALSE); break; case '!' : return(FALSE); break; case '~' : return(FALSE); break; case '\n': return(FALSE); break; case '\t': return(FALSE); break; case ' ' : return(FALSE); break; case '\0': return(FALSE); break; default : return(TRUE); break; } return(TRUE); }/*notspecial*/ /* read in spelling of key into next */ void getkey() { register int i; i = 0; while ( notspecial(lastchar) ) { next.key[i] = lastchar; if (i < SIZE-1) i++; next.key[i] = '\0'; NEXTCHAR; } }/*getkey*/ /* to debug: print SYMBOL type */ void prsymbol(symbol) ITEM symbol; { switch(symbol.symbol) { case LPARENTsymbol : printf("LEFT (\n"); break; case RPARENTsymbol : printf("RIGHT )\n"); break; case ORsymbol : printf("OR |\n"); break; case ANDsymbol : printf("AND &\n"); break; case NOTsymbol : printf("NOT !\n"); break; case EOFsymbol : printf("EOF\n"); break; case KEYsymbol : printf("KEY %s\n",symbol.key); break; default : error("Unknown symbol"); break; } }/*prsymbol*/ /* search for keywords, if not found return KEYsymbol */ /* to search is in next.key */ SYMBOL keyword(key) register char key[]; { switch (key[0]) { case 'a' : if ( strcmp(key,"and") == 0 ) { return(ANDsymbol); } else { return(KEYsymbol); } break; case 'A' : if ( strcmp(key,"AND") == 0 ) { return(ANDsymbol); } else { return(KEYsymbol); } break; case 'o' : if ( strcmp(key,"or") == 0 ) { return(ORsymbol); } else { return(KEYsymbol); } break; case 'O' : if ( strcmp(key,"OR") == 0 ) { return(ORsymbol); } else { return(KEYsymbol); } break; case 'n' : if ( strcmp(key,"not") == 0 ) { return(NOTsymbol); } else { return(KEYsymbol); } break; case 'N' : if ( strcmp(key,"NOT") == 0 ) { return(NOTsymbol); } else { return(KEYsymbol); } break; default : return(KEYsymbol); break; } return(KEYsymbol); }/*keyword*/ /* get next symbol from string, EOFsymbol set if no more */ void getsymbol() { skipblanks(); switch (lastchar) { case '(' : case '{' : case '[' : case '<' : next.symbol = LPARENTsymbol; strcpy(next.key,"("); NEXTCHAR; break; case ')' : case '}' : case ']' : case '>' : next.symbol = RPARENTsymbol; strcpy(next.key,")"); NEXTCHAR; break; case '|' : next.symbol = ORsymbol; strcpy(next.key,"|"); NEXTCHAR; if (lastchar == '|') NEXTCHAR; /* allow || */ break; case '&' : next.symbol = ANDsymbol; strcpy(next.key,"&"); NEXTCHAR; if (lastchar == '&' ) NEXTCHAR; /* allow && */ break; case '~' : case '!' : next.symbol = NOTsymbol; strcpy(next.key,"!"); NEXTCHAR; break; case '\0' : next.symbol = EOFsymbol; strcpy(next.key,""); break; default : getkey(); next.symbol = keyword(next.key); break; } /* prsymbol(next); */ }/* getsymbol*/ /* check if current symbol is correct and then skip it */ void skipsymbol(symbol) SYMBOL symbol; { if (next.symbol != symbol) { switch (symbol) { case LPARENTsymbol : error("'(' expected"); break; case RPARENTsymbol : error("')' expected"); break; case ORsymbol : error("'OR' expected"); break; case ANDsymbol : error("'AND' expected"); break; case NOTsymbol : error("'NOT' expected"); break; case KEYsymbol : error("<key> expected"); break; case EOFsymbol : error("End of query expected"); break; default : error("Something is wrong!!"); break; } } getsymbol(); }/*skipsymbol*/ int query(); /* forward definition */ int factor() { int temp; switch ( next.symbol) { case LPARENTsymbol : getsymbol(); /* skip ( */ temp = query(); skipsymbol(RPARENTsymbol); return(temp); break; case NOTsymbol : getsymbol(); /* skip ! */ return(generate(NOTcode,"",factor(),NOPC,NOPC)); break; case KEYsymbol : temp = generate(KEYcode,next.key,NOPC,NOPC,NOPC); getsymbol(); /* skip KEYcode */ return(temp); break; default : error("Factor expected"); break; } return(NOPC); /* never */ }/*factor*/ /* remember that 'temp1 AND temp2' is equivalent to: ** [temp ] 1. eval temp1 ** [pciff] 2. if ![temp] then [temp2]=false ; goto [temp2]+1 ** [temp2] 3. eval temp2 ** 4. */ int term() { int temp; int pciff; temp = factor(); while ( next.symbol == ANDsymbol ) { getsymbol(); /* skip & */ pciff = generate(IFFcode,"",temp,NOPC,NOPC); temp = factor(); /* backpatch arg2 and arg3 from IFF */ instruction[pciff].arg2 = &(instruction[temp].value); instruction[pciff].arg3 = (BOOL *)&(instruction[temp+1]); } return(temp); }/*term*/ /* remember that 'temp1 OR temp2' is equivalent to: ** [temp] 1. eval temp1 ** [pcift] 2. if [temp] then [temp2]=true ; goto [temp+1] ** [temp2] 3. eval temp2 ** 4. */ int query() { int temp; int pcift; temp = term(); while ( next.symbol == ORsymbol ) { getsymbol(); /* skip | */ pcift = generate(IFTcode,"",temp,NOPC,NOPC); temp = term(); /* backpatch arg2 and arg3 from IFT */ instruction[pcift].arg2 = &(instruction[temp].value); instruction[pcift].arg3 = (BOOL *)&(instruction[temp+1]); } return(temp); }/*query*/ /* findcode return NOPC if not found else place of KEYcode found ** with key=code.key , will always find at least itself */ int find1code(key) char key[]; { int i; for ( i=0 ;; i < MAXNROFCODES ) { switch(instruction[i].code) { case KEYcode : if ( strcmp(instruction[i].key,key) == 0 ) { return(i); } else { i++; /* skip to next */ } break; case RFIcode : return(NOPC); /* not found */ break; default : i++; /* skip to next */ break; }/*switch*/ }/*for*/ }/*find1code*/ /* findcode return NOPC if not found else place of KEYcode found ** with key is substring of code.key will always find itself */ int find2code(key) char key[]; { extern char *sindex(); /* return NULL if not found */ int i; for ( i=0 ;; i < MAXNROFCODES ) { switch(instruction[i].code) { case KEYcode : if ( sindex(instruction[i].key,key) != NULL ) { return(i); } else { i++; /* skip to next */ } break; case RFIcode : return(NOPC); /* not found */ break; default : i++; /* skip to next */ break; }/*switch*/ }/*for*/ }/*find2code*/ /* findcode return NOPC if not found else place of KEYcode found ** with code.key is substring of key will always find itself */ int find3code(key) char key[]; { extern char *sindex(); /* return NULL if not found */ int i; for ( i=0 ;; i < MAXNROFCODES ) { switch(instruction[i].code) { case KEYcode : if ( sindex(key,instruction[i].key) != NULL ) { return(i); } else { i++; /* skip to next */ } break; case RFIcode : return(NOPC); /* not found */ break; default : i++; /* skip to next */ break; }/*switch*/ }/*for*/ }/*find3code*/ /* optimize instructions by looking to add COPcode instructions */ void optkeys1() { int i; int j; for ( i=0 ;; i < MAXNROFCODES ) { switch(instruction[i].code) { case KEYcode : j = find1code(instruction[i].key); if ( j != i) { /* then used before */ SETCODE(i,j,NOPC,NOPC,instruction[i].key,COPcode); instruction[i].arg2 = &(instruction[j].count); } i++; /* skip to next */ break; case RFIcode : return; break; default : i++; /* skip to next */ break; } } }/*optkeys1*/ /* optimize instructions by looking to add CITcode instructions */ /* must call AFTER optkeys1(), otherwise gets a mess */ void optkeys2() { int i; int j; for ( i=0 ;; i < MAXNROFCODES ) { switch(instruction[i].code) { case KEYcode : j = find2code(instruction[i].key); if ( j != i) { /* then used before */ SETCODE(i,j,NOPC,NOPC,instruction[i].key,CITcode); instruction[i].arg2 = &(instruction[j].count); } i++; /* skip to next */ break; case RFIcode : return; break; default : i++; /* skip to next */ break; } } }/*optkeys2*/ /* optimize instructions by looking to add CIFcode instructions */ /* must call AFTER optkeys2(), otherwise gets a mess */ void optkeys3() { int i; int j; for ( i=0 ;; i < MAXNROFCODES ) { switch(instruction[i].code) { case KEYcode : j = find3code(instruction[i].key); if ( j != i) { /* then used before */ SETCODE(i,j,NOPC,NOPC,instruction[i].key,CIFcode); instruction[i].arg2 = &(instruction[j].count); } i++; /* skip to next */ break; case RFIcode : return; break; default : i++; /* skip to next */ break; } } }/*optkeys3*/ /* just call all optimizations in right order */ void optimize() { optkeys1(); /* add COP codes */ optkeys2(); /* add CIT codes */ optkeys3(); /* add CIF codes */ }/*optimize*/ /* return index of instruction where ptr=&instruction[i]{.value} */ int getpc(p) BOOL *p; { CODE *ptr; int i; for (i = 0; ; i++) { ptr = &instruction[i]; /* for speed */ if ( ((int *)ptr == p) || (&(ptr->value) == p) ) { return(i); } if (ptr->code == RFIcode) return(NOPC); }/*for*/ }/*getpc*/ printcode(i,ptr) int i; CODE *ptr; { fprintf(stderr,"[%3d] %s %20s ARG1=(%3d) ARG2=(%3d) ARG3=(%3d)\n", i, prcodesym(ptr->code), ptr->key, getpc(ptr->arg1), getpc(ptr->arg2), getpc(ptr->arg3) ); }/*printcode*/ void dumpcode() { int i; CODE *ptr; for ( i=0 ;; i < MAXNROFCODES ) { ptr = &instruction[i]; printcode(i,ptr); if (ptr->code == RFIcode) return; i++; } }/*dumpcode*/ /* call parse the first time */ void parse(s) char s[]; { int temp; extern BOOL dflag; string = s; string1 = s; lastindex = 0; PC = 0 ; NEXTCHAR; /* get first char */ getsymbol(); /* get first symbol */ temp = query(); skipsymbol(EOFsymbol); /* must be at end here */ (void)generate(RFIcode, "", temp, NOPC, NOPC); optimize(); if (dflag) dumpcode(); }/*parse*/ #define NOT(b1) ( ( b1 ) ? FALSE : TRUE ) /* return result TRUE or FALSE from interpreting */ /* this is were we spend most of our time */ BOOL interpret() { register CODE *ptr; extern BOOL findkey(); /* and here we spend a lot of time */ ptr = instruction; /* for speed reasons */ count++; for (;;) { /*EVER*/ switch(ptr->code) { case KEYcode : ptr->value = findkey(ptr); ptr->count = count; /* set it to done */ ptr++; /* skip to next instruction */ break; case COPcode : if ( *(ptr->arg2) == count ) { /* see if done */ ptr->value = *(ptr->arg1); } else { ptr->value = findkey(ptr); } ptr++; /* skip to next instruction */ break; case CITcode : if ( (*(ptr->arg2) == count) && (*(ptr->arg1)) ) { ptr->value = TRUE; } else { ptr->value = findkey(ptr); } ptr++; /* skip to next instruction */ break; case CIFcode : if ( (*(ptr->arg2) == count) && (!*(ptr->arg1)) ) { ptr->value = FALSE; } else { ptr->value = findkey(ptr); } ptr++; /* skip to next instruction */ break; case IFFcode : if ( *(ptr->arg1) ) { ptr++; /* skip to next instruction */ } else { *(ptr->arg2) = FALSE; ptr = (CODE *)ptr->arg3; /* goto (arg3) */ } break; case IFTcode : if ( *(ptr->arg1) ) { *(ptr->arg2) = TRUE; ptr = (CODE *)ptr->arg3; /* goto (arg3) */ } else { ptr++; /* skip to next instruction */ } break; case NOTcode : ptr->value = NOT(*(ptr->arg1)); ptr++; /* skip to next instruction */ break; case RFIcode : return(*(ptr->arg1)); break; default : error("Unknown instruction, kb in error"); break; } } }/*interpret*/ @@@ Fin de kb.c echo kb.h 1>&2 cat >kb.h <<'@@@ Fin de kb.h' /* kb.h -*-update-version-*- ** HFVR VERSION=Fri May 23 14:46:26 1986 */ #include <stdio.h> #include <ctype.h> typedef enum { EOFsym, FOUNDsym, NOTFOUNDsym } SYM; #define FALSE 0 #define TRUE 1 typedef int BOOL; #define SIZE 20 /* max length of keywords */ #define TSIZE 128 typedef int KEYTAB[TSIZE]; /* for fsindex */ /* 3-address codes */ typedef enum { RFIcode, /* return (*arg1) */ /* Return From Interpreter */ IFTcode, /* if *arg1 then val[arg2]=true, goto arg3 */ IFFcode, /* if !*arg1 then val[arg2]=false,goto arg3 */ NOTcode, /* val = NOT(*arg1) */ KEYcode, /* val = findkey(key) */ COPcode, /* val = *arg1 */ CITcode, /* val = (*arg1 ? *arg1 : findkey(key) ) */ /* Copy If True */ CIFcode, /* val = (*arg1 ? findkey(key) : *arg1 ) */ /* Copy If False */ } CODEsym; typedef struct { BOOL *arg1; /* ptr to argument 1 */ BOOL *arg2; /* ptr to argument 2 */ BOOL *arg3; /* ptr to argument 3 */ int count; /* to indicate if used */ BOOL value; /* result of this 3-address code */ char key[SIZE]; KEYTAB *table; /* ptr to fsindex table */ CODEsym code; /* which code it is */ } CODE; /* usage of CODE by the different codes ** ** CODE arg1 arg2 arg3 count key value ** ---- ------------ ------------- ------------ ----- --- ----- ** IFT &val[pc-1] &val[toassign] &ins[togoto] ** IFF &val[pc-1] &val[toassign] &ins[togoto] ** KEY count key T/F ** COP &val[copfrom] &count[copfrom] key T/F ** CIT &val[copfrom] &count[copfrom] key T/F ** CIF &val[copfrom] &count[copfrom] key T/F ** RFI &val[pc-1] */ extern void initfsindex(); extern char *fsindex(); extern char *sindex(); extern dflag; @@@ Fin de kb.h echo kb.man 1>&2 cat >kb.man <<'@@@ Fin de kb.man' .TH kb 1 "HFVR" .SH NAME .\" name \- one-line description for in permuted index kba, kbc, kbk, kbq, kbu, kbx, kbr \- to work on knowhow database .SH SYNOPSIS .\" bnf on command syntax kba [-e] .br kbc [-d] <query> .br kbk [-d] <query> .br kbq [-d] <query> .br kbr .br kbu [-d] <query> .br kbx [-d] <query> <command> .SH DESCRIPTION .\" semantics kb (Knowledge Base) is a simple database to store items of information. The items can then be retrieved from this database via any key words. .sp kba [-e] will prompt for info which is then stored into the knowhow database. When the -e option is given the $EDITOR is used to enter the information. .sp kbc <query> will give count of items from knowhow database which are specified by the <query> (see below). .sp kbk <query> will print out the keys (filenames) of the items from the knowhow database which are specified by the <query>. (See below). .sp kbq <query> will print all items from the knowhow database which are specified by the <query> (see below). .sp kbr will recreate the database from the old format into the current format. (only needed for old versions). .sp kbu <query> will present all items which are specified by <query> (see below) to the editor one by one. After the edit session the items are updated in the knowhow database. .sp Kbx <query> <command> will execute <command> for each item specified by <query> (see below). The first argument of the <command> is the name of the file with the information in it. .SH QUERY The <query> can be described in BNF as follows: .nf <query> ::= <term> { OR <term> }* <term> ::= <factor> { AND <factor> }* <factor> ::= <key> | NOT <factor> | ( <query> ) <key> ::= <anything alphanumeric lower case only> STANDARD ALTERNATIVES -------- ------------ NOT ! ~ not AND & && and OR | || or ( [ { < ) ] } > .fi .SH OPTIONS .tr ^ .in +6 .ti -6 -d^^^^turns on debug mode, to show internal KBCODE. (For experts only). .in -6 .SH EXAMPLES .nf kba # just follow the prompt kba -e # use $EDITOR to input information kbq test # list all items with keyword 'test' kbq 'test or trial' # list all item with keywords test or trial kbq 'sh & not ksh' # list all items about sh but not about ksh kbu test # edit and update all items with keyword 'test' .fi .SH FILES $HOME/.knowhow.* .SH VARABLES .nf $EDITOR set to favorite editor (default is /bin/ed) $KNOWHOW set to knowhow database (directory) .fi .SH TRICKS You can use any directory as knowlegde base try for example: .nf KNOWHOW=/usr/news export KNOWHOW kbq down .fi This will list all news items with the key 'down' in it. .SH ATTENTION The knowhow database is implemented as a simple directory. All files in this directory are scanned for the required keys. It is up to the user to keep this directory clean. .sp The keys are treated with upper and lowercase folded. So there is not difference between key and KEY. @@@ Fin de kb.man echo kba 1>&2 cat >kba <<'@@@ Fin de kba' # kba to add stuff to db export TMP EDITOR KNOWHOW : ${KNOWHOW=$HOME/.knowhow} : ${EDITOR=/bin/ed} LP}TMP=/usr/tmp/d$$ # create TMP file /bin/rm -f $TMP touch $TMP # check for db exist if test -d $KNOWHOW then : # fine else mkdir $KNOWHOW echo "$KNOWHOW created." fi # get info to store if test "$1" = "-e" then echo "Wait while I start $EDITOR...\c" $EDITOR $TMP elif test "$1" = "-f" then cat $2 > $TMP else echo "\nEnter text (end with ^D)" /bin/cat >> $TMP fi # see if empty or not if test -s $TMP then : # okay else echo "Aborted, no input" exit 1 fi NOW=`date +%y%m%d%H%M%S` cat $TMP > $KNOWHOW/$NOW echo "\n$0: Item $NOW added" /bin/rm -f $TMP @@@ Fin de kba echo kbq.c 1>&2 cat >kbq.c <<'@@@ Fin de kbq.c' /* kbq.c to query db-keys for keys -*-update-version-*- ** HFVR VERSION=Tue Jan 6 14:17:54 1987 */ #include <stdio.h> #include <ctype.h> #include <sys/types.h> #include <sys/stat.h> #include "kb.h" char *blk = (char *)NULL; /* ptr to block allocated */ int blksize = 0; /* size of blk block */ int filsize; /* size of file */ static int count = 0; /* number of files found matching */ char KNOWHOW[512]; /* holds copy of $KNOWHOW */ char *NAME; /* pointer to program name */ char *CMD; /* pointer to <command> */ BOOL dflag = FALSE; /* TRUE if must print code */ /* findkey return TRUE if found else FALSE */ BOOL findkey(ptr) CODE *ptr; { extern char *fsindex(); if ( fsindex(blk,ptr->key,ptr->table) != NULL ) { return(TRUE); } else { return(FALSE); } }/*findkey*/ /* chk file for expression match */ SYM chkfile() { extern BOOL interpret(); if ( TRUE == interpret() ) { return(FOUNDsym); } else { return(NOTFOUNDsym); } }/*readkey*/ /* get dir to work in via $KNOWHOW or $HOME/.knowhow */ void getdir() { extern char *getenv(); char *ptr; ptr = getenv("KNOWHOW"); if ( ptr != NULL ) { strcpy(KNOWHOW,ptr); } else { ptr = getenv("HOME"); strcpy(KNOWHOW,ptr); strcat(KNOWHOW,"/.knowhow"); } }/*getdir*/ /* command */ void command(name) char *name; { char cmd[512]; strcpy(cmd,CMD); strcat(cmd," "); strcat(cmd,name); system(cmd); }/*command*/ /* do update on result of query */ void update(name) char *name; { char *ptr; char EDITOR[512]; char cmd[512]; /* : ${EDITOR=/bin/ed} */ ptr = getenv("EDITOR"); if ( ptr != NULL ) { strcpy(EDITOR,ptr); } else { strcpy(EDITOR,"/bin/ed"); } /* $EDITOR $KNOWHOW/name */ printf("%s: Wait while I start %s ...",NAME,EDITOR); fflush(stdout); strcpy(cmd,EDITOR); strcat(cmd," "); strcat(cmd,name); system(cmd); printf("%s: item %s updated\n",NAME,name); }/*update*/ /* set global NAME to start of program name */ void getname(name) char *name; { extern char *strrchr(); NAME = strrchr(name,'/'); if ( NULL == NAME ) { NAME = name; } else { NAME++; } }/*getname*/ void printkey(name) char *name; { printf("%s\n",name); }/*printkey*/ void printitem(name) { char cmd[512]; strcpy(cmd,"cat "); strcat(cmd,name); strcat(cmd," ; echo"); system(cmd); }/*printitem*/ /* strtolower convert string to uppercase */ void strtolower(s) register char *s; { while ( *s ) { *s = tolower(*s); s++; } }/*strtolower*/ /* determine whether we should print or update */ int workonid(name) { struct stat stbuf; int f1; /* see if file exists, if so read it in buffer */ if (stat(name,&stbuf) == -1) { return(10); /* no such file */ } /* see if we need more space */ filsize = stbuf.st_size; if ( filsize + 1 > blksize ) { blksize = filsize + 1; if (blk != NULL) free(blk); blk = (char *)malloc(blksize); if (blk == NULL) { fprintf(stderr,"%s : ERROR : file %s too big\n",NAME,name); return(11); } } /* read in file */ f1 = open(name,0); if (f1 == -1) { fprintf(stderr,"%s : ERROR : cannot read %s\n",NAME,name); return(12); } read(f1, blk, blksize); close(f1); blk[filsize] = '\0'; strtolower(blk); if ( NOTFOUNDsym == chkfile() ) return(0); count++; switch(NAME[2]) { case 'u' : update(name); break; /* kbu */ case 'x' : command(name); break; /* kbx */ case 'q' : printitem(name); break; /* kbq */ case 'c' : break; /* kbc */ case 'k' : printkey(name); break; /* kbk */ default : printitem(name); break; } return(0); }/*workonid*/ main(argc,argv) int argc; char *argv[]; { register SYM result; extern void parse(); int code; if ( argc < 2) { fprintf(stderr,"\007Usage: %s [-d] <query>\n",argv[0]); exit(1); } getname(argv[0]); if ( strcmp(argv[1],"-d") == 0 ) { dflag = TRUE; CMD = argv[3]; strtolower(argv[2]); parse(argv[2]); } else { CMD = argv[2]; strtolower(argv[1]); parse(argv[1]); } getdir(); code = dir(KNOWHOW,workonid,1,1); switch(code) { case 0 : break; case 1 : fprintf(stderr,"%s : ERROR : %s directory does not exist\n",NAME,KNOWHOW); break; case 2 : fprintf(stderr,"%s : ERROR : %s is not a directory\n",NAME,KNOWHOW); break; case 3 : fprintf(stderr,"%s : ERROR : string '%s' too long to handle\n",NAME,KNOWHOW); break; case 4 : fprintf(stderr,"%s : ERROR : cannot read %s\n",NAME,KNOWHOW); break; case 10: break; case 11: break; case 12: break; default: fprintf(stderr,"%s : ERROR : unknown cause\n"); break; } fprintf(stderr,"%s: %d items found\n",NAME,count); return(code); }/*main*/ @@@ Fin de kbq.c echo sindex.c 1>&2 cat >sindex.c <<'@@@ Fin de sindex.c' #include <stdio.h> /* sindex looks for an occurance of the string s2 in the string ** s1. If s2 does not ocurr, sindex returns NULL. Otherwise, sindex ** returns pointer in s1 to where s2 ocurrs. */ char *sindex(big,small) register char *big; register char *small; { int biglen; int smlen; register char *lastchar; register char *bigptr, *smptr, *curptr; biglen = strlen(big); smlen = strlen(small); if (biglen < smlen || smlen == 0) return(NULL); lastchar = big + biglen - smlen; for (bigptr=big ; bigptr <= lastchar ; bigptr++) { curptr = bigptr; smptr = small; while ((*smptr) && (*smptr == *curptr++)) smptr++; if (*smptr == '\0') return(bigptr); } return(NULL); }/*sindex*/ @@@ Fin de sindex.c