Path: utzoo!utgpu!cs.utexas.edu!wuarchive!rex!uflorida!travis!tom From: tom@ssd.csd.harris.com (Tom Horsley) Newsgroups: alt.sources Subject: mkid 09/11 (identifier cross reference tool) Message-ID: Date: 12 Dec 90 14:47:21 GMT Sender: news@travis.csd.harris.com Organization: Harris Computer Systems Division Lines: 704 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh 'iidfun.c' <<'END_OF_FILE' X/* iidfun.c - This file holds the utility functions called from iid.y X */ X X#include "iiddef.h" X X/* ArgListSize - count the size of an arg list so can alloca() enough X * space for the command. X */ Xint XArgListSize(idlp) X id_list_type * idlp ; X{ X id_type * idep ; X int size = 0; X X idep = idlp->id_list ; X while (idep != NULL) { X size += 1 + strlen(idep->id); X idep = idep->next_id; X } X return size; X} X X/* SetListSize - count the size of a string build up from a set so we can X * alloca() enough space for args. X */ Xint XSetListSize(sp) X set_type * sp ; X{ X int i ; X int size = 0 ; X X for (i = 0; i < NextFileNum; ++i) { X if (FileList[i]->mask_word < sp->set_size) { X if (sp->set_data[FileList[i]->mask_word] & FileList[i]->mask_bit) { X size += 1 + strlen(FileList[i]->name); X } X } X } X return size; X} X X/* FlushFiles - clear out the TheFiles array for the start of a new X * query. X */ Xvoid XFlushFiles() X{ X int i ; X X if (TheFiles != NULL) { X for (i = 0; i <= MaxCurFile; ++i) { X TheFiles[i] = 0 ; X } X } X MaxCurFile = 0 ; X} X X/* fatal - sometimes the only thing to do is die... X */ Xvoid Xfatal(s) X{ X fprintf(stderr,"Fatal error: %s\n",s) ; X exit(1) ; X} X X/* CountBits - count the number of bits in a bit set. Actually fairly X * tricky since it needs to deal with sets having infinite tails X * as a result of a NOT operation. X */ Xint XCountBits(sp) X set_type * sp ; X{ X unsigned long bit_mask ; X int count = 0 ; X int i ; X X i = 0; X for ( ; ; ) { X for (bit_mask = high_bit; bit_mask != 0; bit_mask >>= 1) { X if (bit_mask == NextMaskBit && i == NextMaskWord) { X return(count) ; X } X if (i < sp->set_size) { X if (sp->set_data[i] & bit_mask) { X ++count ; X } X } else { X if (sp->set_tail == 0) return count; X if (sp->set_tail & bit_mask) { X ++count; X } X } X } X ++i; X } X} X X/* OneDescription - Print a description of a set. This includes X * the set number, the number of files in the set, and the X * set description string. X */ Xvoid XOneDescription(sp) X set_type * sp ; X{ X int elt_count ; X char setnum[20] ; X X sprintf(setnum,"S%d",sp->set_num) ; X elt_count = CountBits(sp) ; X printf("%5s %6d %s\n",setnum,elt_count,sp->set_desc) ; X} X X/* DescribeSets - Print description of all the sets. X */ Xvoid XDescribeSets() X{ X int i ; X X if (NextSetNum > 0) { X for (i = 0; i < NextSetNum; ++i) { X OneDescription(TheSets[i]) ; X } X } else { X printf("No sets defined yet.\n") ; X } X} X X/* SetList - Go through the bit set and add the file names in X * it to an identifier list. X */ Xid_list_type * XSetList(idlp, sp) X id_list_type * idlp ; X set_type * sp ; X{ X int i ; X id_type * idep ; X X for (i = 0; i < NextFileNum; ++i) { X if (FileList[i]->mask_word < sp->set_size) { X if (sp->set_data[FileList[i]->mask_word] & FileList[i]->mask_bit) { X idep = (id_type *)malloc(sizeof(id_type) + X strlen(FileList[i]->name)) ; X if (idep == NULL) { X fatal("Out of memory in SetList") ; X } X idep->next_id = NULL ; X strcpy(idep->id, FileList[i]->name) ; X idlp = ExtendList(idlp, idep) ; X } X } X } X return(idlp) ; X} X X/* PrintSet - Go through the bit set and print the file names X * corresponding to all the set bits. X */ Xvoid XPrintSet(sp) X set_type * sp ; X{ X int i ; X X for (i = 0; i < NextFileNum; ++i) { X if (FileList[i]->mask_word < sp->set_size) { X if (sp->set_data[FileList[i]->mask_word] & FileList[i]->mask_bit) { X printf("%s\n",FileList[i]->name) ; X } X } X } X} X X/* Free up all space used by current set of sets and reset all X * set numbers. X */ Xvoid XFlushSets() X{ X int i ; X X for (i = 0; i < NextSetNum; ++i) { X free(TheSets[i]->set_desc) ; X free(TheSets[i]) ; X } X NextSetNum = 0 ; X} X X/* InitList - create an empty identifier list. X */ Xid_list_type * XInitList() X{ X id_list_type * idlp ; X X idlp = (id_list_type *)malloc(sizeof(id_list_type)) ; X if (idlp == NULL) { X fatal("Out of memory in InitList") ; X } X idlp->id_count = 0 ; X idlp->end_ptr_ptr = & (idlp->id_list) ; X idlp->id_list = NULL ; X return(idlp) ; X} X X/* ExtendList - add one identifier to an ID list. X */ Xid_list_type * XExtendList(idlp, idp) X id_list_type * idlp ; X id_type * idp ; X{ X *(idlp->end_ptr_ptr) = idp ; X idlp->end_ptr_ptr = &(idp->next_id) ; X return(idlp) ; X} X X/* InitIid - do all initial processing for iid. X * 1) Determine the size of a unsigned long for bit set stuff. X * 2) Find out the name of the pager program to use. X * 3) Create the HelpSet (pointing to the help file). X * 4) Setup the prompt. X */ Xvoid XInitIid() X{ X unsigned long bit_mask = 1 ; /* find number of bits in long */ X int i ; X char * page ; /* pager program */ X X do { X high_bit = bit_mask ; X bit_mask <<= 1 ; X } while (bit_mask != 0) ; X X NextMaskBit = high_bit ; X X page = getenv("PAGER") ; X if (page == NULL) { X page = PAGER ; X } X strcpy(Pager, page) ; X X FlushFiles() ; X InstallFile(HELPFILE) ; X HelpSet = (set_type *) X malloc(sizeof(set_type) + sizeof(unsigned long) * MaxCurFile) ; X if (HelpSet == NULL) { X fatal("No memory for set in InitIid") ; X } X HelpSet->set_tail = 0 ; X HelpSet->set_desc = NULL ; X HelpSet->set_size = MaxCurFile + 1 ; X for (i = 0; i <= MaxCurFile; ++i) { X HelpSet->set_data[i] = TheFiles[i] ; X } X X page = getenv("PS1") ; X if (page == NULL) { X page = PROMPT ; X } X strcpy(Prompt, page) ; X} X X/* InstallFile - install a file name in the symtab. Return the X * symbol table pointer of the file. X */ Xsymtab_type * XInstallFile(fp) X char * fp ; X{ X char c ; X unsigned long hash_code ; X int i ; X char * sp ; X symtab_type * symp ; X X hash_code = 0 ; X sp = fp ; X while ((c = *sp++) != '\0') { X hash_code <<= 1 ; X hash_code ^= (unsigned long)(c) ; X if (hash_code & high_bit) { X hash_code &= ~ high_bit ; X hash_code ^= 1 ; X } X } X hash_code %= HASH_SIZE ; X symp = HashTable[hash_code] ; X while (symp != NULL && strcmp(symp->name, fp)) { X symp = symp->hash_link ; X } X if (symp == NULL) { X symp = (symtab_type *)malloc(sizeof(symtab_type) + strlen(fp)) ; X if (symp == NULL) { X fatal("No memory for symbol table entry in InstallFile") ; X } X strcpy(symp->name, fp) ; X symp->hash_link = HashTable[hash_code] ; X HashTable[hash_code] = symp ; X if (NextMaskWord >= FileSpace) { X FileSpace += 1000 ; X if (TheFiles != NULL) { X TheFiles = (unsigned long *) X realloc(TheFiles, sizeof(unsigned long) * FileSpace) ; X } else { X TheFiles = (unsigned long *) X malloc(sizeof(unsigned long) * FileSpace) ; X } X if (TheFiles == NULL) { X fatal("No memory for TheFiles in InstallFile") ; X } X for (i = NextMaskWord; i < FileSpace; ++i) { X TheFiles[i] = 0 ; X } X } X symp->mask_word = NextMaskWord ; X symp->mask_bit = NextMaskBit ; X NextMaskBit >>= 1 ; X if (NextMaskBit == 0) { X NextMaskBit = high_bit ; X ++NextMaskWord ; X } X if (NextFileNum >= ListSpace) { X ListSpace += 1000 ; X if (FileList == NULL) { X FileList = (symtab_type **) X malloc(sizeof(symtab_type *) * ListSpace) ; X } else { X FileList = (symtab_type **) X realloc(FileList, ListSpace * sizeof(symtab_type *)) ; X } X if (FileList == NULL) { X fatal("No memory for FileList in InstallFile") ; X } X } X FileList[NextFileNum++] = symp ; X /* put code here to sort the file list by name someday */ X } X TheFiles[symp->mask_word] |= symp->mask_bit ; X if (symp->mask_word > MaxCurFile) { X MaxCurFile = symp->mask_word ; X } X return(symp) ; X} X X/* RunPager - run the users pager program on the list of files X * in the set. X */ Xvoid XRunPager(pp, sp) X char * pp ; X set_type * sp ; X{ X char * cmd = (char *)alloca(SetListSize(sp) + strlen(pp) + 2); X int i ; X id_type * idep ; X X strcpy(cmd, pp) ; X for (i = 0; i < NextFileNum; ++i) { X if (FileList[i]->mask_word < sp->set_size) { X if (sp->set_data[FileList[i]->mask_word] & FileList[i]->mask_bit) { X strcat(cmd, " ") ; X strcat(cmd, FileList[i]->name) ; X } X } X } X system(cmd) ; X} X X/* AddSet - add a new set to the universal list of sets. Assign X * it the next set number. X */ Xvoid XAddSet(sp) X set_type * sp ; X{ X if (NextSetNum >= SetSpace) { X SetSpace += 1000 ; X if (TheSets != NULL) { X TheSets = (set_type **) X realloc(TheSets, sizeof(set_type *) * SetSpace) ; X } else { X TheSets = (set_type **) X malloc(sizeof(set_type *) * SetSpace) ; X } X if (TheSets == NULL) { X fatal("No memory for TheSets in AddSet") ; X } X } X sp->set_num = NextSetNum ; X TheSets[NextSetNum++] = sp ; X} X X/* RunProg - run a program with arguments from id_list and X * accept list of file names back from the program which X * are installed in the symbol table and used to construct X * a new set. X */ Xset_type * XRunProg(pp, idlp) X char * pp ; X id_list_type * idlp ; X{ X int c ; X char * cmd = (char *)alloca(ArgListSize(idlp) + strlen(pp) + 2); X char * dp ; X char file [ MAXCMD ] ; X int i ; X id_type * idep ; X id_type * next_id ; X FILE * prog ; X set_type * sp ; X X FlushFiles() ; X strcpy(cmd, pp) ; X idep = idlp->id_list ; X while (idep != NULL) { X strcat(cmd, " ") ; X strcat(cmd, idep->id) ; X next_id = idep->next_id ; X free(idep) ; X idep = next_id ; X } X free(idlp) ; X X /* run program with popen, reading the output. Assume each X * white space terminated string is a file name. X */ X prog = popen(cmd, "r") ; X dp = file ; X while ((c = getc(prog)) != EOF) { X if (isspace(c)) { X if (dp != file) { X *dp++ = '\0' ; X InstallFile(file) ; X dp = file ; X } X } else { X *dp++ = c ; X } X } X if (dp != file) { X *dp++ = '\0' ; X InstallFile(file) ; X } X if (pclose(prog) != 0) { X /* if there was an error make an empty set, who knows what X * garbage the program printed. X */ X FlushFiles() ; X } X X sp = (set_type *) X malloc(sizeof(set_type) + sizeof(unsigned long) * MaxCurFile) ; X if (sp == NULL) { X fatal("No memory for set in RunProg") ; X } X sp->set_tail = 0 ; X sp->set_desc = (char *)malloc(strlen(cmd) + 1) ; X if (sp->set_desc == NULL) { X fatal("No memory for set description in RunProg") ; X } X strcpy(sp->set_desc, cmd) ; X sp->set_size = MaxCurFile + 1 ; X for (i = 0; i <= MaxCurFile; ++i) { X sp->set_data[i] = TheFiles[i] ; X } X AddSet(sp) ; X return(sp) ; X} X X/* SetDirectory - change the working directory. This will X * determine which ID file is found by the subprograms. X */ Xvoid XSetDirectory(dir) X id_type * dir ; X{ X if (chdir(dir->id) != 0) { X fprintf(stderr,"Directory %s not accessible.\n",dir) ; X } X free(dir) ; X} X X/* SetIntersect - construct a new set from the intersection X * of two others. Also construct a new description string. X */ Xset_type * XSetIntersect(sp1, sp2) X set_type * sp1 ; X set_type * sp2 ; X{ X char * desc ; X int i ; X int len1 ; X int len2 ; X set_type * new_set ; X int new_size ; X X if (sp1->set_tail || sp2->set_tail) { X new_size = MAX(sp1->set_size, sp2->set_size) ; X } else { X new_size = MIN(sp1->set_size, sp2->set_size) ; X } X new_set = (set_type *)malloc(sizeof(set_type) + X (new_size - 1) * sizeof(unsigned long)) ; X if (new_set == NULL) { X fatal("No memory for set in SetIntersect") ; X } X len1 = strlen(sp1->set_desc) ; X len2 = strlen(sp2->set_desc) ; X desc = (char *)malloc(len1 + len2 + 10) ; X if (desc == NULL) { X fatal("No memory for set description in SetIntersect") ; X } X new_set->set_desc = desc ; X strcpy(desc,"(") ; X ++desc ; X strcpy(desc, sp1->set_desc) ; X desc += len1 ; X strcpy(desc, ") AND (") ; X desc += 7 ; X strcpy(desc, sp2->set_desc) ; X desc += len2 ; X strcpy(desc, ")") ; X AddSet(new_set) ; X new_set->set_size = new_size ; X for (i = 0; i < new_size; ++i) { X new_set->set_data[i] = X ((i < sp1->set_size) ? sp1->set_data[i] : sp1->set_tail) & X ((i < sp2->set_size) ? sp2->set_data[i] : sp2->set_tail) ; X } X new_set->set_tail = sp1->set_tail & sp2->set_tail ; X return(new_set) ; X} X X/* SetUnion - construct a new set from the union of two others. X * Also construct a new description string. X */ Xset_type * XSetUnion(sp1, sp2) X set_type * sp1 ; X set_type * sp2 ; X{ X char * desc ; X int i ; X int len1 ; X int len2 ; X set_type * new_set ; X int new_size ; X X new_size = MAX(sp1->set_size, sp2->set_size) ; X new_set = (set_type *)malloc(sizeof(set_type) + X (new_size - 1) * sizeof(unsigned long)) ; X if (new_set == NULL) { X fatal("No memory for set in SetUnion") ; X } X len1 = strlen(sp1->set_desc) ; X len2 = strlen(sp2->set_desc) ; X desc = (char *)malloc(len1 + len2 + 9) ; X if (desc == NULL) { X fatal("No memory for set description in SetUnion") ; X } X new_set->set_desc = desc ; X strcpy(desc,"(") ; X ++desc ; X strcpy(desc, sp1->set_desc) ; X desc += len1 ; X strcpy(desc, ") OR (") ; X desc += 6 ; X strcpy(desc, sp2->set_desc) ; X desc += len2 ; X strcpy(desc, ")") ; X AddSet(new_set) ; X new_set->set_size = new_size ; X for (i = 0; i < new_size; ++i) { X new_set->set_data[i] = X ((i < sp1->set_size) ? (sp1->set_data[i]) : sp1->set_tail) | X ((i < sp2->set_size) ? (sp2->set_data[i]) : sp2->set_tail) ; X } X new_set->set_tail = sp1->set_tail | sp2->set_tail ; X return(new_set) ; X} X X/* SetInverse - construct a new set from the inverse of another. X * Also construct a new description string. X * X * This is kind of tricky. An inverse set in iid may grow during X * the course of a session. By NOTing the set_tail extension the X * inverse at any given time will be defined as the inverse against X * a universe that grows as additional queries are made and new files X * are added to the database. X * X * Several alternative definitions were possible (snapshot the X * universe at the time of the NOT, go read the ID file to X * determine the complete universe), but this one was the one X * I picked. X */ Xset_type * XSetInverse(sp) X set_type * sp ; X{ X char * desc ; X int i ; X set_type * new_set ; X X new_set = (set_type *)malloc(sizeof(set_type) + X (sp->set_size - 1) * sizeof(unsigned long)) ; X if (new_set == NULL) { X fatal("No memory for set in SetInverse") ; X } X desc = (char *)malloc(strlen(sp->set_desc) + 5) ; X if (desc == NULL) { X fatal("No memory for set description in SetInverse") ; X } X new_set->set_desc = desc ; X strcpy(desc,"NOT ") ; X desc += 4 ; X strcpy(desc, sp->set_desc) ; X AddSet(new_set) ; X new_set->set_size = sp->set_size ; X for (i = 0; i < sp->set_size; ++i) { X new_set->set_data[i] = ~ sp->set_data[i] ; X } X new_set->set_tail = ~ sp->set_tail ; X return(new_set) ; X} X X/* RunShell - run a program with arguments from id_list. X */ Xvoid XRunShell(pp, idlp) X char * pp ; X id_list_type * idlp ; X{ X char * cmd = (char *)alloca(ArgListSize(idlp) + strlen(pp) + 2); X id_type * idep ; X id_type * next_id ; X X strcpy(cmd, pp) ; X idep = idlp->id_list ; X while (idep != NULL) { X strcat(cmd, " ") ; X strcat(cmd, idep->id) ; X next_id = idep->next_id ; X free(idep) ; X idep = next_id ; X } X free(idlp) ; X system(cmd) ; X} END_OF_FILE if test 16553 -ne `wc -c <'iidfun.c'`; then echo shar: \"'iidfun.c'\" unpacked with wrong size! fi # end of 'iidfun.c' fi echo shar: End of archive 9 \(of 11\). cp /dev/null ark9isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 11 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 -- ====================================================================== domain: tahorsley@csd.harris.com USMail: Tom Horsley uucp: ...!uunet!hcx1!tahorsley 511 Kingbird Circle Delray Beach, FL 33444 +==== Censorship is the only form of Obscenity ======================+ | (Wait, I forgot government tobacco subsidies...) | +====================================================================+