Kommando Interpreter C

Joe1903

Mitglied
?
Ich habe keine komplette Bourne-Shell gebaut :D

Am besten testest du das so: Du guckst dir den Code an, schaust, wie du ein Kommando erstellst und hinzufügst, und wie ein Kommando intern funktioniert.
Dann schreibst du eines, fügst es hinzu und testest es damit.
C:
//Add our little example function. We shortcut the descriptions 'cause I have no clue what they are for anyways.
    cmd_desc* DEIN_CMD = create_cmd_desc("DEIN_CMD_NAME", 0/*would be param name count*/, NULL/*would be paramnames. Add if you fancy it*/, &DEIN_CMD_CALLBACK);
    if (DEIN_CMD == NULL) printf("Uh. Something really bad happened. And the programmer was too lazy to clean up... Take cover.\n");
    add_cmd_desc(&cmd_desc_arr, &arr_ind, &arr_size, DEIN_CMD);
Alles, was mit "DEIN_CMD" beginnt, solltest du entsprechend personalisieren. (Dieser Code sollte noch vor der ersten Eingabe stehen). Deine Funktion sollte so aussehen wie der adder:
C:
int adder(int argc, char* argv[])
{
   //Dein Code. Achtung: Nie weiter als argv[argc-1] lesen!
   //=======HIER KÖNNTE DEINE KREATIVITÄT STEHEN==============

   return 0;
}

Gruss
cwriter

Zum 2. Post:
Eigentlich nicht - entspricht ja nicht der Spezifikation. Stell dir vor, du lässt jemanden ein komplettes Haus mit allem drum und dran bauen und dieser lässt die Wände ohne Farbe bzw. Tapete. Und wenn du ihn darauf ansprichst, sagt er: "Aber das ist ja nicht wichtig, oder? Das Haus steht ja. Das Geld für die Wände nehme ich aber trotzdem".
Ich glaube nicht, dass du sonderlich glücklich wärst. Aber ich habe es ja schön: Ich bin weder Subunternehmer noch reicht dein Arm weit genug, um mich zu hauen. Daher kann ich es mir leisten, mich nicht 100%ig an die Vorgaben zu halten :cool:
Aber wieder ein bisschen ernsthafter: Wenn das deine Aufgabe ist, solltest du die Aufgabe schon richtig erfüllen. Ich weiss nicht so recht, wofür die Paramternamen gut sein sollen, und ich sah nicht viel Zweck darin, nachzufragen. Das gilt für dich nicht. Also; wenn du den Code selbst schreibst: Frag deinen Prof/Chef/Hund/Was auch immer, was damit gemeint ist und implementiere es entsprechend.
Hey cwriter.
Dürfte ich dich um ein kleines Gefallen bitten.Und zwar wenn ich beim Testen irgendwas schreibe (z.B. awa awa awa beeee) dann kommt 4-mal Next Input please.Aber sollte ja abbrechen eigentlich.Kannst du bitte mal schauen,woran das liegt??Es ist ja dein Code,du siehst schneller als ich.Wäre echt dankbar.
 

cwriter

Erfahrenes Mitglied
Dürfte ich dich um ein kleines Gefallen bitten.Und zwar wenn ich beim Testen irgendwas schreibe (z.B. awa awa awa beeee) dann kommt 4-mal Next Input please.
Naja, ist halt eine scanf-Sache.
Aber sollte ja abbrechen eigentlich.
War das eine Spezifikation? Wenn nein, dann ist es schlicht ein Ausnutzen des Undefined Behaviour.

Kannst du bitte mal schauen,woran das liegt??
Weiss ich auch so: Scanf. Ist nun mal so, dass scanf bei Whitespaces (auch ' ') abbricht.
Eine Lösung: Nach dem printf("Next input please"); ein
C:
scanf("%*[^\n]");
einfügen. Das liest einfach alles bis zum '\n' ein und ignoriert es direkt ('*').

Es ist ja dein Code,du siehst schneller als ich.
Vorsicht. Du bist im Moment entweder auf dem Pfad des Copy-Paste oder auf dem des zeilenweisen Abschreibens. So nicht - du lernst so ja nichts. Ja, es sind 260 Zeilen, und ja, die Thematik ist durch die Edgecases nicht ganz so einfach, aber dann nimm dir halt mal einen Nachmittag Zeit, um den Code zu lesen und zu verstehen.
Im Moment scheint es so, als würdest du Code haben, den du nicht verstehst, und wolltest dann einfach ein paar Änderungen daran vornehmen, weisst aber nicht, wie.
Es ist ok, Fragen zu stellen. Aber ein bisschen ein eigener Aufwand, herauszufinden, wo das Problem liegt, müsste schon drinliegen. Dann wäre deine Frage zu einem "Wie kann ich den Eingabebuffer bis zum nächsten "\n" leeren?", daraus wäre wiederum eine englische Version der Frage geworden, die Google verdaut und dir dann etwa so einen Link ausspuckt:
http://stackoverflow.com/questions/8097620/how-to-read-from-input-until-newline-is-found-using-scanf
Dann noch ohne Buffer (denn das würde ja Speicher brauchen):
http://stackoverflow.com/questions/7607550/scanf-skip-variable

Und schwupps hast du deine Lösung.
Im Übrigen finde ich meinen Code jetzt nicht wirklich schwer verständlich. Er ist ja sogar mit Kommentaren versehen.

Wäre echt dankbar.
Und ich wäre echt dankbar, würdest du mal an den Riemen reissen und ein bisschen Eigeninitiative zeigen.

Ist auch nicht böse gemeint, aber: "Gib jemandem einen Fisch, und er ernährt sich einen Tag lang. Lehre ihn zu fischen, und er ernährt sich ein Leben lang."

Gruss
cwriter
 

Joe1903

Mitglied
Naja, ist halt eine scanf-Sache.

War das eine Spezifikation? Wenn nein, dann ist es schlicht ein Ausnutzen des Undefined Behaviour.


Weiss ich auch so: Scanf. Ist nun mal so, dass scanf bei Whitespaces (auch ' ') abbricht.
Eine Lösung: Nach dem printf("Next input please"); ein
C:
scanf("%*[^\n]");
einfügen. Das liest einfach alles bis zum '\n' ein und ignoriert es direkt ('*').


Vorsicht. Du bist im Moment entweder auf dem Pfad des Copy-Paste oder auf dem des zeilenweisen Abschreibens. So nicht - du lernst so ja nichts. Ja, es sind 260 Zeilen, und ja, die Thematik ist durch die Edgecases nicht ganz so einfach, aber dann nimm dir halt mal einen Nachmittag Zeit, um den Code zu lesen und zu verstehen.
Im Moment scheint es so, als würdest du Code haben, den du nicht verstehst, und wolltest dann einfach ein paar Änderungen daran vornehmen, weisst aber nicht, wie.
Es ist ok, Fragen zu stellen. Aber ein bisschen ein eigener Aufwand, herauszufinden, wo das Problem liegt, müsste schon drinliegen. Dann wäre deine Frage zu einem "Wie kann ich den Eingabebuffer bis zum nächsten "\n" leeren?", daraus wäre wiederum eine englische Version der Frage geworden, die Google verdaut und dir dann etwa so einen Link ausspuckt:
http://stackoverflow.com/questions/8097620/how-to-read-from-input-until-newline-is-found-using-scanf
Dann noch ohne Buffer (denn das würde ja Speicher brauchen):
http://stackoverflow.com/questions/7607550/scanf-skip-variable

Und schwupps hast du deine Lösung.
Im Übrigen finde ich meinen Code jetzt nicht wirklich schwer verständlich. Er ist ja sogar mit Kommentaren versehen.


Und ich wäre echt dankbar, würdest du mal an den Riemen reissen und ein bisschen Eigeninitiative zeigen.

Ist auch nicht böse gemeint, aber: "Gib jemandem einen Fisch, und er ernährt sich einen Tag lang. Lehre ihn zu fischen, und er ernährt sich ein Leben lang."

Gruss
cwriter
Danke für deine Hilfestellung.Ich bin gerade am zeilenweise durchgehen,aber ich werde es nicht abgeben.Ich schiesse mir ja nicht ins eigene Bein wenn ich etwas abgebe was ich zumindest nicht verstehe-aber eine Frage habe ich noch.
Ich habe das scanf eingebaut. Nun funktionier "adder 0 1 2 3 4 <" aber sobald ich "awa awa awea" eingebe,gibt es "Next input please" aus (erwartungsgemäss) jedoch wenn ich danach wieder "adder 10 22 30 40 <" eingebe, gibt es wieder "Next input please". Ich denke, dass es den Speicher nicht (richtig) leert.Bin ich auf dem richtigen Weg?Weisst du,warum es so sporadisch funktioniert?
 

cwriter

Erfahrenes Mitglied
Code:
This is a little command line interface (cli) demo.
Enter 'quit' to quit.
adder 0 <
Sum is 0, Average is 0 and median is 0
Ladies and gentlemen, next round, your input please...
aw aw
Ladies and gentlemen, next round, your input please...
adder 0 <
Sum is 0, Average is 0 and median is 0
Ladies and gentlemen, next round, your input please...
Gibt es bei dir auch so einen Output?

Ich denke, dass es den Speicher nicht (richtig) leert.Bin ich auf dem richtigen Weg?
Wie kommst du darauf? Es kann Speicher weder richtig noch unrichtig leeren, denn scanf() ist POSIX-standardisiert. Würde bei dir etwas anderes rauskommen, hätten wir ein Problem, denn dann wäre die POSIX-Compliance meines Systems von der des deinigen unterschiedlich und es würde ziemlich mühsam werden.
Die Codezeile des Scanf ist so definiert, dass es alle Zeichen bis zum '\n' als dem Eingabestrom löscht. Fertig. D.h. wenn das für dich "richtig" ist, dann ist dieser Teil des Programms semantisch korrekt.
Ich denke eher, dass du das "Next input please" als Fehlermeldung verstehst, was es nicht ist. Es zeigt nicht an, ob ein Fehler passiert war, sondern wird unkonditional ausgeführt. Das sähe man aber auch im Code.

Gruss
cwriter
 

Joe1903

Mitglied
Code:
This is a little command line interface (cli) demo.
Enter 'quit' to quit.
adder 0 <
Sum is 0, Average is 0 and median is 0
Ladies and gentlemen, next round, your input please...
aw aw
Ladies and gentlemen, next round, your input please...
adder 0 <
Sum is 0, Average is 0 and median is 0
Ladies and gentlemen, next round, your input please...
Gibt es bei dir auch so einen Output?


Wie kommst du darauf? Es kann Speicher weder richtig noch unrichtig leeren, denn scanf() ist POSIX-standardisiert. Würde bei dir etwas anderes rauskommen, hätten wir ein Problem, denn dann wäre die POSIX-Compliance meines Systems von der des deinigen unterschiedlich und es würde ziemlich mühsam werden.
Die Codezeile des Scanf ist so definiert, dass es alle Zeichen bis zum '\n' als dem Eingabestrom löscht. Fertig. D.h. wenn das für dich "richtig" ist, dann ist dieser Teil des Programms semantisch korrekt.
Ich denke eher, dass du das "Next input please" als Fehlermeldung verstehst, was es nicht ist. Es zeigt nicht an, ob ein Fehler passiert war, sondern wird unkonditional ausgeführt. Das sähe man aber auch im Code.

Gruss
cwriter
Leider nicht..

Der Code momentan bei mir ist wie folgt:

C++:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define bool int
#define true 1
#define false 0

typedef int (*cmd_func)(int argc, char* argv[]);

typedef struct cmd_desc
{
        char* name;
        int parc;
        char** parv;
        int argc;
        char** argv;
        cmd_func func;

} cmd_desc;


bool exfree(void* p)
{
        if (p != NULL)
        {
                free(p);
                return (true);
        }
        return (false);
}


void clear_cmd_desc(
        cmd_desc* to_clear)
{
        int i;
        exfree(to_clear->name);

        for (i = 0; i < to_clear->parc; i++)
        {
                exfree(to_clear->parv[i]);
        }

        for (i = 0; i < to_clear->argc; i++)
        {
                exfree(to_clear->argv[i]);
        }
        memset(to_clear, 0, sizeof(cmd_desc));
}


cmd_desc* create_cmd_desc(
        const char* name,
        int parc,
        const char** parv,
        cmd_func func)
{
        int i;
        cmd_desc* ptr = NULL;

        if (parc < 0)
        {
                exit(1);
        }

        ptr = (cmd_desc*)calloc(1, sizeof(cmd_desc));

        if (ptr == NULL)
        {
                printf("Allocation failed.\n");
                exit(1);
        }
        ptr->name = (char*)malloc(strlen(name) + 1);
        strcpy(ptr->name, name);

        if (parc > 0)
        {
                ptr->parc = parc;
                ptr->parv = (char**)malloc(sizeof(char*)*parc);

                for (i = 0; i < parc; i++)
                {
                        ptr->parv[i] = (char*)malloc(strlen(parv[i]) + 1);
                        strcpy(ptr->parv[i], parv[i]);
                }
        }
        ptr->func = func;

        return (ptr);
}


bool push_input(
        cmd_desc* d,
        const char* input)
{
        char** tmp = NULL;
        tmp = (char**)realloc(d->argv, sizeof(char*) * (d->argc + 1));

        if (tmp == NULL)
        {
                printf("Reallocation failed.\n");
                exit(1);
        }
        else
        {
                d->argv = tmp;
        }
        d->argv[d->argc] = (char*)malloc(strlen(input) + 1);
        strcpy(d->argv[d->argc], input);
        (d->argc)++;
        return (true);
}


void clear_input(
        cmd_desc* d)
{
        int i;

        for (i = 0; i < d->argc; i++)
        {
                exfree(d->argv[i]);
        }
        exfree(d->argv);
        d->argv = NULL;
        d->argc = 0;
}


bool add_cmd_desc(
        cmd_desc** arr,
        size_t* index,
        size_t* arrsize,
        cmd_desc* desc)
{
        cmd_desc* tmp = NULL;

        if (*index >= *arrsize)
        {
                tmp = (cmd_desc*)realloc(*arr, sizeof(cmd_desc) * *arrsize * 2);

                if (tmp == NULL)
                {
                        printf("Reallocation failed.\n");
                        exit(1);
                }
                else
                {
                        *arrsize *= 2;
                        *arr = tmp;
                }
        }
        (*arr)[(*index)++] = *desc;
        free(desc);
        return (true);
}


int adder(
        int argc,
        char* argv[])
{
        int i;
        int sum = 0;

        if (argc <= 0)
        {
                printf("Invalid parameters.\n");
                exit(1);
        }

        for (i = 0; i < argc; i++)
        {
                sum += atoi(argv[i]);
        }

        printf("Sum is %d, Average is %d and median is %d\n", sum, sum / argc, atoi(argv[argc / 2]));
        return (sum);
}

int main(int argc, char* argv[])
{
        cmd_desc* cmd_desc_arr = NULL;
        cmd_desc* d = NULL;
        size_t arr_ind = 0;
        size_t arr_size = 4;
        size_t i = 0;
        size_t bufstep = 256;
        size_t bufsize = 256;
        char* buf = NULL;
        char* bufbase = NULL;
        char* tmp = NULL;
        int diff;

        cmd_desc_arr = (cmd_desc*)calloc(arr_size, sizeof(cmd_desc));

        if (cmd_desc_arr == NULL)
        {
                printf("Allocation failed.\n");
                exit(1);
        }

        buf = (char*)calloc(bufsize, sizeof(char));
        bufbase = buf;

        if (buf == NULL)
        {
                printf("Allocation failed.\n");
                free(cmd_desc_arr);
                exit(1);
        }

        d = create_cmd_desc("adder", 0, NULL, &adder);

        if (d == NULL)
        {
                printf("Error occured.\n");
                exit(1);
        }

        add_cmd_desc(&cmd_desc_arr, &arr_ind, &arr_size, d);

        printf("Command line interface.\nEnter 'quit' to quit.\n");

        while (scanf("%255s", bufbase) > 0)
        {
                if (strcmp(bufbase, "quit") == 0)
                {
                        break;
                }

                for (; i < arr_ind; i++)
                {
                        cmd_desc* d = &cmd_desc_arr[i];

                        if (d->name == NULL)
                        {
                                continue;
                        }

                        if (strcmp(d->name, buf) == 0)
                        {
                                while (scanf("%255s", buf) > 0)
                                {
                                        if (buf[0] == '<')
                                        {
                                                break;
                                        }

                                        if (buf[bufstep-2] != 0)
                                        {
                                                buf += bufstep-1;
                                        }

                                        if (bufbase[bufsize - 2] != 0)
                                        {
                                                tmp = (char*)realloc(bufbase, bufsize * 2);

                                                if (tmp == NULL)
                                                {
                                                        printf("Failed to realloc.\n");
                                                        goto end;
                                                }

                                                diff = (buf - bufbase);
                                                bufbase = tmp;
                                                buf = buf + diff;
                                                bufsize *= 2;
                                                bufbase[bufsize - 2] = 0;
                                                bufbase[bufsize - 1] = 0;
                                        }

                                        push_input(d, bufbase);
                                }
                                d->func(d->argc, d->argv);
                                clear_input(d);
                                break;
                        }
                }
                printf("Next input please..\n");
                scanf("%*[^\n]");
        }
end:
        free(bufbase);

        for (; i < arr_size; i++)
        {
                clear_cmd_desc(&cmd_desc_arr[i]);
        }
        exfree(cmd_desc_arr);

        getchar();
        return (0);
}

Ausgabe ist so:
Code:
T540972@TD01:/home/t540972/test ==> c2_beta
Command line interface.
Enter 'quit' to quit.
adder 2 3 <
Sum is 5, Average is 2 and median is 3
Next input please..
awa awa
Next input please..
adder 3 4 <
Next input please..
adder 3 <
Next input please..
aqaw
Next input please..
adder 3 4 5 <
Next input please..
 

Joe1903

Mitglied
Ich habe mal deinen Code in meine IDE eingefügt und ausgeführt. Innert 3 Minuten kann man herausfinden, dass du im Loop
C:
for (; i < arr_ind; i++)
Den Zähler nicht auf 0 setzt.
Case closed.

cwriter
CWriter danke für die Antwort.Ich arbeite ohne IDE,weil es so gefordert ist.
Dürfte ich dich etwas letztes fragen?
Du hast in deinem Code "Invalid parameters" falls argc <= 0 ist,also es keine Argumente gibt.Wie erreiche ich aber dies?Wenn ich nichts eingebe,kommt diese Meldung auch nicht.