/* * gdbmbld.c * G. Gerrietts * March, 1998 * * This file implements a one-way database writer. All it does is plug values * into a gdbm database. It assumes input will be tab-delimited and that the * first item on each line is the key. Subsequent items will be data, and data * are also treated as tab-delimited. The tabs could be swapped in either or * both places for just about anything except \0--it uses string routines for * calculating lengths. */ #include /* for the database routines */ #include /* for strsep() */ #include /* for reading stdin */ /* #include /* for getopt() -- eventually */ #define IRIX #ifdef IRIX /* * oak didn't have strsep, so I included an implementation here. I've put it * inside #ifdef/#endif because it does exist on Linux, Solaris, and a couple * others, and it would undoubtedly be more efficient if I hand-tooled it in * assembly code */ char *strsep(char **str, const char *delim) { char *token, *remainder, *breakpt; /* take a pointer to the beginning of the string */ token = (*str); /* locate the beginning of the delimiter */ breakpt = strstr(token, delim); /* loop across the delimiter, writing \0's across it. Keep stepping * remainder until it's past the end of the delim. */ for(remainder = breakpt; remainder <= (breakpt + strlen(delim)); remainder++) *remainder = '\0'; /* reset what (*str) points to -- should now point to the remainder */ (*str) = remainder; /* return 'token', the original (*str) */ return(token); } #endif int main(void) { /* variable decls */ char buffer[255]; /* base buffer. for input */ GDBM_FILE gdb; /* the database itself */ datum key, data; /* key and data structs */ char *first, *second, *third, *temp; /* char *'s for placeholding */ /* Open the gdbm database--hardcoded the name, oops. */ gdb=gdbm_open("local.gdbm", 512, GDBM_WRCREAT, 0644, NULL); /* main loop: while we've still got data coming back from stdin, loop */ while (fgets(buffer,sizeof(buffer),stdin)) { /* chomp, in Perl terms. If the last char in the buffer is a * newline, we step the \0 back one char */ if (buffer[(strlen(buffer)-1)] == '\n') buffer[(strlen(buffer)-1)] = '\0'; /* take a pointer to the beginning of our buffer. using second * here because after the strsep(), the pointer will be moved * to point to the data rather than to the key--right now, * though, it's pointing to the key. */ second = (char *)buffer; /* tokenize: second gets advanced to point to the data while * first is passed the key. first now points to the key (which * is a \0-terminated string) and second points to the data * (which is also a \0-terminated string). The tab that once * separated them has been overwritten. */ first = strsep(&second,"\t"); /* set up the key: the 'datum' struct has dptr (a void *) and * dsize (size_t or long) as its two elements. Here, we * strdup() the string, thus putting it into dynamic memory, * and then stick strlen() + 1 (to account for the \0) into * the length item. */ key.dptr = strdup(first); key.dsize=(strlen(first)+1); /* check to make sure we have a valid pointer in dptr. If not, * blame it on memory avail, but who knows what really * happened. */ if (!key.dptr) { fprintf(stderr,"Unable to malloc key data\n"); break; } /* check for data: a simple fetch from the database using key */ data = gdbm_fetch(gdb, key); /* if we have a valid pointer, then we've got to concatenate * the new data onto the old data. Simple strcat once we have * an unbroken block of memory to stuff 'em in. */ if (data.dptr) { /* malloc as much data as we already have plus the * strlen() of the new data, plus another 1 for the * tab delimiter. Note that our \0 is already included * in the dsize for the old data; it won't be the * /same/ \0, but the counts come out right. */ third = (char *)malloc((data.dsize+strlen(second)+1)); /* put the old data into the new data buffer */ third = strcpy(third, data.dptr); /* plop a tab onto the end of that */ third = strcat(third, "\t"); /* now stick the new data onto the end of that */ third = strcat(third, second); /* free the memory from the old dptr */ free(data.dptr); /* stick the new data into dptr. */ data.dptr=third; } else { /* if we didn't have new data, then all we hafta do is * strdup() the new data so that it's in dynamic * memory. */ data.dptr=strdup(second); } /* Sanity check again. If dptr isn't valid, die horribly. */ if (!data.dptr) { fprintf(stderr, "Unable to malloc data.\n"); break; } /* set the dsize based on the strlen() */ data.dsize=(strlen(data.dptr)+1); /* notification of the event for tracing or public interest or * whatever. */ printf("Adding key:\n%s\nAdding data:\n%s\n\n", key.dptr, data.dptr); /* The actual store itself. Rather unspectacular, really. */ gdbm_store(gdb, key, data, GDBM_REPLACE); /* Now start tossing memory. If we have a valid pointer still * for key, free it. Same with data. If we don't, Hell * probably just froze over and we should die: we deserve the * segmentation fault at that point. :D */ if (key.dptr) free(key.dptr); if (data.dptr) free(data.dptr); } /* main loop */ /* Okay, just a notification that we broke out of the loop, not even * necessarily after finishing--if we got a bad pointer after trying * to malloc(), we'll also pass this point on our way out. Assuming we * don't start segfaulting wildly. */ printf("All done.\n"); /* Yay! We prove Sartre wrong. */ exit(0); }