Skip to main content
deleted 7 characters in body; edited tags; edited title
Source Link
Jamal
  • 34.9k
  • 13
  • 133
  • 237

Parsing function review. How to improve it?configuration files

I've written a function to parse configuration files, it. It doesn't handle file opening, but instead it takes an array with the file contents, and tries to find fields based on an array containing the fields' names and, if. If found, it puts the content into its respective place.

FIELD 1: CONTENT 1
FIELD 2: CONTENT 2
FIELD 3: CONTENT 3
FIELD 4: CONTENT 4
FIELD 5: CONTENT 5
FIELD 1: CONTENT 1
FIELD 2: CONTENT 2
FIELD 3: CONTENT 3
FIELD 4: CONTENT 4
FIELD 5: CONTENT 5

My questions:

My questions:

  • How to improve it?
  • Would it be considered better if the line delimiter was defined by the caller?
  • AddingBy adding the options to not ignore spaces and tabs, and set case sensitivity on/off, would the parameter list be considered too big?

Parsing function review. How to improve it?

I've written a function to parse configuration files, it doesn't handle file opening, instead it takes an array with the file contents, tries to find fields based on an array containing the fields' names and, if found, puts the content into its respective place.

FIELD 1: CONTENT 1
FIELD 2: CONTENT 2
FIELD 3: CONTENT 3
FIELD 4: CONTENT 4
FIELD 5: CONTENT 5

My questions:

  • How to improve it?
  • Would it be considered better if the line delimiter was defined by the caller?
  • Adding the options to not ignore spaces and tabs, and set case sensitivity on/off, would the parameter list be considered too big?

Parsing configuration files

I've written a function to parse configuration files. It doesn't handle file opening, but instead takes an array with the file contents and tries to find fields based on an array containing the fields' names. If found, it puts the content into its respective place.

FIELD 1: CONTENT 1
FIELD 2: CONTENT 2
FIELD 3: CONTENT 3
FIELD 4: CONTENT 4
FIELD 5: CONTENT 5

My questions:

  • Would it be considered better if the line delimiter was defined by the caller?
  • By adding the options to not ignore spaces and tabs, and set case sensitivity on/off, would the parameter list be considered too big?
Source Link
2013Asker
  • 2k
  • 3
  • 18
  • 23

Parsing function review. How to improve it?

I've written a function to parse configuration files, it doesn't handle file opening, instead it takes an array with the file contents, tries to find fields based on an array containing the fields' names and, if found, puts the content into its respective place.

The only rules it has so far are:

  • each field is delimited by a newline '\n'
  • case doesn't matter for the field's name
  • after a field's name has been found, leading spaces and tabs are irrelevant and discarded
  • lines containing unrecognized fields are ignored
  • the character separating the field's name and its respective content must be specified in the field's name

Example file:

FIELD 1: CONTENT 1
FIELD 2: CONTENT 2
FIELD 3: CONTENT 3
FIELD 4: CONTENT 4
FIELD 5: CONTENT 5

Here's an example call:

char *configuration = load_file(file_name);
char *field1;
char *field2;
char *field3;
char *field4;
char *field5;

static const char *fields[] = {
        "FIELD 1:",
        "FIELD 2:",
        "FIELD 3:",
        "FIELD 4:",
        "FIELD 5:",
        0
    };
    char **destinations[] = {
        &field1,
        &field2,
        &field3,
        &field4,
        &field5,
        0
    };

    //Parse and load fields
    parse(destinations, fields, configuration);

And the function:

//strings allocated must be freed by the caller
static void parse(char ***destinations, const char **fields, const char *source)
{
    char buffer[BUFFER_SIZE];
    int i, j, buffer_position;

    while(*source != '\0')
    {
        for(i = 0; fields[i] != 0; ++i)
        {
            //check if first character match, case insensitive
            if(*fields[i] == *source || inverse_case(*fields[i]) == *source)
            {
                //check if subsequent characters match
                for(j = 0; fields[i][j] != '\0'; ++j)
                {
                    if(fields[i][j] != source[j] && inverse_case(fields[i][j]) != source[j]) break;
                }

                //it's not the right field, look for another
                if(fields[i][j] != '\0') continue;

                //found, update pointer position
                source += j;

                //skip leading spaces and tabs
                while(*source == ' ' || *source == '\t') ++source;

                //collect content
                for(buffer_position = 0; *source != '\n' && buffer_position < BUFFER_SIZE - 1; ++buffer_position, ++source)
                {
                    buffer[buffer_position] = *source;
                }
                buffer[buffer_position] = '\0';

                //if it's an empty line, nothing to copy
                if(buffer_position > 0)
                {
                    //allocate memory for destination and copy
                    if((*destinations[i] = malloc(buffer_position + 1)) != 0)
                    {
                        COPY(*destinations[i], buffer);
                    }

                    //if there's an error on malloc(), we just skip the field and notify the user
                    else
                    {
                        printf("Error: malloc(%d)\n", buffer_position + 1);
                    }
                }

                //since we found a field that matches, no need to keep looking
                //break the for loop, skip the while and process next line
                goto next_iteration;
            }
        }
        //no matches for the current line just skip it entirely
        while(*++source && *source != '\n');

        next_iteration:
        ++source;
    }
}

My questions:

  • How to improve it?
  • Would it be considered better if the line delimiter was defined by the caller?
  • Adding the options to not ignore spaces and tabs, and set case sensitivity on/off, would the parameter list be considered too big?