1

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.

Aleksandair
  • 167
  • 1
  • 2
  • 11
  • 1
    What is the question? The return values are documented e.g. here: http://www.manpagez.com/man/3/memcmp/ – harper May 20 '14 at 12:28
  • What are the values of the parameters passed to memcmp, when you put a breakpoint on that line? – Lundin May 20 '14 at 12:31
  • Print contents of values to see whats is wrong! – lsalamon May 20 '14 at 12:32
  • here are the values : p="[section-name]", section="section-name" and I already tried to printf("%s\n",p), section and buff : with p I have "[section-name]", same with buff and "section-name" with section – Aleksandair May 20 '14 at 12:35
  • As I see "[section-name]" are not equal to "section-name". Maybe that's the reason! And check please third argument in memcmp(). – AGo May 20 '14 at 12:47
  • @AGo As you see, I used p+1 and strlen(buff)-2 so I do the comparison on what's inside the []. I also checked the value returned by strlen(buff), same value as strlen(p) and strlen(section)-2 – Aleksandair May 20 '14 at 12:50
  • 1
    @Aleksandair Double and triple check your assumptions. You have `memcmp (p + 1, section, strlen (buff) - 2) `. Now verify the content of `p+1`. Verify the content of `section`. verify that `strlen(buff) -2` returns what it is supposed to do. You can easily go wrong if you have whitespace or newlines in there. It's also odd that you use strlen(buff), when you are not passing `buff` to memcmp, so make sure that's actually what you want. – nos May 20 '14 at 12:56
  • Are characters 8 bits or 16 bits on your system? – Lundin May 20 '14 at 12:56
  • 4
    it seems to no problem in memcmp. Do you copy from windows and use the ini file? I think that there is need to convert the newline of the file if it. – BLUEPIXY May 20 '14 at 12:56
  • Why don't you look at the buffers you pass to memcmp in a debugger? – Werner Henze May 20 '14 at 13:00
  • 1
    As long as your hacking up that string, consider an `rtrim()`, not just a `str_finalize()`, implementation. I concur with BLUEPIXY (+1). If you copied this file from your Windoze box to your Linux box as binary, the `\r\n` windows line-endings will be retained, leaving your code with `\r` after `str_finalize`, You could validate (or debunk) this with a hex-dump function for your char buffer. Strange as it sounds, try ftp'ing that file across to your linux box in "text" mode and see if it makes a difference (note: that isn't a *solution*; its a wtf is going on test). – WhozCraig May 20 '14 at 13:04

2 Answers2

3

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.

Community
  • 1
  • 1
alk
  • 69,737
  • 10
  • 105
  • 255
0

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) {... 
AGo
  • 284
  • 2
  • 6
  • 5
    This is good advise, but it doesn't answer the question. (It may not even be possible to answer the question as it currently stands.) – Lundin May 20 '14 at 12:57
  • I think that your answer is hiding in this strings. – AGo May 20 '14 at 12:58