{"id":106,"date":"2010-05-13T20:43:14","date_gmt":"2010-05-13T19:43:14","guid":{"rendered":"http:\/\/blog.ludovicfavre.ch\/?p=106"},"modified":"2011-04-11T22:19:10","modified_gmt":"2011-04-11T21:19:10","slug":"parser-la-ligne-de-commande-avec-getopt_long","status":"publish","type":"post","link":"https:\/\/www.ludovicfavre.ch\/blog\/2010\/05\/parser-la-ligne-de-commande-avec-getopt_long\/","title":{"rendered":"Parser la ligne de commande avec getopt_long()"},"content":{"rendered":"<p style=\"text-align: justify;\">Durant un projet C\/C++, j&rsquo;ai eu besoin de parser efficacement les arguments du programme. Le nombre d&rsquo;options \u00e9tant devenu important, j&rsquo;ai d\u00e9cid\u00e9 d&rsquo;utiliser getopt_long, disponible avec <a title=\"Manuel getopt_long\" href=\"http:\/\/www.gnu.org\/s\/libc\/manual\/html_node\/Getopt-Long-Options.html\">GNU C<\/a>. Une fois l&rsquo;outil pris en main, j&rsquo;ai eu un peu de mal \u00e0 trouver comment se d\u00e9roulait le parsing des arguments n&rsquo;\u00e9tant pas des options (nom de fichier par exemple). C&rsquo;est finalement en tombant sur de la documentation <a title=\"Source de l'article\" href=\"http:\/\/docs.sun.com\/app\/docs\/doc\/816-5168\/getopt-3c?l=en&amp;n=1&amp;a=view\">oracle\/sun<\/a> que j&rsquo;ai trouv\u00e9 la solution.<\/p>\n<p style=\"text-align: justify;\">Voici tout d&rsquo;abord les d\u00e9clarations de base de pour utiliser getopt_long:<\/p>\n<div class=\"codecolorer-container cpp default\" style=\"overflow:auto;white-space:nowrap;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/>3<br \/>4<br \/>5<br \/>6<br \/>7<br \/>8<br \/>9<br \/>10<br \/>11<br \/>12<br \/>13<br \/>14<br \/>15<br \/>16<br \/>17<br \/>18<br \/>19<br \/>20<br \/><\/div><\/td><td><div class=\"cpp codecolorer\"><span class=\"co2\">#include &lt;getopt.h&gt; \/\/requis pour l'utilisation de getopt_long<\/span><br \/>\n<span class=\"kw4\">struct<\/span> globalArgs_t <span class=\"br0\">&#123;<\/span><br \/>\n<span class=\"kw4\">unsigned<\/span> <span class=\"kw4\">int<\/span> help<span class=\"sy4\">;<\/span> <span class=\"coMULTI\">\/* -h option*\/<\/span><br \/>\n<span class=\"kw4\">unsigned<\/span> <span class=\"kw4\">int<\/span> algorithm<span class=\"sy4\">;<\/span> <span class=\"coMULTI\">\/* -t option *\/<\/span><br \/>\n<span class=\"kw4\">bool<\/span> toStdout <span class=\"sy4\">;<\/span> <span class=\"coMULTI\">\/*-stdout option*\/<\/span><br \/>\n<span class=\"kw4\">bool<\/span> fromStdin <span class=\"sy4\">;<\/span> <span class=\"coMULTI\">\/*-stdin option*\/<\/span><br \/>\nstring<span class=\"sy2\">*<\/span> infile<span class=\"sy4\">;<\/span><br \/>\n<span class=\"kw4\">int<\/span> verbosity<span class=\"sy4\">;<\/span> <span class=\"coMULTI\">\/* -v option *\/<\/span><br \/>\n<span class=\"br0\">&#125;<\/span> globalArgs<span class=\"sy4\">;<\/span><br \/>\n<br \/>\n<span class=\"kw4\">static<\/span> <span class=\"kw4\">const<\/span> <span class=\"kw4\">char<\/span> <span class=\"sy2\">*<\/span>optString <span class=\"sy1\">=<\/span> <span class=\"st0\">&quot;t:h?;&quot;<\/span><span class=\"sy4\">;<\/span><span class=\"co1\">\/\/&quot;Il:o:vh?&quot;; \/\/pour plus de d\u00e9tails, cf doc GNU<\/span><br \/>\n<br \/>\n<span class=\"kw4\">static<\/span> <span class=\"kw4\">const<\/span> <span class=\"kw4\">struct<\/span> option longOpts<span class=\"br0\">&#91;<\/span><span class=\"br0\">&#93;<\/span> <span class=\"sy1\">=<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n<span class=\"br0\">&#123;<\/span> <span class=\"st0\">&quot;help&quot;<\/span>, no_argument, <span class=\"kw2\">NULL<\/span>, <span class=\"st0\">'h'<\/span> <span class=\"br0\">&#125;<\/span>,<br \/>\n<span class=\"br0\">&#123;<\/span> <span class=\"st0\">&quot;algorithm&quot;<\/span>, required_argument, <span class=\"kw2\">NULL<\/span>, <span class=\"st0\">'t'<\/span> <span class=\"br0\">&#125;<\/span>,<br \/>\n<span class=\"br0\">&#123;<\/span> <span class=\"st0\">&quot;stdin&quot;<\/span>, no_argument, <span class=\"kw2\">NULL<\/span>, <span class=\"nu0\">0<\/span> <span class=\"br0\">&#125;<\/span>,<br \/>\n<span class=\"br0\">&#123;<\/span> <span class=\"st0\">&quot;stdout&quot;<\/span>, no_argument, <span class=\"kw2\">NULL<\/span>, <span class=\"nu0\">0<\/span> <span class=\"br0\">&#125;<\/span>,<br \/>\n<span class=\"br0\">&#123;<\/span> <span class=\"st0\">&quot;verbose&quot;<\/span>, no_argument, <span class=\"kw2\">NULL<\/span>, <span class=\"st0\">'v'<\/span> <span class=\"br0\">&#125;<\/span>,<br \/>\n<span class=\"br0\">&#123;<\/span><span class=\"kw2\">NULL<\/span>, <span class=\"nu0\">0<\/span>, <span class=\"kw2\">NULL<\/span>, <span class=\"nu0\">0<\/span><span class=\"br0\">&#125;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><span class=\"sy4\">;<\/span><\/div><\/td><\/tr><\/tbody><\/table><\/div>\n<p style=\"text-align: justify;\">La premi\u00e8re structure\u00a0<em>globalArgs<\/em> permet de stocker les valeurs pour les options de nos programmes (et les utiliser plus tard).<\/p>\n<p style=\"text-align: justify;\">La cha\u00eene\u00a0<em>optString<\/em> permet de d\u00e9finir la structure des arguments. Les deux points signifient par exemple d&rsquo;un param\u00e8tre est attendu pour l&rsquo;option\u00a0<em>-t<\/em>. Pour plus de d\u00e9tails, je vous conseille la <a href=\"http:\/\/www.gnu.org\/s\/libc\/manual\/html_node\/Getopt.html\" target=\"_blank\">doc GNU<\/a>.<\/p>\n<p style=\"text-align: justify;\">Enfin, le tableau d&rsquo;<em>option longOpts[]<\/em> permet de d\u00e9finir les options longues (sp\u00e9cifi\u00e9es par &#8211;option) ainsi que les options courtes comme <em>-h<\/em> ou <em>-t<\/em>.<\/p>\n<div class=\"codecolorer-container cpp default\" style=\"overflow:auto;white-space:nowrap;height:300px;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/>3<br \/>4<br \/>5<br \/>6<br \/>7<br \/>8<br \/>9<br \/>10<br \/>11<br \/>12<br \/>13<br \/>14<br \/>15<br \/>16<br \/>17<br \/>18<br \/>19<br \/>20<br \/>21<br \/>22<br \/>23<br \/>24<br \/>25<br \/>26<br \/>27<br \/>28<br \/>29<br \/>30<br \/>31<br \/>32<br \/>33<br \/>34<br \/>35<br \/>36<br \/>37<br \/>38<br \/>39<br \/>40<br \/>41<br \/>42<br \/>43<br \/>44<br \/>45<br \/>46<br \/>47<br \/>48<br \/>49<br \/>50<br \/>51<br \/>52<br \/>53<br \/>54<br \/>55<br \/>56<br \/>57<br \/>58<br \/>59<br \/><\/div><\/td><td><div class=\"cpp codecolorer\"><span class=\"kw4\">int<\/span> parseCmd<span class=\"br0\">&#40;<\/span><span class=\"kw4\">int<\/span> argc, <span class=\"kw4\">char<\/span><span class=\"sy2\">**<\/span> argv<span class=\"br0\">&#41;<\/span><br \/>\n<br \/>\n<span class=\"br0\">&#123;<\/span><br \/>\n<br \/>\n<span class=\"kw4\">int<\/span> longIndex<span class=\"sy4\">;<\/span><br \/>\n<span class=\"kw4\">int<\/span> opt <span class=\"sy1\">=<\/span> getopt_long<span class=\"br0\">&#40;<\/span> argc, argv, optString, longOpts, <span class=\"sy3\">&amp;<\/span>amp<span class=\"sy4\">;<\/span>longIndex <span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\nglobalArgs.<span class=\"me1\">algorithm<\/span> <span class=\"sy1\">=<\/span> <span class=\"nu0\">0<\/span><span class=\"sy4\">;<\/span><br \/>\n<span class=\"kw1\">while<\/span> <span class=\"br0\">&#40;<\/span> opt <span class=\"sy3\">!<\/span><span class=\"sy1\">=<\/span> <span class=\"sy2\">-<\/span><span class=\"nu0\">1<\/span> <span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n<span class=\"kw1\">switch<\/span> <span class=\"br0\">&#40;<\/span> opt <span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n<span class=\"kw1\">case<\/span> <span class=\"st0\">'t'<\/span><span class=\"sy4\">:<\/span><br \/>\n<span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span> <span class=\"kw3\">strcmp<\/span><span class=\"br0\">&#40;<\/span> <span class=\"st0\">&quot;alg1&quot;<\/span>, optarg <span class=\"br0\">&#41;<\/span> <span class=\"sy1\">==<\/span> <span class=\"nu0\">0<\/span> <span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\nglobalArgs.<span class=\"me1\">algorithm<\/span> <span class=\"sy1\">=<\/span> ALG1<span class=\"sy4\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><br \/>\n<span class=\"co1\">\/\/...<\/span><br \/>\n<span class=\"kw1\">if<\/span><span class=\"br0\">&#40;<\/span>globalArgs.<span class=\"me1\">algorithm<\/span> <span class=\"sy1\">==<\/span> <span class=\"nu0\">0<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n<span class=\"kw3\">fprintf<\/span><span class=\"br0\">&#40;<\/span><span class=\"kw2\">stderr<\/span>,<span class=\"st0\">&quot;Invalid algorithm option, defaulting to alg5<span class=\"es1\">\\n<\/span>&quot;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\nglobalArgs.<span class=\"me1\">algorithm<\/span> <span class=\"sy1\">=<\/span> ALG5<span class=\"sy4\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><br \/>\n<span class=\"kw1\">break<\/span><span class=\"sy4\">;<\/span><br \/>\n<br \/>\n<span class=\"kw1\">case<\/span> <span class=\"st0\">'v'<\/span><span class=\"sy4\">:<\/span><br \/>\nglobalArgs.<span class=\"me1\">verbosity<\/span><span class=\"sy2\">++<\/span><span class=\"sy4\">;<\/span> <span class=\"co1\">\/\/-vv will set verbosity to 2 for example<\/span><br \/>\n<span class=\"kw1\">break<\/span><span class=\"sy4\">;<\/span><br \/>\n<br \/>\n<span class=\"kw1\">case<\/span> <span class=\"st0\">'h'<\/span><span class=\"sy4\">:<\/span> &nbsp; <span class=\"coMULTI\">\/* fall-through is intentional *\/<\/span><br \/>\n<span class=\"kw1\">case<\/span> <span class=\"st0\">'?'<\/span><span class=\"sy4\">:<\/span><br \/>\ndisplayHelp<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n<span class=\"kw1\">break<\/span><span class=\"sy4\">;<\/span><br \/>\n<span class=\"kw1\">case<\/span> <span class=\"nu0\">0<\/span><span class=\"sy4\">:<\/span> &nbsp; &nbsp; <span class=\"coMULTI\">\/* long option without a short arg *\/<\/span><br \/>\n<span class=\"kw3\">fprintf<\/span><span class=\"br0\">&#40;<\/span><span class=\"kw2\">stderr<\/span>,<span class=\"st0\">&quot;case 0&quot;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\nfiltered <span class=\"sy1\">=<\/span> <span class=\"kw2\">false<\/span><span class=\"sy4\">;<\/span><br \/>\n<span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span> <span class=\"kw3\">strcmp<\/span><span class=\"br0\">&#40;<\/span> <span class=\"st0\">&quot;stdin&quot;<\/span>, longOpts<span class=\"br0\">&#91;<\/span>longIndex<span class=\"br0\">&#93;<\/span>.<span class=\"me1\">name<\/span> <span class=\"br0\">&#41;<\/span> <span class=\"sy1\">==<\/span> <span class=\"nu0\">0<\/span> <span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\nglobalArgs.<span class=\"me1\">fromStdin<\/span> <span class=\"sy1\">=<\/span> <span class=\"kw2\">true<\/span><span class=\"sy4\">;<\/span><br \/>\nfiltered <span class=\"sy1\">=<\/span> <span class=\"kw2\">true<\/span><span class=\"sy4\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><br \/>\n<br \/>\n<span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span> <span class=\"kw3\">strcmp<\/span><span class=\"br0\">&#40;<\/span> <span class=\"st0\">&quot;stdout&quot;<\/span>, longOpts<span class=\"br0\">&#91;<\/span>longIndex<span class=\"br0\">&#93;<\/span>.<span class=\"me1\">name<\/span> <span class=\"br0\">&#41;<\/span> <span class=\"sy1\">==<\/span> <span class=\"nu0\">0<\/span> <span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\nglobalArgs.<span class=\"me1\">toStdout<\/span> <span class=\"sy1\">=<\/span> <span class=\"kw2\">true<\/span><span class=\"sy4\">;<\/span><br \/>\nfiltered <span class=\"sy1\">=<\/span> <span class=\"kw2\">true<\/span><span class=\"sy4\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><br \/>\n<span class=\"kw1\">break<\/span><span class=\"sy4\">;<\/span><br \/>\n<br \/>\n<span class=\"kw1\">default<\/span><span class=\"sy4\">:<\/span><br \/>\n<span class=\"coMULTI\">\/* You won't actually get here. *\/<\/span><br \/>\n<span class=\"kw3\">fprintf<\/span><span class=\"br0\">&#40;<\/span><span class=\"kw2\">stderr<\/span>,<span class=\"st0\">&quot;Error parsing arguments...&quot;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n<span class=\"kw1\">return<\/span> <span class=\"sy2\">-<\/span><span class=\"nu0\">1<\/span><span class=\"sy4\">;<\/span><br \/>\n<span class=\"kw1\">break<\/span><span class=\"sy4\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><br \/>\n<br \/>\nopt <span class=\"sy1\">=<\/span> getopt_long<span class=\"br0\">&#40;<\/span> argc, argv, optString, longOpts, <span class=\"sy3\">&amp;<\/span>amp<span class=\"sy4\">;<\/span>longIndex <span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><br \/>\n<span class=\"kw1\">for<\/span> <span class=\"br0\">&#40;<\/span> <span class=\"sy4\">;<\/span> optind <span class=\"sy3\">&amp;<\/span>lt<span class=\"sy4\">;<\/span> argc<span class=\"sy4\">;<\/span> optind<span class=\"sy2\">++<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n<span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>access<span class=\"br0\">&#40;<\/span>argv<span class=\"br0\">&#91;<\/span>optind<span class=\"br0\">&#93;<\/span>, R_OK<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n<span class=\"co1\">\/\/ c'est ici que l'on pourra r\u00e9cup\u00e9rer, par exemple, un non de fichier en entr\u00e9e et tenter de l'ouvrir<\/span><br \/>\n<span class=\"kw3\">fprintf<\/span><span class=\"br0\">&#40;<\/span><span class=\"kw2\">stderr<\/span>,<span class=\"st0\">&quot;Non-option argument: %s<span class=\"es1\">\\n<\/span>&quot;<\/span>,argv<span class=\"br0\">&#91;<\/span>optind<span class=\"br0\">&#93;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><br \/>\n<span class=\"kw1\">return<\/span> <span class=\"nu0\">0<\/span><span class=\"sy4\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/td><\/tr><\/tbody><\/table><\/div>\n<p style=\"text-align: justify;\">L&rsquo;appel \u00e0 <em>getopt_long()<\/em> ne permet pas de r\u00e9cup\u00e9rer un non de fichier (par exemple) autrement qu&rsquo;avec <em>-i fichier<\/em>. Pour utiliser les arguments n&rsquo;\u00e9tant pas des options, il faut proc\u00e9der comme ci-dessus en utilisant <em>optind.<br \/>\n<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Durant un projet C\/C++, j&rsquo;ai eu besoin de parser efficacement les arguments du programme. Le nombre d&rsquo;options \u00e9tant devenu important, j&rsquo;ai d\u00e9cid\u00e9 d&rsquo;utiliser getopt_long, disponible avec GNU C. Une fois l&rsquo;outil pris en main, j&rsquo;ai eu un peu de mal \u00e0 trouver comment se d\u00e9roulait le parsing des arguments n&rsquo;\u00e9tant pas des options (nom de fichier par exemple)&#8230; <a href=\"https:\/\/www.ludovicfavre.ch\/blog\/2010\/05\/parser-la-ligne-de-commande-avec-getopt_long\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"footnotes":""},"categories":[1],"tags":[19,18,65,8],"class_list":["post-106","post","type-post","status-publish","format-standard","hentry","category-uncategorized","tag-cc","tag-gnu","tag-linux","tag-unix"],"_links":{"self":[{"href":"https:\/\/www.ludovicfavre.ch\/blog\/wp-json\/wp\/v2\/posts\/106","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.ludovicfavre.ch\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.ludovicfavre.ch\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.ludovicfavre.ch\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.ludovicfavre.ch\/blog\/wp-json\/wp\/v2\/comments?post=106"}],"version-history":[{"count":15,"href":"https:\/\/www.ludovicfavre.ch\/blog\/wp-json\/wp\/v2\/posts\/106\/revisions"}],"predecessor-version":[{"id":115,"href":"https:\/\/www.ludovicfavre.ch\/blog\/wp-json\/wp\/v2\/posts\/106\/revisions\/115"}],"wp:attachment":[{"href":"https:\/\/www.ludovicfavre.ch\/blog\/wp-json\/wp\/v2\/media?parent=106"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.ludovicfavre.ch\/blog\/wp-json\/wp\/v2\/categories?post=106"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.ludovicfavre.ch\/blog\/wp-json\/wp\/v2\/tags?post=106"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}