diff options
Diffstat (limited to 'iid.y')
-rw-r--r-- | iid.y | 1359 |
1 files changed, 0 insertions, 1359 deletions
@@ -1,1359 +0,0 @@ -%{ -/* iid.y -- interactive mkid query language - Copyright (C) 1991 Tom Horsley - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include <stdio.h> -#include <ctype.h> -#include <string.h> -#include <stdlib.h> -#include <unistd.h> -#include <getopt.h> - -#include <config.h> -#include "strxtra.h" -#include "obstack.h" -#include "xmalloc.h" - -FILE *popen (); - -#define obstack_chunk_alloc xmalloc -#define obstack_chunk_free free - -#if HAVE_ALLOCA - -#if HAVE_ALLOCA_H -#include <alloca.h> -#endif -#define TEMP_ALLOC(s) alloca(s) -#define TEMP_FREE(s) - -#else /* not HAVE_ALLOCA */ - -#define TEMP_ALLOC(s) malloc(s) -#define TEMP_FREE(s) free(s) - -#endif /* not HAVE_ALLOCA */ - -#define HASH_SIZE 947 /* size of hash table for file names */ -#define INIT_FILES 8000 /* start with bits for this many */ -#define INIT_SETSPACE 500 /* start with room for this many */ -#define MAXCMD 1024 /* input command buffer size */ - -#define MAX(a,b) (((a)<(b))?(b):(a)) -#define MIN(a,b) (((a)>(b))?(b):(a)) - -#ifndef PAGER -#define PAGER "pg" -#endif - -#define PROMPT "iid> " - -/* set_type is the struct defining a set of file names - * The file names are stored in a symbol table and assigned - * unique numbers. The set is a bit set of file numbers. - * One of these set structs is calloced for each new set - * constructed, the size allocated depends on the max file - * bit number. An array of pointers to sets are kept to - * represent the complete set of sets. - */ - -struct set_struct { - char * set_desc ; /* string describing the set */ - int set_num ; /* the set number */ - int set_size ; /* number of long words in set */ - unsigned long int set_tail ; /* set extended with these bits */ - unsigned long int set_data[1] ;/* the actual set data (calloced) */ -} ; -typedef struct set_struct set_type ; - -/* id_type is one element of an id_list - */ - -struct id_struct { - struct id_struct * next_id ; /* Linked list of IDs */ - char id [ 1 ] ; /* calloced data holding id string */ -} ; -typedef struct id_struct id_type ; - -/* id_list_type is used during parsing to build lists of - * identifiers that will eventually represent arguments - * to be passed to the database query programs. - */ - -struct id_list_struct { - int id_count ; /* count of IDs in the list */ - id_type * * end_ptr_ptr ;/* pointer to link word at end of list */ - id_type * id_list ; /* pointer to list of IDs */ -} ; -typedef struct id_list_struct id_list_type ; - -/* symtab_type is used to record file names in the symbol table. - */ -struct symtab_struct { - struct symtab_struct * hash_link ; /* list of files with same hash code */ - int mask_word ; /* word in bit vector */ - unsigned long mask_bit ; /* bit in word */ - char name [ 1 ] ; /* the file name */ -} ; -typedef struct symtab_struct symtab_type ; - -/* LidCommand is the command to run for a Lid_group. It is set - * to "lid -kmn" if explicitly preceeded by "lid", otherwise - * it is the default command which is determined by an option. - */ -char const * LidCommand ; - -/* DefaultCommand is the default command for a Lid_group. If - * the -a option is given to iid, it is set to use 'aid'. - */ -char const * DefaultCommand = "lid -kmn" ; - -/* FileList is a lexically ordered list of file symbol table - * pointers. It is dynamically expanded when necessary. - */ -symtab_type * * FileList = NULL ; - -/* FileSpace is the number of long ints in TheFiles array. - */ -int FileSpace = 0 ; - -/* HashTable is the symbol table used to store file names. Each - * new name installed is assigned the next consecutive file number. - */ -symtab_type * HashTable [ HASH_SIZE ] ; - -/* HelpSet is a dummy set containing only one bit set which corresponds - * to the help file name. Simply a cheesy way to maximize sharing of - * the code that runs the pager. - */ -set_type * HelpSet ; - -/* high_bit is a unsigned long with the most significant bit set. - */ -unsigned long high_bit ; - -/* ListSpace is the amount of space avail in the FileList. - */ -int ListSpace = 0 ; - -/* MaxCurFile - max word that has any bit currently set in the - * TheFiles array. - */ -int MaxCurFile = 0 ; - -/* NextFileNum is the file number that will be assigned to the next - * new file name seen when it is installed in the symtab. - */ -int NextFileNum = 0 ; - -/* NextMaskBit is the bit within the next mask word that will - * correspond to the next file added to the symbol table. - */ -unsigned long NextMaskBit ; - -/* NextMaskWord is the next word number to be assigned to a file - * bit mask entry. - */ -int NextMaskWord = 0 ; - -/* NextSetNum is the number that will be assigned to the next set - * created. Starts at 0 because I am a C programmer. - */ -int NextSetNum = 0 ; - -/* The PAGER program to run on a SHOW command. - */ -char Pager[MAXCMD] ; - -/* Prompt - the string to use for a prompt. - */ -char Prompt[MAXCMD] ; - -/* SetSpace is the number of pointers available in TheSets. TheSets - * is realloced when we run out of space. - */ -int SetSpace = 0 ; - -/* TheFiles is a bit set used to construct the initial set of files - * generated while running one of the subprograms. It is copied to - * the alloced set once we know how many bits are set. - */ -unsigned long * TheFiles = NULL ; - -/* TheSets is a dynamically allocated array of pointers pointing - * the sets that have been allocated. It represents the set of - * sets. - */ -set_type * * TheSets = NULL ; - -/* VerboseQuery controls the actions of the semantic routines during - * the process of a query. If TRUE the sets are described as they - * are constructed. - */ -int VerboseQuery ; - -char const *program_name ; - -int yyerror __P(( char const * s )) ; -void ScanInit __P(( char * line )) ; -int yylex __P(( void )) ; -int ArgListSize __P(( id_list_type * idlp )) ; -int SetListSize __P(( set_type * sp )) ; -void FlushFiles __P(( void )) ; -void fatal __P(( char const * s )) ; -int CountBits __P(( set_type * sp )) ; -void OneDescription __P(( set_type * sp )) ; -void DescribeSets __P(( void )) ; -id_list_type * SetList __P(( id_list_type * idlp , set_type * sp )) ; -void PrintSet __P(( set_type * sp )) ; -void FlushSets __P(( void )) ; -id_list_type * InitList __P(( void )) ; -id_list_type * ExtendList __P(( id_list_type * idlp , id_type * idp )) ; -void InitIid __P(( void )) ; -symtab_type * InstallFile __P(( char const * fp )) ; -void RunPager __P(( char * pp , set_type * sp )) ; -void AddSet __P(( set_type * sp )) ; -set_type * RunProg __P(( char const * pp , id_list_type * idlp )) ; -void SetDirectory __P(( id_type * dir )) ; -set_type * SetIntersect __P(( set_type * sp1 , set_type * sp2 )) ; -set_type * SetUnion __P(( set_type * sp1 , set_type * sp2 )) ; -set_type * SetInverse __P(( set_type * sp )) ; -void RunShell __P(( char * pp , id_list_type * idlp )) ; - -%} - -%union { - set_type * setdef ; - id_type * strdef ; - id_list_type * listdef ; -} - -%token < setdef > SET - -%token < strdef > ID SHELL_QUERY SHELL_COMMAND - -%type < setdef > Query Primitive - -%type < listdef > Lid_group Aid_group Id_list Command_list - -%token LID AID BEGIN SETS SS FILES SHOW HELP OFF MATCH - -%left OR - -%left AND - -%left NOT - -%start Command - -%% - -Command : - BEGIN ID - { - /* cd to the directory specified as argument, flush sets */ - - SetDirectory($2) ; - FlushSets() ; - } -| Set_query Query -| File_query Query - { - /* print the list of files resulting from Query */ - - PrintSet($2) ; - } -| SHOW SET - { - /* run PAGER on the list of files in SET */ - - RunPager(Pager, $2) ; - } -| SETS - { - /* describe sets created so far */ - - DescribeSets() ; - } -| HELP - { - /* run PAGER on the help file */ - - RunPager(Pager, HelpSet) ; - } -| OFF - { - exit(0) ; - } -| SHELL_QUERY Command_list - { - /* run the shell command and eat the results as a file set */ - - OneDescription(RunProg($1->id, $2)) ; - free($1) ; - } -| SHELL_COMMAND Command_list - { - /* run the shell command */ - - RunShell($1->id, $2) ; - free($1) ; - } -; - -Set_query : - SS - { - /* Turn on verbose query flag */ - - VerboseQuery = 1 ; - } -; - -File_query : - FILES - { - /* Turn off verbose query flag */ - - VerboseQuery = 0 ; - } -; - -Query : - Primitive - { - /* value of query is set associated with primitive */ - - $$ = $1 ; - } -| Query AND Query - { - /* value of query is intersection of the two query sets */ - - $$ = SetIntersect($1, $3) ; - if (VerboseQuery) { - OneDescription($$) ; - } - } -| Query OR Query - { - /* value of query is union of the two query sets */ - - $$ = SetUnion($1, $3) ; - if (VerboseQuery) { - OneDescription($$) ; - } - } -| NOT Query - { - /* value of query is inverse of other query */ - - $$ = SetInverse($2) ; - if (VerboseQuery) { - OneDescription($$) ; - } - } -; - -Primitive : - SET - { - /* Value of primitive is value of recorded set */ - - $$ = $1 ; - } -| Lid_group - { - /* Value of primitive is obtained by running an lid query */ - - $$ = RunProg(LidCommand, $1) ; - if (VerboseQuery) { - OneDescription($$) ; - } - } -| Aid_group - { - /* Value of primitive is obtained by running an aid query */ - - $$ = RunProg("aid -kmn", $1) ; - if (VerboseQuery) { - OneDescription($$) ; - } - } -| MATCH Id_list - { - /* Match names from database against pattern */ - $$ = RunProg("pid -kmn", $2) ; - if (VerboseQuery) { - OneDescription($$) ; - } - } -| '(' Query ')' - { - /* value of primitive is value of query */ - - $$ = $2 ; - } -; - -Lid_group : - ID - { - /* make arg list holding single ID */ - - $$ = InitList() ; - $$ = ExtendList($$, $1) ; - LidCommand = DefaultCommand ; - } -| LID Id_list - { - /* arg list is Id_list */ - - $$ = $2 ; - LidCommand = "lid -kmn" ; - } -; - -Aid_group : - AID Id_list - { - /* arg list is Id_list */ - - $$ = $2 ; - } -; - -Command_list : - ID - { - /* make arg list holding single ID */ - - $$ = InitList() ; - $$ = ExtendList($$, $1) ; - } -| SET - { - /* make arg list holding names from set */ - - $$ = InitList() ; - $$ = SetList($$, $1) ; - } -| Command_list ID - { - /* extend arg list with additional ID */ - - $$ = ExtendList($1, $2) ; - } -| Command_list SET - { - /* extend arg list with additional file names */ - - $$ = SetList($1, $2) ; - } -; - -Id_list : - ID - { - /* make arg list holding single ID */ - - $$ = InitList() ; - $$ = ExtendList($$, $1) ; - } -| Id_list ID - { - /* extend arg list with additional ID */ - - $$ = ExtendList($1, $2) ; - } -; - -%% - -/* ScanLine - a global variable holding a pointer to the current - * command being scanned. - */ -char * ScanLine ; - -/* ScanPtr - a global pointer to the current scan position in ScanLine. - */ -char * ScanPtr ; - -/* yytext - buffer holding the token. - */ -char yytext [ MAXCMD ] ; - -/* yyerror - process syntax errors. - */ -int -yyerror( char const * s ) -{ - if (*ScanPtr == '\0') { - fprintf(stderr,"Syntax error near end of command.\n") ; - } else { - fprintf(stderr,"Syntax error on or before %s\n",ScanPtr) ; - } - return(0) ; -} - -/* ScanInit - initialize the yylex routine for the new line of input. - * Basically just initializes the global variables that hold the char - * ptrs the scanner uses. - */ -void -ScanInit( char * line ) -{ - /* skip the leading white space - the yylex routine is sensitive - * to keywords in the first position on the command line. - */ - - while (isspace(*line)) ++line ; - ScanLine = line ; - ScanPtr = line ; -} - -/* yylex - the scanner for iid. Basically a kludge ad-hoc piece of junk, - * but what the heck, if it works... - * - * Mostly just scans for non white space strings and returns ID for them. - * Does check especially for '(' and ')'. Just before returning ID it - * checks for command names if it is the first token on line or - * AND, OR, LID, AID if it is in the middle of a line. - */ -int -yylex( void ) -{ - char * bp ; - char c ; - int code = ID ; - char * dp ; - char * sp ; - int val ; - - bp = ScanPtr ; - while (isspace(*bp)) ++bp ; - sp = bp ; - c = *sp++ ; - if ((c == '(') || (c == ')') || (c == '\0')) { - ScanPtr = sp ; - if (c == '\0') { - --ScanPtr ; - } - return(c) ; - } else { - dp = yytext ; - while (! ((c == '(') || (c == ')') || (c == '\0') || isspace(c))) { - *dp++ = c ; - c = *sp++ ; - } - *dp++ = '\0' ; - ScanPtr = sp - 1 ; - if (bp == ScanLine) { - - /* first token on line, check for command names */ - - if (strcaseequ(yytext, "SS")) return(SS) ; - if (strcaseequ(yytext, "FILES")) return(FILES) ; - if (strcaseequ(yytext, "F")) return(FILES) ; - if (strcaseequ(yytext, "HELP")) return(HELP) ; - if (strcaseequ(yytext, "H")) return(HELP) ; - if (strcaseequ(yytext, "?")) return(HELP) ; - if (strcaseequ(yytext, "BEGIN")) return(BEGIN) ; - if (strcaseequ(yytext, "B")) return(BEGIN) ; - if (strcaseequ(yytext, "SETS")) return(SETS) ; - if (strcaseequ(yytext, "SHOW")) return(SHOW) ; - if (strcaseequ(yytext, "P")) return(SHOW) ; - if (strcaseequ(yytext, "OFF")) return(OFF) ; - if (strcaseequ(yytext, "Q")) return(OFF) ; - if (strcaseequ(yytext, "QUIT")) return(OFF) ; - if (yytext[0] == '!') { - code = SHELL_COMMAND ; - } else { - code = SHELL_QUERY ; - } - } else { - - /* not first token, check for operator names */ - - if (strcaseequ(yytext, "LID")) return(LID) ; - if (strcaseequ(yytext, "AID")) return(AID) ; - if (strcaseequ(yytext, "AND")) return(AND) ; - if (strcaseequ(yytext, "OR")) return(OR) ; - if (strcaseequ(yytext, "NOT")) return(NOT) ; - if (strcaseequ(yytext, "MATCH")) return(MATCH) ; - if ((yytext[0] == 's' || yytext[0] == 'S') && isdigit(yytext[1])) { - - /* this might be a set specification */ - - sp = &yytext[1] ; - val = 0 ; - for ( ; ; ) { - c = *sp++ ; - if (c == '\0') { - if (val < NextSetNum) { - yylval.setdef = TheSets[val] ; - return(SET) ; - } - } - if (isdigit(c)) { - val = (val * 10) + (c - '0') ; - } else { - break ; - } - } - } - } - yylval.strdef = (id_type *)malloc(sizeof(id_type) + strlen(yytext)) ; - if (yylval.strdef == NULL) { - fatal("Out of memory in yylex") ; - } - yylval.strdef->next_id = NULL ; - if (code == SHELL_COMMAND) { - strcpy(yylval.strdef->id, &yytext[1]) ; - } else { - strcpy(yylval.strdef->id, yytext) ; - } - return(code) ; - } -} - -/* The main program for iid - parse the command line, initialize processing, - * loop processing one command at a time. - */ -int -main( int argc , char * argv [ ] ) -{ - int c ; /* current option */ - char * CmdPtr = NULL ; /* Points to the command string */ - char Command [ MAXCMD ] ; /* Buffer for reading commands */ - int DoPrompt ; /* 1 if should write a prompt */ - int errors = 0 ; /* error count */ - - program_name = argv[0]; - DoPrompt = isatty(fileno(stdin)) ; - while ((c = getopt(argc, argv, "Hac:")) != EOF) { - switch(c) { - case 'a': - DefaultCommand = "aid -kmn" ; - break ; - case 'c': - CmdPtr = optarg ; - break ; - case 'H': - fputs("\ -iid: interactive ID database query tool. Call with:\n\ - iid [-a] [-c] [-H]\n\ -\n\ --a\tUse the aid as the default query command (not lid).\n\ --c cmd\tExecute the single query cmd and exit.\n\ --H\tPrint this message and exit.\n\ -\n\ -To get help after starting program type 'help'.\n\ -",stderr) ; - exit(0) ; - default: - ++errors ; - break ; - } - } - if (argc != optind) { - fputs("iid: Excess arguments ignored.\n",stderr) ; - ++errors ; - } - if (errors) { - fputs("run iid -H for help.\n",stderr) ; - exit(1) ; - } - - /* initialize global data */ - - InitIid() ; - - /* run the parser */ - - if (CmdPtr) { - ScanInit(CmdPtr) ; - exit(yyparse()) ; - } else { - for ( ; ; ) { - if (DoPrompt) { - fputs(Prompt, stdout) ; - fflush(stdout) ; - } - gets(Command) ; - if (feof(stdin)) { - if (DoPrompt) fputs("\n", stdout) ; - strcpy(Command, "off") ; - } - ScanInit(Command) ; - errors += yyparse() ; - } - } -} - - -/* ArgListSize - count the size of an arg list so can alloca() enough - * space for the command. - */ -int -ArgListSize( id_list_type * idlp ) -{ - id_type * idep ; - int size = 0; - - idep = idlp->id_list ; - while (idep != NULL) { - size += 1 + strlen(idep->id); - idep = idep->next_id; - } - return size; -} - -/* SetListSize - count the size of a string build up from a set so we can - * alloca() enough space for args. - */ -int -SetListSize( set_type * sp ) -{ - int i ; - int size = 0 ; - - for (i = 0; i < NextFileNum; ++i) { - if (FileList[i]->mask_word < sp->set_size) { - if (sp->set_data[FileList[i]->mask_word] & FileList[i]->mask_bit) { - size += 1 + strlen(FileList[i]->name); - } - } - } - return size; -} - -/* FlushFiles - clear out the TheFiles array for the start of a new - * query. - */ -void -FlushFiles( void ) -{ - int i ; - - if (TheFiles != NULL) { - for (i = 0; i <= MaxCurFile; ++i) { - TheFiles[i] = 0 ; - } - } - MaxCurFile = 0 ; -} - -/* fatal - sometimes the only thing to do is die... - */ -void -fatal( char const * s ) -{ - fprintf(stderr,"Fatal error: %s\n", s) ; - exit(1) ; -} - -/* CountBits - count the number of bits in a bit set. Actually fairly - * tricky since it needs to deal with sets having infinite tails - * as a result of a NOT operation. - */ -int -CountBits( set_type * sp ) -{ - unsigned long bit_mask ; - int count = 0 ; - int i ; - - i = 0; - for ( ; ; ) { - for (bit_mask = high_bit; bit_mask != 0; bit_mask >>= 1) { - if (bit_mask == NextMaskBit && i == NextMaskWord) { - return(count) ; - } - if (i < sp->set_size) { - if (sp->set_data[i] & bit_mask) { - ++count ; - } - } else { - if (sp->set_tail == 0) return count; - if (sp->set_tail & bit_mask) { - ++count; - } - } - } - ++i; - } -} - -/* OneDescription - Print a description of a set. This includes - * the set number, the number of files in the set, and the - * set description string. - */ -void -OneDescription( set_type * sp ) -{ - int elt_count ; - char setnum[20] ; - - sprintf(setnum,"S%d",sp->set_num) ; - elt_count = CountBits(sp) ; - printf("%5s %6d %s\n",setnum,elt_count,sp->set_desc) ; -} - -/* DescribeSets - Print description of all the sets. - */ -void -DescribeSets( void ) -{ - int i ; - - if (NextSetNum > 0) { - for (i = 0; i < NextSetNum; ++i) { - OneDescription(TheSets[i]) ; - } - } else { - printf("No sets defined yet.\n") ; - } -} - -/* SetList - Go through the bit set and add the file names in - * it to an identifier list. - */ -id_list_type * -SetList( id_list_type * idlp , set_type * sp ) -{ - int i ; - id_type * idep ; - - for (i = 0; i < NextFileNum; ++i) { - if (FileList[i]->mask_word < sp->set_size) { - if (sp->set_data[FileList[i]->mask_word] & FileList[i]->mask_bit) { - idep = (id_type *)malloc(sizeof(id_type) + - strlen(FileList[i]->name)) ; - if (idep == NULL) { - fatal("Out of memory in SetList") ; - } - idep->next_id = NULL ; - strcpy(idep->id, FileList[i]->name) ; - idlp = ExtendList(idlp, idep) ; - } - } - } - return(idlp) ; -} - -/* PrintSet - Go through the bit set and print the file names - * corresponding to all the set bits. - */ -void -PrintSet( set_type * sp ) -{ - int i ; - - for (i = 0; i < NextFileNum; ++i) { - if (FileList[i]->mask_word < sp->set_size) { - if (sp->set_data[FileList[i]->mask_word] & FileList[i]->mask_bit) { - printf("%s\n",FileList[i]->name) ; - } - } - } -} - -/* Free up all space used by current set of sets and reset all - * set numbers. - */ -void -FlushSets( void ) -{ - int i ; - - for (i = 0; i < NextSetNum; ++i) { - free(TheSets[i]->set_desc) ; - free(TheSets[i]) ; - } - NextSetNum = 0 ; -} - -/* InitList - create an empty identifier list. - */ -id_list_type * -InitList( void ) -{ - id_list_type * idlp ; - - idlp = (id_list_type *)malloc(sizeof(id_list_type)) ; - if (idlp == NULL) { - fatal("Out of memory in InitList") ; - } - idlp->id_count = 0 ; - idlp->end_ptr_ptr = & (idlp->id_list) ; - idlp->id_list = NULL ; - return(idlp) ; -} - -/* ExtendList - add one identifier to an ID list. - */ -id_list_type * -ExtendList( id_list_type * idlp , id_type * idp ) -{ - *(idlp->end_ptr_ptr) = idp ; - idlp->end_ptr_ptr = &(idp->next_id) ; - return(idlp) ; -} - -/* InitIid - do all initial processing for iid. - * 1) Determine the size of a unsigned long for bit set stuff. - * 2) Find out the name of the pager program to use. - * 3) Create the HelpSet (pointing to the help file). - * 4) Setup the prompt. - */ -void -InitIid( void ) -{ - unsigned long bit_mask = 1 ; /* find number of bits in long */ - int i ; - char const * page ; /* pager program */ - - do { - high_bit = bit_mask ; - bit_mask <<= 1 ; - } while (bit_mask != 0) ; - - NextMaskBit = high_bit ; - - page = getenv("PAGER") ; - if (page == NULL) { - page = PAGER ; - } - strcpy(Pager, page) ; - - FlushFiles() ; - InstallFile(IID_HELP_FILE) ; - HelpSet = (set_type *) - malloc(sizeof(set_type) + sizeof(unsigned long) * MaxCurFile) ; - if (HelpSet == NULL) { - fatal("No memory for set in InitIid") ; - } - HelpSet->set_tail = 0 ; - HelpSet->set_desc = NULL ; - HelpSet->set_size = MaxCurFile + 1 ; - for (i = 0; i <= MaxCurFile; ++i) { - HelpSet->set_data[i] = TheFiles[i] ; - } - - page = getenv("PS1") ; - if (page == NULL) { - page = PROMPT ; - } - strcpy(Prompt, page) ; -} - -/* InstallFile - install a file name in the symtab. Return the - * symbol table pointer of the file. - */ -symtab_type * -InstallFile( char const * fp ) -{ - char c ; - unsigned long hash_code ; - int i ; - char const * sp ; - symtab_type * symp ; - - hash_code = 0 ; - sp = fp ; - while ((c = *sp++) != '\0') { - hash_code <<= 1 ; - hash_code ^= (unsigned long)(c) ; - if (hash_code & high_bit) { - hash_code &= ~ high_bit ; - hash_code ^= 1 ; - } - } - hash_code %= HASH_SIZE ; - symp = HashTable[hash_code] ; - while (symp != NULL && strcmp(symp->name, fp)) { - symp = symp->hash_link ; - } - if (symp == NULL) { - symp = (symtab_type *)malloc(sizeof(symtab_type) + strlen(fp)) ; - if (symp == NULL) { - fatal("No memory for symbol table entry in InstallFile") ; - } - strcpy(symp->name, fp) ; - symp->hash_link = HashTable[hash_code] ; - HashTable[hash_code] = symp ; - if (NextMaskWord >= FileSpace) { - FileSpace += 1000 ; - if (TheFiles != NULL) { - TheFiles = (unsigned long *) - realloc(TheFiles, sizeof(unsigned long) * FileSpace) ; - } else { - TheFiles = (unsigned long *) - malloc(sizeof(unsigned long) * FileSpace) ; - } - if (TheFiles == NULL) { - fatal("No memory for TheFiles in InstallFile") ; - } - for (i = NextMaskWord; i < FileSpace; ++i) { - TheFiles[i] = 0 ; - } - } - symp->mask_word = NextMaskWord ; - symp->mask_bit = NextMaskBit ; - NextMaskBit >>= 1 ; - if (NextMaskBit == 0) { - NextMaskBit = high_bit ; - ++NextMaskWord ; - } - if (NextFileNum >= ListSpace) { - ListSpace += 1000 ; - if (FileList == NULL) { - FileList = (symtab_type **) - malloc(sizeof(symtab_type *) * ListSpace) ; - } else { - FileList = (symtab_type **) - realloc(FileList, ListSpace * sizeof(symtab_type *)) ; - } - if (FileList == NULL) { - fatal("No memory for FileList in InstallFile") ; - } - } - FileList[NextFileNum++] = symp ; - /* put code here to sort the file list by name someday */ - } - TheFiles[symp->mask_word] |= symp->mask_bit ; - if (symp->mask_word > MaxCurFile) { - MaxCurFile = symp->mask_word ; - } - return(symp) ; -} - -/* RunPager - run the users pager program on the list of files - * in the set. - */ -void -RunPager( char * pp , set_type * sp ) -{ - char * cmd ; - int i ; - - cmd = (char *)TEMP_ALLOC(SetListSize(sp) + strlen(pp) + 2); - strcpy(cmd, pp) ; - for (i = 0; i < NextFileNum; ++i) { - if (FileList[i]->mask_word < sp->set_size) { - if (sp->set_data[FileList[i]->mask_word] & FileList[i]->mask_bit) { - strcat(cmd, " ") ; - strcat(cmd, FileList[i]->name) ; - } - } - } - system(cmd) ; - TEMP_FREE(cmd) ; -} - -/* AddSet - add a new set to the universal list of sets. Assign - * it the next set number. - */ -void -AddSet( set_type * sp ) -{ - if (NextSetNum >= SetSpace) { - SetSpace += 1000 ; - if (TheSets != NULL) { - TheSets = (set_type **) - realloc(TheSets, sizeof(set_type *) * SetSpace) ; - } else { - TheSets = (set_type **) - malloc(sizeof(set_type *) * SetSpace) ; - } - if (TheSets == NULL) { - fatal("No memory for TheSets in AddSet") ; - } - } - sp->set_num = NextSetNum ; - TheSets[NextSetNum++] = sp ; -} - -/* RunProg - run a program with arguments from id_list and - * accept list of file names back from the program which - * are installed in the symbol table and used to construct - * a new set. - */ -set_type * -RunProg( char const * pp , id_list_type * idlp ) -{ - int c ; - char * cmd ; - char * dp ; - struct obstack pipe_output_obstack; - int i ; - id_type * idep ; - id_type * next_id ; - FILE * prog ; - set_type * sp ; - - cmd = (char *)TEMP_ALLOC(ArgListSize(idlp) + strlen(pp) + 2); - FlushFiles() ; - strcpy(cmd, pp) ; - idep = idlp->id_list ; - while (idep != NULL) { - strcat(cmd, " ") ; - strcat(cmd, idep->id) ; - next_id = idep->next_id ; - free(idep) ; - idep = next_id ; - } - free(idlp) ; - - /* run program with popen, reading the output. Assume each - * white space terminated string is a file name. - */ - - prog = popen(cmd, "r") ; - obstack_init (&pipe_output_obstack); - - while (1) - { - c = getc (prog); - if (c == EOF || isspace (c)) - { - int n; - if ((n = obstack_object_size (&pipe_output_obstack)) > 0) - { - char *_file; - - obstack_1grow (&pipe_output_obstack, 0); - ++n; - _file = obstack_finish (&pipe_output_obstack); - InstallFile(_file) ; - if (n != strlen (_file) + 1) - abort (); - obstack_free (&pipe_output_obstack, _file); - } - if (c == EOF) - break; - } - else - { - obstack_1grow (&pipe_output_obstack, c); - } - } - obstack_free (&pipe_output_obstack, NULL); - - if (pclose(prog) != 0) { - /* if there was an error make an empty set, who knows what - * garbage the program printed. - */ - FlushFiles() ; - } - - sp = (set_type *) - malloc(sizeof(set_type) + sizeof(unsigned long) * MaxCurFile) ; - if (sp == NULL) { - fatal("No memory for set in RunProg") ; - } - sp->set_tail = 0 ; - sp->set_desc = (char *)malloc(strlen(cmd) + 1) ; - if (sp->set_desc == NULL) { - fatal("No memory for set description in RunProg") ; - } - strcpy(sp->set_desc, cmd) ; - sp->set_size = MaxCurFile + 1 ; - for (i = 0; i <= MaxCurFile; ++i) { - sp->set_data[i] = TheFiles[i] ; - } - AddSet(sp) ; - TEMP_FREE(cmd); - return(sp) ; -} - -/* SetDirectory - change the working directory. This will - * determine which ID file is found by the subprograms. - */ -void -SetDirectory( id_type * dir ) -{ - if (chdir(dir->id) != 0) { - fprintf(stderr,"Directory %s not accessible.\n", dir->id) ; - } - free(dir) ; -} - -/* SetIntersect - construct a new set from the intersection - * of two others. Also construct a new description string. - */ -set_type * -SetIntersect( set_type * sp1 , set_type * sp2 ) -{ - char * desc ; - int i ; - int len1 ; - int len2 ; - set_type * new_set ; - int new_size ; - - if (sp1->set_tail || sp2->set_tail) { - new_size = MAX(sp1->set_size, sp2->set_size) ; - } else { - new_size = MIN(sp1->set_size, sp2->set_size) ; - } - new_set = (set_type *)malloc(sizeof(set_type) + - (new_size - 1) * sizeof(unsigned long)) ; - if (new_set == NULL) { - fatal("No memory for set in SetIntersect") ; - } - len1 = strlen(sp1->set_desc) ; - len2 = strlen(sp2->set_desc) ; - desc = (char *)malloc(len1 + len2 + 10) ; - if (desc == NULL) { - fatal("No memory for set description in SetIntersect") ; - } - new_set->set_desc = desc ; - strcpy(desc,"(") ; - ++desc ; - strcpy(desc, sp1->set_desc) ; - desc += len1 ; - strcpy(desc, ") AND (") ; - desc += 7 ; - strcpy(desc, sp2->set_desc) ; - desc += len2 ; - strcpy(desc, ")") ; - AddSet(new_set) ; - new_set->set_size = new_size ; - for (i = 0; i < new_size; ++i) { - new_set->set_data[i] = - ((i < sp1->set_size) ? sp1->set_data[i] : sp1->set_tail) & - ((i < sp2->set_size) ? sp2->set_data[i] : sp2->set_tail) ; - } - new_set->set_tail = sp1->set_tail & sp2->set_tail ; - return(new_set) ; -} - -/* SetUnion - construct a new set from the union of two others. - * Also construct a new description string. - */ -set_type * -SetUnion( set_type * sp1 , set_type * sp2 ) -{ - char * desc ; - int i ; - int len1 ; - int len2 ; - set_type * new_set ; - int new_size ; - - new_size = MAX(sp1->set_size, sp2->set_size) ; - new_set = (set_type *)malloc(sizeof(set_type) + - (new_size - 1) * sizeof(unsigned long)) ; - if (new_set == NULL) { - fatal("No memory for set in SetUnion") ; - } - len1 = strlen(sp1->set_desc) ; - len2 = strlen(sp2->set_desc) ; - desc = (char *)malloc(len1 + len2 + 9) ; - if (desc == NULL) { - fatal("No memory for set description in SetUnion") ; - } - new_set->set_desc = desc ; - strcpy(desc,"(") ; - ++desc ; - strcpy(desc, sp1->set_desc) ; - desc += len1 ; - strcpy(desc, ") OR (") ; - desc += 6 ; - strcpy(desc, sp2->set_desc) ; - desc += len2 ; - strcpy(desc, ")") ; - AddSet(new_set) ; - new_set->set_size = new_size ; - for (i = 0; i < new_size; ++i) { - new_set->set_data[i] = - ((i < sp1->set_size) ? (sp1->set_data[i]) : sp1->set_tail) | - ((i < sp2->set_size) ? (sp2->set_data[i]) : sp2->set_tail) ; - } - new_set->set_tail = sp1->set_tail | sp2->set_tail ; - return(new_set) ; -} - -/* SetInverse - construct a new set from the inverse of another. - * Also construct a new description string. - * - * This is kind of tricky. An inverse set in iid may grow during - * the course of a session. By NOTing the set_tail extension the - * inverse at any given time will be defined as the inverse against - * a universe that grows as additional queries are made and new files - * are added to the database. - * - * Several alternative definitions were possible (snapshot the - * universe at the time of the NOT, go read the ID file to - * determine the complete universe), but this one was the one - * I picked. - */ -set_type * -SetInverse( set_type * sp ) -{ - char * desc ; - int i ; - set_type * new_set ; - - new_set = (set_type *)malloc(sizeof(set_type) + - (sp->set_size - 1) * sizeof(unsigned long)) ; - if (new_set == NULL) { - fatal("No memory for set in SetInverse") ; - } - desc = (char *)malloc(strlen(sp->set_desc) + 5) ; - if (desc == NULL) { - fatal("No memory for set description in SetInverse") ; - } - new_set->set_desc = desc ; - strcpy(desc,"NOT ") ; - desc += 4 ; - strcpy(desc, sp->set_desc) ; - AddSet(new_set) ; - new_set->set_size = sp->set_size ; - for (i = 0; i < sp->set_size; ++i) { - new_set->set_data[i] = ~ sp->set_data[i] ; - } - new_set->set_tail = ~ sp->set_tail ; - return(new_set) ; -} - -/* RunShell - run a program with arguments from id_list. - */ -void -RunShell( char * pp , id_list_type * idlp ) -{ - char * cmd ; - id_type * idep ; - id_type * next_id ; - - cmd = (char *)TEMP_ALLOC(ArgListSize(idlp) + strlen(pp) + 2); - strcpy(cmd, pp) ; - idep = idlp->id_list ; - while (idep != NULL) { - strcat(cmd, " ") ; - strcat(cmd, idep->id) ; - next_id = idep->next_id ; - free(idep) ; - idep = next_id ; - } - free(idlp) ; - system(cmd) ; - TEMP_FREE(cmd); -} |