J'essaie d'écrire un programme capable de comparer deux fichiers ligne par ligne, mot par mot ou caractère par caractère en C. Il doit pouvoir lire dans les options de ligne de commande -l -w -i or --
...
- si l'option est -l, elle compare les fichiers ligne par ligne.
- si l'option est -w, elle compare les fichiers mot par mot.
- si les options sont - cela suppose automatiquement que l'argument suivant est le premier nom de fichier.
- si l'option est -i, il les compare sans tenir compte de la casse.
- par défaut, comparer les fichiers caractère par caractère.
Le nombre de fois où les options sont saisies n'a pas d'importance tant que -w et -l ne sont pas saisis en même temps et qu'il n'y a pas plus ou moins de 2 fichiers.
Je ne sais même pas par où commencer pour analyser les arguments de la ligne de commande. VEUILLEZ AIDER :(
C'est donc le code que j'ai trouvé pour tout. Je n'ai pas encore vérifié d'erreur, mais je me demandais si j'écrivais les choses de manière trop compliquée?
/*
* 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;
}
c
command-line-arguments
user1251020
la source
la source
Réponses:
À ma connaissance, les trois méthodes les plus courantes pour analyser les arguments de ligne de commande en C sont:
#include <unistd.h>
de la bibliothèque POSIX C), qui peut résoudre de simples tâches d' analyse d'arguments . Si vous êtes un peu familier avec bash, le getopt intégré de bash est basé sur Getopt de la libc GNU.#include <argp.h>
de la bibliothèque GNU C), qui peut résoudre des tâches plus complexes et s'occupe de choses comme, par exemple:-?
,--help
pour un message d'aide , y compris l'adresse e-mail-V
,--version
pour les informations de version--usage
pour le message d'utilisationLa documentation de la bibliothèque GNU C contient de jolis exemples pour Getopt et Argp.
Exemple d'utilisation de Getopt
Exemple d'utilisation d' Argp
Exemple pour le faire vous-même
Avis de non-responsabilité: Je suis nouveau sur Argp, l'exemple peut contenir des erreurs.
la source
Utilisez
getopt()
, ou peut-êtregetopt_long()
.Notez que vous devez déterminer les en-têtes à inclure (j'en fais 4 qui sont requis), et la façon dont j'ai écrit le
op_mode
type signifie que vous avez un problème dans la fonctionprocess()
- vous ne pouvez pas accéder à l'énumération là-bas. Il est préférable de déplacer l'énumération en dehors de la fonction; vous pourriez même faireop_mode
une variable de portée fichier sans lien externe (une manière sophistiquée de direstatic
) pour éviter de la passer à la fonction. Ce code ne traite pas-
comme synonyme d'entrée standard, un autre exercice pour le lecteur. Notez quegetopt()
prend automatiquement soin de--
marquer la fin des options pour vous.Je n'ai exécuté aucune version du typage ci-dessus après un compilateur; il pourrait y avoir des erreurs.
Pour un crédit supplémentaire, écrivez une fonction (bibliothèque):
qui encapsule la logique de traitement des options de nom de fichier après la
getopt()
boucle. Il doit gérer-
comme entrée standard. Notez que l'utilisation de ceci indiquerait qu'ilop_mode
devrait s'agir d'une variable d'étendue de fichier statique. Lafilter()
fonction prendargc
,argv
,optind
et un pointeur vers la fonction de traitement. Il doit renvoyer 0 (EXIT_SUCCESS) s'il a pu ouvrir tous les fichiers et toutes les invocations de la fonction rapportée 0, sinon 1 (ou EXIT_FAILURE). Avoir une telle fonction simplifie l'écriture de programmes de «filtre» de style Unix qui lisent les fichiers spécifiés sur la ligne de commande ou l'entrée standard.la source
getopt()
ne le fait pas; GNU legetopt()
fait par défaut. Faites votre choix. Je ne suis pas intéressé par les options après le comportement des noms de fichiers, principalement parce qu'il n'est pas fiable sur toutes les plates-formes.J'ai trouvé Gengetopt très utile - vous spécifiez les options que vous voulez avec un simple fichier de configuration, et il génère une paire .c / .h que vous incluez simplement et liez avec votre application. Le code généré utilise getopt_long, semble gérer les types les plus courants de paramètres de ligne de commande, et il peut gagner beaucoup de temps.
Un fichier d'entrée gengetopt peut ressembler à ceci:
La génération du code est facile et crache
cmdline.h
etcmdline.c
:Le code généré est facilement intégré:
Si vous avez besoin de faire des vérifications supplémentaires (telles que vous assurer que les indicateurs sont mutuellement exclusifs), vous pouvez le faire assez facilement avec les données stockées dans la
gengetopt_args_info
structure.la source
#include
, pas dans le fichier généré lui-même. pour moi, désactiver les avertissements est verboten :-)Je suis très surpris que personne n'ait évoqué le package "opt" de James Theiler.
Vous pouvez trouver opt sur http://public.lanl.gov/jt/Software/
et un post flatteur avec quelques exemples de la façon dont c'est tellement plus simple que d'autres approches est ici:
http://www.decompile.com/not_invented_here/opt/
la source
Docopt a une implémentation C que je trouvais assez sympa: https://github.com/docopt/docopt.c
À partir d'un format normalisé de page de manuel décrivant les options de ligne de commande, docopt déduit et crée un analyseur d'arguments. Cela a commencé en python; la version python analyse littéralement juste la docstring et renvoie un dict. Faire cela en C demande un peu plus de travail, mais il est propre à utiliser et n'a pas de dépendances externes.
la source
Il existe une excellente bibliothèque C à usage général libUCW qui inclut l' analyse des options de ligne de commande et le chargement du fichier de configuration .
La bibliothèque est également livrée avec une bonne documentation et comprend d'autres éléments utiles (E / S rapides, structures de données, allocateurs, ...) mais cela peut être utilisé séparément.
Exemple d'analyseur d'option libUCW (à partir de la documentation de la bibliothèque)
la source
J'ai écrit une petite bibliothèque qui analyse des arguments similaires à POpt, avec laquelle j'ai eu plusieurs problèmes, appelée XOpt . Utilise l'analyse des arguments de style GNU et a une interface très similaire à POpt.
Je l'utilise de temps en temps avec beaucoup de succès, et cela fonctionne à peu près n'importe où.
la source
Si vous me le permettez, j'aimerais également vous suggérer de jeter un œil à une bibliothèque d'analyse d'options que j'ai écrite: dropt .
Une fonctionnalité qu'il offre que beaucoup d'autres n'offrent pas est la possibilité de remplacer les options précédentes. Par exemple, si vous avez un alias shell:
et que vous souhaitez utiliser
bar
mais avec--flag1
désactivé, cela vous permet de faire:la source
la source
getopt()
ougetopt_long()
.Modèle pédagogique pour analyser les arguments de ligne de commande en C.
C:> nom_programme -w - fileOne.txt fileTwo.txt
la source
_Bool
à tout moment, et un en-tête<stdbool.h>
qui définitbool
comme_Bool
ettrue
etfalse
et__bool_true_false_are_defined
, toutes les macros (qui, exceptionnellement, peuvent être indéfinies et redéfinies sans invoquer un comportement indéfini; cette licence est cependant étiquetée `` obsolescent ''). Donc, si vous avez un compilateur C99, vous pouvez utiliser<stdbool.h>
etbool
. Sinon, vous en écrivez un pour vous-même (ce n'est pas difficile) ou vous utilisez un équivalent natif.la source
D'accord, c'est le début d'une longue histoire - en bref, l'analyse d'une ligne de commande en C ...
Notez que cette version prend également en charge la combinaison d'arguments: donc au lieu d'écrire / h / s -> / hs fonctionnera également.
Désolé d'être la n-ième personne à poster ici - mais je n'étais pas vraiment satisfait de toutes les versions autonomes que j'ai vues ici. Eh bien, les lib sont gentils. Je préférerais donc l' analyseur d'option libUCW , Arg ou Getopt à ceux faits maison.
Notez que vous pouvez changer:
*++argv[i]
->(++argv*)[0]
plus longtemps moins cryptique mais toujours cryptique.Bon, décomposons-le: 1. argv [i] -> accéder au i-ième élément dans le champ de pointeur argv-char
++ * ... -> fera suivre le pointeur argv d'un caractère
... [0] -> suivra le pointeur lisant le caractère
++ (...) -> bracket sont là donc nous allons augmenter le pointeur et non la valeur char elle-même.
Tellement sympa qu'en C ## les pointeurs «sont morts» - vive les pointeurs !!!
la source