1 /*-
2 ***********************************************************************
3 *
4 * $Id: options.c,v 1.7 2014/07/18 06:40:44 mavrik Exp $
5 *
6 ***********************************************************************
7 *
8 * Copyright 2006-2014 The FTimes Project, All Rights Reserved.
9 *
10 ***********************************************************************
11 */
12 #include "all-includes.h"
13
14 /*-
15 ***********************************************************************
16 *
17 * OptionsFreeOptionsContext
18 *
19 ***********************************************************************
20 */
21 void
OptionsFreeOptionsContext(OPTIONS_CONTEXT * psOptionsContext)22 OptionsFreeOptionsContext(OPTIONS_CONTEXT *psOptionsContext)
23 {
24 if (psOptionsContext != NULL)
25 {
26 if (psOptionsContext->piArgumentTypes != NULL)
27 {
28 free(psOptionsContext->piArgumentTypes);
29 }
30 free(psOptionsContext);
31 }
32 }
33
34
35 /*-
36 ***********************************************************************
37 *
38 * OptionsGetArgumentIndex
39 *
40 ***********************************************************************
41 */
42 int
OptionsGetArgumentIndex(OPTIONS_CONTEXT * psOptionsContext)43 OptionsGetArgumentIndex(OPTIONS_CONTEXT *psOptionsContext)
44 {
45 return psOptionsContext->iArgumentIndex;
46 }
47
48
49 /*-
50 ***********************************************************************
51 *
52 * OptionsGetArgumentsLeft
53 *
54 ***********************************************************************
55 */
56 int
OptionsGetArgumentsLeft(OPTIONS_CONTEXT * psOptionsContext)57 OptionsGetArgumentsLeft(OPTIONS_CONTEXT *psOptionsContext)
58 {
59 return (psOptionsContext->iArgumentCount - (psOptionsContext->iArgumentIndex + 1));
60 }
61
62
63 /*-
64 ***********************************************************************
65 *
66 * OptionsGetCommand
67 *
68 ***********************************************************************
69 */
70 TCHAR *
OptionsGetCommand(OPTIONS_CONTEXT * psOptionsContext)71 OptionsGetCommand(OPTIONS_CONTEXT *psOptionsContext)
72 {
73 return psOptionsContext->pptcArgumentVector[0];
74 }
75
76
77 /*-
78 ***********************************************************************
79 *
80 * OptionsGetCurrentArgument
81 *
82 ***********************************************************************
83 */
84 TCHAR *
OptionsGetCurrentArgument(OPTIONS_CONTEXT * psOptionsContext)85 OptionsGetCurrentArgument(OPTIONS_CONTEXT *psOptionsContext)
86 {
87 TCHAR *ptcArgument = NULL;
88
89 if (psOptionsContext->iArgumentIndex < psOptionsContext->iArgumentCount)
90 {
91 ptcArgument = psOptionsContext->pptcArgumentVector[psOptionsContext->iArgumentIndex];
92 }
93
94 return ptcArgument;
95 }
96
97
98 /*-
99 ***********************************************************************
100 *
101 * OptionsGetCurrentOperand
102 *
103 ***********************************************************************
104 */
105 TCHAR *
OptionsGetCurrentOperand(OPTIONS_CONTEXT * psOptionsContext)106 OptionsGetCurrentOperand(OPTIONS_CONTEXT *psOptionsContext)
107 {
108 TCHAR *ptcOperand = NULL;
109
110 if (psOptionsContext->iOperandIndex < psOptionsContext->iArgumentCount)
111 {
112 ptcOperand = psOptionsContext->pptcArgumentVector[psOptionsContext->iOperandIndex];
113 }
114
115 return ptcOperand;
116 }
117
118
119 /*-
120 ***********************************************************************
121 *
122 * OptionsGetFirstArgument
123 *
124 ***********************************************************************
125 */
126 TCHAR *
OptionsGetFirstArgument(OPTIONS_CONTEXT * psOptionsContext)127 OptionsGetFirstArgument(OPTIONS_CONTEXT *psOptionsContext)
128 {
129 TCHAR *ptcArgument = NULL;
130
131 psOptionsContext->iArgumentIndex = 1;
132 if (psOptionsContext->iArgumentIndex < psOptionsContext->iArgumentCount)
133 {
134 ptcArgument = psOptionsContext->pptcArgumentVector[psOptionsContext->iArgumentIndex];
135 }
136
137 return ptcArgument;
138 }
139
140
141 /*-
142 ***********************************************************************
143 *
144 * OptionsGetFirstOperand
145 *
146 ***********************************************************************
147 */
148 TCHAR *
OptionsGetFirstOperand(OPTIONS_CONTEXT * psOptionsContext)149 OptionsGetFirstOperand(OPTIONS_CONTEXT *psOptionsContext)
150 {
151 TCHAR *ptcOperand = NULL;
152
153 for (psOptionsContext->iOperandIndex = 0; psOptionsContext->iOperandIndex < psOptionsContext->iArgumentCount; psOptionsContext->iOperandIndex++)
154 {
155 if (psOptionsContext->piArgumentTypes[psOptionsContext->iOperandIndex] == OPTIONS_ARGUMENT_TYPE_OPERAND)
156 {
157 ptcOperand = psOptionsContext->pptcArgumentVector[psOptionsContext->iOperandIndex];
158 break;
159 }
160 }
161
162 return ptcOperand;
163 }
164
165
166 /*-
167 ***********************************************************************
168 *
169 * OptionsGetNextArgument
170 *
171 ***********************************************************************
172 */
173 TCHAR *
OptionsGetNextArgument(OPTIONS_CONTEXT * psOptionsContext)174 OptionsGetNextArgument(OPTIONS_CONTEXT *psOptionsContext)
175 {
176 TCHAR *ptcArgument = NULL;
177
178 if ((psOptionsContext->iArgumentIndex + 1) < psOptionsContext->iArgumentCount)
179 {
180 ptcArgument = psOptionsContext->pptcArgumentVector[++psOptionsContext->iArgumentIndex];
181 }
182
183 return ptcArgument;
184 }
185
186
187 /*-
188 ***********************************************************************
189 *
190 * OptionsGetNextOperand
191 *
192 ***********************************************************************
193 */
194 TCHAR *
OptionsGetNextOperand(OPTIONS_CONTEXT * psOptionsContext)195 OptionsGetNextOperand(OPTIONS_CONTEXT *psOptionsContext)
196 {
197 TCHAR *ptcOperand = NULL;
198
199 while ((psOptionsContext->iOperandIndex + 1) < psOptionsContext->iArgumentCount)
200 {
201 if (psOptionsContext->piArgumentTypes[++psOptionsContext->iOperandIndex] == OPTIONS_ARGUMENT_TYPE_OPERAND)
202 {
203 ptcOperand = psOptionsContext->pptcArgumentVector[psOptionsContext->iOperandIndex];
204 break;
205 }
206 }
207
208 return ptcOperand;
209 }
210
211
212 /*-
213 ***********************************************************************
214 *
215 * OptionsGetOperandCount
216 *
217 ***********************************************************************
218 */
219 int
OptionsGetOperandCount(OPTIONS_CONTEXT * psOptionsContext)220 OptionsGetOperandCount(OPTIONS_CONTEXT *psOptionsContext)
221 {
222 int iOperandCount = 0;
223 int iOperandIndex = 0;
224
225 for (iOperandIndex = 0; iOperandIndex < psOptionsContext->iArgumentCount; iOperandIndex++)
226 {
227 if (psOptionsContext->piArgumentTypes[iOperandIndex] == OPTIONS_ARGUMENT_TYPE_OPERAND)
228 {
229 iOperandCount++;
230 }
231 }
232
233 return iOperandCount;
234 }
235
236
237 /*-
238 ***********************************************************************
239 *
240 * OptionsHaveRequiredOptions
241 *
242 ***********************************************************************
243 */
244 int
OptionsHaveRequiredOptions(OPTIONS_CONTEXT * psOptionsContext)245 OptionsHaveRequiredOptions(OPTIONS_CONTEXT *psOptionsContext)
246 {
247 int iIndex = 0;
248
249 for (iIndex = 0; iIndex < psOptionsContext->iNOptions; iIndex++)
250 {
251 if (psOptionsContext->psOptions[iIndex].iRequired == 1 && psOptionsContext->psOptions[iIndex].iFound == 0)
252 {
253 return 0;
254 }
255 }
256
257 return 1;
258 }
259
260
261 /*-
262 ***********************************************************************
263 *
264 * OptionsHaveSpecifiedOption
265 *
266 ***********************************************************************
267 */
268 int
OptionsHaveSpecifiedOption(OPTIONS_CONTEXT * psOptionsContext,int iId)269 OptionsHaveSpecifiedOption(OPTIONS_CONTEXT *psOptionsContext, int iId)
270 {
271 int iIndex = 0;
272
273 for (iIndex = 0; iIndex < psOptionsContext->iNOptions; iIndex++)
274 {
275 if (iId == psOptionsContext->psOptions[iIndex].iId && psOptionsContext->psOptions[iIndex].iFound)
276 {
277 return 1;
278 }
279 }
280
281 return 0;
282 }
283
284
285 /*-
286 ***********************************************************************
287 *
288 * OptionsNewOptionsContext
289 *
290 ***********************************************************************
291 */
292 OPTIONS_CONTEXT *
OptionsNewOptionsContext(int iArgumentCount,TCHAR * pptcArgumentVector[],TCHAR * ptcError)293 OptionsNewOptionsContext(int iArgumentCount, TCHAR *pptcArgumentVector[], TCHAR *ptcError)
294 {
295 OPTIONS_CONTEXT *psOptionsContext = NULL;
296
297 /*-
298 *********************************************************************
299 *
300 * Allocate and clear memory for the structure.
301 *
302 *********************************************************************
303 */
304 psOptionsContext = (OPTIONS_CONTEXT *) calloc(sizeof(OPTIONS_CONTEXT), 1);
305 if (psOptionsContext == NULL)
306 {
307 _sntprintf(ptcError, MESSAGE_SIZE, _T("OptionsNewOptionsContext(): calloc(): %s"), strerror(errno));
308 return NULL;
309 }
310
311 /*-
312 *********************************************************************
313 *
314 * Allocate and clear memory for the argument types.
315 *
316 *********************************************************************
317 */
318 psOptionsContext->piArgumentTypes = (int *) calloc(sizeof(int), iArgumentCount);
319 if (psOptionsContext->piArgumentTypes == NULL)
320 {
321 _sntprintf(ptcError, MESSAGE_SIZE, _T("OptionsNewOptionsContext(): calloc(): %s"), strerror(errno));
322 return NULL;
323 }
324
325 /*-
326 *********************************************************************
327 *
328 * Initialize members.
329 *
330 *********************************************************************
331 */
332 psOptionsContext->pptcArgumentVector = pptcArgumentVector;
333 psOptionsContext->iArgumentCount = iArgumentCount;
334 psOptionsContext->piArgumentTypes[0] = OPTIONS_ARGUMENT_TYPE_PROGRAM;
335
336 return psOptionsContext;
337 }
338
339
340 /*-
341 ***********************************************************************
342 *
343 * OptionsProcessOptions
344 *
345 ***********************************************************************
346 */
347 int
OptionsProcessOptions(OPTIONS_CONTEXT * psOptionsContext,void * pvProperties,TCHAR * ptcError)348 OptionsProcessOptions(OPTIONS_CONTEXT *psOptionsContext, void *pvProperties, TCHAR *ptcError)
349 {
350 TCHAR atcLocalError[MESSAGE_SIZE] = { 0 };
351 TCHAR *ptcArgument = NULL;
352 int iError = 0;
353 int iIndex = 0;
354 int iStopIndex = psOptionsContext->iArgumentIndex;
355 int iStopIndexSaved = 0;
356 OPTIONS_TABLE *psOptions = NULL;
357
358 /*-
359 *********************************************************************
360 *
361 * Define local variables to make the code easier to read.
362 *
363 *********************************************************************
364 */
365 psOptions = psOptionsContext->psOptions;
366
367 /*-
368 *********************************************************************
369 *
370 * Walk the argument list.
371 *
372 *********************************************************************
373 */
374 while ((ptcArgument = OptionsGetNextArgument(psOptionsContext)) != NULL)
375 {
376 /*-
377 *******************************************************************
378 *
379 * Check for the end of options token ("--"). If it is found, save
380 * the current argument index, classify the remaining arguments as
381 * operands, and break.
382 *
383 *******************************************************************
384 */
385 if (_tcscmp(ptcArgument, _T("--")) == 0)
386 {
387 OptionsSetArgumentType(psOptionsContext, OPTIONS_ARGUMENT_TYPE_END_OF_OPTIONS);
388 if (!iStopIndexSaved)
389 {
390 iStopIndex = psOptionsContext->iArgumentIndex;
391 iStopIndexSaved = 1;
392 }
393 while ((ptcArgument = OptionsGetNextArgument(psOptionsContext)) != NULL)
394 {
395 OptionsSetArgumentType(psOptionsContext, OPTIONS_ARGUMENT_TYPE_OPERAND);
396 }
397 break;
398 }
399
400 /*-
401 *******************************************************************
402 *
403 * Scan the options table looking for a match on the nick name or
404 * the full name. If a match is found, pass the option and its
405 * argument, if any, to the designated handler.
406 *
407 *******************************************************************
408 */
409 for (iIndex = 0; iIndex < psOptionsContext->iNOptions; iIndex++)
410 {
411 if (
412 (psOptions[iIndex].atcNickName[0] && _tcscmp(ptcArgument, psOptions[iIndex].atcNickName) == 0) ||
413 (psOptions[iIndex].atcFullName[0] && _tcscmp(ptcArgument, psOptions[iIndex].atcFullName) == 0)
414 )
415 {
416 if (psOptions[iIndex].iAllowRepeats == 0 && psOptions[iIndex].iFound == 1)
417 {
418 _sntprintf(ptcError, MESSAGE_SIZE, _T("OptionsProcessOptions(): The %s option may not be specified more than once."), ptcArgument);
419 return OPTIONS_ER;
420 }
421 OptionsSetArgumentType(psOptionsContext, OPTIONS_ARGUMENT_TYPE_OPTION);
422 /* TODO: Modify this section (down to the break) to support multiple arguments per option. */
423 if (psOptions[iIndex].iNArguments > 0)
424 {
425 if (OptionsGetArgumentsLeft(psOptionsContext) < 1)
426 {
427 return OPTIONS_USAGE;
428 }
429 ptcArgument = OptionsGetNextArgument(psOptionsContext);
430 OptionsSetArgumentType(psOptionsContext, OPTIONS_ARGUMENT_TYPE_OPTION_ARGUMENT);
431 }
432 else
433 {
434 ptcArgument = NULL;
435 }
436 psOptions[iIndex].iFound = 1;
437 iError = psOptions[iIndex].piHandler(&psOptions[iIndex], ptcArgument, pvProperties, atcLocalError);
438 if (iError != OPTIONS_OK)
439 {
440 _sntprintf(ptcError, MESSAGE_SIZE, _T("OptionsProcessOptions(): %s"), atcLocalError);
441 return OPTIONS_ER;
442 }
443 break;
444 }
445 }
446
447 /*-
448 *******************************************************************
449 *
450 * Reject unmatched arguments that look like options. Treat single
451 * hyphens ("-") as arguments/operands rather than options. Save
452 * the index of the first argument that looks like an operand. It
453 * will be needed to adjust the options context before returning
454 * to the caller. In older implementations of this routine, option
455 * processing stopped once the first operand was identified.
456 *
457 *******************************************************************
458 */
459 if (iIndex == psOptionsContext->iNOptions)
460 {
461 if (ptcArgument[0] == '-' && ptcArgument[1] != 0)
462 {
463 _sntprintf(ptcError, MESSAGE_SIZE, _T("OptionsProcessOptions(): option=[%s]: Unknown option."), ptcArgument);
464 return OPTIONS_ER;
465 }
466 else
467 {
468 OptionsSetArgumentType(psOptionsContext, OPTIONS_ARGUMENT_TYPE_OPERAND);
469 if (!iStopIndexSaved)
470 {
471 iStopIndex = psOptionsContext->iArgumentIndex - 1; /* Subtract one from the index so the next call to OptionsGetNextArgument() outside this routine will get the correct argument (i.e., the argument that was just checked). */
472 iStopIndexSaved = 1;
473 }
474 }
475 }
476 }
477
478 /*-
479 *********************************************************************
480 *
481 * Set the argument index back to where it should have been if option
482 * processing stopped at the first operand.
483 *
484 *********************************************************************
485 */
486 psOptionsContext->iArgumentIndex = iStopIndex;
487
488 return OPTIONS_OK;
489 }
490
491
492 /*-
493 ***********************************************************************
494 *
495 * OptionsSetArgumentType
496 *
497 ***********************************************************************
498 */
499 void
OptionsSetArgumentType(OPTIONS_CONTEXT * psOptionsContext,int iType)500 OptionsSetArgumentType(OPTIONS_CONTEXT *psOptionsContext, int iType)
501 {
502 psOptionsContext->piArgumentTypes[psOptionsContext->iArgumentIndex] = iType;
503 }
504
505
506 /*-
507 ***********************************************************************
508 *
509 * OptionsSetOptions
510 *
511 ***********************************************************************
512 */
513 void
OptionsSetOptions(OPTIONS_CONTEXT * psOptionsContext,OPTIONS_TABLE * psOptions,int iNOptions)514 OptionsSetOptions(OPTIONS_CONTEXT *psOptionsContext, OPTIONS_TABLE *psOptions, int iNOptions)
515 {
516 psOptionsContext->psOptions = psOptions;
517 psOptionsContext->iNOptions = iNOptions;
518 }
519