/* * Hash table utility program. * * Copyright 2000 by Gray Watson * * This file is part of the table package. * * Permission to use, copy, modify, and distribute this software for any * purpose and without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies, * and that the name of Gray Watson not be used in advertising or * publicity pertaining to distribution of the document or software * without specific, written prior permission. * * Gray Watson makes no representations about the suitability of the * software described herein for any purpose. It is provided "as is" * without express or implied warranty. * * The author may be reached via http://256.com/gray/ * * $Id: table_util.c,v 1.5 2000/03/09 03:30:42 gray Exp $ */ #include #include #include #include "table.h" static char *rcs_id = "$Id: table_util.c,v 1.5 2000/03/09 03:30:42 gray Exp $"; #define WRITE_MODE 0640 /* mode to write out table */ #define SPECIAL_CHARS "e\033^^\"\"''\\\\n\nr\rt\tb\bf\fa\007" /* * expand_chars * * DESCRIPTION: * * Copies a buffer into a output buffer while translates * non-printables into %03o octal values. If it can, it will also * translate certain \ characters (\r, \n, etc.) into \\%c. The * routine is useful for printing out binary values. * * NOTE: It does _not_ add a \0 at the end of the output buffer. * * RETURNS: * * Returns the number of characters added to the output buffer. * * ARGUMENTS: * * buf - the buffer to convert. * * buf_size - size of the buffer. If < 0 then it will expand till it * sees a \0 character. * * out - destination buffer for the convertion. * * out_size - size of the output buffer. */ int expand_chars(const void *buf, const int buf_size, char *out, const int out_size) { int buf_c; const unsigned char *buf_p, *spec_p; char *max_p, *out_p = out; /* setup our max pointer */ max_p = out + out_size; /* run through the input buffer, counting the characters as we go */ for (buf_c = 0, buf_p = (const unsigned char *)buf;; buf_c++, buf_p++) { /* did we reach the end of the buffer? */ if (buf_size < 0) { if (*buf_p == '\0') { break; } } else { if (buf_c >= buf_size) { break; } } /* search for special characters */ for (spec_p = (unsigned char *)SPECIAL_CHARS + 1; *(spec_p - 1) != '\0'; spec_p += 2) { if (*spec_p == *buf_p) { break; } } /* did we find one? */ if (*(spec_p - 1) != '\0') { if (out_p + 2 >= max_p) { break; } (void)sprintf(out_p, "\\%c", *(spec_p - 1)); out_p += 2; continue; } /* print out any 7-bit printable characters */ if (*buf_p < 128 && isprint(*buf_p)) { if (out_p + 1 >= max_p) { break; } *out_p = *(char *)buf_p; out_p += 1; } else { if (out_p + 4 >= max_p) { break; } (void)sprintf(out_p, "\\%03o", *buf_p); out_p += 4; } } return out_p - out; } /* * dump_table * * DESCRIPTION: * * Dump a table file to the screen. * * RETURNS: * * None. * * ARGUMENTS: * * tab_p - a table pointer that we are dumping. */ static void dump_table(table_t *tab_p) { char buf[10240]; void *key_p, *data_p; int ret, key_size, data_size, len, entry_c; for (ret = table_first(tab_p, (void **)&key_p, &key_size, (void **)&data_p, &data_size), entry_c = 0; ret == TABLE_ERROR_NONE; ret = table_next(tab_p, (void **)&key_p, &key_size, (void **)&data_p, &data_size), entry_c++) { /* expand the key */ len = expand_chars(key_p, key_size, buf, sizeof(buf)); (void)printf("%d: key '%.*s' (%d), ", entry_c, len, buf, len); /* now dump the data */ len = expand_chars(data_p, data_size, buf, sizeof(buf)); (void)printf("data '%.*s' (%d)\n", len, buf, len); } } /* * usage * * DESCRIPTION: * * Print the usage message to stderr. * * RETURNS: * * None. * * ARGUMENTS: * * tab_p - a table pointer that we are dumping. */ static void usage(void) { (void)fprintf(stderr, "Usage: table_util\n" " [-b number] or --buckets num buckets to adjust table\n" " [-o file] or --out-file output filename\n" " [-v] or --verbose verbose messages\n" " file input table filename\n"); exit(1); } int main(int argc, char **argv) { table_t *tab_p; char do_write = 0, verbose = 0; char *out_file = NULL, *in_file; int ret, entry_n, bucket_n, num_buckets = 0; /* process the args */ for (argc--, argv++; argc > 0 && **argv == '-'; argc--, argv++) { switch (*(*argv + 1)) { case 'b': argc--, argv++; if (argc == 0) { usage(); } num_buckets = atoi(*argv); break; case 'o': argc--, argv++; if (argc == 0) { usage(); } out_file = *argv; break; case 'v': verbose = 1; break; default: usage(); break; } } if (argc != 1) { usage(); } /* take the last argument as the input file */ in_file = *argv; /* read in the table from disk */ tab_p = table_read(in_file, &ret); if (tab_p == NULL) { (void)fprintf(stderr, "table_util: unable to table_read from '%s': %s\n", in_file, table_strerror(ret)); exit(1); } /* get info about the table */ ret = table_info(tab_p, &bucket_n, &entry_n); if (ret != TABLE_ERROR_NONE) { (void)fprintf(stderr, "table_util: unable to get info on table in '%s': %s\n", in_file, table_strerror(ret)); exit(1); } (void)printf("Read table of %d buckets and %d entries from '%s'\n", bucket_n, entry_n, in_file); if (verbose) { dump_table(tab_p); } if (num_buckets > 0) { /* adjust the table's buckets */ ret = table_adjust(tab_p, num_buckets); if (ret != TABLE_ERROR_NONE) { (void)fprintf(stderr, "table_util: unable to adjust table to %d buckets: %s\n", num_buckets, table_strerror(ret)); exit(1); } do_write = 1; } /* did we modify the table at all */ if (do_write) { if (out_file == NULL) { out_file = in_file; } /* write out our table */ ret = table_write(tab_p, out_file, WRITE_MODE); if (ret != TABLE_ERROR_NONE) { (void)fprintf(stderr, "table_util: unable to write table to '%s': %s\n", out_file, table_strerror(ret)); exit(1); } (void)printf("Wrote table to '%s'\n", out_file); } /* free the table */ ret = table_free(tab_p); if (ret != TABLE_ERROR_NONE) { (void)fprintf(stderr, "table_util: unable to free table: %s\n", table_strerror(ret)); /* NOTE: not a critical error */ } exit(0); } /* For Emacs: * Local Variables: * mode:c * indent-tabs-mode:t * tab-width:4 * c-basic-offset:4 * End: * For VIM: * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: */