線形リストでスタック #1

intをデータに持つ単方向連結の線形リストで実装するスタック。
先頭要素の追加と削除でpush/pop操作を実現する。
文字列から整数への変換にはatoiよりエラーを認識できるstrtolを用いた方がいいだろうと思う。

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

typedef struct tagNode Node;

struct tagNode {
    int data;
    Node *next;
};

typedef enum {
    CMD_INVALID, CMD_TOOLONG, CMD_PUSH, CMD_POP, CMD_PRINT, CMD_QUIT
} CmdType;

typedef struct {
    CmdType type;
    int value;
} Cmd;

void init(Node *head);
void push(Node *head, int data);
void pop(Node *head);
void print(Node *head);
void get_cmd(Cmd *cmd);

void init(Node *head)
{
    head->next = NULL;
}

void push(Node *head, int data)
{
    Node *n = malloc(sizeof(Node));
    n->data = data;
    n->next = head->next;
    head->next = n;
}

void pop(Node *head)
{
    Node *n = head->next;
    if (n == NULL) {
        puts("empty list");
    } else {
        printf("%d\n", n->data);
        head->next = n->next;
        free(n);
    }
}

void print(Node *head)
{
    Node *n;

    for (n = head->next; n != NULL; n = n->next) {
        printf("%d ", n->data);
    }
    putchar('\n');
}

void get_cmd(Cmd *cmd)
{
    char s[4096];

    putchar('>');
    if (fgets(s, sizeof s, stdin) == NULL) {
        cmd->type = CMD_QUIT;
    } else if (s[strlen(s) - 1] != '\n') {
        for (;;) {
            int c = getchar();
            if (c == '\n' || c == EOF) break;
        }
        cmd->type = CMD_TOOLONG;
    } else {
        s[strlen(s) - 1] = '\0';
        if (strncmp(s, "push ", 5) == 0) {
            cmd->type = CMD_PUSH;
            cmd->value = atoi(s + 5);
        } else if(strcmp(s, "pop") == 0) {
            cmd->type = CMD_POP;
        } else if(strcmp(s, "print") == 0) {
            cmd->type = CMD_PRINT;
        } else if(strcmp(s, "quit") == 0) {
            cmd->type = CMD_QUIT;
        } else {
            cmd->type = CMD_INVALID;
        }
    }
}

int main(void)
{
    int quit_requested = 0;
    Node head;
    Cmd cmd;

    init(&head);
    do {
        get_cmd(&cmd);
        switch (cmd.type) {
        case CMD_PUSH:
            push(&head, cmd.value);
            break;
        case CMD_POP:
            pop(&head);
            break;
        case CMD_PRINT:
            print(&head);
            break;
        case CMD_QUIT:
            quit_requested = 1;
            break;
        case CMD_INVALID:
            puts("incomprehensible command");
            break;
        case CMD_TOOLONG:
            puts("too long command");
            break;
        default:
            puts("something strange...");
        }
    } while (! quit_requested);
    return 0;
}