## root/source/datagen.c

/* [<][>][^][v][top][bottom][index][help] */

## DEFINITIONS

This source file includes following definitions.

1. main
2. parse_comm_line
3. do_switch
4. usage

    /* datagen - Program to generate random data.
       Rick Smereka, Copyright (C) 1990-2005.

       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 of the License, 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; if not, get a copy via the Internet at
       http://gnu.org/copyleft/gpl.html or write to the Free Software
       Foundation, Inc., 59 Temple Place, Suite 330, Boston,
       MA 02111-1307 USA

       You can contact the author via email at rsmereka@future-lab.com

       Program syntax is:

       datagen -Snnn -N -Fnnn -Rnnn -L -V mxrec mxkey_char char_range
               outfile

       Where 'mxrec' is the number of records to generate,
       'mxkey_char' is the number of 5 character numbers to
       generate, 'char_range' is the maximum number generated
       per field and 'outfile' is the name and path of the
       output file. Each data record will be preceeded with a
       5 digit sequence number. The sequence number will start
       at one by default, but can be altered by using the 'S'
       switch. The 'N' switch will suppress the generation
       of sequence numbers.

       Original DOS code Feb/90, Rick Smereka

       Added switches 'F' which is the field separator in ASCII
       decimal and 'R' which is the record separator. The default
       field separator is the space character and the default record
       separator is the carriage return/line feed combination.
       Jun/95, Rick Smereka

       Added 'L' switch to generate record length as first field.
       Removed 'mxkey_int' and 'int_range'. Jul/95, Rick Smereka

       Changed length field to 11 digits instead of 10 and
       added an extra byte on the beginning for a status
       indicator which will allways be 'A'. Jul/95, Rick Smereka

       Added 'V' switch for variable length fields.
       Jul/95, Rick Smereka

       Changed size of record header to 12 bytes (1st byte status,
       10 bytes record length and the record mark) from 13 bytes
       (1st byte status, 11 bytes record length and the record
       mark). Jul/95, Rick Smereka

       Port to QNX V4.23a. Jan/97, Rick Smereka

       Changed 'record' character array to be dynamically
       allocated so that records larger than 2k can be
       built. Size of 'record' is calculated as: (maxkey_char + 1) *
       6 + 1. Six is composed of a maximum of five digits plus the
       field mark. The extra byte is the record mark. Note that five
       bytes per field data is always assumed even though (with
       'is_var' 'TRUE') the data could be variable length.
       Jan/99, Rick Smereka

       Port to 32bit Windows under CodeWarrior V4.
       Port to HP-UX under GNU C 2.8.1.
       Feb/99, Rick Smereka

       Port to Red Hat Linux 5.2, Jul/99, Rick Smereka

       Fixed a bug that caused an infinite loop in the switch
       parse function. Changed 'usage' function to display
       correct switch character based on platform. Sep/99,
       Rick Smereka

       Removed log statements and unecessary 'printf' statements.
       Apr/2000, Rick Smereka

       Ported to Debian Linux. Jan/2003, Rick Smereka

       Fixed calculation of record size which was too short.
       Jan/2005, Rick Smereka */

    #include "stdhead.h"

    #define VERSION "1.94.01-2005.01.01"

    int parse_comm_line(int, char **);
    int do_switch(char *);
    void usage(void);

    /* option or switch structure */

    struct
       {
       long seqn;           /* starting sequence number */
       int do_seq;          /* perform sequence number flag */
       int do_len;          /* place length as first field */
       int is_var;          /* are fields variable length */
       int field_sep;       /* field separator */
       int rec_sep;         /* record separator */
       long maxrec;         /* number of records to generate */
       int maxkey_char;     /* number of character key to generate */
       int char_range;      /* upper range of char number to generate */
       char outfile[200];   /* name of output file */
       } opt;

    int main(int argc, char **argv)
    {
       long i;
       int j;
       long now;
       int rnd;
       int len;
       char *record, key[200], *tmp;
       FILE *out;

          /* display logo based on platform */
    #ifdef OS_UNIX
       printf("datagen for %s Version %s\n", SUB_PLATFORM_STRING, VERSION);
    #else
       printf("datagen for %s Version %s\n", PLATFORM_STRING, VERSION);
    #endif

       printf("by Rick Smereka, Copyright (c) 1990-2005\n");
       printf("datagen comes with ABSOLUTELY NO WARRANTY\n");
       printf("This is free software, and you are welcome to redistribute it\n");
       printf("under certain conditions; see 'gpl.txt' for information.\n");

       /* check number of parameters passed */

       if (argc == 1)
          {
          usage();
          return(0);
          }

       /* initialize */

       opt.seqn = 1L;
       opt.do_seq = TRUE;
       opt.do_len = FALSE;
       opt.is_var = FALSE;
       opt.field_sep = ' ';
       opt.rec_sep = 0;
       opt.maxrec = 0L;
       opt.maxkey_char = 0;
       opt.char_range = 0;
       opt.outfile[0] = EOS;

       /* parse switches */

       if (!parse_comm_line(argc, argv))
          exit(0);

       srand(time(&now) % 37);    /* seed random generator */

       if ((out = fopen(opt.outfile, "wb")) == NULL)
          {
          printf("datagen:Unable to open %s for writing, "
                 "program abort\n", opt.outfile);
          exit(0);
          }

       /* allocate 'record' and tmp based on calculated
          length */

       len = (opt.maxkey_char + 1) * 6 + 16;

       if ((record = (char *)malloc(len + 1)) == (char *)NULL)
          {
          printf("datagen:alloc fail[record], program abort\n");
          exit(0);
          }

       if ((tmp = (char *)malloc(len + 1)) == (char *)NULL)
          {
          printf("datagen:alloc fail[tmp], program abort\n");
          free(record);
          exit(0);
          }

       for(i = 0L; i < opt.maxrec; i++)
          {
          record[0] = EOS;

          if (opt.do_seq)
             sprintf(record, "%05ld%c", opt.seqn++, opt.field_sep);

          for(j = 0; j < opt.maxkey_char; j++)
             {
             rnd = rand() % opt.char_range;

             if (opt.is_var)
                sprintf(key, "%d%c", rnd, opt.field_sep);
             else
                sprintf(key, "%05d%c", rnd, opt.field_sep);

             strcat(record, key);

             if (j == (opt.maxkey_char - 1))
                {
                len = strlen(record);
                record[len - 1] = EOS;
                }
             }

          len = strlen(record);

          /* if record delimter is zero, use CR/LF */

          if (!opt.rec_sep)
             {
             record[len] = (char)0x0d;
             record[len + 1] = (char)0x0a;
             record[len + 2] = EOS;
             }
          else
             {
             record[len] = opt.rec_sep;
             record[len + 1] = EOS;
             }

          if (opt.do_len)
             {
             len = strlen(record);
             sprintf(key, "A%010d%c", len, opt.field_sep);
             sprintf(tmp, "%s%s", key, record);
             strcpy(record, tmp);
             }

          fprintf(out, "%s", record);

          if (((i + 1L) % 1000) == 0L)
             printf("datagen:processed record %ld\r", i + 1L);
          }

       fclose(out);
       free(record);
       free(tmp);
       printf("datagen:done, created %ld records\n", opt.maxrec);
       return(0);
    }

    int parse_comm_line(int gc, char **gv)
    {
       /* Parse entire command line. Function returns 'TRUE' upon success,
          'FALSE' otherwise. */

       char prm[255];
       int curparm = 1;
       int man_parms = 1;
       int req_man_parms = 4;

       while(curparm < gc)
          {
          strcpy(prm, gv[curparm]);

          if (prm[0] == SWITCH_CHAR)
             {
             if (!do_switch(prm))
                return(FALSE);

             curparm++;
             continue;
             }

          switch(man_parms)
             {
             case 1:
                if ((opt.maxrec = atol(prm)) <= 0L)
                   {
                   printf("datagen:illegal value[maxrec][%ld]\n", opt.maxrec);
                   return(FALSE);
                   }

                man_parms++;
                break;

             case 2:
                if ((opt.maxkey_char = atoi(prm)) < 0)
                   {
                   printf("datagen:illegal value[maxkey_char]\n");
                   return(FALSE);
                   }

                man_parms++;
                break;

             case 3:
                opt.char_range = atoi(prm);

                if (opt.maxkey_char > 0)
                   {
                   if (opt.char_range <= 0)
                      {
                      printf("datagen:illegal value[char_range]\n");
                      return(FALSE);
                      }
                   }
                else
                   if (opt.char_range < 0)
                      {
                      printf("datagen:illegal value[char_range]\n");
                      return(FALSE);
                      }

                man_parms++;
                break;

             case 4:
                strcpy(opt.outfile, prm);

                if (!strlen(opt.outfile))
                   {
                   printf("datagen:name of output file is null\n");
                   return(FALSE);
                   }

                man_parms++;
                break;
             };

          curparm++;
          }

       if (man_parms < (req_man_parms + 1))
          {
          printf("datagen:incorrect number of parameters\n");
          usage();
          return(FALSE);
          }

       return(TRUE);
    }

    int do_switch(char *parm)
    {
       /* Parse and set one option based on a switch. */

       switch(toupper(parm[1]))
          {
          case 'S':
             if ((opt.seqn = atol(&parm[2])) <= 1L)
                {
                printf("datagen:illegal value on 'S' parameter\n");
                return(FALSE);
                }

             break;

          case 'N':
             opt.do_seq = FALSE;
             break;

          case 'F':
             if ((opt.field_sep = atoi(&parm[2])) < 1)
                {
                printf("datagen:illegal value on 'F' parameter\n");
                return(FALSE);
                }

             if (opt.field_sep > 255)
                {
                printf("datagen:out of range value on 'F' parameter\n");
                return(FALSE);
                }

             break;

          case 'R':
             if ((opt.rec_sep = atoi(&parm[2])) <= 1)
                {
                printf("datagen:illegal value on 'R' parameter\n");
                return(FALSE);
                }

             if (opt.rec_sep > 255)
                {
                printf("datagen:out of range value on 'R' parameter\n");
                return(FALSE);
                }

             break;

          case 'L':
             opt.do_len = TRUE;
             break;

          case 'V':
             opt.is_var = TRUE;
             break;

          default:
             printf("datagen:unknown parameter %s\n", parm);
          };

       return(TRUE);
    }

    void usage(void)
    {
       /* Display program usage. */

       printf("DATAGEN: A program to generate numeric ASCII data.\n\n");
       printf("usage: datagen %cN %cSnnn %cFnnn %cRnnn %cL %cV maxrec\n", SWITCH_CHAR,
               SWITCH_CHAR, SWITCH_CHAR, SWITCH_CHAR, SWITCH_CHAR, SWITCH_CHAR);
       printf("               maxkey_char char_range outfile\n\n");
       printf("Where:\n");
       printf("'maxrec' is the number of records to generate\n");
       printf("'maxkey_char' is the number of fields in each record\n");
       printf("'char_range' is the largest ASCII number to be generated in a field\n");
       printf("'outfile' is the output file name\n");
       printf("'%cFnnn' is the field mark separator char (default is space %cF32)\n",
              SWITCH_CHAR, SWITCH_CHAR);
       printf("'%cL' is generate record length as first field\n", SWITCH_CHAR);
       printf("'%cN' is do not generate sequence numbers\n", SWITCH_CHAR);
       printf("'%cRnnn' is the record mark separator char (default is CRLF)\n", SWITCH_CHAR);
       printf("'%cSnnn' is the starting sequence number (default is 1 %cS1)\n",
              SWITCH_CHAR, SWITCH_CHAR);
       printf("'%cV' is generate variable length fields (instead of all being 5 char)\n",
              SWITCH_CHAR);
    }

/* [<][>][^][v][top][bottom][index][help] */