/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- main
- parse_comm_line
- do_switch
- 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);
}