Search code examples
cmacosunixdarwin

escaped whitespaces in paths osx/unix/darwin, plain C


Here's a simple file path plain-C routine which should programmatically expand tildes and accept whitespaces as legitimate characters in file names. It works fine with names such as:

~/Test Folder/test.txt

/Users/Shared/Test Folder/test.txt

but does not seem to work with path syntax as suggested by Apple or as generated by Terminal.app if drag&dropping file's icon to the Terminal.app's window:

/Users/Shared/Test\ Folder/test.txt

or

~/Test\ Folder/test.txt

Here's the code. I'm obviously missing the routine which would substitute 'escaped whitespace' for 'plain whitespace' characters. On the other hand, any search routine for '\ ' results in compiler complaints about "unknown escape sequence" 0x20 (which btw. seems to be the valid whitespace code in some unix and linux systems, possibly not in OSX?).

Is there a solution to the problem within plain-C and C-strings, without having to deal with Apple's proprietary CFStrings and NSStrings, where I know that solutions are simple? I just can't afford using any of those in this program. Also no shell scripts, ruby, gawk, grep, perl, python, etc..., please.

Thanks in advance!

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wordexp.h>

void get_file_path(char path[])
{
    char *p;
    size_t len = 0;
    wordexp_t exp_result;

    printf("Enter file name: \n");    
    p = fgets(path, TEXT_SIZE, stdin);
    fflush(stdin);

    if(p != NULL)len = strlen(path);

    //get rid of newline characters
    for(p = path; p < path + len; p++){
        if(*p == '\n') *p = '\0';
    }

    if(path[0] == '~'){
        wordexp(path, &exp_result, 0);
        //printf("Num.expansions: %zd\n", exp_result.we_wordc);
        strcpy(path, exp_result.we_wordv[0]);        

        for(size_t i = 1; i < exp_result.we_wordc; i++){
        //printf("%s\n", exp_result.we_wordv[i]);
        strcat(path, " ");
        strcat(path, exp_result.we_wordv[i]);
        }
    wordfree(&exp_result);        
    }
    printf("File path: %s\n", path);
    return;
}

Here's the shell output:

Enter file name: 
/Users/Shared/Test\ Folder/test.txt
File path: /Users/Shared/Test\ Folder/test.txt
Can't open file: /Users/Shared/Test\ Folder/test.txt

Solution

  • This is not an answer to the main issue with code, but it is a problem with the code.

    if(path[0] == '~'){ is a subtle problem.

    p = fgets(path, TEXT_SIZE, stdin);
    ...
    if(path[0] == '~'){
    

    When p == NULL the content of path is not define on IO error and likely the previous buffer contents when EOF occurs. Better to change return type from void to char *, and return when p == NULL.

    p = fgets(path, TEXT_SIZE, stdin);
    if (p == NULL) { 
      return NULL;
    }