/** * \file main.c * \brief Fichier principal du programme * * Ce fichier contient les fonctions principales du logiciel qui ne sont pas * directement liées à la logique et au traitement des données du logiciel, * mais plutôt au traitement des arguments passés au processus et au lancement * des fonctions cœures du programme. */ #include "compress.h" #include "uncompress.h" #include #include /** * \brief Affiche un message d'aide * * Affiche un message d'aide pour le logiciel ainsi que son utilisation, puis * termine le processus avec le code de sortie indiqué par l'argument de la * fonction. * * \param[in] t_exit_code Code de sortie du processus */ void help(int t_exit_code) { puts("Usage:\n" "surfaces-unies -i path [-o path] [--options] [-t 0-100]\n\n" "The default action is to compress the mandatory input image to a .su\n" "file saved in the current directory.\n" "The input image MUST be saved in the ppm format.\n" "Options available:\n" "-h --help\n\tDisplay the current message\n" "-i --input\n\tPath to the input file (MANDATORY)\n" "-o --output\n" "\tPath to the output file (if the file already exists, it will be\n" "\toverwritten)\n" "-t --tolerance\n" "\tColor tolerance for lossy compression. By default at 0 for lossless\n" "\tcompression, at 100 will consider every color to be the same.\n" "-c --compress\n\tCompress the input file\n" "-u --uncompress\n\tUncompresses the input file to the output file."); exit(t_exit_code); } /** * \struct Argres * \brief Résultats du traitement des arguments du processus * * Cette structure est utilisée pour consolider ensemble les résultats du * traitement des arguments et les renvoyer en une fois au lieu d'avoir à * utiliser des variables globales ou des pointeurs en arguments * supplémentaires aux fonctions. */ struct Argres { char *input; /*!< Nom du fichier d'entrée */ char *output; /*!< Nom du fichier de sortie */ char compress; /*!< Le fichier d'entrée doit-il être compressé ? */ int32_t tolerance; /*!< Tolérance en pourcentage des différences de couleur */ }; typedef struct Argres Argres; /** * \brief Processes independently the arguments of the process * * Each option and switch will be processed here and will modify appropriately * the parameter `args` * * \param[out] t_args Result of the arguments processing * \param[in] t_c Switch or option passed */ void get_args(Argres *t_args, const int *const t_c) { switch (*t_c) { case 0: break; case 'h': help(NOERROR); break; case 'i': (*t_args).input = optarg; break; case 'o': (*t_args).output = optarg; break; case 'c': (*t_args).compress = 1; break; case 'u': (*t_args).compress = 0; break; case 't': (*t_args).tolerance = atoi(optarg); if(t_args->tolerance < 0 || t_args->tolerance > 100) { help(ARGERROR); } break; case '?': default: help(ARGERROR); } } /** * \brief Traite les arguments passés au processus * * Les arguments passés au processus seront traités ici. Les arguments passés * dans cette fonction ne subiront aucune modification. La fonction renvoie une * structure \ref Argres contenant le nom de fichier d’entrée et de sortie * ainsi qu’un booléen indiquant si le fichier d’entrée doit être compressé ou * décompressé. * * \param[in] t_argc Nombre d’arguments reçus * \param[in] t_argv Arguments reçus par le processus * \return structure \ref Argres */ Argres process_args(const int t_argc, char *t_argv[]) { Argres res; res.input = NULL; res.compress = 1; res.output = NULL; res.tolerance = 0; while (1) { int option_index = 0; static struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"input", required_argument, NULL, 'i'}, {"output", required_argument, NULL, 'o'}, {"tolerance", required_argument, NULL, 't'}, {"compress", no_argument, NULL, 'c'}, {"uncompress", no_argument, NULL, 'u'}, {NULL, 0, NULL, 0}}; int c = getopt_long(t_argc, t_argv, "hi:o:t:cu", long_options, &option_index); if (c == -1) break; get_args(&res, &c); } return res; } /** * \brief Fonction `main` lancée avec le processus * * This function is launched with the process. It will analyze the arguments it * received, and depending on them will either compress or uncompress the input * file, or will throw an error and stop in case of incorrect arguments. * * \param[in] argc Nombre d’arguments reçus par le processus * \param[in] argv Tableau des arguments reçus par le processus * \return Code de status du processus */ int main(int argc, char **argv) { Argres argresults = process_args(argc, argv); if (NULL == argresults.input) { fprintf(stderr, "ERROR: no input file."); help(ARGERROR); } if (argresults.compress) { compress(argresults.input, argresults.output, argresults.tolerance); } else { uncompress(argresults.input, argresults.output); } return 0; }