1
votes

I am quite familiar with Python coding but now I have to do stringparsing in C.

My input:

input = "command1 args1 args2 arg3;command2 args1 args2 args3;cmd3 arg1 arg2 arg3"

My Python solution:

input = "command1 args1 args2 arg3;command2 args1 args2 args3;command3 arg1 arg2 arg3"
compl = input.split(";")
tmplist =[]
tmpdict = {}

for line in compl:
    spl = line.split()
    tmplist.append(spl)

for l in tmplist:
     first, rest = l[0], l[1:]
     tmpdict[first] = ' '.join(rest)

print tmpdict

#The Output: 
#{'command1': 'args1 args2 arg3', 'command2': 'args1 args2 args3', 'cmd3': 'arg1 arg2 arg3'}

Expected output: Dict with the command as key and the args joined as a string in values

My C solution so far:

I want to save my commands and args in a struct like this:

struct cmdr{
    char* command;
    char* args[19];
};
  1. I make a struct char* array to save the cmd + args seperated by ";":

    struct ari { char* value[200];};

The function:

struct ari inputParser(char* string){
    char delimiter[] = ";";
    char *ptrsemi;  
    int i = 0;
    struct ari sepcmds;
    ptrsemi = strtok(string, delimiter);

    while(ptrsemi != NULL) {
        sepcmds.value[i] = ptrsemi;
        ptrsemi = strtok(NULL, delimiter);
        i++;

    }
return sepcmds;     
  1. Seperate commands and arrays by space and save them in my struct:

First I added a help struct:

struct arraycmd {
struct cmdr lol[10];
};



struct arraycmd parseargs (struct ari z){
    struct arraycmd result;
    char * pch;
    int i;
    int j = 0;

    for (i=0; i < 200;i++){
         j = 0;
         if (z.value[i] == NULL){
               break;
             }
            pch = strtok(z.value[i]," ");
    while(pch != NULL) {
        if (j == 0){
            result.lol[i].command = pch;    
            pch = strtok(NULL, " ");
            j++;
        } else {
        result.lol[i].args[j]= pch;
        pch = strtok(NULL, " ");
        j++;
        }
    }
    pch = strtok(NULL, " ");
      }
         return result; 

My output function looks like this:

void output(struct arraycmd b){ 
int i;
int j;

for(i=0; i<200;i++){
     if (b.lol[i].command != NULL){
        printf("Command %d: %s",i,b.lol[i].command);
    }
    for (j = 0; j < 200;j++){
        if  (b.lol[i].args[j] != NULL){
            printf(" Arg %d = %s",j,b.lol[i].args[j]);
        }
    }   
    printf(" \n");  
}    
}

But it produces only garbage (Same input as in my python solution) :
(command1 args1 args2 arg3;command2 args1 args2 args3;command3 arg1 arg2 arg3 )

Command 0: command1 Arg 0 = command2 Arg 1 = args1 Arg 2 = args2 Arg 3 = arg3 Arg 19 = command2 Arg 21 = args1 Arg 22 = args2 Arg 23 = args3 Arg 39 = command3 Arg 41 = arg1 Arg 42 = arg2 Arg 43 = arg3 Segmentation fault

So I hope someone can help me to fix this.

3
What does your main() look like, where you call all of the above? Have you tried stepping through your code in a debugger?Markku K.
Also, you might check out the example in the strtok man page.Markku K.
@W0bble check my answer . i did what u wanted . u can useqwr

3 Answers

1
votes

It may be easier to get your C logic straight in python. This is closer to C, and you can try to transliterate it to C. You can use strncpy instead to extract the strings and copy them to your structures.

str = "command1 args1 args2 arg3;command2 args1 args2 args3;command3 arg1 arg2 arg3\000"

start = 0
state = 'in_command'

structs = []

command = ''
args = []
for i in xrange(len(str)):
    ch = str[i]
    if ch == ' ' or ch == ';' or ch == '\0':
        if state == 'in_command':
            command = str[start:i]
        elif state == 'in_args':
            arg = str[start:i]
            args.append(arg)
        state = 'in_args'
        start = i + 1
    if ch == ';' or ch == '\0':
        state = 'in_command'
        structs.append((command, args))
        command = ''
        args = []

for s in structs:
    print s
1
votes

check this solution . tested with valgrind no leak . but i implemented printing inside freeing .u can implement by yourself looking at free function .further u can improve splitter function to achieve better parsing.

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

typedef struct arr {
    char** words;
    int count;
} uarr;
#define null 0

typedef struct cmdr {
    char* command;
    char** argv;
    int argc;
} cmd;

typedef struct list {
    cmd* listcmd;
    int count;

} cmdlist;

uarr splitter(char* str, char delim);
cmdlist* getcommandstruct(char* string);
void freecmdlist(cmdlist* cmdl);

int main(int argc, char** argv) {
    char input[] = "command1 arg1 arg2 arg3 arg4;command2 arg1 arg2 ;command3 arg1 arg2  arg3;command4 arg1 arg2  arg3";

    cmdlist* cmdl = getcommandstruct((char*) input);
    //it will free . also i added print logic inside free u can seperate
    freecmdlist(cmdl);
    free(cmdl);
    return (EXIT_SUCCESS);
}

/**
 * THIS FUNCTION U CAN USE FOR GETTING STRUCT
 * @param string
 * @return 
 */
cmdlist* getcommandstruct(char* string) {
    cmdlist* cmds = null;
    cmd* listcmd = null;
    uarr resultx = splitter(string, ';');
    //lets allocate
    if (resultx.count > 0) {
        listcmd = (cmd*) malloc(sizeof (cmd) * resultx.count);
        memset(listcmd, 0, sizeof (cmd) * resultx.count);
        int i = 0;
        for (i = 0; i < resultx.count; i++) {
            if (resultx.words[i] != null) {

                printf("%s\n", resultx.words[i]);
                char* def = resultx.words[i];
                uarr defres = splitter(def, ' ');

                listcmd[i].argc = defres.count - 1;
                listcmd[i].command = defres.words[0];
                if (defres.count > 1) {
                    listcmd[i].argv = (char**) malloc(sizeof (char*) *(defres.count - 1));
                    int j = 0;
                    for (; j < defres.count - 1; j++) {
                        listcmd[i].argv[j] = defres.words[j + 1];
                    }

                }
                free(defres.words);
                free(def);
            }
        }

        cmds = (cmdlist*) malloc(sizeof (cmdlist));
        cmds->count = resultx.count;
        cmds->listcmd = listcmd;
    }
    free(resultx.words);
    return cmds;

}

uarr splitter(char* str, char delim) {
    char* holder = str;
    uarr result = {null, 0};
    int count = 0;
    while (1) {
        if (*holder == delim) {
            count++;
        }
        if (*holder == '\0') {
            count++;
            break;
        };
        holder++;
    }
    if (count > 0) {

        char** arr = (char**) malloc(sizeof (char*) *count);
        result.words = arr;
        result.count = count;
        //real split
        holder = str;
        char* begin = holder;
        int index = 0;
        while (index < count) {
            if (*holder == delim || *holder == '\0') {
                int size = holder + 1 - begin;
                if (size > 1) {
                    char* dest = (char*) malloc(size);
                    memcpy(dest, begin, size);
                    dest[size - 1] = '\0';
                    arr[index] = dest;
                } else {
                    arr[index] = null;
                }
                index++;
                begin = holder + 1;
            }
            holder++;
        }

    }
    return result;
}

void freecmdlist(cmdlist* cmdl) {
    if (cmdl != null) {
        int i = 0;
        for (; i < cmdl->count; i++) {
            cmd def = cmdl->listcmd[i];
            char* defcommand = def.command;
            char** defargv = def.argv;
            if (defcommand != null)printf("command=%s\n", defcommand);
            free(defcommand);
            int j = 0;
            for (; j < def.argc; j++) {
                char* defa = defargv[j];
                if (defa != null)printf("arg[%i] = %s\n", j, defa);
                free(defa);
            }
            free(defargv);
        }
        free(cmdl->listcmd);
    }

}
1
votes

Your problem is that you are relying on the pointers in your structures to be initialised to NULL.

They will just be random values, hence the SEGV.

You are also printing 200 commands and 200 arguments when the structure only has 10 commands and 19 arguments.