/* $Id: cfg.c,v 1.62.2.3 2005/11/13 05:54:11 stas_degteff Exp $ ****************************************************************************** * FIDOCONFIG --- library for fidonet configs ****************************************************************************** * Copyright (C) 2000-2002 * * Max Levenkov * Husky development team * http://husky.sourceforge.net/team.html * * This file is part of FIDOCONFIG. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; see file COPYING. If not, write to the Free * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * See also http://www.gnu.org ***************************************************************************** */ #include #include #include #include #include #include #include #include #include #include #if defined (__OS2__) # define INCL_DOSFILEMGR # include #endif #include "typesize.h" #include "fidoconf.h" #include "common.h" #include "xstr.h" #include "log.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; static char **cfgNames=NULL; int init_conf(const char *conf_name) { if( conf_name==NULL || conf_name[0]==0 ) { w_log(LL_ERR, __FILE__ "::init_conf(): config name %s", conf_name?"has null length":"is NULL pointer"); return -1; } 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__) setvar("OS", "WIN"); #elif defined(__DOS__) setvar("OS", "MSDOS"); #endif setvar("[", "["); setvar("`", "`"); return 0; } char *getvar(char *name) { int i; for (i=0; i= 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 (sstrlen(p1) > sstrlen(src)+2) { newparsed = srealloc(parsed, curlen += sstrlen(p1)-sstrlen(src)-2); dest = newparsed+(unsigned)(dest-parsed); parsed = newparsed; } sstrcpy(dest, p1); dest += sstrlen(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[0]=='\\' && (p1[1]=='\\' || p1[1]=='\"')) { p1++; continue; } if (*p1=='\"') { inquote = !inquote; continue; } if (!inquote) if ((p1[0] == '=' || p1[0] == '!') && (p1[1] == '=' || p1[1] == '~')) break; } if (*p1==0) { fprintf(stderr, "Bad if expression in config %s, line %d: '%s'\n", curconfname, actualLineNr, str); wasError = 1; return ret; } if (p1[0]=='!') ret=!ret; relax=(p1[1]=='~'); *p1=0; for (p2=p1-1; isspace(*p2); *p2--=0); for (p1+=2; isspace(*p1); p1++); for (p2=p1+sstrlen(p1)-1; isspace(*p2); *p2--=0); if (relax ? patimat(p, p1) : sstricmp(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+sstrlen(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 || strncasecmp(str, "elif ", 5) == 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(strchr(str, ' ')); 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+sstrlen(p)-1; isspace(*p1); *p1--=0); for (i=0; i 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 sstricmp(path1, path2); } #elif defined(__WATCOMC__) && defined(__DOS__) && defined(__FLAT__) #include /* struct REGPACKX { unsigned int eax, ebx, ecx, edx, ebp, esi, edi; unsigned short ds, es, fs, gs; unsigned int flags; }; union REGPACK { struct REGPACKB h; struct REGPACKW w; #if defined(__386__) && !defined(__WINDOWS_386__) struct REGPACKX x; #else struct REGPACKW x; #endif }; */ int cmpfnames(char *file1, char *file2) { union REGPACK r; char path1[128], path2[128]; r.x.ds = (unsigned short)FP_SEG(file1); r.x.esi = (unsigned int) FP_OFF(file1); r.x.es = (unsigned short)FP_SEG(path1); r.x.edi = (unsigned int) FP_OFF(path1); r.x.eax = 0x6000; intr(0x21, &r); r.x.ds = (unsigned short)FP_SEG(file2); r.x.esi = (unsigned int) FP_OFF(file2); r.x.es = (unsigned short)FP_SEG(path2); r.x.edi = (unsigned int) FP_OFF(path2); r.x.eax = 0x6000; intr(0x21, &r); return sstricmp(path1, path2); } #else /* Unknown OS */ int cmpfnames(char *file1, char *file2) { return sstricmp(file1, file2); } #endif void checkIncludeLogic(ps_fidoconfig config) { UINT i, j; for (j=0; jlinkCount; j++) { if (config->links[j].autoAreaCreateFile==NULL) continue; for (i=0; ilinks[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; jlinkCount; j++) { if (config->links[j].autoFileCreateFile==NULL) continue; for (i=0; ilinks[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); } } /* check for duplicate includes */ for( i = 0; i < cfgNamesCount - 1; i++ ) for ( j = i+1; j < cfgNamesCount; j++ ) if (cmpfnames(cfgNames[i],cfgNames[j])==0) { printf("File %s is included in config more then one time!\n",cfgNames[i]); exit(EX_CONFIG); } } const char* getCurConfName() { return curconfname; } long getCurConfPos() { return curconfpos; } long get_hcfgPos() { return ftell(hcfg); } FILE *get_hcfg() { return hcfg; }