Разбор записей командной строки в C: реализация оболочки

Я реализую оболочку в C, и я столкнулся с некоторыми проблемами при разборе записей командной строки. Я хочу, чтобы мой метод синтаксического анализа разделял записи командной строки, разделенные символом пробела, и возвращал результат в виде двойного указателя на символ. то есть, скажем, у меня есть "ls -l>ls.txt", мой парсер должен вернуть char **r с r[0]="ls", r[1]="-l" и r[2]=">ls.txt".

Вот код для моего текущего метода синтаксического анализа, который, кстати, является segfaulting, и у меня нет идей относительно того, как это исправить:

 char **parser(int *argc, char *s)
 {
     char **r;
     char *t, *m;
     int i,n,size;

     t = malloc(strlen(s)); // firs i used this instead of *r, but i run 
                            // into trouble when i have more than two
                            // argc. ( You see why, right?)
    //strcpy(t,s);
    i = 0;
    size = 5;
    r = malloc(size*sizeof(char *));
    while (( m = strchr(s, ' '))) {
        n = ((int)m) - ((int)s);
        if (i==0) {
          *r = malloc(n);
        } else {
           *r = realloc(*r, n);
        }
        strncpy(*r, s, n);
        *r[n]= '\0';
        s = (char*)(s+n+1);
        if (i == size)
            r = realloc(r, (size = 2*size)*sizeof(char*));
        i++;
        r = (char **)(r + sizeof(char*));
   }

   s[strlen(s)-1] = '\0';
   if ((i<1) || (strlen(s)>1)) {
       *r = s;
   }
   *argcp = ++i;
   return r;
}

Я знаю, что мой код не идеален. Это можно было бы сделать лучше с помощью strsep, но моя главная задача - как управлять памятью для указателя с двумя символами, который я хочу вернуть.

Спасибо за помощь!

1 ответ

Решение

Это быстрый удар.

Мой C такой ржавый, что все петли застряли.

Предполагается, что в итоге вы получите указатель на массив указателей. Однако ключевая деталь в конце этого списка указателей - это сами данные аргумента. Поэтому, когда вы закончите, вам просто нужно освободить возвращенный указатель.

Непроверенные. Здесь вполне может быть одна ошибка.

Отредактируйте, я скомпилировал и быстро проверил это.

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


char **parser(int *argc, char *s) {
    char **r, **rp;
    char *t, *p, *w;
    void *vp;
    int l;

    l = strlen(s); // size of cmd line
    vp = malloc(l + (*argc * sizeof(char *))); // total buffer size
    t = (char *)(vp + (*argc * sizeof(char *))); // offset into buffer for argument copy
    r = (char **)vp;  // start of buffer, start of pointer array to arguments
    strcpy(t, s);  // copy arguments in to buffer
    p = t;  // parsing pointer
    w = t;  // word pointer for each argument
    rp = r;  // storage for first pointer

    while(*p) {  // while not at end of string
        if (*p == ' ') {  // if we find a space
            if (w) {  // if we have a word pointer assigned
                *rp++ = w;  // store the word pointer
                w = NULL;  // set word pointer to null
                *p = '\0';  // terminate argument with a 0
            } // else do nothing continue to skip spaces
        } else {
            if (w == NULL) {  // If we haven't got a new arg yet
                w = p;  // set it
            }  // otherwise, just keep scanning
        }
        p++;  // move along the string
    }
    if (w) {  // clean up at the end if we have an arg
        *rp++ = w;
        w = NULL;  // no reason to set 0 at the end, it's already there from strcpy
    }

    return r;
}

int main() {
    char *cmd = "arg1 arg2";
    int argc = 2;

    char **r = parser(&argc, cmd);

    printf("%s\n",r[0]);
    printf("%s\n",r[1]);
}
Другие вопросы по тегам