C语言--配置文件解析

来源:互联网 发布:中国汽车历年进口数据 编辑:程序博客网 时间:2024/04/28 14:03

/*****************************************************************************

file like this :

[section]

parameter = value

*****************************************************************************

*/

#include <stdio.h>

#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
#include <sys/stat.h>
#include <sys/types.h>


#ifdef WIN32
#include <io.h>
#define open _open
#define read _read
#define close _close
#endif
#ifndef WIN32
#include <unistd.h>
#endif


#define BUFR_INC 1024
#define False (0)
#define True (1)
#define Auto (2)
#ifndef _BOOL
typedef int BOOL;
#define _BOOL   /* So we don't typedef BOOL again in vfs.h */
#endif


#ifndef SAFE_FREE
#define SAFE_FREE(x) do { if ((x) != NULL) {free((x)); (x)=NULL;} } while(0)
#endif


extern int global_is_multibyte_codepage;
extern int (*_skip_multibyte_char)(char c);
#define skip_multibyte_char(c) ((*_skip_multibyte_char)((c)))


#define get_character_len(x) 0
static char *bufr = NULL;
static int bSize = 0;


typedef struct {
char *buf;
char *p;
size_t size;
} myFILE;


static int mygetc(myFILE *f)
{
if (f->p >= f->buf+f->size) return EOF;
    /* be sure to return chars >127 as positive values */
return (int)( *(f->p++) & 0x00FF );
}


static void myfile_close(myFILE *f)
{
if (!f)
return;
SAFE_FREE(f->buf);
SAFE_FREE(f);
}


static int EatWhitespace( myFILE *InFile )
{
   int c;
   for( c = mygetc( InFile ); isspace( c ) && ('\n' != c); c = mygetc( InFile ) )
    ;
   return( c );
} /* EatWhitespace */


static int EatComment( myFILE *InFile )
{
   int c;
   for( c = mygetc( InFile ); ('\n'!=c) && (EOF!=c) && (c>0); c = mygetc( InFile ) )
   ;
   return( c );
} /* EatComment */


static int Continuation( char *line, int pos )
{
   int pos2 = 0;
   pos--;
   while( (pos >= 0) && isspace((int)line[pos]) )
    pos--;
   /* we should recognize if `\` is part of a multibyte character or not. */
   while(pos2 <= pos) {
       size_t skip = 0;
       skip = get_character_len(line[pos2]);
       if (skip) {
        pos2 += skip;
       } else if (pos == pos2) {
        return( ((pos >= 0) && ('\\' == line[pos])) ? pos : -1 );
       } else {
        pos2++;
       }
   }
   return (-1);
}


void *Realloc(void *p,size_t size)
{
   void *ret=NULL;
    if (size == 0) 
    {
       if (p) 
            free(p);
       //DEBUG(5,("Realloc asked for 0 bytes\n"));
       return NULL;
    }
   if (!p)
    ret = (void *)malloc(size);
   else
    ret = (void *)realloc(p,size);
    if (!ret)
        printf("Memory allocation error: failed to expand to %d bytes\n",(int)size);
   return(ret);
}
 /* ------------------------------------------------------------------------ **
 * Scan a section name, and pass the name to function sfunc().
 *
 * Input: InFile - Input source.
 * sfunc - Pointer to the function to be called if the section
 * name is successfully read.
 *
 * Output: True if the section name was read and True was returned from
 * <sfunc>. False if <sfunc> failed or if a lexical error was
 * encountered.
 *
* ------------------------------------------------------------------------ **
 */
static BOOL Section( myFILE *InFile, BOOL (*sfunc)(char *) )
{
   int c;
   int i;
   int end;
   char *func = "params.c:Section() -";
   i = 0;       /* <i> is the offset of the next free byte in bufr[] and */
   end = 0;         /* <end> is the current "end of string" offset. In most */
        /* cases these will be the same, but if the last */
        /* character written to bufr[] is a space, then <end> */
        /* will be one less than <i>. */
   c = EatWhitespace( InFile ); /* We've already got the '['. Scan */
    /* past initial white space. */
   while( (EOF != c) && (c > 0) )
   {
       /* Check that the buffer is big enough for the next character. */
       if( i > (bSize - 2) )
       {
           char *tb;
           tb = (char*)Realloc( bufr, bSize +BUFR_INC );
           if( NULL == tb )
           {
            //DEBUG(0, ("%s Memory re-allocation failure.", func) );
             return( False );
           }
           bufr = tb;
           bSize += BUFR_INC;
       }
       /* Handle a single character. */
       switch( c )
       {
           case ']': /* Found the closing bracket. */
               bufr[end] = '\0';
               if( 0 == end ) /* Don't allow an empty name. */
               {
                //DEBUG(0, ("%s Empty section name in configuration file.\n", func ));
                return( False );
               }
               //if( !sfunc( unix_to_dos(bufr) ) ) /* Got a valid name. Deal with it. */
               if( !sfunc( bufr ) ) /* Got a valid name. Deal with it. */
                return( False );
               (void)EatComment( InFile ); /* Finish off the line. */
               return( True );
           case '\n': /* Got newline before closing ']'. */
               i = Continuation( bufr, i ); /* Check for line continuation. */
               if( i < 0 )
               {
                   bufr[end] = '\0';
                   //DEBUG(0, ("%s Badly formed line in configuration file: %s\n",func, bufr ));
                   return( False );
               }
               end = ( (i > 0) && (' ' == bufr[i - 1]) ) ? (i - 1) : (i);
               c = mygetc( InFile ); /* Continue with next line. */
               break;
           default: /* All else are a valid name chars. */
               if( isspace( c ) ) /* One space per whitespace region. */
               {
                   bufr[end] = ' ';
                   i = end + 1;
                   c = EatWhitespace( InFile );
               }
               else /* All others copy verbatim. */
               {
                   bufr[i++] = c;
                   end = i;
                   c = mygetc( InFile );
               }
       }
   }
   /* We arrive here if we've met the EOF before the closing bracket. */
   //DEBUG(0, ("%s Unexpected EOF in the configuration file: %s\n", func, bufr ));
   return( False );
} /* Section */


static BOOL Parameter( myFILE *InFile, BOOL (*pfunc)(char *, char *), int c )
 {
   int i = 0; /* Position within bufr. */
   int end = 0; /* bufr[end] is current end-of-string. */
   int vstart = 0; /* Starting position of the parameter value. */
   char *func = "params.c:Parameter() -";
   /* Read the parameter name. */
   while( 0 == vstart ) /* Loop until we've found the start of the value. */
   {
       if( i > (bSize - 2) ) /* Ensure there's space for next char. */
       {
           char *tb;
           tb = (char*)Realloc( bufr, bSize + BUFR_INC );
           if( NULL == tb )
           {
               //DEBUG(0, ("%s Memory re-allocation failure.", func) );
               return( False );
           }
           bufr = tb;
           bSize += BUFR_INC;
       }
       switch( c )
       {
            case '=': /* Equal sign marks end of param name. */
                if( 0 == end ) /* Don't allow an empty name. */
                {
                        //DEBUG(0, ("%s Invalid parameter name in config. file.\n", func ));
                       return( False );
                    }
                    bufr[end++] = '\0'; /* Mark end of string & advance. */
                    i = end; /* New string starts here. */
                    vstart = end; /* New string is parameter value. */
                    bufr[i] = '\0'; /* New string is nul, for now. */
                    break;
            case '\n': /* Find continuation char, else error. */
                   i = Continuation( bufr, i );
                   if( i < 0 )
                   {
                        bufr[end] = '\0';
                     //DEBUG(1,("%s Ignoring badly formed line in configuration file: %s\n",func, bufr ));
                    return( True );
                   }
                   end = ( (i > 0) && (' ' == bufr[i - 1]) ) ? (i - 1) : (i);
                   c = mygetc( InFile ); /* Read past eoln. */
                   break;
            case '\0': /* Shouldn't have EOF within param name. */
            case EOF:
                   bufr[i] = '\0';
                   //DEBUG(1,("%s Unexpected end-of-file at: %s\n", func, bufr ));
                   return( True );
            default:
                   if( isspace( c ) ) /* One ' ' per whitespace region. */
                   {
                       bufr[end] = ' ';
                       i = end + 1;
                       c = EatWhitespace( InFile );
                   }
                   else /* All others verbatim. */
                   {
                       bufr[i++] = c;
                       end = i;
                       c = mygetc( InFile );
                   }
       }
   }
        /* Now parse the value. */
   c = EatWhitespace( InFile ); /* Again, trim leading whitespace. */
   while( (EOF !=c) && (c > 0) )
   {
       if( i > (bSize - 2) ) /* Make sure there's enough room. */
       {
           bSize += BUFR_INC;
           bufr = (char*)Realloc( bufr, bSize );
           if( NULL == bufr )
           {
            //DEBUG(0, ("%s Memory re-allocation failure.", func) );
            return( False );
           }
       }
       switch( c )
       {
           case '\r': /* Explicitly remove '\r' because the older */
                c = mygetc( InFile ); /* version called fgets_slash() which also */
                break; /* removes them. */
           case '\n': /* Marks end of value unless there's a '\'. */
                i = Continuation( bufr, i );
                if( i < 0 )
                    c = 0;
                else
                {
                    for( end = i; (end >= 0) && isspace((int)bufr[end]); end-- );
                    c = mygetc( InFile );
                }
                break;
            default: /* All others verbatim. Note that spaces do */
                   bufr[i++] = c; /* not advance <end>. This allows trimming */
                   if( !isspace( c ) ) /* of whitespace at the end of the line. */
                   end = i;
                   c = mygetc( InFile );
                   break;
       }
   }
   bufr[end] = '\0'; /* End of value. */
   return( pfunc( bufr, &bufr[vstart] ) ); /* Pass name & value to pfunc(). */
} /* Parameter */


static BOOL Parse( myFILE *InFile,BOOL (*sfunc)(char *),BOOL (*pfunc)(char *, char *) )
{
   int c;
   c = EatWhitespace( InFile );
   while( (EOF != c) && (c > 0) )
   {
       switch( c )
       {
           case '\n': /* Blank line. */
                c = EatWhitespace( InFile );
                break;
           case ';': /* Comment line. */
           case '#':
                c = EatComment( InFile );
                break;
           case '[': /* Section Header. */
                if( !Section( InFile, sfunc ) )
                    return( False );
                c = EatWhitespace( InFile );
                break;
           case '\\': /* Bogus backslash. */
                c = EatWhitespace( InFile );
                break;
           default: /* Parameter line. */
                if( !Parameter( InFile, pfunc, c ) )
                    return( False );
                c = EatWhitespace( InFile );
                break;
       }
   }
   return( True );
} /* Parse */


/****************************************************************************
  load a file into memory from a fd.
****************************************************************************/ 
char *fd_load(int fd, size_t *size)

struct stat sbuf;
char *p;
if (fstat(fd, &sbuf) != 0) 
        return NULL;
p = (char *)malloc(sbuf.st_size+1);
if (!p) 
        return NULL;
if (read(fd, p, sbuf.st_size) != sbuf.st_size) {
SAFE_FREE(p);
return NULL;
}
p[sbuf.st_size] = 0;
if (size) 
        *size = sbuf.st_size;
return p;
}


/****************************************************************************
  load a file into memory
  ****************************************************************************/
char *file_load(char *fname, size_t *size)
{
int fd;
char *p;
if (!fname || !*fname) 
        return NULL;
fd = open( fname, O_RDONLY );
if (fd == -1) 
        return NULL;
p = fd_load(fd, size);
    close(fd);
return p;
}


static myFILE *OpenConfFile( char *FileName )
{
   char *func = "params.c:OpenConfFile() -";
        //extern BOOL in_client;
        //int lvl = in_client?1:0;
   myFILE *ret;
   ret = (myFILE *)malloc(sizeof(*ret));
   if (!ret) 
        return NULL;
   ret->buf = file_load(FileName, &ret->size);
   if( NULL == ret->buf )
   {
       //DEBUG( lvl,
       // ("%s Unable to open configuration file \"%s\":\n\t%s\n",
       // func, FileName, strerror(errno)) );
       SAFE_FREE(ret);
       return NULL;
   }
   ret->p = ret->buf;
   return( ret );
} /* OpenConfFile */


BOOL pm_process( char *FileName,BOOL (*sfunc)(char *),BOOL (*pfunc)(char *, char *) )
{
   int result;
   myFILE *InFile;
   char *func = "params.c:pm_process() -";
   InFile = OpenConfFile( FileName ); /* Open the config file. */
   if( NULL == InFile )
    return( False );
        //DEBUG( 3, ("%s Processing configuration file \"%s\"\n", func, FileName) );
   if( NULL != bufr ) /* If we already have a buffer */
    result = Parse( InFile, sfunc, pfunc ); /* (recursive call), then just */
    /* use it. */
   else     /* If we don't have a buffer */
   {        /* allocate one, then parse, */
       bSize = BUFR_INC; /* then free. */
       bufr = (char *)malloc( bSize );
       if( NULL == bufr )
       {
           //DEBUG(0,("%s memory allocation failure.\n", func));
           myfile_close(InFile);
           return( False );
       }
       result = Parse( InFile, sfunc, pfunc );
       SAFE_FREE( bufr );
       bufr = NULL;
       bSize = 0;
   }
   myfile_close(InFile);
   if( !result ) /* Generic failure. */
   {
        //DEBUG(0,("%s Failed. Error returned from params.c:parse().\n", func));
     return( False );
   }
   return( True ); /* Generic success. */
} /* pm_process */
BOOL section(char *s){
  printf("[%s]\n",s);
  return True;
}
BOOL parameter(char *p,char*v){
    printf("\t %s = %s \n",p,v);
    return True;
}
int main(int argc,char*argv[])
{
    char * filename="/etc/samba/smb.conf";
    pm_process(filename,section,parameter);


}