1 /*-
2  ***********************************************************************
3  *
4  * $Id: options.c,v 1.6 2012/05/01 14:43:49 mavrik Exp $
5  *
6  ***********************************************************************
7  *
8  * Copyright 2006-2012 The WebJob 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     free(psOptionsContext);
27   }
28 }
29 
30 
31 /*-
32  ***********************************************************************
33  *
34  * OptionsGetArgumentIndex
35  *
36  ***********************************************************************
37  */
38 int
OptionsGetArgumentIndex(OPTIONS_CONTEXT * psOptionsContext)39 OptionsGetArgumentIndex(OPTIONS_CONTEXT *psOptionsContext)
40 {
41   return psOptionsContext->iArgumentIndex;
42 }
43 
44 
45 /*-
46  ***********************************************************************
47  *
48  * OptionsGetArgumentsLeft
49  *
50  ***********************************************************************
51  */
52 int
OptionsGetArgumentsLeft(OPTIONS_CONTEXT * psOptionsContext)53 OptionsGetArgumentsLeft(OPTIONS_CONTEXT *psOptionsContext)
54 {
55   return (psOptionsContext->iArgumentCount - (psOptionsContext->iArgumentIndex + 1));
56 }
57 
58 
59 /*-
60  ***********************************************************************
61  *
62  * OptionsGetCommand
63  *
64  ***********************************************************************
65  */
66 TCHAR *
OptionsGetCommand(OPTIONS_CONTEXT * psOptionsContext)67 OptionsGetCommand(OPTIONS_CONTEXT *psOptionsContext)
68 {
69   return psOptionsContext->pptcArgumentVector[0];
70 }
71 
72 
73 /*-
74  ***********************************************************************
75  *
76  * OptionsGetCurrentArgument
77  *
78  ***********************************************************************
79  */
80 TCHAR *
OptionsGetCurrentArgument(OPTIONS_CONTEXT * psOptionsContext)81 OptionsGetCurrentArgument(OPTIONS_CONTEXT *psOptionsContext)
82 {
83   TCHAR              *ptcArgument = NULL;
84 
85   if (psOptionsContext->iArgumentIndex < psOptionsContext->iArgumentCount)
86   {
87     ptcArgument = psOptionsContext->pptcArgumentVector[psOptionsContext->iArgumentIndex];
88   }
89 
90   return ptcArgument;
91 }
92 
93 
94 /*-
95  ***********************************************************************
96  *
97  * OptionsGetFirstArgument
98  *
99  ***********************************************************************
100  */
101 TCHAR *
OptionsGetFirstArgument(OPTIONS_CONTEXT * psOptionsContext)102 OptionsGetFirstArgument(OPTIONS_CONTEXT *psOptionsContext)
103 {
104   TCHAR              *ptcArgument = NULL;
105 
106   psOptionsContext->iArgumentIndex = 1;
107   if (psOptionsContext->iArgumentIndex < psOptionsContext->iArgumentCount)
108   {
109     ptcArgument = psOptionsContext->pptcArgumentVector[psOptionsContext->iArgumentIndex];
110   }
111 
112   return ptcArgument;
113 }
114 
115 
116 /*-
117  ***********************************************************************
118  *
119  * OptionsGetNextArgument
120  *
121  ***********************************************************************
122  */
123 TCHAR *
OptionsGetNextArgument(OPTIONS_CONTEXT * psOptionsContext)124 OptionsGetNextArgument(OPTIONS_CONTEXT *psOptionsContext)
125 {
126   TCHAR              *ptcArgument = NULL;
127 
128   if ((psOptionsContext->iArgumentIndex + 1) < psOptionsContext->iArgumentCount)
129   {
130     ptcArgument = psOptionsContext->pptcArgumentVector[++psOptionsContext->iArgumentIndex];
131   }
132 
133   return ptcArgument;
134 }
135 
136 
137 /*-
138  ***********************************************************************
139  *
140  * OptionsHaveRequiredOptions
141  *
142  ***********************************************************************
143  */
144 int
OptionsHaveRequiredOptions(OPTIONS_CONTEXT * psOptionsContext)145 OptionsHaveRequiredOptions(OPTIONS_CONTEXT *psOptionsContext)
146 {
147   int                 iIndex = 0;
148 
149   for (iIndex = 0; iIndex < psOptionsContext->iNOptions; iIndex++)
150   {
151     if (psOptionsContext->psOptions[iIndex].iRequired == 1 && psOptionsContext->psOptions[iIndex].iFound == 0)
152     {
153       return 0;
154     }
155   }
156 
157   return 1;
158 }
159 
160 
161 /*-
162  ***********************************************************************
163  *
164  * OptionsHaveSpecifiedOption
165  *
166  ***********************************************************************
167  */
168 int
OptionsHaveSpecifiedOption(OPTIONS_CONTEXT * psOptionsContext,int iId)169 OptionsHaveSpecifiedOption(OPTIONS_CONTEXT *psOptionsContext, int iId)
170 {
171   int                 iIndex = 0;
172 
173   for (iIndex = 0; iIndex < psOptionsContext->iNOptions; iIndex++)
174   {
175     if (iId == psOptionsContext->psOptions[iIndex].iId && psOptionsContext->psOptions[iIndex].iFound)
176     {
177       return 1;
178     }
179   }
180 
181   return 0;
182 }
183 
184 
185 /*-
186  ***********************************************************************
187  *
188  * OptionsNewOptionsContext
189  *
190  ***********************************************************************
191  */
192 OPTIONS_CONTEXT *
OptionsNewOptionsContext(int iArgumentCount,TCHAR * pptcArgumentVector[],TCHAR * ptcError)193 OptionsNewOptionsContext(int iArgumentCount, TCHAR *pptcArgumentVector[], TCHAR *ptcError)
194 {
195   OPTIONS_CONTEXT    *psOptionsContext = NULL;
196 
197   /*-
198    *********************************************************************
199    *
200    * Allocate and clear memory for the structure.
201    *
202    *********************************************************************
203    */
204   psOptionsContext = (OPTIONS_CONTEXT *) calloc(sizeof(OPTIONS_CONTEXT), 1);
205   if (psOptionsContext == NULL)
206   {
207     _sntprintf(ptcError, MESSAGE_SIZE, _T("OptionsNewOptionsContext(): calloc(): %s"), strerror(errno));
208     return NULL;
209   }
210 
211   /*-
212    *********************************************************************
213    *
214    * Initialize members.
215    *
216    *********************************************************************
217    */
218   psOptionsContext->pptcArgumentVector = pptcArgumentVector;
219   psOptionsContext->iArgumentCount = iArgumentCount;
220 
221   return psOptionsContext;
222 }
223 
224 
225 /*-
226  ***********************************************************************
227  *
228  * OptionsProcessOptions
229  *
230  ***********************************************************************
231  */
232 int
OptionsProcessOptions(OPTIONS_CONTEXT * psOptionsContext,void * pvProperties,TCHAR * ptcError)233 OptionsProcessOptions(OPTIONS_CONTEXT *psOptionsContext, void *pvProperties, TCHAR *ptcError)
234 {
235   TCHAR               atcLocalError[MESSAGE_SIZE] = { 0 };
236   TCHAR              *ptcArgument = NULL;
237   int                 iError = 0;
238   int                 iIndex = 0;
239   OPTIONS_TABLE      *psOptions = NULL;
240 
241   /*-
242    *********************************************************************
243    *
244    * Define local variables to make the code easier to read.
245    *
246    *********************************************************************
247    */
248   psOptions = psOptionsContext->psOptions;
249 
250   /*-
251    *********************************************************************
252    *
253    * Walk the argument list.
254    *
255    *********************************************************************
256    */
257   while ((ptcArgument = OptionsGetNextArgument(psOptionsContext)) != NULL)
258   {
259     /*-
260      *******************************************************************
261      *
262      * Check for the end of options token ("--"), and break if found.
263      *
264      *******************************************************************
265      */
266     if (_tcscmp(ptcArgument, _T("--")) == 0)
267     {
268       break;
269     }
270 
271     /*-
272      *******************************************************************
273      *
274      * Scan the options table looking for a match on the nick name or
275      * the full name. If a match is found, pass the option and its
276      * argument, if any, to the designated handler.
277      *
278      *******************************************************************
279      */
280     for (iIndex = 0; iIndex < psOptionsContext->iNOptions; iIndex++)
281     {
282       if (
283            (psOptions[iIndex].atcNickName[0] && _tcscmp(ptcArgument, psOptions[iIndex].atcNickName) == 0) ||
284            (psOptions[iIndex].atcFullName[0] && _tcscmp(ptcArgument, psOptions[iIndex].atcFullName) == 0)
285          )
286       {
287         if (psOptions[iIndex].iAllowRepeats == 0 && psOptions[iIndex].iFound == 1)
288         {
289           _sntprintf(ptcError, MESSAGE_SIZE, _T("OptionsProcessOptions(): The %s option may not be specified more than once."), ptcArgument);
290           return OPTIONS_ER;
291         }
292 /* TODO: Modify this section (down to the break) to support multiple arguments per option. */
293         if (psOptions[iIndex].iNArguments > 0)
294         {
295           if (OptionsGetArgumentsLeft(psOptionsContext) < 1)
296           {
297             return OPTIONS_USAGE;
298           }
299           ptcArgument = OptionsGetNextArgument(psOptionsContext);
300         }
301         else
302         {
303           ptcArgument = NULL;
304         }
305         psOptions[iIndex].iFound = 1;
306         iError = psOptions[iIndex].piHandler(&psOptions[iIndex], ptcArgument, pvProperties, atcLocalError);
307         if (iError != OPTIONS_OK)
308         {
309           _sntprintf(ptcError, MESSAGE_SIZE, _T("OptionsProcessOptions(): %s"), atcLocalError);
310           return OPTIONS_ER;
311         }
312         break;
313       }
314     }
315 
316     /*-
317      *******************************************************************
318      *
319      * Reject unmatched arguments that look like options. Treat single
320      * hyphens ("-") as arguments/operands, rather than options. Stop
321      * searching for options at the first argument that looks like an
322      * operand.
323      *
324      *******************************************************************
325      */
326     if (iIndex == psOptionsContext->iNOptions)
327     {
328       if (ptcArgument[0] == '-' && ptcArgument[1] != 0)
329       {
330         _sntprintf(ptcError, MESSAGE_SIZE, _T("OptionsProcessOptions(): option=[%s]: Unknown option."), ptcArgument);
331         return OPTIONS_ER;
332       }
333       else
334       {
335         psOptionsContext->iArgumentIndex--; /* Decrement the index so the next OptionsGetNextArgument() will get this argument. */
336         break;
337       }
338     }
339   }
340 
341   return OPTIONS_OK;
342 }
343 
344 
345 /*-
346  ***********************************************************************
347  *
348  * OptionsSetOptions
349  *
350  ***********************************************************************
351  */
352 void
OptionsSetOptions(OPTIONS_CONTEXT * psOptionsContext,OPTIONS_TABLE * psOptions,int iNOptions)353 OptionsSetOptions(OPTIONS_CONTEXT *psOptionsContext, OPTIONS_TABLE *psOptions, int iNOptions)
354 {
355   psOptionsContext->psOptions = psOptions;
356   psOptionsContext->iNOptions = iNOptions;
357 }
358