Linha de Comandos


Informação complementar:

Uma forma comum de passar argumentos a programas é através da linha de comandos. Uma linha de comandos simplificada consiste num conjunto de palavras separadas por espaços que no seu conjunto representam um determinado comando e os seus argumentos. Quando um utilizador invoca um comando através da linha de comandos, 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 irá executar 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 na linha de comandos. 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);

  int 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, o código acima usa as bibliotecas readline e history que permitem fazer edição e historial da linha de comandos de forma simples. A utilização destas bibliotecas requer que o programa seja compilado com a opção -lreadline.

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().

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.

Quando a sua linha de comandos estiver a funcionar corretamente, repita o exercício mas altere a declaração da variável com na função main() por COMMAND *com e faça as adaptações necessárias ao restante código.