Search code examples
cmingwfunction-pointerscase-sensitivestrstr

strstr and StrStrI in MinGW and with function as parameter in C


What I have

I have a weird problem. I have a big program which reads a PCAP File. Now I want to do a search in this pcap file. As I mentioned this program is really big, so I have a lot of functions and a lot of parameters etc. It's a Win32 Application and I use MinGW.

What I want

Now I want to perform a case sensitive search (strstr) or a case insensitive search (StrStrI from Shlwapi) depends on what the user has selected in the GUI. The search is quite huge and a lot of parameters can be set. So I don't want always to ask if (caseSensitve) then strstr(...) else StrStrI(...) , I want to make the decision at the beginning and I write it in a structure and the struct goes through the different functions.

What's the Problem:

When I do it like shown below my program stops working after using 3 times __strstr when case insensitive is chosen (So it will run StrStrI). When Case sensitive is chosen __strstr (strstr) works perfect. But when I use StrStrI directly it works perfect, too ...

I always get a warning from Eclipse:

assignment from incompatible pointer type [enabled by default]

But why? LPSTR is the same as char*, isn't it? And the typedef return of the function is char*?!

This sounds all quite complicated, eh? Here is a example code. This is exactly the way programmed as it is in my big program. To test it you need to add the Shlwapi library.

/*
 * pcap.c
 *
 *  Created on: 05.01.2015
 *      Author: Max
 */

#include <windef.h>
#include <stdlib.h>
#include <stdio.h>
#include <shlwapi.h>//need to add library shlwapi!

typedef char* (*__StrStr)(const char* str1, const char* str2);

typedef struct _findData {
    __StrStr               __strstr; //string in string function (either strstr (cs) or StrStrI (ci))
    char fCaseSensitve :1;
} findData;

void findDataTest(findData *tFindData);
void findDataTest2(findData *tFindData);

char * Test1 = "HELLO";
char * Test2 = "lo";

int main() {
    findData *tFindData = malloc(sizeof(findData));

    setbuf(stdout, NULL); //do not buffer stdout

    tFindData->fCaseSensitve = 1; //set case sensitve

    findDataTest(tFindData); //works perfect!

    tFindData->fCaseSensitve = 0; //set case insensitve

    findDataTest(tFindData); //abort after 3 times
    return 0;
}

void findDataTest(findData *tFindData) {
    if (tFindData->fCaseSensitve)
        tFindData->__strstr = strstr; //if case sensitive use strstr
    else
        tFindData->__strstr = StrStrIA; //Warning from Eclipse: assignment from incompatible pointer type [enabled by default], but why? LPSTR == char*

    findDataTest2(tFindData); //and here we test it
}

void findDataTest2(findData *tFindData) {
    __StrStr  __strstr;
    int i = 0;

    __strstr = tFindData->__strstr;

    for (; i < 10; i++) {
        printf("Test %d:\t", i);

        //if (StrStrI(Test1, Test2)) //this works like a charm!
        if (__strstr(Test1, Test2)) //this abborts after 3 times on case insenstive
            printf("str is in str!\n");
        else
            printf("nope! str isn't in str!\n");
    }
}

Solution

  • The StrStrI*()-functions do not use the cdecl but the stdcall calling convention.

    To ship around this you might want to introduce a wrapper around the StrStrI*()-function like this

    char * strstri(const char * s1, const char * s2) 
    {
      return StrStrIA(s1, s2);
    }
    

    and to initialise the the pointer to the compare function use

    void findDataTest(findData *tFindData) 
    {
      if (tFindData->fCaseSensitve)
        tFindData->__strstr = strstr; //if case sensitive use strstr
      else
        tFindData->__strstr = strstri;
    
      findDataTest2(tFindData); //and here we test it
    }
    

    As a side note: Do not use __ to prefix anything in your C code as (in most cases) this is not allowed by the C-Standard.

    For example replace __StrStr by StrStrFunc and __strstr by pfstrstr or strstrfunc.