1 /*
2  * parseargs.cc
3  *
4  * Command line argument parser.
5  *
6  * Copyright 1996-2003 Glyph & Cog, LLC
7  */
8 
9 /*========================================================================
10 
11  Modified under the Poppler project - http://poppler.freedesktop.org
12 
13  Poppler project changes to this file are under the GPLv2 or later license
14 
15  All changes made under the Poppler project to this file are licensed
16  under GPL version 2 or later
17 
18  Copyright (C) 2008, 2009, 2018 Albert Astals Cid <aacid@kde.org>
19  Copyright (C) 2011, 2012 Adrian Johnson <ajohnson@redneon.com>
20 
21  To see a description of the changes please see the Changelog file that
22  came with your tarball or type make ChangeLog if you are building from git
23 
24 ========================================================================*/
25 
26 #include <cstdio>
27 #include <cstddef>
28 #include <cstring>
29 #include <cstdlib>
30 #include <cctype>
31 #include "parseargs.h"
32 
33 #include "goo/gstrtod.h"
34 #include "goo/GooString.h"
35 
36 static const ArgDesc *findArg(const ArgDesc *args, char *arg);
37 static bool grabArg(const ArgDesc *arg, int i, int *argc, char *argv[]);
38 
parseArgs(const ArgDesc * args,int * argc,char * argv[])39 bool parseArgs(const ArgDesc *args, int *argc, char *argv[])
40 {
41     const ArgDesc *arg;
42     int i, j;
43     bool ok;
44 
45     ok = true;
46     i = 1;
47     while (i < *argc) {
48         if (!strcmp(argv[i], "--")) {
49             --*argc;
50             for (j = i; j < *argc; ++j)
51                 argv[j] = argv[j + 1];
52             break;
53         } else if ((arg = findArg(args, argv[i]))) {
54             if (!grabArg(arg, i, argc, argv))
55                 ok = false;
56         } else {
57             ++i;
58         }
59     }
60     return ok;
61 }
62 
printUsage(const char * program,const char * otherArgs,const ArgDesc * args)63 void printUsage(const char *program, const char *otherArgs, const ArgDesc *args)
64 {
65     const ArgDesc *arg;
66     const char *typ;
67     int w, w1;
68 
69     w = 0;
70     for (arg = args; arg->arg; ++arg) {
71         if ((w1 = strlen(arg->arg)) > w)
72             w = w1;
73     }
74 
75     fprintf(stderr, "Usage: %s [options]", program);
76     if (otherArgs)
77         fprintf(stderr, " %s", otherArgs);
78     fprintf(stderr, "\n");
79 
80     for (arg = args; arg->arg; ++arg) {
81         fprintf(stderr, "  %s", arg->arg);
82         w1 = 9 + w - strlen(arg->arg);
83         switch (arg->kind) {
84         case argInt:
85         case argIntDummy:
86             typ = " <int>";
87             break;
88         case argFP:
89         case argFPDummy:
90             typ = " <fp>";
91             break;
92         case argString:
93         case argStringDummy:
94         case argGooString:
95             typ = " <string>";
96             break;
97         case argFlag:
98         case argFlagDummy:
99         default:
100             typ = "";
101             break;
102         }
103         fprintf(stderr, "%-*s", w1, typ);
104         if (arg->usage)
105             fprintf(stderr, ": %s", arg->usage);
106         fprintf(stderr, "\n");
107     }
108 }
109 
findArg(const ArgDesc * args,char * arg)110 static const ArgDesc *findArg(const ArgDesc *args, char *arg)
111 {
112     const ArgDesc *p;
113 
114     for (p = args; p->arg; ++p) {
115         if (p->kind < argFlagDummy && !strcmp(p->arg, arg))
116             return p;
117     }
118     return nullptr;
119 }
120 
grabArg(const ArgDesc * arg,int i,int * argc,char * argv[])121 static bool grabArg(const ArgDesc *arg, int i, int *argc, char *argv[])
122 {
123     int n;
124     int j;
125     bool ok;
126 
127     ok = true;
128     n = 0;
129     switch (arg->kind) {
130     case argFlag:
131         *(bool *)arg->val = true;
132         n = 1;
133         break;
134     case argInt:
135         if (i + 1 < *argc && isInt(argv[i + 1])) {
136             *(int *)arg->val = atoi(argv[i + 1]);
137             n = 2;
138         } else {
139             ok = false;
140             n = 1;
141         }
142         break;
143     case argFP:
144         if (i + 1 < *argc && isFP(argv[i + 1])) {
145             *(double *)arg->val = gatof(argv[i + 1]);
146             n = 2;
147         } else {
148             ok = false;
149             n = 1;
150         }
151         break;
152     case argString:
153         if (i + 1 < *argc) {
154             strncpy((char *)arg->val, argv[i + 1], arg->size - 1);
155             ((char *)arg->val)[arg->size - 1] = '\0';
156             n = 2;
157         } else {
158             ok = false;
159             n = 1;
160         }
161         break;
162     case argGooString:
163         if (i + 1 < *argc) {
164             ((GooString *)arg->val)->Set(argv[i + 1]);
165             n = 2;
166         } else {
167             ok = false;
168             n = 1;
169         }
170         break;
171     default:
172         fprintf(stderr, "Internal error in arg table\n");
173         n = 1;
174         break;
175     }
176     if (n > 0) {
177         *argc -= n;
178         for (j = i; j < *argc; ++j)
179             argv[j] = argv[j + n];
180     }
181     return ok;
182 }
183 
isInt(const char * s)184 bool isInt(const char *s)
185 {
186     if (*s == '-' || *s == '+')
187         ++s;
188     while (isdigit(*s))
189         ++s;
190     if (*s)
191         return false;
192     return true;
193 }
194 
isFP(const char * s)195 bool isFP(const char *s)
196 {
197     int n;
198 
199     if (*s == '-' || *s == '+')
200         ++s;
201     n = 0;
202     while (isdigit(*s)) {
203         ++s;
204         ++n;
205     }
206     if (*s == '.')
207         ++s;
208     while (isdigit(*s)) {
209         ++s;
210         ++n;
211     }
212     if (n > 0 && (*s == 'e' || *s == 'E')) {
213         ++s;
214         if (*s == '-' || *s == '+')
215             ++s;
216         n = 0;
217         if (!isdigit(*s))
218             return false;
219         do {
220             ++s;
221         } while (isdigit(*s));
222     }
223     if (*s)
224         return false;
225     return true;
226 }
227