/*
* protini.c - Read and process an NDIS protocol.ini file
*
* Copyright (C) 1998-2003 Gero Kuhlmann <gero@gkminix.han.de>
*
* 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
* 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.
*
* $Id: protini.c,v 1.4 2003/01/25 23:29:42 gkminix Exp $
*/
#define NEED_BINARY 1
#include <common.h>
#include <nblib.h>
#include "makerom.h"
#include "protini.h"
/*
* Definitions local to this module
*/
#define BUFSIZE 1024 /* chunk size of input buffer */
#define MAXPARLEN 15 /* max section & parameter name len */
/*
* Structure holding each parameter argument
*/
struct argdef {
size_t arglen; /* length of argument string */
char *argptr; /* pointer to argument string */
struct argdef *next; /* pointer to next argument */
};
/*
* Variables private to this module
*/
static char *inbuf; /* input buffer pointer */
static char *inpos; /* current write position in buffer */
static size_t inbufsize; /* input buffer size */
static __u8 *outbuf; /* memory image output buffer */
static __u8 *outpos; /* current write position in buffer */
static size_t outbufsize; /* output buffer size */
static long lastmod; /* offset to last module header */
static long lastkeyword; /* offset to last keyword header */
/*
**************************************************************************
*
* Reading of PROTOCOL.INI file
*
**************************************************************************
*/
/*
* Put a character at the end of the input buffer
*/
static void putinbuf(c)
char c;
{
size_t len;
char *cp;
/* Check that we don't get at the end of the input buffer */
len = (inpos - inbuf);
if (len >= (inbufsize - 1)) {
cp = (char *)nbmalloc(inbufsize + BUFSIZE);
memcpy(cp, inbuf, inbufsize);
free(inbuf);
inbuf = cp;
inbufsize += BUFSIZE;
inpos = inbuf + len;
}
/* Finally put new character into line buffer */
*inpos++ = c;
}
/*
* Read a protocol.ini file into a local buffer. This will not
* parse the file, as that's done later.
*/
char *readprotini(fname)
char *fname;
{
FILE *infile;
int c;
/* Open input file */
if ((infile = fopen(fname, "r")) == NULL) {
prnerr1("unable to open %s", fname);
exit(EXIT_OPEN);
}
/*
* Reset the input buffer pointers. The caller has to make sure, that
* the old buffer is freed before calling this routine successivly.
* Therefore, we can safely overwrite the pointers here.
*/
inbuf = inpos = (char *)nbmalloc(BUFSIZE);
inbufsize = BUFSIZE;
/*
* Simply read the whole input file without any further processing,
* except skipping return characters, which will only be found in
* DOS written files.
*/
while (TRUE) {
if ((c = fgetc(infile)) == EOF)
break;
if (c != '\r')
putinbuf(c);
}
putinbuf('\0');
fclose(infile);
return(inbuf);
}
/*
**************************************************************************
*
* Processing of PROTOCOL.INI contents
*
**************************************************************************
*/
/*
* Put a byte at the end of the output buffer
*/
static void putoutbuf(b)
__u8 b;
{
size_t len;
__u8 *cp;
/* Check that we don't get at the end of the input buffer */
len = (outpos - outbuf);
if (len >= (outbufsize - 1)) {
cp = (__u8 *)nbmalloc(outbufsize + BUFSIZE);
memcpy(cp, outbuf, outbufsize);
free(outbuf);
outbuf = cp;
outbufsize += BUFSIZE;
outpos = outbuf + len;
}
/* Finally put new character into line buffer */
*outpos++ = b;
}
/*
* Put a section header structure into protocol.ini memory image
*/
static char *putsection(name, len)
char *name;
size_t len;
{
struct module_config mod, *mp;
unsigned long newofs;
int i;
__u8 *bp;
/* Clear module header structure */
memset(&mod, 0, sizeof(mod));
/* Copy section name into module header */
if (len > 15)
return("section name too long");
i = 0;
while (i < len && *name) {
if (!isalpha(*name) && !isdigit(*name))
return("invalid character in section name");
mod.name[i++] = toupper(*(name++)) & 0xff;
}
/* Setup pointers to last module header */
newofs = (unsigned long)(outpos - outbuf);
if (lastmod >= 0) {
mp = (struct module_config *)(outbuf + lastmod);
assign(mp->next.offset, htot(newofs));
assign(mod.prev.offset, htot(lastmod));
}
lastmod = newofs;
lastkeyword = -1L;
/* Copy new module header into output buffer */
bp = (__u8 *)&mod;
for (i = 0; i < MODCONF_SIZE; i++)
putoutbuf(*(bp++));
return(NULL);
}
/*
* Put a numeric argument into protocol.ini memory image
*/
static void putnumeric(num)
long num;
{
struct param_struct par;
int i;
__u8 *bp;
/* Setup and copy parameter header */
assign(par.paramtype, htot(PARAM_NUM));
assign(par.paramlen, htot(4));
bp = (__u8 *)∥
for (i = 0; i < PARAM_SIZE; i++)
putoutbuf(*(bp++));
/* Copy number into output image */
for (i = 0; i < 4; i++) {
putoutbuf((num % 256) & 0xff);
num /= 256;
}
}
/*
* Put a string argument into protocol.ini memory image
*/
static void putstring(str)
char *str;
{
struct param_struct par;
int i;
__u8 *bp;
/* Setup and copy parameter header */
assign(par.paramtype, htot(PARAM_STRING));
assign(par.paramlen, htot(strlen(str) + 1));
bp = (__u8 *)∥
for (i = 0; i < PARAM_SIZE; i++)
putoutbuf(*(bp++));
/* Copy string into output image */
while (*str)
putoutbuf(*(str++) & 0xff);
putoutbuf(0);
}
/*
* Put a parameter header structure into protocol.ini memory image,
* followed by all individual parameter arguments.
*/
static char *putparam(name, len, args, argnum)
char *name;
size_t len;
struct argdef *args;
int argnum;
{
struct keyword_entry key, *kp;
struct argdef *ap;
unsigned long newofs;
__u8 *bp;
char *cp, *str;
long numeric;
int i;
/* Clear module header structure */
memset(&key, 0, sizeof(key));
/* Copy section name into module header */
if (len > 15)
return("keyword name too long");
i = 0;
while (i < len && *name) {
if (!isalpha(*name) && !isdigit(*name))
return("invalid character in keyword name");
key.name[i++] = toupper(*(name++)) & 0xff;
}
/* Set number of parameters */
assign(key.numparams, htot(argnum));
/* Setup pointers to last keyword header */
newofs = (unsigned long)(outpos - outbuf);
if (lastkeyword >= 0) {
kp = (struct keyword_entry *)(outbuf + lastkeyword);
assign(kp->next.offset, htot(newofs));
assign(key.prev.offset, htot(lastkeyword));
}
lastkeyword = newofs;
/* Copy new keyword header into output buffer */
bp = (__u8 *)&key;
for (i = 0; i < KEYWORD_SIZE; i++)
putoutbuf(*(bp++));
/* Put each parameter into output buffer */
ap = args;
while (ap != NULL) {
if (ap->arglen > 0 && ap->argptr != NULL) {
str = (char *)nbmalloc(ap->arglen + 1);
memcpy(str, ap->argptr, ap->arglen);
str[ap->arglen] = '\0';
if (str[0] == '0' && toupper(str[1]) == 'X') {
cp = str + 2;
while (*cp && isxdigit(*cp))
cp++;
if (*cp)
return("invalid character in hexadecimal argument");
sscanf(str, "%lx", &numeric);
if (numeric > 0x7FFFFFFFL)
return("hexadecimal number too large");
putnumeric(numeric);
} else if (((str[0] == '+' || str[0] == '-') &&
isdigit(str[1])) || isdigit(str[0])) {
cp = str;
if (*cp == '+' || *cp == '-')
cp++;
while (*cp && isdigit(*cp))
cp++;
if (*cp)
return("invalid character in decimal argument");
cp = str;
if (*cp == '+')
cp++;
sscanf(cp, "%ld", &numeric);
if (numeric > 0x7FFFFFFFL)
return("decimal number too large");
else if (numeric < -0x7FFFFFFFL)
return("decimal number too small");
putnumeric(numeric);
} else {
putstring(str);
}
free(str);
}
ap = ap->next;
}
return(NULL);
}
/*
* Parse the contents of a PROTOCOL.INI file. This will remove
* unnecessary comments and blanks and convert parameter and section
* names to upper case as required per the NDIS specification. Then
* put everything into the NDIS binary memory format.
*/
void parseprotini(protini, image, imglen)
char *protini;
__u8 **image;
size_t *imglen;
{
int errnum = 0;
int linenum = 0;
char *errtext = NULL;
char *inptr, *lineptr, *cp;
char *paramnameptr;
size_t paramnamelen;
size_t len;
int sectionnum = 0;
int paramnum = 0;
int argnum;
struct argdef *args, *arglast, *ap;
/* Don't do anything if protocol.ini image is empty */
assert(image != NULL && imglen != NULL);
if (protini == NULL || !*protini) {
*image = NULL;
*imglen = 0;
return;
}
/*
* Reset the output buffer pointers. The caller has to make sure, that
* the old buffer is freed before calling this routine successivly.
* Therefore, we can safely overwrite the pointers here.
*/
outbuf = outpos = (__u8 *)nbmalloc(BUFSIZE);
outbufsize = BUFSIZE;
lastmod = lastkeyword = -1L;
/* Scan through input buffer and handle each line seperately */
inptr = protini;
while (*inptr) {
/* Isolate the next line from the input buffer */
linenum++;
lineptr = inptr;
while (*inptr && *inptr != '\n')
inptr++;
if (*inptr == '\n') {
*inptr = '\0';
inptr++;
}
/* Skip any blanks at the beginning of the line */
while (*lineptr == ' ' || *lineptr == '\t')
lineptr++;
/* Skip any blank line and any comment at the beginning of the line */
if (!*lineptr || *lineptr == ';')
continue;
/* Handle section name */
if (*lineptr == '[') {
if (sectionnum > 0 && paramnum == 0) {
errtext = "empty section";
goto doerr;
}
cp = ++lineptr;
while (*lineptr && *lineptr != ']')
lineptr++;
if (!*lineptr) {
errtext = "unterminated section name";
goto doerr;
}
len = lineptr - cp;
if ((errtext = putsection(cp, len)) != NULL)
goto doerr;
lineptr++;
while (*lineptr == ' ' || *lineptr == '\t')
lineptr++;
if (*lineptr && *lineptr != ';') {
errtext = "junk after section name";
goto doerr;
}
sectionnum++;
paramnum = 0;
continue;
}
/* We can only accept parameters within a section */
if (sectionnum == 0) {
errtext = "text outside section definition";
goto doerr;
}
/* Isolate parameter name */
paramnameptr = lineptr;
while (*lineptr &&
!(*lineptr == ' ' || *lineptr == '\t' || *lineptr == '='))
lineptr++;
paramnamelen = lineptr - paramnameptr;
/* Check for equal sign and isolate all arguments */
argnum = 0;
args = arglast = NULL;
while (*lineptr == ' ' || *lineptr == '\t')
lineptr++;
if (*lineptr == '=') {
lineptr++;
while (TRUE) {
while (*lineptr == ' ' || *lineptr == '\t')
lineptr++;
if (*lineptr == '"') {
cp = ++lineptr;
while (*lineptr && *lineptr != '"')
lineptr++;
if (!*lineptr) {
errtext = "unterminated string character";
goto doerr;
}
len = lineptr - cp;
lineptr++;
} else {
cp = lineptr;
while (*lineptr &&
!(*lineptr == ',' || *lineptr == ';' ||
*lineptr == '\t' || *lineptr == ' '))
lineptr++;
len = lineptr - cp;
}
if (len > 0) {
ap = (struct argdef *)nbmalloc(sizeof(struct argdef));
ap->arglen = len;
ap->argptr = cp;
ap->next = NULL;
if (args == NULL)
args = ap;
if (arglast != NULL)
arglast->next = ap;
arglast = ap;
argnum++;
}
while (*lineptr == ' ' || *lineptr == '\t')
lineptr++;
if (*lineptr != ',')
break;
lineptr++;
}
}
/* Check for correct termination of argument list */
if (*lineptr && *lineptr != ';') {
errtext = "junk after parameter";
goto doerr;
}
/* Put parameter into memory image and clear argument list */
if ((errtext = putparam(paramnameptr, paramnamelen, args, argnum)) != NULL)
goto doerr;
paramnum++;
while (args != NULL) {
ap = args;
args = args->next;
free(ap);
}
continue;
/* Check for error */
doerr:
if (errtext != NULL) {
prnerr2("protocol.ini [%d]: %s", linenum, errtext);
errtext = NULL;
errnum++;
}
}
/* Exit if error */
if (errnum > 0)
exit(EXIT_MAKEROM_PROTINI);
/* The last section should not be empty */
if (sectionnum == 0) {
*image = NULL;
*imglen = 0;
return;
} else if (paramnum == 0) {
prnerr0("unexpected end of protocol.ini");
exit(EXIT_MAKEROM_PROTINI);
}
/* Prepare return values */
*image = outbuf;
*imglen = (outpos - outbuf);
}
syntax highlighted by Code2HTML, v. 0.9.1