Main Page | Class Hierarchy | Data Structures | Directories | File List | Data Fields | Related Pages

code.c

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: code.c,v 1.10 2005/10/14 12:52:24 bostic Exp $
00008  */
00009 
00010 #include "csv.h"
00011 
00012 typedef struct {
00013         char            *name;          /* Field name */
00014         char            *upper;         /* Field name in upper-case */
00015         datatype         type;          /* Data type */
00016         int              indx;          /* Index */
00017 } FIELD;
00018 
00019 int      code_source(void);
00020 int      code_header(void);
00021 int      desc_dump(void);
00022 int      desc_load(void);
00023 char    *type_to_string(datatype);
00024 int      usage(void);
00025 
00026 /*
00027  * Globals
00028  */
00029 FILE    *cfp;                           /* C source file */
00030 FILE    *hfp;                           /* C source file */
00031 char    *progname;                      /* Program name */
00032 int      verbose;                       /* Verbose flag */
00033 
00034 u_int    field_cnt;                     /* Count of fields */
00035 FIELD   *fields;                        /* Field list */
00036 
00037 int
00038 main(int argc, char *argv[])
00039 {
00040         int ch;
00041         char *cfile, *hfile;
00042 
00043         /* Initialize globals. */
00044         if ((progname = strrchr(argv[0], '/')) == NULL)
00045                 progname = argv[0];
00046         else
00047                 ++progname;
00048 
00049         /* Initialize arguments. */
00050         cfile = "csv_local.c";          /* Default header/source files */
00051         hfile = "csv_local.h";
00052 
00053         /* Process arguments. */
00054         while ((ch = getopt(argc, argv, "c:f:h:v")) != EOF)
00055                 switch (ch) {
00056                 case 'c':
00057                         cfile = optarg;
00058                         break;
00059                 case 'f':
00060                         if (freopen(optarg, "r", stdin) == NULL) {
00061                                 fprintf(stderr,
00062                                     "%s: %s\n", optarg, strerror(errno));
00063                                 return (EXIT_FAILURE);
00064                         }
00065                         break;
00066                 case 'h':
00067                         hfile = optarg;
00068                         break;
00069                 case 'v':
00070                         ++verbose;
00071                         break;
00072                 case '?':
00073                 default:
00074                         return (usage());
00075                 }
00076         argc -= optind;
00077         argv += optind;
00078 
00079         if (*argv != NULL)
00080                 return (usage());
00081 
00082         /* Load records from the input file. */
00083         if (desc_load())
00084                 return (EXIT_FAILURE);
00085 
00086         /* Dump records for debugging. */
00087         if (verbose && desc_dump())
00088                 return (EXIT_FAILURE);
00089 
00090         /* Open output files. */
00091         if ((cfp = fopen(cfile, "w")) == NULL) {
00092                 fprintf(stderr,
00093                     "%s: %s: %s\n", progname, cfile, strerror(errno));
00094                 return (EXIT_FAILURE);
00095         }
00096         if ((hfp = fopen(hfile, "w")) == NULL) {
00097                 fprintf(stderr,
00098                     "%s: %s: %s\n", progname, hfile, strerror(errno));
00099                 return (EXIT_FAILURE);
00100         }
00101 
00102         /* Build the source and header files. */
00103         if (code_header())
00104                 return (EXIT_FAILURE);
00105         if (code_source())
00106                 return (EXIT_FAILURE);
00107 
00108         return (EXIT_SUCCESS);
00109 }
00110 
00111 /*
00112  * desc_load --
00113  *      Load a description file.
00114  */
00115 int
00116 desc_load()
00117 {
00118         u_int field_alloc;
00119         int version;
00120         char *p, *t, save_ch, buf[256];
00121 
00122         field_alloc = version = 0;
00123         while (fgets(buf, sizeof(buf), stdin) != NULL) {
00124                 if ((p = strchr(buf, '\n')) == NULL) {
00125                         fprintf(stderr, "%s: input line too long\n", progname);
00126                         return (1);
00127                 }
00128                 *p = '\0';
00129 
00130                 /* Skip leading whitespace. */
00131                 for (p = buf; isspace(*p); ++p)
00132                         ;
00133 
00134                 /* Skip empty lines or lines beginning with '#'. */
00135                 if (*p == '\0' || *p == '#')
00136                         continue;
00137 
00138                 /* Get a version. */
00139                 if (!version) {
00140                         if (strncasecmp(
00141                             p, "version", sizeof("version") - 1) == 0) {
00142                                 version = 1;
00143                                 continue;
00144                         }
00145                         fprintf(stderr,
00146                             "%s: expected \"version\" line\n", progname);
00147                         return (1);
00148                 }
00149 
00150                 /*
00151                  * Skip block close -- not currently useful, but when this
00152                  * code supports versioned descriptions, it will matter.
00153                  */
00154                 if (*p == '}') {
00155                         version = 0;
00156                         continue;
00157                 }
00158 
00159                 /* Allocate a new field structure as necessary. */
00160                 if (field_cnt == field_alloc &&
00161                     (fields = realloc(fields, field_alloc += 100)) == NULL) {
00162                         fprintf(stderr, "%s: %s\n", progname, strerror(errno));
00163                         return (1);
00164                 }
00165 
00166                 /* Find the end of the field name. */
00167                 for (t = p; *t != '\0' && !isspace(*t); ++t)
00168                         ;
00169                 save_ch = *t;
00170                 *t = '\0';
00171                 if ((fields[field_cnt].name = strdup(p)) == NULL ||
00172                     (fields[field_cnt].upper = strdup(p)) == NULL) {
00173                         fprintf(stderr, "%s: %s\n", progname, strerror(errno));
00174                         return (1);
00175                 }
00176                 *t = save_ch;
00177                 p = t;
00178 
00179                 fields[field_cnt].indx = 0;
00180                 fields[field_cnt].type = NOTSET;
00181                 for (;;) {
00182                         /* Skip to the next field, if any. */
00183                         for (; *p != '\0' && isspace(*p); ++p)
00184                                 ;
00185                         if (*p == '\0')
00186                                 break;
00187 
00188                         /* Find the end of the field. */
00189                         for (t = p; *t != '\0' && !isspace(*t); ++t)
00190                                 ;
00191                         save_ch = *t;
00192                         *t = '\0';
00193                         if (strcasecmp(p, "double") == 0)
00194                                 fields[field_cnt].type = DOUBLE;
00195                         else if (strcasecmp(p, "index") == 0)
00196                                 fields[field_cnt].indx = 1;
00197                         else if (strcasecmp(p, "string") == 0)
00198                                 fields[field_cnt].type = STRING;
00199                         else if (strcasecmp(p, "ulong") == 0)
00200                                 fields[field_cnt].type = ULONG;
00201                         else {
00202                                 fprintf(stderr,
00203                                     "%s: unknown keyword: %s\n", progname, p);
00204                                 return (1);
00205                         }
00206                         *t = save_ch;
00207                         p = t;
00208                 }
00209 
00210                 /* Create a copy of the field name that's upper-case. */
00211                 for (p = fields[field_cnt].upper; *p != '\0'; ++p)
00212                         if (islower(*p))
00213                                 *p = (char)toupper(*p);
00214                 ++field_cnt;
00215         }
00216         if (ferror(stdin)) {
00217                 fprintf(stderr, "%s: stdin: %s\n", progname, strerror(errno));
00218                 return (1);
00219         }
00220         return (0);
00221 }
00222 
00223 /*
00224  * desc_dump --
00225  *      Dump a set of FIELD structures.
00226  */
00227 int
00228 desc_dump()
00229 {
00230         FIELD *f;
00231         u_int i;
00232 
00233         for (f = fields, i = 0; i < field_cnt; ++i, ++f) {
00234                 fprintf(stderr, "field {%s}: (", f->name);
00235                 switch (f->type) {
00236                 case NOTSET:
00237                         fprintf(stderr, "ignored");
00238                         break;
00239                 case DOUBLE:
00240                         fprintf(stderr, "double");
00241                         break;
00242                 case STRING:
00243                         fprintf(stderr, "string");
00244                         break;
00245                 case ULONG:
00246                         fprintf(stderr, "ulong");
00247                         break;
00248                 }
00249                 if (f->indx)
00250                         fprintf(stderr, ", indexed");
00251                 fprintf(stderr, ")\n");
00252         }
00253         return (0);
00254 }
00255 
00256 /*
00257  * code_header --
00258  *      Print out the C #include file.
00259  */
00260 int
00261 code_header()
00262 {
00263         FIELD *f;
00264         u_int i;
00265 
00266         fprintf(hfp, "/*\n");
00267         fprintf(hfp, " *  DO NOT EDIT: automatically built by %s.\n", progname);
00268         fprintf(hfp, " *\n");
00269         fprintf(hfp, " * Record structure.\n");
00270         fprintf(hfp, " */\n");
00271         fprintf(hfp, "typedef struct __DbRecord {\n");
00272         fprintf(hfp, "\tu_int32_t\t recno;\t\t/* Record number */\n");
00273         fprintf(hfp, "\n");
00274         fprintf(hfp, "\t/*\n");
00275         fprintf(hfp, "\t * Management fields\n");
00276         fprintf(hfp, "\t */\n");
00277         fprintf(hfp, "\tvoid\t\t*raw;\t\t/* Memory returned by DB */\n");
00278         fprintf(hfp, "\tu_char\t\t*record;\t/* Raw record */\n");
00279         fprintf(hfp, "\tsize_t\t\t record_len;\t/* Raw record length */\n\n");
00280         fprintf(hfp, "\tu_int32_t\t field_count;\t/* Field count */\n");
00281         fprintf(hfp, "\tu_int32_t\t version;\t/* Record version */\n\n");
00282         fprintf(hfp, "\tu_int32_t\t*offset;\t/* Offset table */\n");
00283         fprintf(hfp, "\n");
00284 
00285         fprintf(hfp, "\t/*\n");
00286         fprintf(hfp, "\t * Indexed fields\n");
00287         fprintf(hfp, "\t */\n");
00288         for (f = fields, i = 0; i < field_cnt; ++i, ++f) {
00289                 if (f->type == NOTSET)
00290                         continue;
00291                 if (i != 0)
00292                         fprintf(hfp, "\n");
00293                 fprintf(hfp, "#define   CSV_INDX_%s\t%d\n", f->upper, i + 1);
00294                 switch (f->type) {
00295                 case NOTSET:
00296                         /* NOTREACHED */
00297                         abort();
00298                         break;
00299                 case DOUBLE:
00300                         fprintf(hfp, "\tdouble\t\t %s;\n", f->name);
00301                         break;
00302                 case STRING:
00303                         fprintf(hfp, "\tchar\t\t*%s;\n", f->name);
00304                         break;
00305                 case ULONG:
00306                         fprintf(hfp, "\tu_long\t\t %s;\n", f->name);
00307                         break;
00308                 }
00309         }
00310         fprintf(hfp, "} DbRecord;\n");
00311 
00312         return (0);
00313 }
00314 
00315 /*
00316  * code_source --
00317  *      Print out the C structure initialization.
00318  */
00319 int
00320 code_source()
00321 {
00322         FIELD *f;
00323         u_int i;
00324 
00325         fprintf(cfp, "/*\n");
00326         fprintf(cfp,
00327            " *  DO NOT EDIT: automatically built by %s.\n", progname);
00328         fprintf(cfp, " *\n");
00329         fprintf(cfp, " * Initialized record structure.\n");
00330         fprintf(cfp, " */\n");
00331         fprintf(cfp, "\n");
00332         fprintf(cfp, "#include \"csv.h\"\n");
00333         fprintf(cfp, "#include \"csv_local.h\"\n");
00334         fprintf(cfp, "\n");
00335         fprintf(cfp, "DbRecord DbRecord_base = {\n");
00336         fprintf(cfp, "\t0,\t\t/* Record number */\n");
00337         fprintf(cfp, "\tNULL,\t\t/* Memory returned by DB */\n");
00338         fprintf(cfp, "\tNULL,\t\t/* Raw record */\n");
00339         fprintf(cfp, "\t0,\t\t/* Raw record length */\n");
00340         fprintf(cfp, "\t%d,\t\t/* Field count */\n", field_cnt);
00341         fprintf(cfp, "\t0,\t\t/* Record version */\n");
00342         fprintf(cfp, "\tNULL,\t\t/* Offset table */\n");
00343         fprintf(cfp, "\n");
00344         for (f = fields, i = 0; i < field_cnt; ++i, ++f) {
00345                 if (f->type == NOTSET)
00346                         continue;
00347                 switch (f->type) {
00348                 case NOTSET:
00349                         abort();
00350                         /* NOTREACHED */
00351                         break;
00352                 case DOUBLE:
00353                 case ULONG:
00354                         fprintf(cfp, "\t0,\t\t/* %s */\n", f->name);
00355                         break;
00356                 case STRING:
00357                         fprintf(cfp, "\tNULL,\t\t/* %s */\n", f->name);
00358                         break;
00359                 }
00360         }
00361         fprintf(cfp, "};\n");
00362 
00363         fprintf(cfp, "\n");
00364         fprintf(cfp, "DbField fieldlist[] = {\n");
00365         for (f = fields, i = 0; i < field_cnt; ++i, ++f) {
00366                 if (f->type == NOTSET)
00367                         continue;
00368                 fprintf(cfp, "\t{ \"%s\",", f->name);
00369                 fprintf(cfp, " CSV_INDX_%s,", f->upper);
00370                 fprintf(cfp, "\n\t    %s,", type_to_string(f->type));
00371                 fprintf(cfp, " %d,", f->indx ? 1 : 0);
00372                 fprintf(cfp, " NULL,");
00373                 fprintf(cfp, " FIELD_OFFSET(%s)},\n", f->name);
00374         }
00375         fprintf(cfp, "\t{NULL, 0, STRING, 0, NULL, 0}\n};\n");
00376 
00377         return (0);
00378 }
00379 
00380 char *
00381 type_to_string(type)
00382         datatype type;
00383 {
00384         switch (type) {
00385         case NOTSET:
00386                 return ("NOTSET");
00387         case DOUBLE:
00388                 return ("DOUBLE");
00389         case STRING:
00390                 return ("STRING");
00391         case ULONG:
00392                 return ("ULONG");
00393         }
00394 
00395         abort();
00396         /* NOTREACHED */
00397 }
00398 
00399 int
00400 usage()
00401 {
00402         (void)fprintf(stderr,
00403             "usage: %s [-v] [-c source-file] [-f input] [-h header-file]\n",
00404             progname);
00405         exit(1);
00406 }

Generated on Sun Dec 25 12:14:25 2005 for Berkeley DB 4.4.16 by  doxygen 1.4.2