📄 genargs.c
字号:
/* genargs.c - code generator
*
* GENARGS - argv parser generator
*
* Copyright (C) 2000 Richard Heathfield
* Eton Computer Systems Ltd
* Macmillan Computer Publishing
*
* 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, write
* to the Free Software Foundation, Inc., 675 Mass Ave,
* Cambridge, MA 02139, USA.
*
* Richard Heathfield may be contacted by email at:
* binary@eton.powernet.co.uk
*
*/
/* This program generates the GetArgs() function.
* It takes as input (from stdin) a file with the
* following grammar:
*
* infile:
* specifier
* infile specifier
*
* specifier: one of
* switchspecifier
* doublespecifier
* longspecifier
* stringspecifier
*
* switchspecifier:
* -identifier
*
* doublespecifier:
* identifier D
*
* longspecifier:
* identifier L
*
* stringspecifier:
* identifier S length
*
* identifier:
* letter
* identifiertail letter
*
* identifiertail:
* letterorunderscore identifiertail
* digit identifiertail
* letterorunderscore
* digit
*
* letterorunderscore:
* letter
* _
*
* letter: one of
* A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
* a b c d e f g h i j k l m n o p q r s t u v w x y z
*
* digit: one of
* 0 1 2 3 4 5 6 7 8 9
*
* length:
* 1 to 255
*
*
* Example input:
* -r infile S 20 outfile S 20 lbound D ubound D maxrec L
*
* Output: a program fragment on stdout.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "dllist.h"
#define INDENT_2 " "
#define INDENT_4 " "
#define MAX_IDENT_LEN 32
#define MAX_STR_LEN 255
#define LINES_PER_SCREEN 23
#define BOOL 'B'
#define DOUBLE 'D'
#define LONG 'L'
#define STRING 'S'
/* Arguments of type 'B' are switches,
* which are either On or Off, so they
* don't need a data type or a length.
*/
#define NON_SWITCH_TYPES "DLS"
#define GET_VARIABLE 'V'
#define GET_TYPE 'T'
#define GET_LEN 'L'
#define STOP 'S'
#define SWITCH_CHAR '-'
typedef struct ARGUMENT
{
char Name[MAX_IDENT_LEN];
int Type;
size_t Len; /* for strings */
} ARGUMENT;
int ParseInput(DLLIST **ArgList,
FILE *InStream,
FILE *LogStream)
{
int Status = EXIT_SUCCESS;
ARGUMENT Arg = {0};
char InBuff[256];
char *VarName;
char *VarType;
char *VarLen;
char *EndPtr;
const char Delims[] = " ,\t\n";
char *Data;
char *NextToken;
int HaveData = 0;
int State = GET_VARIABLE;
while(EXIT_SUCCESS == Status &&
State != STOP)
{
fprintf(LogStream,
"Status report: Data? %s\n",
HaveData ? "Yes" : "No");
if(!HaveData)
{
Data = fgets(InBuff, sizeof InBuff, InStream);
if(Data != NULL)
{
fprintf(LogStream,
"Status report: Got data %s\n",
InBuff);
HaveData = 1;
NextToken = InBuff;
}
else
{
if(State != GET_VARIABLE)
{
fprintf(LogStream,
"Syntax error - unexpected "
"end of stream.\n");
Status = EXIT_FAILURE;
}
State = STOP;
}
}
fprintf(LogStream,
"Status report: Current State: %c\n",
State);
switch(State)
{
case STOP:
break;
case GET_VARIABLE:
VarName = strtok(NextToken, Delims);
NextToken = NULL;
if(VarName == NULL)
{
fprintf(LogStream,
"Status report: Couldn't find "
"variable name. Looking again...\n");
HaveData = 0;
}
else
{
fprintf(LogStream,
"Status report: Found variable name "
"[%s].\n",
VarName);
if(VarName[0] == SWITCH_CHAR)
{
if(strlen(VarName + 1) > MAX_IDENT_LEN)
{
fprintf(LogStream,
"Constraint violation -"
" Identifier name too long.\n");
Status = EXIT_FAILURE;
State = STOP;
}
else
{
strcpy(Arg.Name, VarName + 1);
Arg.Type = BOOL;
Arg.Len = 0;
if(DL_SUCCESS != DLAppend(ArgList,
0,
&Arg,
sizeof Arg))
{
/* A */
fprintf(LogStream,
"Program error A - Couldn't"
" add to list (memory alloc"
"ation failure?).\n");
Status = EXIT_FAILURE;
State = STOP;
}
}
}
else
{
if(strlen(VarName) > MAX_IDENT_LEN)
{
fprintf(LogStream,
"Constraint violation - "
"Identifier name too long.\n");
Status = EXIT_FAILURE;
State = STOP;
}
else
{
strcpy(Arg.Name, VarName);
State = GET_TYPE;
}
}
}
break;
case GET_TYPE:
VarType = strtok(NextToken, Delims);
NextToken = NULL;
if(VarType == NULL)
{
fprintf(LogStream,
"Status report: Couldn't find variable"
" type. Looking again...\n");
HaveData = 0;
}
else
{
fprintf(LogStream,
"Status report: Found variable"
" type [%s].\n",
VarType);
if(VarType[1] != '\0' ||
strchr(NON_SWITCH_TYPES, VarType[0]) == NULL)
{
fprintf(LogStream,
"Syntax error - Unknown type %s.\n",
VarType);
State = STOP;
Status = EXIT_FAILURE;
}
else
{
fprintf(LogStream,
"Status report: saving var [%s]\n",
VarName);
Arg.Type = VarType[0];
Arg.Len = 0;
if(VarType[0] == STRING)
{
State = GET_LEN;
}
else
{
if(DL_SUCCESS != DLAppend(ArgList,
0,
&Arg,
sizeof Arg))
{
/* B */
fprintf(LogStream,
"Program error B - Couldn't add"
" to list (memory allocation fa"
"ilure?).\n");
Status = EXIT_FAILURE;
State = STOP;
}
else
{
State = GET_VARIABLE;
}
}
}
}
break;
case GET_LEN:
VarLen = strtok(NextToken, Delims);
NextToken = NULL;
if(VarLen == NULL)
{
fprintf(LogStream,
"Status report: Couldn't find string "
"length. Looking again...\n");
HaveData = 0;
}
else
{
fprintf(LogStream,
"Status report: Found string"
" length %s.\n",
VarLen);
Arg.Len = (size_t)strtoul(VarLen, &EndPtr, 10);
if(EndPtr == VarLen ||
Arg.Len == 0 ||
Arg.Len > MAX_STR_LEN)
{
fprintf(LogStream,
"Constraint violation - "
"illegal string length.\n");
State = STOP;
Status = EXIT_FAILURE;
}
else
{
if(DL_SUCCESS != DLAppend(ArgList,
0,
&Arg,
sizeof Arg))
{
/* C */
fprintf(LogStream,
"Program error C - Couldn't"
" add to list (memory alloc"
"ation failure?).\n");
Status = EXIT_FAILURE;
State = STOP;
}
else
{
State = GET_VARIABLE;
}
}
}
break;
default:
/* D */
fprintf(LogStream,
"Program error D - Unknown state %c.\n",
State);
fflush(LogStream);
assert(0); /* This program is broken */
State = STOP;
State = EXIT_FAILURE;
break;
}
}
return Status;
}
int WalkArgs(int Tag, void *p, void *Parms)
{
ARGUMENT *Arg = p;
FILE *fp = Parms;
switch(Arg->Type)
{
case BOOL:
fprintf(fp,
"-%s\n",
Arg->Name);
break;
case STRING:
fprintf(fp,
"%s, %c, %u\n",
Arg->Name,
Arg->Type,
Arg->Len);
break;
default:
fprintf(fp,
"%s, %c\n",
Arg->Name,
Arg->Type);
break;
}
return 0;
}
int WriteHeaders(FILE *OutStream, char *OutFile)
{
fprintf(OutStream, "/* %s */\n", OutFile);
fprintf(OutStream,
"/* automatically generated file. Do not\n");
fprintf(OutStream,
" * modify this file by hand. Change\n");
fprintf(OutStream,
" * genargs.c and regenerate the file\n");
fprintf(OutStream,
" * instead.\n");
fprintf(OutStream,
" */\n");
fprintf(OutStream, "#include <stdio.h>\n");
fprintf(OutStream, "#include <stdlib.h>\n");
fprintf(OutStream, "#include <string.h>\n\n");
fprintf(OutStream,
"#define SWITCH_CHAR '%c'\n\n",
SWITCH_CHAR);
return EXIT_SUCCESS;
}
int WriteTypedef(FILE *OutStream, DLLIST *ArgList)
{
ARGUMENT *Arg;
fprintf(OutStream, "typedef struct ARG\n{\n");
while(ArgList)
{
Arg = DLGetData(ArgList, NULL, NULL);
fprintf(OutStream, " ");
switch(Arg->Type)
{
case BOOL:
fprintf(OutStream, "int %s;\n", Arg->Name);
break;
case LONG:
fprintf(OutStream, "long %s;\n", Arg->Name);
break;
case DOUBLE:
fprintf(OutStream, "double %s;\n", Arg->Name);
break;
case STRING:
fprintf(OutStream, "char %s[%u];\n",
Arg->Name,
(unsigned)(Arg->Len + 1));
break;
}
ArgList = DLGetNext(ArgList);
}
fprintf(OutStream, "} ARG;\n\n");
return EXIT_SUCCESS;
}
int CountBools(DLLIST *ArgList)
{
int Count = 0;
ARGUMENT *Arg;
while(ArgList)
{
Arg = DLGetData(ArgList, NULL, NULL);
if(BOOL == Arg->Type)
{
++Count;
}
ArgList = DLGetNext(ArgList);
}
return Count;
}
int WriteFunction(FILE *OutStream, DLLIST *ArgList)
{
DLLIST *Start;
ARGUMENT *Arg;
int CompArgs;
int OptArgs;
int ThisArg;
int ThisCompArg;
char *Indent = INDENT_2;
OptArgs = CountBools(ArgList);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -