tags:

views:

411

answers:

4

I'm going to try to explain the problem.

I am getting a string containing a registry key. For example:

HKEY_CURRENT_USER\Software\MyProgram\SomeOtherValue\SomeKey

now, I need to parse that string into 3 different char (or char *) variables. After the parsing it'll be something like:

string1 = HKEY_CURRENT_USER
string2 = \Software\MyProgram\SomeOtherValue\   /* with the '\' */
string3 = SomeKey

Not only do I need to group the backslashes; I also don't know how many of them are there. I could have something like:

HKEY_CURRENT_USER\Software\SomeKey

or something like:

HKEY_CURRENT_USER\Software\SomeValue\SomeOthervalue\Someblah\SomeKey

I tried with strtok() and strcspn() but i'm getting very confused here... Any idea how to get this done? Code is appreciated.

Thanks!

+2  A: 

Copy the string into an allocated one and split the variable placing a '\0' in the slash where you want to truncate it.

You can "scan" the string for slashes using the strchr function.

void to_split(char *original, int first_slash, int second_slash, char **first, char **second, char **third) {
        int i;
        char *first_null;
        char *second_null;
        char *allocated;

        if (first_slash >= second_slash)
                return;
        allocated = malloc(strlen(original) + 1);
        *first = allocated;
        strcpy(allocated, original);
        for (i = 0, first_null = allocated; i < first_slash && (first_null = strchr(first_null,'\\')); i++);

        if (first_null) {
                *first_null = '\0';
                *second = first_null + 1;
        }

        second_null = allocated + strlen(original);
        i = 0;
        while (i < second_slash && second_null > allocated)
            i += *second_null-- == '\\';

        if (++second_null > allocated) {
            *second_null = '\0';
            *third = second_null + 1;
        }
}

Usage:

int main (int argc, char **argv) {
        char *toSplit = "HKEY_CURRENT_USER\\Software\\MyProgram\\SomeOtherValue\\SomeKey";
        char *first;
        char *second;
        char *third;
        to_split(toSplit, 1, 3, &first, &second, &third);
        printf("%s %s %s\n", first, second, third);
        return 0;
}

It isn't the best code in the world, but it gives you an idea.

akappa
I tried this using both strtok() and strcspn() but I keep getting lost. Do you have an example?Thanks!
wonderer
Wait a moment and I'll give you the code ;)
akappa
+2  A: 

Pseudo-Code:

Step 1: Scan forward until the first "\", note the index.

Step 2: Scan Backward from the end to the last "\" (the first "\" encountered when going backwards), note the index.

Step 3: StrCpy the relevant pieces out into 3 strings.

Code: (does not rely on strrchr, or other methods you seem to have issues with)

void ParseRegEntry(char* regKey, char** TopLevel, char** Path, char** Key);

int main(void)
{
    char* regKey = "HKEY_CURRENT_USER\\Software\\MyProgram\\SomeOtherValue\\SomeKey";
    char* TopLevel;
    char* Path;
    char* Key;

    ParseRegEntry(regKey, &TopLevel, &Path, &Key);

    printf("1: %s\n2: %s\n3: %s\n", TopLevel, Path, Key);
    free(TopLevel);
    free(Path);
    free(Key);

    return 0;
}

void ParseRegEntry(char* regKey, char** TopLevel, char** Path, char** Key)
{
    int firstDelimiter = 0;
    int lastDelimiter = strlen(regKey)-1;
    int keyLen;

    while(regKey[firstDelimiter] != '\\')
    {
     firstDelimiter++;
    }

    while(regKey[lastDelimiter] != '\\')
    {
     lastDelimiter--;
    }
    keyLen = strlen(regKey) - lastDelimiter-1;

    *TopLevel = (char*)malloc(firstDelimiter+1);
    strncpy(*TopLevel, regKey, firstDelimiter);
    (*TopLevel)[firstDelimiter] = '\0';

    *Path = (char*)malloc(lastDelimiter - firstDelimiter+2);
    strncpy(*Path, regKey+firstDelimiter, lastDelimiter - firstDelimiter);
    (*Path)[lastDelimiter-firstDelimiter] = '\0';


    *Key = (char*)malloc(keyLen+1);
    strncpy(*Key, regKey+lastDelimiter+1, keyLen);
    (*Key)[keyLen] = '\0';
}
abelenky
Thank you. works very smoothly.
wonderer
Note that in a rush to get the code out, I didn't completely test the boundaries. I recommend you recheck all my math (+1 here... -1 there... +2 in another spot). Validate your input, and prepare for the possibility that regKey is bad input, malloc fails, or other errors happen.
abelenky
+2  A: 

strchr(char*, char) : locate first occurrence of char in string

strrchr(char*, char) : locate last occurrence of char in string

char* str = "HKEY_CURRENT_USER\Software\MyProgram\SomeOtherValue\SomeKey";
char token1[SIZE], token2[SIZE], token3[SIZE];

char* first = strchr(str, '\\');
char* last = strrchr(str, '\\')+1;

strncpy(token1, str, first-str);
token1[first-str] = '\0';
strncpy(token2, first, last-first);
token2[last-first] = '\0';
strcpy(token3, last);

We use strchr to find the first '\', and strrchr to find the last '\'. We then copy to token1, token2, token3 based on those positions.

I decided to just use fixed size buffers instead of calloc-ing, because that's not so important to illustrate the point. And I kept messing it up. :)

Nick Lewis
strchr and strrchr return pointers to the character in side the search string not positions. you need something like this:char *p = strchr (str, '\\');int first = p - str;
Twotymz
Thanks, but again: int first = strchr(str, '\\');int last = strrchr(str, '\\'); are giving me errors. how can you return a char* into an integer?
wonderer
I'm sorry, I failed to fully read the spec of strchr and strrchr. They do return char*, not integer; you can get an index from that by subtracting the start of the string from the returned value of strchr/strrchr. But you don't really need an index. I've fixed my code (AGAIN) and it shooouuuld be correct this time.
Nick Lewis
yes, it is, however there is a lot of garbage because I can set SIZE to whatever number and the \0 is not being added. Now, I added the \0 but i'm getting an exception
wonderer
Hmm, whoops, of course you did.. token1[strlen(token1)] only works if there's ALREADY a null byte on the end, oops. I fixed it to use the same calculated value strncpy used (first-str and last-first, respectively). Also, if you're concerned about extra space, it would be wise to use char*'s instead of char[], and dynamically allocate only as much memory as needed (first-str+1, last-first+1, and strlen(str)-(last-str)+1) using calloc. I used char[] to simplify the memory portion.
Nick Lewis
Oh if you mean garbage as in when you print, you can replace the declarations with something like char token1[SIZE] = {'\0'}, to initialize every byte to null. Then there is no need to put a null byte on the end after copying.
Nick Lewis
+1  A: 

Here's an example using strchr and strrchr to scan forwards and backwards in the string for the '\'.

char str[] = "HKEY_CURRENT_USER\Software\MyProgram\SomeOtherValue\SomeKey";
char *p, *start;
char root[128], path[128], key[128];

p = strchr (str, '\\');
strncpy (root, str, p - str);
start = p;
p = strrchr (str, '\\') + 1;
strncpy (path, start, p - start);
strcpy (key, p);
Twotymz
Thanks, it seems to be working ok. The only thing is that I get a lot of junk because of the [128]
wonderer
Do you mean when you print the values out using printf?
Twotymz