una tipos texto que premisa ejemplos ejemplo contraargumento argumentos argumento argumentativo argumentacion c

texto - tipos de argumentacion



¿Analizar argumentos de línea de comandos? (12)

Hola, estoy intentando escribir un programa que pueda comparar dos archivos línea por línea, palabra por palabra o carácter por carácter en C. Tiene que poder leer en las opciones de línea de comando "-l -w -i o - "... si la opción es -l, compara los archivos línea por línea. si la opción es -w, compara los archivos palabra por palabra. si las opciones son, automáticamente asume que la siguiente arg es el primer nombre de archivo. y si la opción es -i, los compara de una manera que no distingue entre mayúsculas y minúsculas. De lo contrario, el valor predeterminado es comparar los archivos carácter por carácter

Se supone que no importa la cantidad de tiempo que se ingresan las opciones, siempre que -w y -l no se ingresen al mismo tiempo y no haya más o menos de 2 archivos.

Ni siquiera sé por dónde empezar con el análisis de los argumentos de la línea de comando. POR FAVOR AYUDA :(

Este es el código que se me ocurrió para todo. Todavía no lo he comprobado por error, pero me preguntaba si estoy escribiendo cosas de una manera demasiado complicada.

/* * Functions to compare files. */ int compare_line(); int compare_word(); int compare_char(); int case_insens(); /* * Program to compare the information in two files and print message saying * whether or not this was successful. */ int main(int argc, char* argv[]) { /*Loop counter*/ size_t i = 0; /*Variables for functions*/ int caseIns = 0; int line = 0; int word = 0; /*File pointers*/ FILE *fp1, *fp2; /* * Read through command-line arguments for options. */ for (i = 1; i < argc; i++) { printf("argv[%u] = %s/n", i, argv[i]); if (argv[i][0] == ''-'') { if (argv[i][1] == ''i'') { caseIns = 1; } if (argv[i][1] == ''l'') { line = 1; } if (argv[i][1] == ''w'') { word = 1; } if (argv[i][1] == ''-'') { fp1 = argv[i][2]; fp2 = argv[i][3]; } else { printf("Invalid option."); return 2; } } else { fp1(argv[i]); fp2(argv[i][1]); } } /* * Check that files can be opened. */ if(((fp1 = fopen(fp1, "rb")) == NULL) || ((fp2 = fopen(fp2, "rb")) == NULL)) { perror("fopen()"); return 3; } else{ if (caseIns == 1) { if(line == 1 && word == 1) { printf("That is invalid."); return 2; } if(line == 1 && word == 0) { if(compare_line(case_insens(fp1, fp2)) == 0) return 0; } if(line == 0 && word == 1) { if(compare_word(case_insens(fp1, fp2)) == 0) return 0; } else { if(compare_char(case_insens(fp1,fp2)) == 0) return 0; } } else { if(line == 1 && word == 1) { printf("That is invalid."); return 2; } if(line == 1 && word == 0) { if(compare_line(fp1, fp2) == 0) return 0; } if(line == 0 && word == 1) { if(compare_word(fp1, fp2) == 0) return 0; } else { if(compare_char(fp1, fp2) == 0) return 0; } } } return 1; if(((fp1 = fclose(fp1)) == NULL) || (((fp2 = fclose(fp2)) == NULL))) { perror("fclose()"); return 3; } else { fp1 = fclose(fp1); fp2 = fclose(fp2); } } /* * Function to compare two files line-by-line. */ int compare_line(FILE *fp1, FILE *fp2) { /*Buffer variables to store the lines in the file*/ char buff1 [LINESIZE]; char buff2 [LINESIZE]; /*Check that neither is the end of file*/ while((!feof(fp1)) && (!feof(fp2))) { /*Go through files line by line*/ fgets(buff1, LINESIZE, fp1); fgets(buff2, LINESIZE, fp2); } /*Compare files line by line*/ if(strcmp(buff1, buff2) == 0) { printf("Files are equal./n"); return 0; } printf("Files are not equal./n"); return 1; } /* * Function to compare two files word-by-word. */ int compare_word(FILE *fp1, FILE *fp2) { /*File pointers*/ FILE *fp1, *fp2; /*Arrays to store words*/ char fp1words[LINESIZE]; char fp2words[LINESIZE]; if(strtok(fp1, " ") == NULL || strtok(fp2, " ") == NULL) { printf("File is empty. Cannot compare./n"); return 0; } else { fp1words = strtok(fp1, " "); fp2words = strtok(fp2, " "); if(fp1words == fp2words) { fputs(fp1words); fputs(fp2words); printf("Files are equal./n"); return 0; } } return 1; } /* * Function to compare two files character by character. */ int compare_char(FILE *fp1,FILE *fp2) { /*Variables to store the characters from both files*/ int c; int d; /*Buffer variables to store chars*/ char buff1 [LINESIZE]; char buff2 [LINESIZE]; while(((c = fgetc(fp1))!= EOF) && (((d = fgetc(fp2))!=EOF))) { if(c == d) { if((fscanf(fp1, "%c", buff1)) == (fscanf(fp2, "%c", buff2))) { printf("Files have equivalent characters./n"); return 1; break; } } } return 0; } /* * Function to compare two files in a case-insensitive manner. */ int case_insens(FILE *fp1, FILE *fp2, size_t n) { /*Pointers for files.*/ FILE *fp1, *fp2; /*Variable to go through files.*/ size_t i = 0; /*Arrays to store file information.*/ char fp1store[LINESIZE]; char fp2store[LINESIZE]; while(!feof(fp1) && !feof(fp2)) { for(i = 0; i < n; i++) { fscanf(fp1, "%s", fp1store); fscanf(fp2, "%s", fp2store); fp1store = tolower(fp1store); fp2store = tolower(fp2store); return 1; } } return 0; }


De acuerdo, ese es el comienzo de una larga historia: hecho un corto bort analizando una línea de comando en C ...

/** * Helper function to parse the command line * @param argc Argument Counter * @param argv Argument Vector * @param prog Program Instance Reference to fill with options */ bool parseCommandLine(int argc, char* argv[], DuplicateFileHardLinker* prog) { bool pathAdded = false; // iterate over all arguments... for ( int i = 1; i<argc; i++ ) { // is argv a command line option ? if ( argv[i][0] == ''-'' || argv[i][0] == ''/'' ) { // ~~~~~~ Optionally Cut that part vvvvvvvvvvvvv for sake of simplicity ~~~~~~~ // check for longer options if ( stricmp( &argv[i][1], "NoFileName" ) == 0 || strcmp( &argv[i][1], "q1" ) == 0 ) { boNoFileNameLog = true; } else if ( strcmp( &argv[i][1], "FuckNow?" ) == 0 ) { logInfo( "SECRET FOUND: Well - wow I''m glad ya ask me."); } else { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Now here comes the main thing: // // check for one char options while ( char option = *++argv[i] ) { switch ( option ) { case ''?'': // Show program usage logInfo(L"Options:"); logInfo(L" /q/t>Quite mode"); logInfo(L" /v/t>Verbose mode"); logInfo(L" /d/t>Debug mode"); return false; // Log options case ''q'': setLogLevel(LOG_ERROR); break; case ''v'': setLogLevel(LOG_VERBOSE); break; case ''d'': setLogLevel(LOG_DEBUG); break; default: logError(L"''%s'' is an illegal command line option!" " Use /? to see valid options!", option); return false; } // switch one-char-option } //while one-char-options } //else one vs longer options } // if isArgAnOption // // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ So that''s it! ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // What follows now is are some usefull extras... // else { // the command line options seems to be a path... WCHAR tmpPath[MAX_PATH_LENGTH]; mbstowcs(tmpPath, argv[i], sizeof(tmpPath)); // check if the path is existing! //... prog->addPath(tmpPath); //Comment or remove to get a working example pathAdded = true; } } // check for parameters if ( !pathAdded ) { logError("You need to specify at least one folder to process!/n" "Use /? to see valid options!"); return false; } return true; } int main(int argc, char* argv[]) { try { // parse the command line if ( !parseCommandLine(argc, argv, prog) ) { return 1; } // I know that sample is just to show how the nicely parse commandline Arguments // So Please excuse more nice useful C-glatter that follows now... } catch ( LPCWSTR err ) { DWORD dwError = GetLastError(); if ( wcslen(err) > 0 ) { if ( dwError != 0 ) { logError(dwError, err); } else { logError(err); } } return 2; } } #define LOG_ERROR 1 #define LOG_INFO 0 #define LOG_VERBOSE -1 #define LOG_DEBUG -2 /** Logging Level for the console output */ int logLevel = LOG_INFO; void logError(LPCWSTR message, ...) { va_list argp; fwprintf(stderr, L"ERROR: "); va_start(argp, message); vfwprintf(stderr, message, argp); va_end(argp); fwprintf(stderr, L"/n"); } void logInfo(LPCWSTR message, ...) { if ( logLevel <= LOG_INFO ) { va_list argp; va_start(argp, message); vwprintf(message, argp); va_end(argp); wprintf(L"/n"); } }

Tenga en cuenta que esta versión también admitirá la combinación de argumentos: en lugar de escribir / h / s -> / hs también funcionará.

Perdón por ser la n-ésima persona que publica aquí; sin embargo, no estaba realmente satisfecho con todas las versiones independientes que vi aquí. Bueno, los lib son bonitos. Así que preferiría el analizador de opciones de libUCW , Arg o Getopt sobre los de fabricación casera.

Tenga en cuenta que puede cambiar:

*++argv[i] -> (++argv*)[0] más largo menos críptico pero aún críptico.

Bien, vamos a descomponerlo: 1. argv [i] -> acceder al elemento i-ésimo en el campo puntero argv-char

  1. ++ * ... -> reenviará el puntero argv con un char

  2. ... [0] -> seguirá el puntero leer el char

  3. ++ (...) -> el soporte está allí, así que aumentaremos el puntero y no el valor de char en sí.

Tan agradable que en C ## los punteros ''murieron'' - ¡¡¡vivan los indicadores !!!


Docopt tiene una implementación en C que me pareció bastante agradable: https://github.com/docopt/docopt.c

A partir de un formato estandarizado de página de manual que describe las opciones de línea de comando, docopt infiere y crea un analizador de argumentos. Esto comenzó en Python; la versión de Python literalmente solo analiza el docstring y devuelve un dict. Hacer esto en C requiere un poco más de trabajo, pero está limpio de usar y no tiene dependencias externas.


Escribí una pequeña biblioteca que analiza argumentos similares a POpt, con los que tuve varios problemas, llamados XOpt . Utiliza el análisis de argumentos al estilo GNU y tiene una interfaz muy similar a POpt.

Lo uso de vez en cuando con gran éxito, y funciona prácticamente en cualquier lugar.



Hay una gran biblioteca de C de uso general, libUCW que incluye un prolijo análisis de opciones de línea de comandos y carga de archivos de configuración .

La biblioteca también viene con buena documentación e incluye algunas otras cosas útiles (IO rápido, estructuras de datos, asignadores, ...) pero esto se puede usar por separado.

Ejemplo de analizador de opciones libUCW (de los documentos de la biblioteca)

#include <ucw/lib.h> #include <ucw/opt.h> int english; int sugar; int verbose; char *tea_name; static struct opt_section options = { OPT_ITEMS { OPT_HELP("A simple tea boiling console."), OPT_HELP("Usage: teapot [options] name-of-the-tea"), OPT_HELP(""), OPT_HELP("Options:"), OPT_HELP_OPTION, OPT_BOOL(''e'', "english-style", english, 0, "/tEnglish style (with milk)"), OPT_INT(''s'', "sugar", sugar, OPT_REQUIRED_VALUE, "<spoons>/tAmount of sugar (in teaspoons)"), OPT_INC(''v'', "verbose", verbose, 0, "/tVerbose (the more -v, the more verbose)"), OPT_STRING(OPT_POSITIONAL(1), NULL, tea_name, OPT_REQUIRED, ""), OPT_END } }; int main(int argc, char **argv) { opt_parse(&options, argv+1); return 0; }


He descubierto que Gengetopt es bastante útil: usted especifica las opciones que desea con un archivo de configuración simple, y genera un par .c / .h que simplemente incluye y vincula con su aplicación. El código generado hace uso de getopt_long, parece manejar los tipos más comunes de parámetros de línea de comando y puede ahorrar mucho tiempo.

Un archivo de entrada gengetopt puede tener un aspecto similar a este:

version "0.1" package "myApp" purpose "Does something useful." # Options option "filename" f "Input filename" string required option "verbose" v "Increase program verbosity" flag off option "id" i "Data ID" int required option "value" r "Data value" multiple(1-) int optional

Generar el código es fácil y cmdline.h y cmdline.c :

$ gengetopt --input=myApp.cmdline --include-getopt

El código generado se integra fácilmente:

#include <stdio.h> #include "cmdline.h" int main(int argc, char ** argv) { struct gengetopt_args_info ai; if (cmdline_parser(argc, argv, &ai) != 0) { exit(1); } printf("ai.filename_arg: %s/n", ai.filename_arg); printf("ai.verbose_flag: %d/n", ai.verbose_flag); printf("ai.id_arg: %d/n", ai.id_arg); int i; for (i = 0; i < ai.value_given; ++i) { printf("ai.value_arg[%d]: %d/n", i, ai.value_arg[i]); } }

Si necesita realizar una comprobación adicional (como garantizar que los indicadores sean mutuamente exclusivos), puede hacerlo de forma bastante fácil con los datos almacenados en la estructura gengetopt_args_info .


Plantilla instruccional para analizar argumentos de línea de comando en C.

C:> programName -w - fileOne.txt fileTwo.txt

BOOL argLine = FALSE; BOOL argWord = FALSE; BOOL argChar = FALSE; char * fileName1 = NULL; char * fileName2 = NULL; int main(int argc, char * argv[]) { int i; printf("Argument count=%d/n",argc); for (i = 0; i < argc; i++) { printf("Argument %s/n",argv[i]); if (strcmp(argv[i],"-l")==0) { argLine = TRUE; printf(" argLine=TRUE/n"); } else if (strcmp(argv[i],"-w")==0) { argWord = TRUE; printf(" argWord=TRUE/n"); } else if (strcmp(argv[i],"-c")==0) { argChar = TRUE; printf(" argChar=TRUE/n"); } else if (strcmp(argv[i],"--")==0) { if (i+1 <= argc) { fileName1 = argv[++i]; printf(" fileName1=%s/n",fileName1); } if (i+1 <= argc) { fileName2 = argv[++i]; printf(" fileName2=%s/n",fileName2); } } } return 0; }


Que yo sepa, las tres formas más populares de analizar argumentos de línea de comando en C son:

  • Getopt ( #include <unistd.h> de la Biblioteca POSIX C), que puede resolver tareas simples de análisis de argumentos . Si estás un poco familiarizado con bash, el getopt incorporado de bash está basado en Getopt de GNU libc.
  • Argp ( #include <argp.h> de la Biblioteca GNU C), que puede resolver tareas más complejas y se encarga de cosas como, por ejemplo:
    • -? , --help por mensaje de ayuda , incluida la dirección de correo electrónico
    • -V , --version para información de la versión
    • --usage mensaje de uso para el uso
  • Haciéndolo tú mismo , que no recomiendo para programas que se le darían a otra persona, ya que hay demasiado que podría salir mal o una calidad inferior. El error popular de olvidarse de ''-'' detener el análisis de opciones es solo un ejemplo.

La documentación de la Biblioteca GNU C tiene algunos buenos ejemplos para Getopt y Argp.

Ejemplo para usar Getopt

#include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> int main(int argc, char *argv[]) { bool isCaseInsensitive = false; int opt; enum { CHARACTER_MODE, WORD_MODE, LINE_MODE } mode = CHARACTER_MODE; while ((opt = getopt(argc, argv, "ilw")) != -1) { switch (opt) { case ''i'': isCaseInsensitive = true; break; case ''l'': mode = LINE_MODE; break; case ''w'': mode = WORD_MODE; break; default: fprintf(stderr, "Usage: %s [-ilw] [file...]/n", argv[0]); exit(EXIT_FAILURE); } } // Now optind (declared extern int by <unistd.h>) is the index of the first non-option argument. // If it is >= argc, there were no non-option arguments. // ... }

Ejemplo para usar Argp

#include <argp.h> #include <stdbool.h> const char *argp_program_version = "programname programversion"; const char *argp_program_bug_address = "<[email protected]>"; static char doc[] = "Your program description."; static char args_doc[] = "[FILENAME]..."; static struct argp_option options[] = { { "line", ''l'', 0, 0, "Compare lines instead of characters."}, { "word", ''w'', 0, 0, "Compare words instead of characters."}, { "nocase", ''i'', 0, 0, "Compare case insensitive instead of case sensitive."}, { 0 } }; struct arguments { enum { CHARACTER_MODE, WORD_MODE, LINE_MODE } mode; bool isCaseInsensitive; }; static error_t parse_opt(int key, char *arg, struct argp_state *state) { struct arguments *arguments = state->input; switch (key) { case ''l'': arguments->mode = LINE_MODE; break; case ''w'': arguments->mode = WORD_MODE; break; case ''i'': arguments->isCaseInsensitive = true; break; case ARGP_KEY_ARG: return 0; default: return ARGP_ERR_UNKNOWN; } return 0; } static struct argp argp = { options, parse_opt, args_doc, doc, 0, 0, 0 }; int main(int argc, char *argv[]) { struct arguments arguments; arguments.mode = CHARACTER_MODE; arguments.isCaseInsensitive = false; argp_parse(&argp, argc, argv, 0, 0, &arguments); // ... }

Ejemplo para hacerlo usted mismo

#include <stdbool.h> #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { bool isCaseInsensitive = false; enum { CHARACTER_MODE, WORD_MODE, LINE_MODE } mode = CHARACTER_MODE; size_t optind; for (optind = 1; optind < argc && argv[optind][0] == ''-''; optind++) { switch (argv[optind][1]) { case ''i'': isCaseInsensitive = true; break; case ''l'': mode = LINE_MODE; break; case ''w'': mode = WORD_MODE; break; default: fprintf(stderr, "Usage: %s [-ilw] [file...]/n", argv[0]); exit(EXIT_FAILURE); } } // *argv points to the remaining non-option arguments. // If *argv is NULL, there were no non-option arguments. // ... }

Descargo de responsabilidad: soy nuevo en Argp, el ejemplo podría contener errores.


Tocar mi propia bocina si puedo, también me gustaría sugerir echar un vistazo a una biblioteca de análisis de opciones que he escrito: dropt .

  • Es una biblioteca C (con un contenedor C ++ si lo desea).
  • Es liviano
  • Es extensible (los tipos de argumentos personalizados se pueden agregar fácilmente y tienen el mismo nivel con los tipos de argumentos incorporados).
  • Debe ser muy portable (está escrito en C estándar) sin dependencias (que no sea la biblioteca estándar de C).
  • Tiene una licencia muy poco restrictiva (zlib / libpng).

Una característica que ofrece que muchos otros no tienen es la capacidad de anular las opciones anteriores. Por ejemplo, si tiene un alias de shell:

alias bar="foo --flag1 --flag2 --flag3"

y desea utilizar la bar pero con --flag1 desactivado, le permite hacer:

bar --flag1=0


Usa getopt() , o quizás getopt_long() .

int iflag = 0; enum { WORD_MODE, LINE_MODE } op_mode = WORD_MODE; // Default set int opt; while ((opt = getopt(argc, argv, "ilw") != -1) { switch (opt) { case ''i'': iflag = 1; break; case ''l'': op_mode = LINE_MODE; break; case ''w'': op_mode = WORD_MODE; break; default: fprintf(stderr, "Usage: %s [-ilw] [file ...]/n", argv[0]); exit(EXIT_FAILURE); } } /* Process file names or stdin */ if (optind >= argc) process(stdin, "(standard input)", op_mode); else { int i; for (i = optind; i < argc; i++) { FILE *fp = fopen(argv[i], "r"); if (fp == 0) fprintf(stderr, "%s: failed to open %s (%d %s)/n", argv[0], argv[i], errno, strerror(errno)); else { process(fp, argv[i], op_mode); fclose(fp); } } }

Tenga en cuenta que necesita determinar qué encabezados incluir (lo hago 4 que son necesarios), y la forma en que escribí el tipo op_mode significa que tiene un problema en el process() función process() - no puede acceder a la enumeración allí. Lo mejor es mover la enumeración fuera de la función; incluso podría hacer que op_mode una variable de alcance de archivo sin enlace externo (una forma elegante de decir static ) para evitar pasarla a la función. Este código no funciona - como sinónimo de entrada estándar, otro ejercicio para el lector. Tenga en cuenta que getopt() se ocupa automáticamente de -- marcar el final de las opciones por usted.

No he ejecutado ninguna versión del tipeo anterior más allá de un compilador; podría haber errores en eso.

Para crédito adicional, escriba una función (biblioteca):

int filter(int argc, char **argv, int idx, int (*function)(FILE *fp, const char *fn));

que encapsula la lógica para procesar las opciones de nombre de archivo después del bucle getopt() . Debe manejar - como entrada estándar. Tenga en cuenta que usar esto indicaría que op_mode debería ser una variable de alcance de archivo estático. La función filter() toma argc , argv , optind y un puntero a la función de procesamiento. Debe devolver 0 (EXIT_SUCCESS) si fue capaz de abrir todos los archivos y todas las invocaciones de la función informó 0, de lo contrario 1 (o EXIT_FAILURE). Tener una función de este tipo simplifica la escritura de programas de ''filtro'' estilo Unix que leen los archivos especificados en la línea de comando o entrada estándar.


/* Here''s a rough one not relying on any libraries. Example: -wi | -iw //word case insensitive -li | -il //line case insensitive -- file //specify the first filename (you could just get the files as positional arguments in the else statement instead) PS: don''t mind the #define''s, they''re just pasting code :D */ #ifndef OPT_H #define OPT_H //specify option requires argument #define require / optarg = opt_pointer + 1; / if (*optarg == ''/0'') / { / if (++optind == argc) / goto opt_err_arg; / else / optarg = argv[optind]; / } / opt_pointer = opt_null_terminator; //start processing argv #define opt / int optind = 1; / char *opt_pointer = argv[1]; / char *optarg = NULL; / char opt_null_terminator[2] = {''/0'',''/0''}; / if (0) / { / opt_err_arg: / fprintf(stderr,"option %c requires argument./n",*opt_pointer); / return 1; / opt_err_opt: / fprintf(stderr,"option %c is invalid./n",*opt_pointer); / return 1; / } / for (; optind < argc; opt_pointer = argv[++optind]) / if (*opt_pointer++ == ''-'') / { / for (;;++opt_pointer) / switch (*opt_pointer) / { //stop processing argv #define done / default: / if (*opt_pointer != ''/0'') / goto opt_err_opt; / else / goto opt_next; / break; / } / opt_next:; / } #endif //opt.h #include <stdio.h> #include "opt.h" int main (int argc, char **argv) { #define by_character 0 #define by_word 1 #define by_line 2 int cmp = by_character; int case_insensitive = 0; opt case ''h'': puts ("HELP!"); break; case ''v'': puts ("fileCMP Version 1.0"); break; case ''i'': case_insensitive = 1; break; case ''w'': cmp = by_word; break; case ''l'': cmp = by_line; break; case ''-'':required printf("first filename: %s/n", optarg); break; done else printf ("Positional Argument %s/n", argv[optind]); return 0; }


#include <stdio.h> int main(int argc, char **argv) { size_t i; size_t filename_i = -1; for (i = 0; i < argc; i++) { char const *option = argv[i]; if (option[0] == ''-'') { printf("I am a flagged option"); switch (option[1]) { case ''a'': /*someting*/ break; case ''b'': break; case ''-'': /* "--" -- the next argument will be a file.*/ filename_i = i; i = i + 1; break; default: printf("flag not recognised %s", option); break; } } else { printf("I am a positional argument"); } /* At this point, if -- was specified, then filename_i contains the index into argv that contains the filename. If -- was not specified, then filename_i will be -1*/ } return 0; }