Hlavní navigace

Programování pod Linuxem pro všechny (2)

Jakub Matys

Vítám vás u nového dílu našeho programovacího seriálu. Jak už jsem v minulém dílu předeslal, dnes se budeme zabývat funkcí getopt_long, naučíme se používat systémové proměnné a vytvářet dočasné soubory. Tak tedy s chutí do toho!

getopt_long()

Jak už jste si určitě někdy všimli, většině programů se při jejich spouštění předávají parametry. Někdy to je jen písmeno uvedené pomlčkou (-), ale někdy to jsou dvě pomlčky (–) následované slovem či více slovy. Tyto parametry mění chod programu. Pro obsluhu parametrů se používá funkce getopt_long. Při použití této funkce musíte do svého kódu vložit hlavičkový soubor getopt.h.

Při použití funkce getopt_long musíte definovat dvě speciální datové struktury. První je znakový řetězec obsahující krátké volby. Píší se bez pomlčky a ty, za nimiž bude náslodovat další argument, jsou následovány dvojtečkou. Pokud chcete používat dlouhé volby, musíte sestavit pole, které bude obsahovat struktury struct option. Každá tato struktura představuje jednu volbu a obsahuje čtyři položky. První položkou je jméno volby (znakový řetězec uzavřený do uvozovek); druhá obsahuje 1, pokud má za volbou následovat další argument, nebo 0. Třetí položkou je konstantaNULL a čtvrtou je odpovídající krátká volba. Posledními elementy by měly být nuly. Menší příklad pro názornost:

/* retezec obsahujici kratke volby */
const char *kratke_volby = "ho:i:";

/* pole s dlouhymi volbami */
const struct option long_options[] = {
   { "help",     0, NULL, 'h' },
   { "output",   1, NULL, 'o' },
   { "input"     1, NULL, 'i' },
   { NULL,       0, NULL, 0   }
};

Při volání funkce getopt_long je nutné předat jako parametry proměnné argc, argv, řetězec s krátkými volbami a pole s dlouhými volbami. Funkce pracuje následovně:

  • Po každém volání provádí syntaktickou analýzu volby a vrátí jednoznakové písmeno pro volbu, nebo –1, pokud další volby nebyly nalezeny.
  • Běžně se funkce volá v cyklu, a tak se postupně zpracují všechny volby předané z shellu. Každá konkrétní volba se pak zpracuje v příkazu switch.
  • Pokud funkce getopt_long zjistí zadání neplatné volby, zobrazí chybové hlášení a vrátí znak ?. Většina programů na to reaguje ukončením a vypsáním zprávy o zadání neplatné volby.
  • Pokud za volbami následuje další argument, vrátí se globální proměnná optarg ukazující na textový řetězec.
  • Po ukončení syntaktické analýzy vrátí funkce getopt_long v globální proměnné optind index (do pole argv) prvního argumentu, který není volbou.

Všechny výše napsané informace si předvedeme na příkladu:

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

/* Jmeno programu. */
const char *program_name;

/* Tato funkce vypise napovedu do vystupniho
 * proudu STREAM(stderr, stdout) a ukonci se
 * s kodem EXIT_CODE.
 */
void print_help(FILE *stream, int exit_code)
{
  fprintf(stream, "Usage: %s options\n", program_name);
  fprintf(stream, "  -h  --help         Display this help screen.\n"
                  "  -o  --output file  Write output to file.\n"
                  "  -i  --input file   Read input from file.\n");
  exit(exit_code);
}

/* Funkci main zacina program. */
int main(int argc, char *argv[])
{
  int next_option;

  /* Retezec obsahujici kratke volby */
  const char *short_options = "ho:i:";

  /* Pole struktur s dlouhymi volbami */
  const struct option long_options[] = {
    { "help",    0, NULL, 'h' },
    { "output",  1, NULL, 'o' },
    { "input",   1, NULL, 'i' },
    { NULL,      0, NULL,  0  }
  };

  /* Jmeno souboru pro vystup nebo NULL pro stdout */
  const char *output_file = NULL;

  /* Jmeno souboru pro vstup nebo NULL pro stdin */
  const char *input_file = NULL;

  /* Jmeno programu je ulozeno v promene argv[0]. */
  program_name = argv[0];

  do {
    next_option = getopt_long(argc, argv, short_options, long_options, NULL);

    switch(next_option)
    {
      case 'h': /* -h nebo --help */
           print_help(stdout, 0);
      case 'o': /* -o nebo --output */
           output_file = optarg;
           break;
      case 'i': /* -i nebo --input */
           input_file = optarg;
           break;
      case '?': /* Uzivatel specifikoval neznamou volbu */
           print_help(stderr, 1);
      case -1 : /* Konec */
           break;
      default:
           abort();
    }
  } while(next_option != -1);

  /* Volby byly zpracovany. Promena OPTIND ukazuje
   * na prvni argument, ktery neni volbou.
   */

  ...
  ...
  ...

  return(0); /* Ukonceni programu s kodem 0 */
} 

To by bylo vše k funkci getopt_long. Někomu by se mohlo zdát ze je její použití příliž pracné. Ale pokud byste si vytvořili vlastní funkci, stálo by vás to mnohem více úsilí.

Systémové proměnné

Každý program běžící v Linuxu ma přiřazeno jisté prostředí (enviroment). Prostředí je množina dvojic [systémová proměnná, hodnota]. Systémové proměnné jsou znakové řetězce a jejich jména se píší velkými písmeny. Je vysoce pravděpodobné, že jste se už setkali s proměnnými USER, HOME, PATH, DISPLAY. Proměnné můžete vytvářet v shellu zápisem PROMENNA=hodnota, poté je nutné je exportovat z shellu do prostředí příkazem export PROMENNA. Zjistit hodnotu proměnné můžete příkazem echo $PROMENNA. A konečně, chcete-li vypsat prostředí shellu, zadejte příkaz printenv.

V programu lze systémové proměnné zpřístupňovat pomocí funkce getenv, která je popsána v stdlib.h. Tato funkce má jediný argument, a to jméno proměnné, jejíž hodnotu chcete zjistit. Pokud není systémová proměnná definována, vrací funkce NULL, jinak vrací textový řetězec, který obsahuje hodnotu proměnné. Jestliže budete chtít nastavit nebo zrušit systémovou proměnnou, použijte funkci setenvresp. unsetenv. Menší příklad použití systémových proměnných:

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

int main()
{
   char *conf_file = getenv("CONFIG_FILE");
   if(conf_file == NULL)
      /* Promenna CONFIG_FILE nebyla definovana,
       * pouzije se defaultni configuracni soubor
       */
      conf_file = "/etc/config";
   ...
   ...
   ...

   return(0);
}

To by bylo pro dnešek vše, slíbené vytváření dočasných souborů si necháme na příště. A navíc si povíme něco o statických a dynamických knihovnách.

Našli jste v článku chybu?