Cómo gestionar los parámetros de un programa en C (parte 2: parámetros largos)

Publicado el 12 noviembre 2015 por Gaspar Fernández Moreno @gaspar_fm

Hace unos días publiqué Cómo gestionar los parámetros de nuestros programas con getopt en C como una introducción a la gestión de los argumentos desde nuestros programas en C. De esta forma podremos hacer nuestros programas más flexibles aceptando una entrada del usuario en forma de parámetros y así modificar el comportamiento.

Antes de nada: WordPress cuando ve dos guiones seguidos (- y -) lo interpreta como un guión largo. En ocasiones viene bien y no molesta, pero en un post como este sí que perjudica más que beneficia, puedo desactivar el filtro, pero tengo mis dudas de que haya un post en el que lo quiera así. Tendré que estudiar la opción de desactivarlo sólo para un post determinado.

Para ello vimos getopt(), que nos permitía introducir opciones cortas (-v, -a, -j...) incluso con un parámetro asociado, por lo que podíamos empezar a introducir claves y valores en nuestros programas.

Hoy vemos un ejemplo de getopt_long() (también parecido al ejemplo del manual y derivado del anterior de getopt()) con algunos extras curiosos intentando contemplar varias opciones. El programa simula una conexión a un servicio, para ello especificamos host, usuario, contraseña y algunas cosas más, aunque no conecta ni nada, sólo es hipotético.

En este caso tenemos opciones largas, es decir en lugar de (-v, -h, -p, etc) podemos utilizar ademas (-verbose, -host, -pass, etc). Es más, podemos utilizar los dos tipos, incluso mezclados:

$ ./connect -verbose -h localhost

Incluso podemos tener opciones como (-output) que no tienen su equivalente en opción corta. Es decir, sólo tienen opción larga, y está bien, porque nos podemos quedar sin abecedario para las opciones cortas y seguir necesitando algunas más.

¿Si ya tenemos opciones cortas, con las que se teclea menos, para qué queremos las largas?
Sobre todo, porque son más fáciles de recordar, en el ejemplo, tenemos dos opciones -p (para el password) y -P (para el puerto), pero en opciones largas tenemos (-pass y -port) lo que hace que sea más fácil recordar cada una de ellas, imaginad cuando tengamos un programa con muchas opciones... puede ser muy confuso.
Además, como decía antes, puede que nos quedemos sin letras para las opciones cortas (tenemos mayúsculas, minúsculas y números, pero aún así puede que nos quedemos cortos, en ese caso, tenemos las opciones largas, que al tener más de una letra habrá muchas más combinaciones.

Veo un struct muy raro para definir las opciones, ¿cómo se hace?
El struct donde se definen las opciones largas es el siguiente:

Es un array de structs y cada struct tiene cuatro variabes:

  • nombre de la opción
  • ¿tiene argumento? Vale 0 (o no_argument) si no tiene argumento, es decir, si no queremos darle un valor a esa opción. Valdrá 1 (o required_argument) si es necesario ese argumento, como cuando en las opciones cortas ponemos dos puntos (:), o 2 (o optional_argument) si podemos incluir el argumento o no, vamos que sea opcional, como cuando en las opciones cortas ponemos dos signos de dos puntos (::). Para este último caso, el argumento deberá ser introducido desde línea de comandos con el signo igual:

    $ ./connect -pass=miContraseña

  • La tercera variable:
  • La cuarta variable está explicada junto con la tercera

Como con getopt() el tema de opciones obligatorias o control de errores en los argumentos, es decir, que una opción reciba un valor no válido, etc debemos controlarlo nosotros. Por ejemplo, -output sólo acepta json o xml. En este caso he decidido comprobarlo con str ncmp(), con una n en medio, igual que str n cpy() y similares, para que el programa tenga cierta tolerancia a fallos, valores muy grandes que no caben en nuestras variables, etc.

Aquí he querido incluir varios tipos de opciones
Foto: Maya Karmon