]> git.sur5r.net Git - cc65/blob - src/common/cmdline.c
add gotox, gotoy, and gotoxy
[cc65] / src / common / cmdline.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 cmdline.c                                 */
4 /*                                                                           */
5 /*                 Helper functions for command line parsing                 */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2000-2009, Ullrich von Bassewitz                                      */
10 /*                Roemerstrasse 52                                           */
11 /*                D-70794 Filderstadt                                        */
12 /* EMail:         uz@cc65.org                                                */
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     /* Initialize the struct */
81     L->Size    = 8;
82     L->Count   = 0;
83     L->Vec     = xmalloc (L->Size * sizeof (L->Vec[0]));
84 }
85
86
87
88 static void AddArg (CmdLine* L, char* Arg)
89 /* Add one argument to the list */
90 {
91     if (L->Size <= L->Count) {
92         /* No space left, reallocate */
93         unsigned NewSize = L->Size * 2;
94         char**   NewVec  = xmalloc (NewSize * sizeof (L->Vec[0]));
95         memcpy (NewVec, L->Vec, L->Count * sizeof (L->Vec[0]));
96         xfree (L->Vec);
97         L->Vec  = NewVec;
98         L->Size = NewSize;
99     }
100
101     /* We have space left, add a copy of the argument */
102     L->Vec[L->Count++] = Arg;
103 }
104
105
106
107 static void ExpandFile (CmdLine* L, const char* Name)
108 /* Add the contents of a file to the command line. Each line is a separate
109  * argument with leading and trailing whitespace removed.
110  */
111 {
112     char Buf [256];
113
114     /* Try to open the file for reading */
115     FILE* F = fopen (Name, "r");
116     if (F == 0) {
117         AbEnd ("Cannot open \"%s\": %s", Name, strerror (errno));
118     }
119
120     /* File is open, read all lines */
121     while (fgets (Buf, sizeof (Buf), F) != 0) {
122
123         /* Get a pointer to the buffer */
124         const char* B = Buf;
125
126         /* Skip trailing whitespace (this will also kill the newline that is
127          * appended by fgets().
128          */
129         unsigned Len = strlen (Buf);
130         while (Len > 0 && IsSpace (Buf [Len-1])) {
131             --Len;
132         }
133         Buf [Len] = '\0';
134
135         /* Skip leading spaces */
136         while (IsSpace (*B)) {
137             ++B;
138         }
139
140         /* Skip empty lines to work around problems with some editors */
141         if (*B == '\0') {
142             continue;
143         }
144
145         /* Add anything not empty to the command line */
146         AddArg (L, xstrdup (B));
147
148     }
149
150     /* Close the file, ignore errors here since we had the file open for
151      * reading only.
152      */
153     (void) fclose (F);
154 }
155
156
157
158 /*****************************************************************************/
159 /*                                   Code                                    */
160 /*****************************************************************************/
161
162
163
164 void InitCmdLine (int* aArgCount, char** aArgVec[], const char* aProgName)
165 /* Initialize command line parsing. aArgVec is the argument array terminated by
166  * a NULL pointer (as usual), ArgCount is the number of valid arguments in the
167  * array. Both arguments are remembered in static storage.
168  */
169 {
170     CmdLine     L;
171     int         I;
172
173     /* Get the program name from argv[0] but strip a path */
174     if (*(aArgVec)[0] == 0) {
175         /* Use the default name given */
176         ProgName = aProgName;
177     } else {
178         /* Strip a path */
179         ProgName = FindName ((*aArgVec)[0]);
180         if (ProgName[0] == '\0') {
181             /* Use the default */
182             ProgName = aProgName;
183         }
184     }
185
186     /* Make a CmdLine struct */
187     NewCmdLine (&L);
188
189     /* Walk over the parameters and add them to the CmdLine struct. Add a
190      * special handling for arguments preceeded by the '@' sign - these are
191      * actually files containing arguments.
192      */
193     for (I = 0; I < *aArgCount; ++I) {
194
195         /* Get the next argument */
196         char* Arg = (*aArgVec)[I];
197
198         /* Is this a file argument? */
199         if (Arg && Arg[0] == '@') {
200
201             /* Expand the file */
202             ExpandFile (&L, Arg+1);
203
204         } else {
205
206             /* No file, just add a copy */
207             AddArg (&L, Arg);
208
209         }
210     }
211
212     /* Store the new argument list in a safe place... */
213     ArgCount = L.Count;
214     ArgVec   = L.Vec;
215
216     /* ...and pass back the changed data also */
217     *aArgCount = L.Count;
218     *aArgVec   = L.Vec;
219 }
220
221
222
223 void UnknownOption (const char* Opt)
224 /* Print an error about an unknown option and die. */
225 {
226     AbEnd ("Unknown option: %s", Opt);
227 }
228
229
230
231 void NeedArg (const char* Opt)
232 /* Print an error about a missing option argument and exit. */
233 {
234     AbEnd ("Option requires an argument: %s", Opt);
235 }
236
237
238
239 void InvArg (const char* Opt, const char* Arg)
240 /* Print an error about an invalid option argument and exit. */
241 {
242     AbEnd ("Invalid argument for %s: `%s'", Opt, Arg);
243 }
244
245
246
247 void InvDef (const char* Def)
248 /* Print an error about an invalid definition and die */
249 {
250     AbEnd ("Invalid definition: `%s'", Def);
251 }
252
253
254
255 const char* GetArg (unsigned* ArgNum, unsigned Len)
256 /* Get an argument for a short option. The argument may be appended to the
257  * option itself or may be separate. Len is the length of the option string.
258  */
259 {
260     const char* Arg = ArgVec[*ArgNum];
261     if (Arg[Len] != '\0') {
262         /* Argument appended */
263         return Arg + Len;
264     } else {
265         /* Separate argument */
266         Arg = ArgVec[*ArgNum + 1];
267         if (Arg == 0) {
268             /* End of arguments */
269             NeedArg (ArgVec[*ArgNum]);
270         }
271         ++(*ArgNum);
272         return Arg;
273     }
274 }
275
276
277
278 void LongOption (unsigned* ArgNum, const LongOpt* OptTab, unsigned OptCount)
279 /* Handle a long command line option */
280 {
281     /* Get the option and the argument (which may be zero) */
282     const char* Opt = ArgVec[*ArgNum];
283
284     /* Search the table for a match */
285     while (OptCount) {
286         if (strcmp (Opt, OptTab->Option) == 0) {
287             /* Found, call the function */
288             if (OptTab->ArgCount > 0) {
289                 /* We need an argument, check if we have one */
290                 const char* Arg = ArgVec[++(*ArgNum)];
291                 if (Arg == 0) {
292                     NeedArg (Opt);
293                 }
294                 OptTab->Func (Opt, Arg);
295             } else {
296                 OptTab->Func (Opt, 0);
297             }
298             /* Done */
299             return;
300         }
301
302         /* Next table entry */
303         --OptCount;
304         ++OptTab;
305     }
306
307     /* Invalid option */
308     UnknownOption (Opt);
309 }
310
311
312
313