/* lookup.c */ /* A simple database lookup. * every entry in the database files is of the form: initial string value * We just have to match the initial string, no separators required. * Not that the specification just asks for a matching entry, not * necessarily the first or the last. */ /* $Id: lookup.c,v 1.2 1992/07/22 14:50:25 espie Exp espie $ */ /* $Log: lookup.c,v $ * Revision 1.2 1992/07/22 14:50:25 espie * open_file changed, so lookup had to change to incorporate paths as well. * * Revision 1.1 1992/07/16 17:02:00 espie * Initial revision * * */ #include #include //#include #include "defs.h" #include "extern.h" LOCAL char *id="$Id"; /* the lookup structure is PRIVATE */ #define HANDLE 0 /* a null type, for memory handling */ #define FNAME 1 /* a filename, which has not yet been opened */ #define FOPENED 2 /* a file, once opened */ #define STRING 3 /* an already accounted for string */ struct lookup { int type; union { char *filename; FILE *file; char *string; char *path; } value; struct lookup *next; }; /*** * * lookup memory handling * ***/ /* link_lookup(base, new): link a new element inside the existing chain */ LOCAL void link_lookup(handle, new) struct lookup *handle, *new; { new->next = handle->next; handle->next = new; } LOCAL void set_lookup(handle, path) struct lookup *handle; char *path; { handle->type = HANDLE; handle->value.path = path; } /* new = create_lookup(): create an empty element, * chain anchor or to be filled */ struct lookup *create_lookup(path) char *path; { struct lookup *new; new = (struct lookup *)malloc(sizeof(struct lookup)); if (!new) exit(10); set_lookup(path); new->next = NULL; return new; } /* free_lookup(handle): free the whole chain. Note that filenames * do not belong to us */ void free_lookup(handle) struct lookup *handle; { struct lookup *to_free; while(handle) { to_free = handle; handle = handle->next; switch(to_free->type) { case HANDLE: case FNAME: /* filenames don't belong to you */ break; case FOPENED: close_file(to_free->value.file.fhandle, to_free->value.file.filetype); break; case STRING: free(to_free->value.string); break; } free(to_free); } } /* add_lookup(handle, filename): add a new potential filename to the lookup * handle */ void add_lookup(handle, filename) struct lookup *handle; char *filename; { struct lookup *new; new = create_lookup(); new->type = FNAME; new->value.filename = filename; link_lookup(handle, new); } /* postfix = check_prefix(template, s): * if s is a prefix of template, return the remaining part of template, * else return NULL. * Note difference between NULL result and empty postfix (pointer to NULL) */ static char *check_prefix(template, s) char *template; char *s; { for (; *s; template++, s++) /* *s != 0 at that point */ if (*template != *s) return NULL; while(*template == ' ' || *template == '\t') template++; return template; } /* copy = create_copy(s): allocate memory and create a copy of string s. * get rid of spurious \n at the end. */ static char *create_copy(s) char *s; { char *new; int len; len = strlen(s); while(s[len - 1] == '\n') s[--len] = 0; new = (char *)malloc(len + 1); if (!new) exit(10); return strcpy(new, s); } #define BUFSIZE 1500 LOCAL char *internal_lookup(); /* postfix = lookup(handle, s): lookup string s in the database indexed by * handle. */ char *lookup(handle, s) struct lookup *handle; char *s; { /* the internal handler also maintains a current path */ return internal_lookup(handle, s, NULL); } LOCAL char *internal_lookup(handle, s, path) struct lookup *handle; char *s; char *path; { char *r; static char buffer[BUFSIZE]; struct lookup *new; if (handle) { switch(handle->type) { case STRING: r = check_string(handle->value.string, s); if (r) return r; else return internal_lookup(handle->next, s, path); case HANDLE: return internal_lookup(handle->next, s, handle->value.path ? handle->value.path : path); case FNAME: r = internal_lookup(handle->next, s, path); if (r) return r; else { if (handle->value.file = open_file(handle->value.filename, "r", path)) { handle->type = FOPENED; return internal_lookup(handle, s, path); } else { set_lookup(handle, NULL); return NULL; } } case FOPENED: r = internal_lookup(handle->next, s, path); if (r) return r; else { if (fgets(buffer, BUFSIZE, handle->value.file)) { new = create_lookup(NULL); new->type = STRING; new->value.string = create_copy(buffer); link_lookup(handle, new); r = check_prefix(new->value.string, s); if (r) return r; else return internal_lookup(handle, s, path); } else { close_file(handle->value.file); set_lookup(new, NULL); } } } } else return NULL; }