#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <ctype.h>
#if defined(OS2)
#define INCL_DOSFILEMGR
#include <os2.h>
#endif
#include "fidoconf.h"
#include "typesize.h"
#include "common.h"
#include "xstr.h"
#define setcond for (i=0, condition=1; i<=iflevel; condition=ifstack[i++].state && condition);
static char *curconfname=NULL;
static long curconfpos=0;
static FILE *hcfg=NULL;
static short condition;
static int iflevel, nvars, sp;
static int maxnvars, maxsp, maxif;
static struct { short state, inelse, wastrue;
} *ifstack=NULL;
static struct { char *var, *value;
} *set=NULL;
static struct {
FILE *farr;
int curline;
char *confname;
} *incstack=NULL;
static unsigned int cfgNamesCount=0;
static char **cfgNames=NULL;
int init_conf(char *conf_name)
{
iflevel=-1;
condition=1;
sp=0;
cfgNamesCount=0;
hcfg=fopen(conf_name, "rb");
if (hcfg==NULL)
{
fprintf(stderr, "Can't open config file %s: %s!\n",
conf_name, strerror(errno));
wasError = 1;
return -1;
}
curconfname=sstrdup(conf_name);
actualLineNr=0;
#if defined(UNIX)
setvar("OS", "UNIX");
#elif defined(OS2)
setvar("OS", "OS/2");
#elif defined(NT) || defined(WINNT) || defined(__NT__)
setvar("OS", "WIN");
#elif defined(MSDOS)
setvar("OS", "MSDOS");
#endif
setvar("[", "[");
setvar("`", "`");
return 0;
}
char *getvar(char *name)
{ int i;
for (i=0; i<nvars; i++)
if (stricmp(name, set[i].var)==0)
{ if (set[i].value[0]==0)
return NULL;
return set[i].value;
}
return getenv(name);
}
void setvar(char *name, char *value)
{ int i, j;
/* find var */
for (i=0; i<nvars; i++)
if (stricmp(set[i].var, name)==0)
break;
if (i<nvars)
{ /* remove var */
nfree(set[i].var);
for (j=i; j<nvars-1; j++)
{ set[j].var=set[j+1].var;
set[j].value=set[j+1].value;
}
nvars--;
}
if (value==NULL) value="";
if (value[0]==0)
if (getvar(value)==NULL)
return;
if (nvars==maxnvars)
set = srealloc(set, (maxnvars+=10)*sizeof(*set));
set[nvars].var=smalloc(strlen(name)+strlen(value)+2);
strcpy(set[nvars].var, name);
set[nvars].value=set[nvars].var+strlen(name)+1;
strcpy(set[nvars].value, value);
nvars++;
return;
}
void close_conf(void)
{
int i;
char *module;
module = getvar("module");
if (module) module = sstrdup(module);
for(i=0; i<nvars; i++)
nfree(set[i].var);
maxnvars=nvars=0;
nfree(set);
if (module)
{ setvar("module", module);
nfree(module);
}
nfree(ifstack);
maxif=0;
if (hcfg) fclose(hcfg);
hcfg=NULL;
for (i=0; i<sp; i++) {
fclose(incstack[i].farr);
nfree(incstack[i].confname);
}
nfree(curconfname);
nfree(incstack);
sp=maxsp=0;
for (i=0; i<(int)cfgNamesCount; i++) nfree(cfgNames[i]);
nfree(cfgNames);
cfgNamesCount=0;
}
static char *_configline(void)
{
char *line;
curconfpos = ftell(hcfg);
line = readLine(hcfg);
if (line == NULL)
return NULL;
actualLineNr++;
return line;
}
char *vars_expand(char *line)
{
int curlen;
char *parsed, *src, *dest, *p, *p1, *newparsed;
#if defined(UNIX) || (defined(OS2) && defined(__EMX__))
FILE *f;
int i;
#endif
#if defined(UNIX) || (defined(OS2) && defined(__EMX__))
if (strpbrk(line, "[`")==NULL)
#else
if (strchr(line, '[')==NULL)
#endif
return line;
curlen = strlen(line)+1;
parsed = dest = smalloc(curlen);
for (src = line; *src; src++)
{
if (dest-parsed >= curlen-2)
{
size_t offset = (size_t) (dest - parsed);
/* we need this to fake around boundary checking */
newparsed = srealloc(parsed, curlen+=80);
dest = newparsed + offset;
parsed = newparsed;
}
switch (*src)
{
#if defined(UNIX) || (defined(OS2) && defined(__EMX__))
case '`':
p = strchr(src+1, '`');
if (p == NULL)
{
*dest++ = *src;
continue;
}
*p = '\0';
src++;
f = popen(src, "r");
*p = '`';
src = p;
while ((i = fgetc(f)) != EOF)
{
if (dest-parsed >= curlen-2)
{
newparsed = srealloc(parsed, curlen+=80);
dest = newparsed+(unsigned)(dest-parsed);
parsed = newparsed;
}
if (i!='\n') *dest++ = (char)i;
}
pclose(f);
continue;
#endif
case '[':
p = strchr(src, ']');
if (p)
{
src++;
*p = '\0';
if ((p1 = getvar(src)) == NULL)
p1 = src;
if (strlen(p1) > strlen(src)+2)
{
newparsed = srealloc(parsed, curlen += strlen(p1)-strlen(src)-2);
dest = newparsed+(unsigned)(dest-parsed);
parsed = newparsed;
}
strcpy(dest, p1);
dest += strlen(p1);
*p = ']';
src = p;
continue;
}
default:
*dest++ = *src;
continue;
}
}
*dest++ = '\0';
if (curlen != dest-parsed)
parsed = srealloc(parsed, (unsigned)(dest-parsed));
nfree(line);
return parsed;
}
static short boolexpr(char *str)
{ char *p, *p1, *p2;
short ret, inquote, relax;
ret=1;
for (p=str; isspace(*p); p++);
if (strncasecmp(p, "not ", 4)==0)
{ ret=0;
for (p+=4; isspace(*p); p++);
}
inquote=0;
for (p1=p; *p1; p1++)
{ if (*p1=='\"')
{ if (*(p1-1)=='\\')
continue;
inquote =! inquote;
continue;
}
if (!inquote)
if (strncmp(p1, "==", 2)==0 || strncmp(p1, "=~", 2)==0)
break;
}
if (*p1==0)
{ fprintf(stderr, "Bad if expression in config %s, line %d: '%s'\n",
curconfname, actualLineNr, str);
wasError = 1;
return ret;
}
relax=(p1[1]=='~');
*p1=0;
for (p2=p1-1; isspace(*p2); *p2--=0);
for (p1+=2; isspace(*p1); p1++);
for (p2=p1+strlen(p1)-1; isspace(*p2); *p2--=0);
if (relax ? patimat(p, p1) : stricmp(p, p1))
ret=!ret;
return ret;
}
char *configline(void)
{ int i;
char *p, *p1, *p2, *str, *line=NULL;
for (;;) {
nfree(line);
line=str=_configline();
if (str==NULL) {
// save parsed config name
cfgNames = srealloc(cfgNames, sizeof(char*)*(cfgNamesCount+1));
cfgNames[cfgNamesCount] = NULL;
xstrcat(&cfgNames[cfgNamesCount], curconfname);
cfgNamesCount++;
if (sp) {
fclose(hcfg);
nfree(curconfname);
hcfg=incstack[--sp].farr;
actualLineNr=incstack[sp].curline;
curconfname=incstack[sp].confname;
continue;
}
return NULL;
}
while (*str && isspace(*str)) str++;
if (strncasecmp(str, "if ", 3)==0)
{
p=vars_expand(line); str+=(p-line); line=p;
iflevel++;
if (iflevel==maxif)
ifstack=srealloc(ifstack, (maxif+=10)*sizeof(*ifstack));
ifstack[iflevel].inelse=0;
ifstack[iflevel].state=ifstack[iflevel].wastrue=boolexpr(str+3);
condition = condition && ifstack[iflevel].state;
continue;
}
if ((strncasecmp(str, "ifdef ", 6)==0) ||
(strncasecmp(str, "ifndef ", 7)==0))
{
p=vars_expand(line); str+=(p-line); line=p;
for (p1=str+strlen(str)-1; isspace(*p1); *p1--='\0');
for (p=str+6; isspace(*p); p++);
if (*p=='\0')
{ fprintf(stderr, "Bad %s in config %s line %d!\n",
str, curconfname, actualLineNr);
wasError = 1;
continue;
}
iflevel++;
if (iflevel==maxif)
ifstack=srealloc(ifstack, (maxif+=10)*sizeof(*ifstack));
ifstack[iflevel].inelse=0;
ifstack[iflevel].state=(getvar(p)!=NULL);
if (tolower(str[2])=='n') /* ifndef */
ifstack[iflevel].state=!ifstack[iflevel].state;
ifstack[iflevel].wastrue=ifstack[iflevel].state;
condition = condition && ifstack[iflevel].state;
continue;
}
if (strncasecmp(str, "elseif ", 7)==0)
{
if ((iflevel==-1) || ifstack[iflevel].inelse)
{ fprintf(stderr, "Misplaces elseif in config %s line %d ignored!\n",
curconfname, actualLineNr);
wasError = 1;
continue;
}
p=vars_expand(line); str+=(p-line); line=p;
if (ifstack[iflevel].wastrue)
ifstack[iflevel].state=0;
else
ifstack[iflevel].state=ifstack[iflevel].wastrue=boolexpr(str+6);
setcond;
continue;
}
if (strncasecmp(str, "else", 4)==0)
{
if ((iflevel==-1) || ifstack[iflevel].inelse)
{ fprintf(stderr, "Misplaces else in config %s line %d ignored!\n",
curconfname, actualLineNr);
wasError = 1;
continue;
}
ifstack[iflevel].inelse=1;
ifstack[iflevel].state=!ifstack[iflevel].wastrue;
setcond;
continue;
}
if (strncasecmp(str, "endif", 5)==0)
{
if (iflevel==-1)
{ fprintf(stderr, "Misplaced endif in config %s line %d ignored!\n",
curconfname, actualLineNr);
wasError = 1;
continue;
}
iflevel--;
setcond;
continue;
}
if (!condition)
continue;
if (strncasecmp(str, "set ", 4)==0)
{
p=vars_expand(line); str+=(p-line); line=p;
p=strchr(str, '\n');
if (p) *p=0;
p1=strchr(str+4, '=');
if (p1==NULL)
{ fprintf(stderr, "Incorrect set in config %s line %d!\n",
curconfname, actualLineNr);
wasError = 1;
continue;
}
*p1=0;
for (p=p1-1; isspace(*p); *p--='\0');
for (p=str+4; isspace(*p); p++);
/* now p - name of var */
for (p1++; isspace(*p1); p1++);
if (*p1=='\"')
{ /* remove quote chars */
for (p2=p1; (p2=strchr(p2+1, '\"'))!=NULL;)
if (*(p2-1)!='\\')
*p2--='\0';
p1++;
}
setvar(p, p1);
continue;
}
if (strncasecmp(str, "include", 7)==0)
{
p=vars_expand(line); str+=(p-line); line=p;
for (p=str+7; (*p==' ') || (*p=='\t'); p++);
for (p1=p+strlen(p)-1; isspace(*p1); *p1--=0);
for (i=0; i<sp; i++)
if (strcmp(incstack[i].confname, p) == 0)
{ fprintf(stderr, "Line %d: WARNING: recursive include of file %s detected and fixed!\n", actualLineNr, p);
continue;
}
if (sp==maxsp)
incstack=srealloc(incstack, (maxsp+=10)*sizeof(*incstack));
incstack[sp].farr=hcfg;
hcfg=fopen(p, "rb");
if (hcfg==NULL)
{ fprintf(stderr, "Can't open include file %s: %s!\n", p, strerror(errno));
hcfg=incstack[sp].farr;
wasError = 1;
continue;
}
incstack[sp].confname=curconfname;
incstack[sp].curline=actualLineNr;
sp++;
curconfname=sstrdup(p);
actualLineNr=0;
continue;
}
if ((strncasecmp(str, "commentchar", 11) == 0) && isspace(str[11]))
{
for (p=str+11; isspace(*p); p++);
if (!*p)
{ printf("\"%s\", line %d: There is a comment character missing after CommentChar!\n", curconfname, actualLineNr);
continue;
}
if (!strchr(TRUE_COMMENT, *p))
{ printf("\"%s\", line %d: CommentChar - '%c' is not valid comment characters!\n", curconfname, actualLineNr, *p);
} else
{ CommentChar = *p;
}
continue;
}
return line;
}
}
#if defined (UNIX)
int cmpfnames(char *file1, char *file2)
{
struct stat st1, st2;
if (stat(file1, &st1) || stat(file2, &st2))
return 1;
if (st1.st_dev!=st2.st_dev || st1.st_ino!=st2.st_ino)
return 1;
return 0;
}
#elif defined(NT) || defined(WINNT) || defined(__NT__) || defined(__MINGW32__)
#ifdef __MINGW32__
typedef unsigned long DWORD;
typedef char *LPSTR;
typedef const char *LPCSTR;
DWORD __stdcall GetFullPathNameA(LPCSTR,DWORD,LPSTR,LPSTR*);
DWORD __stdcall GetShortPathNameA(LPCSTR,LPSTR,DWORD);
#define GetFullPathName GetFullPathNameA
#define GetShortPathName GetShortPathNameA
#else
#include <windows.h>
#endif
int cmpfnames(char *file1, char *file2)
{
char buf[256], path1[256], path2[256], *p;
if (stricmp(file1, file2) == 0) return 0;
if (!GetShortPathName(file1, buf, sizeof(buf)))
strncpy(buf, file1, sizeof(buf));
if (!GetFullPathName(buf, sizeof(path1), path1, &p)) return 1;
if (!GetShortPathName(file2, buf, sizeof(buf)))
strncpy(buf, file2, sizeof(buf));
if (!GetFullPathName(buf, sizeof(path2), path2, &p)) return 1;
return stricmp(path1, path2);
}
#elif defined (OS2)
int cmpfnames(char *file1, char *file2)
{
char path1[256], path2[256];
/* DosQueryPathInfo declaration in os2emx.h:
ULONG DosQueryPathInfo (PCSZ pszPathName, ULONG ulInfoLevel, PVOID pInfoBuffer, ULONG ulInfoLength);
(PCSZ defined as const char* or unsigned const char* for different conditions)
*/
if( DosQueryPathInfo( (PCSZ)file1, FIL_QUERYFULLNAME, path1, sizeof(path1) ) ) return 1;
if( DosQueryPathInfo( (PCSZ)file2, FIL_QUERYFULLNAME, path2, sizeof(path2) ) ) return 1;
return stricmp(path1, path2);
}
#elif defined (__DJGPP__)
int cmpfnames(char *file1, char *file2)
{
char *path1 = NULL, *path2 = NULL;
int result;
/* _truename() call DOS FN 0x60 (undocumented: return real file name)
and store string into 2nd parameter (if NULL - malloc).
Return value is pointer to this string or NULL.
See c:\djgpp\src\libc\dos\dos\truename.c for details */
if( file1==NULL || file2==NULL ) /* compare filed if any filename is NULL */
return -1;
result = stricmp(file1, file2);
if( result==0 )
return result;
path1 = _truename( file1, NULL );
path2 = _truename( file2, NULL );
if( path1 && path2 ) /* if _truename() error: use result of compare original filenames */
result = stricmp(path1, path2); /* else compare pathnames */
nfree(path1);
nfree(path2);
return result;
}
#elif defined(MSDOS) || defined(__MSDOS__) && !defined(__DJGPP__)
#include <dos.h>
int cmpfnames(char *file1, char *file2)
{
struct REGPACK r;
char path1[128], path2[128];
r.r_ds = FP_SEG(file1);
r.r_si = FP_OFF(file1);
r.r_es = FP_SEG(path1);
r.r_di = FP_OFF(path1);
r.r_ax = 0x6000;
intr(0x21, &r);
r.r_ds = FP_SEG(file2);
r.r_si = FP_OFF(file2);
r.r_es = FP_SEG(path2);
r.r_di = FP_OFF(path2);
r.r_ax = 0x6000;
intr(0x21, &r);
return stricmp(path1, path2);
}
#else // Unknown OS
int cmpfnames(char *file1, char *file2)
{
return stricmp(file1, file2);
}
#endif
void checkIncludeLogic(ps_fidoconfig config)
{
unsigned int i, j;
for (j=0; j<config->linkCount; j++) {
if (config->links[j].autoAreaCreateFile==NULL) continue;
for (i=0; i<cfgNamesCount; i++) {
if (cmpfnames(cfgNames[i],config->links[j].autoAreaCreateFile)==0)
break;
}
// if not found include file - return error
if (i==cfgNamesCount) {
printf("AutoAreaCreateFile %s has never been included in config!\n",
config->links[j].autoAreaCreateFile);
exit(EX_CONFIG);
}
}
for (j=0; j<config->linkCount; j++) {
if (config->links[j].autoFileCreateFile==NULL) continue;
for (i=0; i<cfgNamesCount; i++) {
if (cmpfnames(cfgNames[i],config->links[j].autoFileCreateFile)==0) break;
}
// if not found include file - return error
if (i==cfgNamesCount) {
printf("AutoFileCreateFile %s has never been included in config!\n",
config->links[j].autoFileCreateFile);
exit(EX_CONFIG);
}
}
}
const char* getCurConfName()
{
return curconfname;
}
long getCurConfPos()
{
return curconfpos;
}
long get_hcfgPos()
{
return ftell(hcfg);
}
FILE *get_hcfg()
{
return hcfg;
}
syntax highlighted by Code2HTML, v. 0.9.1