Unix goto Quellcode



  • Guten Abend 🙂

    Ich bin mit Java sehr vertraut, muss nun aber als C-Neuling den Quellcode des Unix-Kommandos goto verstehen und auch erklären können.

    Ich poste nun mal den gesamten Quellcode (ist nicht viel) und dann wäre es toll wenn wir Stück für Stück den Code durcharbeiten könnten. 👍

    int offset 0;
    
    main(argc, argv)
    char *argv[];
    {
            extern fin;
            char line[64];
    
            if (argc<2 || ttyn(0)!='x') {
                    write(1, "goto error\n", 11);
                    seek(0, 0, 2);
                    return;
            }
            seek(0, 0, 0);
            fin = dup(0);
    
    loop:
            if (getlin(line)) {
                    write(1, "label not found\n", 16);
                    return;
                    }
            if (compar(line, argv[1])) goto loop;
            seek(0, offset, 0);
    }
    
    getlin(s)
    char s[];
    {
            int ch, i;
    
            i = 0;
    l:
            if ((ch=getc())=='\0') return(1);
            if (ch!=':') {
                    while(ch!='\n' && ch!='\0')
                            ch = getc();
                    goto l;
                    }
            while ((ch=getc())==' ');
            while (ch!=' ' && ch!='\n' && ch!='\0') {
                    s[i++] = ch;
                    ch = getc();
                    }
            while(ch != '\n')
                    ch = getc();
            s[i] = '\0';
            return(0);
    }
    
    compar(s1, s2)
    char s1[], s2[];
    {
            int c, i;
    
            i = 0;
    l:
            if(s1[i] != s2[i]) return(1);
            if (s1[i++] == '\0') return(0);
            goto l;
    }
    
    getc()
    {
    
            offset++;
            return(getchar());
    }
    

    Meine Fragen zum ersten Teil.

    (1) Zeile 7: Wie kann diese Zeile überhaupt vor der geschweiften Klammer stehen?

    (2.) Zeile 20: Was genau macht ttyn(0)? Und was bedeutet der Parameter 0?

    (3.) Zeile 23: Das erste Argument von write ist soweit ich weiß der Filedeskriptor. Warum ist es hier 1 und bei seek dann 0? Es wurden ja bis jetzt keine Filedeskriptoren erzeugt, wofür steht dann die 0 und die 1?

    (4.) Zeile 26: Was genau macht diese Zeile? Der zweite Parameter ist die aktuelle Position und der dritte das Offset. Aber was bedeutet eine Verschiebung/Änderung um 2? Was wird da genau verschoben/geändert?



  • Der Quellcode verwendet die (sehr) alte Art Funktionen zu deklararieren.
    Moderner sähen die Funktionssignaturen so aus:

    int main(int arg, char* argv[]);
    int getline(char s[]);
    int compare(char s1[], char s2[]);
    int getc();
    


  • Vielen Dank Nathan, damit wäre Frage 1 geklärt. 👍



  • fallersleben schrieb:

    (3.) Zeile 23: Das erste Argument von write ist soweit ich weiß der Filedeskriptor. Warum ist es hier 1 und bei seek dann 0? Es wurden ja bis jetzt keine Filedeskriptoren erzeugt, wofür steht dann die 0 und die 1?

    unistd.h schrieb:

    `/* Standard file descriptors. */

    #define STDIN_FILENO 0 /* Standard input. */

    #define STDOUT_FILENO 1 /* Standard output. */

    #define STDERR_FILENO 2 /* Standard error output. */`

    fallersleben schrieb:

    (4.) Zeile 26: Was genau macht diese Zeile? Der zweite Parameter ist die aktuelle Position und der dritte das Offset. Aber was bedeutet eine Verschiebung/Änderung um 2? Was wird da genau verschoben/geändert?

    Nö.
    Der zweite Parameter ist der Offset von der Position, die mit dem 3. Parameter spezifiziert wird.

    unistd.h schrieb:

    `# define SEEK_SET 0 /* Seek from beginning of file. */

    define SEEK_CUR 1 /* Seek from current position. */

    define SEEK_END 2 /* Seek from end of file. */`



  • fallersleben schrieb:

    (2.) Zeile 20: Was genau macht ttyn(0)? Und was bedeutet der Parameter 0?

    http://man.cat-v.org/unix-6th/3/ttyn



  • Zu Frage 2: s. ttyn

    Und für deine 3. Frage gibt es sogar einen eigenen Wiki-Beitrag: File descriptor (in der deutschen Version steht es auch, aber nur im Text, nicht als übersichtlichere Tabelle 😉

    Und auch zur 5. Frage kann man in die "man pages" schauen: seek - der "Input-Dateizeiger" wird also an das Ende der Eingabe gesetzt.



  • @Offtopic
    Goto und Gosub waren die ersten Verzweigungsbefehle die ich als Kind in den C64 gehackt hatte. Mit 13 Jahren kamen dann die ersten Assemblerversuche dazu, ohne Google und Internet und mit schlechten Büchern hat das schon ein paar Wochen gedauert.

    Ich habe damals dann echt eine Weile gebraucht, um ohne goto und gosub denken zu können. Ganz krass war dann OOP. Das hat seeeeehr lange gedauert, bis ich da einen Nutzen für meine Programme daraus ableiten konnte und auch heute noch finde ich OOP-Code sehr anstrengend zu lesen, wenn da zu sehr generalisiert wurde. Da wurde dann die Fähigkeit zu Erweiterung gegen die Lesbarkeit des Code eingetauscht.



  • Recht herzlichen Dank an dich DirkB und Th69 👍
    Auch die Anmerkung von Goto10 war interessant 🙂

    Ich versuche mir mal die Fragen jetzt selber zu beantworten.

    (1.) Zeile 20: Was genau macht ttyn(0)!='x'?
    Die 0 steht für die Standardeingabe.
    Man überprüft also, ob die Standardeingabe ein Terminal ist. Falls es ein Terminal ist, dann geben wir den Fehler aus. Denn wir erwarten, dass die Standardeingabe das Skript ist.

    (2.) Zeile 26: Was genau macht dieser Aufruf seek(0,0,2)?
    Der erste Parameter entspricht der Standardeingabe, der zweite dem Offset, welcher 0 ist und der dritte steht laut man page für

    the pointer is set to the size of the file plus offset.

    Das heißt im Buffer der Standardeingabe mag irgendwas stehen und durch diesen Befehl setzten wir den Lese und -Schreibpointer an das Ende des Buffers, sodass beim nächsten Zugriff auf die Standardeingabe kein Inhalt vorhanden ist. Die Standardeingabe wurde quasi zurückgesetzt.


Anmelden zum Antworten