Unexpected memcmp return value

917 Views Asked by At

I made a INI file parser, it works well on Windows but not with Linux, the problem comes from the memcmp function, it doesn't return 0 when it should, I already checked with printf and strlen, (I also tried to use strncmp instead, it returned different value but still different than 0) but couldn't find where the problem comes from.

Here is the code :


#define INI_KEY_LENGTH   128
#define BEGIN        '['
#define SEP          '='
#define COMMENT      ';'

static char configfilename[255];


static char * str_dup (const char * str){
    char * dup = NULL;

    if (str != NULL){
        size_t size = strlen (str) + 1;
        dup = malloc (size);
        if (dup != NULL){
            memcpy (dup, str, size);
        }
    }
    return dup;
}


static void str_finalize (char * str){
    char * p = strchr (str, '\n');

    if (p != NULL){
        *p = '\0';
    }
}


static char * get (const char * filename, const char * section, const char * key){
    char *   ret         = NULL;
    char     buff        [INI_KEY_LENGTH];
    FILE *   file        = NULL;
    int      opened      = 0;

    file = fopen (filename, "r");
    if (file != NULL){
        while ((fgets (buff, INI_KEY_LENGTH, file)) != NULL){
            str_finalize (buff);
            if (! opened && buff [0] == BEGIN){
                char * p = buff;
                // Don't work here
                if (memcmp (p + 1, section, strlen (buff) - 2) == 0){
                    opened = 1;
                    continue;
                }
            }
            else if (opened){
                if (buff [0] == BEGIN){
                    opened = 0;
                    break;
                }
                if(buff [0] != COMMENT){
                    if (strstr (buff, key) != NULL){
                        char * p = strchr (buff, SEP);

                        if (p != NULL){
                            p++;
                            ret = str_dup (p);

                            break;
                        }
                    }
                }
            }
        }
        fclose (file);
    }
    return ret;
}


int init_iniFile (const char * filename){
    int ret = 0;
    FILE * file;

    if ((file = fopen(filename, "r")) != NULL){
        fclose(file);
        strcpy(configfilename, filename);
        ret = 1;
    }
    return ret;
}


char * get_string (const char * section, const char * key){
    return get (configfilename, section, key);
}

I suspect the error to be stupid, but I'm a noob in C, sorry for the inconvenience.

2

There are 2 best solutions below

0
On BEST ANSWER

Seeing this hack:

... strlen(buff) - 2)

along with reading "works on windows and doesn't on Linux" my senses tell me the code stumbles over the fact that windows new-lines are \r\n and Linux new-lines are \n , that is on windows they are 2 chars and one char long on Linux.

My advise to get around this is to add some (perhaps platform specific) code to get rid of any new-lines before working with "the rest" of the line read.

Some code showing how the might be done is here: https://stackoverflow.com/a/16000784/694576

Adding a general advise: If you trap yourself writing strlen(..) - x with x possibly being a positive value always think twice if this is really what you need, as this is a way into desaster if the result of this substraction ever becomes negativ, especially if you are using (as you ought to) size_t as the result type. It will underflow then. And as such construct typically is used to later index another string, this will happend with a BIG number ... - the rest is "bleeding" history.

2
On

IMHO There is too much operation for one line, try to split it and check

if (memcmp (p + 1, section, strlen (buff) - 2) == 0)

to

char *lefthand = p + 1;
size_t comaprecnt = strlen (buff) - 2;
if ( memcmp(lefthand, section, comparecnt) == 0) {...