views:

441

answers:

6

I was previously using the following code to determine if a file was an .exe or .o file and thus set binFile to 1:

if(strstr(fpath,".exe") != NULL || strstr(fpath,".o") != NULL)
          binFile = 1;

Through debugging, I noticed that this method will also set binFile to 1 with files like foo.out or foo.execute. What I really want is to match '.exe\0' and '.o\0' but strstr() says it ignores the terminating NUL bytes. How should I go about this?

Thanks

+2  A: 

You could check one past the result of strstr (taking into account the length of the search string) to see if it is NULL. Example:

const char* p = strstr(fpath,".exe");

if (p != NULL && *(p + 4 + 1) == 0) // 4 is the length of ".exe"; +1 should get you to \0
    binFile = 1;
fbrereto
Your code doesn't do the right thing for a file called "foo.exe.exe"
asveikau
+4  A: 
int iLen = strlen(fpath);
if  ((iLen >= 4 && strcmp(&fpath[iLen - 4], ".exe") == 0)
  || (iLen >= 2 && strcmp(&fpath[iLen - 2], ".o") == 0))
   binfile = 1;

Edit added test on length, to handle very short file names.

mjv
you'd probably want to check and make sure that fpath's length is greater than 4 or 2, respectively. iLen -4 is great until iLen is 3. :)
Joe
I've sort of generalized this approach in my answer - without unsafe indexing.
gnud
@Joe, right on, thanks for pointing that out!. I'll edit accordingly.
mjv
Also, you missed the parens around the if-statement. But thanks for the efficient answer.
SiegeX
@SiegeX, right, forgot that too. Been doing too much Python lately, lucky me ;-)
mjv
A: 

one way of doing it:

char * suffix = fpath;
char * i = fpath;
while (*i++) {
    if (*i == '.') {
        suffix = i;
    }
}

if (!strcmp(suffix, ".o") || !strcmp(suffix, ".exe")) {
    /* do stuff */
}
cobbal
This will fail if your filepath contains more .'s than just the file extension: ie: "d:\hello.there\somefile.o"You should search from the right to the left for the period.
KSchmidt
@KSchmidt: no it won't. Note how the while loop continues even after finding a dot, hence ensuring that suffix will point to the last once encountered.
mjv
I see that now, but why not just use strrchr?
KSchmidt
`strrchr` would be the preferred way of doing it, I just wasn't familiar with it an hour ago.
cobbal
+6  A: 
#include <stdio.h>
#include <string.h>

int endswith(const char* haystack, const char* needle)
{
    size_t hlen;
    size_t nlen;
    /* find the length of both arguments - 
    if needle is longer than haystack, haystack can't end with needle */
    hlen = strlen(haystack); 
    nlen = strlen(needle);
    if(nlen > hlen) return 0;

    /* see if the end of haystack equals needle */
    return (strcmp(&haystack[hlen-nlen], needle)) == 0;
}

int main(int argc, char** argv) {

    if(argc != 3) {
     printf("Usage: %s <string> <test-ending>\n", argv[0]);
     return 1;
    }

    printf("Does \"%s\" end with \"%s\"? ", argv[1], argv[2]);

    if(endswith(argv[1], argv[2])) {
     printf("Yes!\n");
    } else {
     printf("No!\n");
    }

    return 0;
}
gnud
Thank you for the well-commented program
SiegeX
It would be a good idea to use `size_t` instead of `int` for string lengths.
Adam Rosenfield
You're right, Adam - fixed.
gnud
+4  A: 
char *ext = strrchr(fpath, '.');

if (ext && (!strcmp(ext, ".exe") || !strcmp(ext, ".o")))
   binfile = 1;

If your system has the BSD/POSIX strcasecmp, you should probably use that instead of strcmp.

caf
I've never understood why the case-*insensitive* version has *case* in its name. It seems backwards to me. I hope it's not just me.
dreamlax
+2  A: 

I like to get the extension and then check it.

char *suffix = strrchr(fpath,'.');

if (suffix)
{
  suffix++;
  if (strcasecmp(suffix,"exe"))
  {
    // you got it
  }
}

Incrementing suffix is okay since you know it points at a found a period at that point. Incrementing it will at worst make it point at the null termination character, which will not bother strcasecmp at all.

You can easily check against a list of extensions this way too.

Southern Hospitality
+1 for using strrchr()... All of these other answers are reinventing it, using way too much code. (PS: you want single quotes for strrchr(), not double-quotes..)
asveikau
asveikau is right, I fixed my double quotes to be single. I guess I rely on the compiler to catch my typos too much.
Southern Hospitality
Beware the null suffix in "file."
Jonathan Leffler
Null suffix is no problem, it's addressed in the first sentence after my code. "Incrementing it will at worst make it point at the null termination character, which will not bother strcasecmp at all." strcasecmp will just return no match to exe.
Southern Hospitality