Exercícios II: Linha de Comandos

Em UNIX é comum passar argumentos a programas através da linha de comandos. Uma linha de comando UNIX consiste num conjunto de palavras separadas por espaços, tabs, ou backslash seguido do caracter mudança de linha (\n). Quando um utilizador escreve um comando, a shell apanha a linha de comando como uma string, determina nessa string qual a palavra correspondente ao comando do utilizador e constrói um vector de strings com os argumentos a passar ao programa que executa o comando. De seguida executa o programa passando-lhe os argumentos determinados.

Neste exercício pretende-se que implemente um programa que mostre uma prompt ao utilizador (por exemplo my_prompt$), leia as strings correspondentes aos comandos que o utilizador for invocando, e para cada string lida chame uma função parse para estruturar os argumentos correspondentes ao comando invocado e uma função print_parse para imprimir o conteúdo da estrutura retornada por parse. O programa deve terminar quando o utilizador invocar o comando exit.

Para tal, considere o extracto de código que se segue e complete-o de acordo com as indicações abaixo:


  #include <stdio.h>
  #include <stdlib.h>
  #include <readline/readline.h>
  #include <readline/history.h>

  #define MAXARGS 100
  typedef struct command {
    char *cmd;              // string apenas com o comando
    int argc;               // número de argumentos
    char *argv[MAXARGS+1];  // vector de argumentos do comando
  } COMMAND;

  COMMAND parse(char *linha);
  void print_parse(COMMAND com);

  main() {
    char *linha;
    COMMAND com;

    while (1) {
      if ((linha = readline("my_prompt$ ")) == NULL)
        exit(0);
      if (strlen(linha) != 0) {
        add_history(linha);
        com = parse(linha);
        print_parse(com);
      }
      free(linha);
    }
  }

  COMMAND parse(char *linha) {
    // ...
  }

  void print_parse(COMMAND com) {
    // ...
  }

Para obter a string da linha de comando, use a biblioteca readline, que permite fazer edição e historial da linha de comandos de forma simples. A utilização desta biblioteca requer que o programa seja compilado com a opção -lreadline -lcurses.

A função parse deverá retornar uma estrutura do tipo COMMAND em que COMMAND é a estrutura de dados sugerida para estruturar os argumentos do comando invocado. O campo cmd possui o comando propriamente dito, o campo argc contém o número de argumentos, enquanto que o campo argv possui o vector de argumentos do comando. O primeiro argumento é o próprio comando (argv[0]=cmd), seguem-se os argumentos correspondentes aos argumentos do comando (argv[1], ..., argv[argc-1]) e termina com o argumento NULL (argv[argc]=NULL). Para percorrer a string do comando utilize a função strtok. Para mais informação consulte a man page respectiva.

A função print_parse deverá imprimir o conteúdo da estrutura COMMAND retornada por parse e no caso do comando invocado ser exit deverá terminar.