]> git.sur5r.net Git - cc65/blob - src/common/cmdline.c
More instruction set stuff
[cc65] / src / common / cmdline.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 cmdline.c                                 */
4 /*                                                                           */
5 /*                 Helper functions for command line parsing                 */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2000     Ullrich von Bassewitz                                        */
10 /*              Wacholderweg 14                                              */
11 /*              D-70597 Stuttgart                                            */
12 /* EMail:       uz@musoftware.de                                             */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <stdio.h>
37 #include <string.h>
38 #include <errno.h>
39
40 /* common */
41 #include "abend.h"
42 #include "chartype.h"
43 #include "fname.h"
44 #include "xmalloc.h"
45 #include "cmdline.h"
46
47
48
49 /*****************************************************************************/
50 /*                                   Data                                    */
51 /*****************************************************************************/
52
53
54
55 /* Program name - is set after call to InitCmdLine */
56 const char* ProgName;
57
58 /* The program argument vector */
59 char** ArgVec     = 0;
60 unsigned ArgCount = 0;
61
62 /* Struct to pass the command line */
63 typedef struct {
64     char**      Vec;            /* The argument vector */
65     unsigned    Count;          /* Actual number of arguments */
66     unsigned    Size;           /* Number of argument allocated */
67 } CmdLine;
68
69
70
71 /*****************************************************************************/
72 /*                             Helper functions                              */
73 /*****************************************************************************/
74
75
76
77 static void NewCmdLine (CmdLine* L)
78 /* Initialize a CmdLine struct */
79 {
80     unsigned I;
81
82     /* Initialize the struct */
83     L->Size    = 8;
84     L->Count   = 0;
85     L->Vec     = xmalloc (L->Size * sizeof (L->Vec[0]));
86
87     /* Copy the arguments. We have to allocate them on free store, otherwise
88      * we would have to keep track which one is on free store and which not,
89      * which is a lot more overhead.
90      */
91     for (I = 0; I < L->Count; ++I) {
92         L->Vec[I] = xstrdup (ArgVec[I]);
93     }
94 }
95
96
97
98 static void AddArg (CmdLine* L, char* Arg)
99 /* Add one argument to the list */
100 {
101     if (L->Size <= L->Count) {
102         /* No space left, reallocate */
103         unsigned NewSize = L->Size * 2;
104         char**   NewVec  = xmalloc (NewSize * sizeof (L->Vec[0]));
105         memcpy (NewVec, L->Vec, L->Count * sizeof (L->Vec[0]));
106         xfree (L->Vec);
107         L->Vec  = NewVec;
108         L->Size = NewSize;
109     }
110
111     /* We have space left, add a copy of the argument */
112     L->Vec[L->Count++] = Arg;
113 }
114
115
116
117 static void ExpandFile (CmdLine* L, const char* Name)
118 /* Add the contents of a file to the command line. Each line is a separate
119  * argument with leading and trailing whitespace removed.
120  */
121 {
122     char Buf [256];
123
124     /* Try to open the file for reading */
125     FILE* F = fopen (Name, "r");
126     if (F == 0) {
127         AbEnd ("Cannot open \"%s\": %s", Name, strerror (errno));
128     }
129
130     /* File is open, read all lines */
131     while (fgets (Buf, sizeof (Buf), F) != 0) {
132
133         /* Get a pointer to the buffer */
134         const char* B = Buf;
135
136         /* Skip trailing whitespace (this will also kill the newline that is
137          * appended by fgets().
138          */
139         unsigned Len = strlen (Buf);
140         while (Len > 0 && IsSpace (Buf [Len-1])) {
141             --Len;
142         }
143         Buf [Len] = '\0';
144
145         /* Skip leading spaces */
146         while (IsSpace (*B)) {
147             ++B;
148         }
149
150         /* Skip empty lines to work around problems with some editors */
151         if (*B == '\0') {
152             continue;
153         }
154
155         /* Add anything not empty to the command line */
156         AddArg (L, xstrdup (B));
157
158     }
159
160     /* Close the file, ignore errors here since we had the file open for
161      * reading only.
162      */
163     (void) fclose (F);
164 }
165
166
167
168 /*****************************************************************************/
169 /*                                   Code                                    */
170 /*****************************************************************************/
171
172
173
174 void InitCmdLine (int* aArgCount, char** aArgVec[], const char* aProgName)
175 /* Initialize command line parsing. aArgVec is the argument array terminated by
176  * a NULL pointer (as usual), ArgCount is the number of valid arguments in the
177  * array. Both arguments are remembered in static storage.
178  */
179 {
180     CmdLine     L;
181     int         I;
182
183     /* Get the program name from argv[0] but strip a path */
184     if (*(aArgVec)[0] == 0) {
185         /* Use the default name given */
186         ProgName = aProgName;
187     } else {
188         /* Strip a path */
189         ProgName = FindName ((*aArgVec)[0]);
190         if (ProgName[0] == '\0') {
191             /* Use the default */
192             ProgName = aProgName;
193         }
194     }
195
196     /* Make a CmdLine struct */
197     NewCmdLine (&L);
198
199     /* Walk over the parameters and add them to the CmdLine struct. Add a
200      * special handling for arguments preceeded by the '@' sign - these are
201      * actually files containing arguments.
202      */
203     for (I = 0; I < *aArgCount; ++I) {
204
205         /* Get the next argument */
206         char* Arg = (*aArgVec)[I];
207
208         /* Is this a file argument? */
209         if (Arg && Arg[0] == '@') {
210
211             /* Expand the file */
212             ExpandFile (&L, Arg+1);
213
214         } else {
215
216             /* No file, just add a copy */
217             AddArg (&L, Arg);
218
219         }
220     }
221
222     /* Store the new argument list in a safe place... */
223     ArgCount = L.Count;
224     ArgVec   = L.Vec;
225
226     /* ...and pass back the changed data also */
227     *aArgCount = L.Count;
228     *aArgVec   = L.Vec;
229 }
230
231
232
233 void UnknownOption (const char* Opt)
234 /* Print an error about an unknown option and die. */
235 {
236     AbEnd ("Unknown option: %s", Opt);
237 }
238
239
240
241 void NeedArg (const char* Opt)
242 /* Print an error about a missing option argument and exit. */
243 {
244     AbEnd ("Option requires an argument: %s", Opt);
245 }
246
247
248
249 void InvDef (const char* Def)
250 /* Print an error about an invalid definition and die */
251 {
252     AbEnd ("Invalid definition: `%s'", Def);
253 }
254
255
256
257 const char* GetArg (unsigned* ArgNum, unsigned Len)
258 /* Get an argument for a short option. The argument may be appended to the
259  * option itself or may be separate. Len is the length of the option string.
260  */
261 {
262     const char* Arg = ArgVec[*ArgNum];
263     if (Arg[Len] != '\0') {
264         /* Argument appended */
265         return Arg + Len;
266     } else {
267         /* Separate argument */
268         Arg = ArgVec[*ArgNum + 1];
269         if (Arg == 0) {
270             /* End of arguments */
271             NeedArg (ArgVec[*ArgNum]);
272         }
273         ++(*ArgNum);
274         return Arg;
275     }
276 }
277
278
279
280 void LongOption (unsigned* ArgNum, const LongOpt* OptTab, unsigned OptCount)
281 /* Handle a long command line option */
282 {
283     /* Get the option and the argument (which may be zero) */
284     const char* Opt = ArgVec[*ArgNum];
285
286     /* Search the table for a match */
287     while (OptCount) {
288         if (strcmp (Opt, OptTab->Option) == 0) {
289             /* Found, call the function */
290             if (OptTab->ArgCount > 0) {
291                 /* We need an argument, check if we have one */
292                 const char* Arg = ArgVec[++(*ArgNum)];
293                 if (Arg == 0) {
294                     NeedArg (Opt);
295                 }
296                 OptTab->Func (Opt, Arg);
297             } else {
298                 OptTab->Func (Opt, 0);
299             }
300             /* Done */
301             return;
302         }
303
304         /* Next table entry */
305         --OptCount;
306         ++OptTab;
307     }
308
309     /* Invalid option */
310     UnknownOption (Opt);
311 }
312
313
314
315