-
Notifications
You must be signed in to change notification settings - Fork 22
/
Copy pathCommandLine.c
266 lines (231 loc) · 9.38 KB
/
CommandLine.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
/*
Copyright E J Jaquay 2020
This file is part of VCC (Virtual Color Computer).
VCC (Virtual Color Computer) is free software: you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of the License,
or (at your option) any later version.
VCC (Virtual Color Computer) is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with VCC (Virtual Color Computer). If not, see <http://www.gnu.org/licenses/>.
*/
//-------------------------------------------------------------------
//
// Command line arguments and options to VCC
//
// Since VCC is a windows application traditional Unix command arguments (argc,argV)
// are not availiable. However the third argument to WinMain() does provide the
// command string less the program name. Historically this argument is used
// to supply the path of a Color Computer image file that is loaded into memory
// after VCC starts.
//
// This program permits the command string to supply other information to VCC when
// it starts up. It allows the specification of differing VCC init files.
//
// When writing this I tried to make as flexible as possible as possible without
// adding any new dependancies to VCC. By making simple changes to this file
// and to the functions that use them it should be possible to add other things.
// It maybe. however, that the ability to specify the vcc config file and
// possibly logging options will be sufficent for most.
//
// Syntax:
//
// Items on command string are separated by blanks unless within quotes.
//
// Options are specified by a leading dash "-" followed by a single character
// option code. This may be followed by an option value.
//
// Anything that is not an option is considered to be a positional argument.
// It is intended that the legacy image file path name will remain the first
// such argument so that existing usage is not affected. If there is no longer
// a need to specify an image file on the command line this could change.
//
// Examples:
//
// Specify the config file fred wants to use:
// $ VCC -i C:\users\fred\my-vcc.ini
//
// Inifile in VCC appdir:
// $ VCC -i %APPDIR%/vcc/my-vcc.ini
//
// In current working directory:
// $ VCC -i my-vcc.ini
//
// Quick load image file:
// $ VCC "C:\barney's good image.ima"
//
// Errors returned:
// CL_ERR_UNKOPT Unknown option found
// CL_ERR_XTRARG Too many arguments
//
// Caveauts:
//
// o Supports short (single char) option codes only.
// o Option codes may not be combined. Each must be preceeded by dash: '-'
// o Command string cannot be longer than 255 characters.
// o Wide character or control character input is not supported.
// o No provision to escape double quotes or other special characters.
//-------------------------------------------------------------------
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "CommandLine.h"
// Define global command line settings
struct CmdLineArguments CmdArg;
#define SEPMARK 3 //To mark spaces as separators
char *ParseCmdString(char *, const char *);
char *GetNextToken ();
static char *NxtTokenPtr;
//-------------------------------------------------------------------
// Parse the VCC command string and set ConfigFile, QuickLoadFile, and
// possibly other things. Variables set by this routine are global and
// are defined in CommandLine.h
//
// vcc.exe [-d[level]] [-i ConfigFile] [QuickLoadFile]
//
// CmdString: The third arg to WinMain()
//-------------------------------------------------------------------
int GetCmdLineArgs(char *CmdString)
{
char *token; // token pointer (to item in command string)
int argnum = 0; // non-option argument number
// Options that require values need to be known by the parser
// to allow seperation between option code and value.
// OPtion codes for these should be placed in the ValueRequired
// String. If the value is optional it can not be seperated from
// the code. These should not be included in the Valurequired
// string.
static char * ValueRequired = "i";
// Initialize the global variables set by this routine
CmdArg.QLoadFile[0] = '\0';
CmdArg.IniFile[0] = '\0';
CmdArg.Logging = 0;
// Get the first token from the command string
token = ParseCmdString(CmdString,ValueRequired);
while (token) {
// Option?
if (*token == '-') {
switch (*(token+1)) {
// "-i" specfies the Vcc configuration file to use.
// The value is required and will be found starting
// at the third character of the option string.
// Default config file is "vcc.ini"
case 'i':
strncpy(CmdArg.IniFile,token+2,CL_MAX_PATH);
break;
// "-d[level]" enables logging console and sets log level (default=1)
// level is optional. It defaults to 1 and is forced to be
// a positive integer 0 to 3.
case 'd':
if (*(token+2)) {
CmdArg.Logging = atoi(token+2);
if (CmdArg.Logging < 1) CmdArg.Logging = 0;
if (CmdArg.Logging > 3) CmdArg.Logging = 3;
} else {
CmdArg.Logging = 1;
}
break;
// Unknown option code returns an error
default:
return CL_ERR_UNKOPT;
}
// else Positional argument
// argnum indicates argument position starting at one.
} else {
switch (++argnum) {
// First (currently only) positional arg is Quick Load filename.
case 1:
strncpy(CmdArg.QLoadFile,token,CL_MAX_PATH);
break;
// Extra positional argument returns an error
default:
return CL_ERR_XTRARG;
}
}
// Get next token
token = ParseCmdString(NULL,ValueRequired);
}
return 0;
}
//-------------------------------------------------------------------
// Command string parser.
//
// Input string is tokenized using one or more blanks as a separator, excepting
// blanks within quotes. If the input String is not null a pointer to the
// first token is returned. Otherwise pointers to subsequent tokens are returned.
// When there are no more tokens a null pointer is returned.
//
// ValueRequired: String containing option codes that require values.
//
//-------------------------------------------------------------------
char * ParseCmdString(char *CmdString, const char *ValueRequired)
{
static char string[256]; // Copy of cmd string
static char option[256]; // Used to append value to option
int quoted;
char *token;
char *value;
// Initial call sets command string. Subsequent calls expect a NULL
if (CmdString) {
while (*CmdString == ' ') CmdString++; // Skip leading blanks
strncpy(string,CmdString,256); // Make a copy of what is left
string[255]='\0'; // Be sure it is terminated
NxtTokenPtr = string; // Save it's location
// Mark unquoted blanks
quoted = 0;
for( char * p = NxtTokenPtr; *p; p++) {
if (*p == '"') {
quoted = !quoted;
} else if (!quoted) {
if (*p == ' ') *p = SEPMARK;
}
}
}
if (token = GetNextToken()) {
// Check if it is an option token. If a option value is
// required and value is seperated make a copy and append
// next token to it
if ((token[0] == '-') && (token[1] != '\0') && (token[2] == '\0')) {
if (strchr(ValueRequired,token[1])) {
if ((NxtTokenPtr[0] != '\0') && (NxtTokenPtr[0] != '-')) {
if (value = GetNextToken()) {
strcpy(option,token);
strcat(option,value);
return option;
}
}
}
}
}
return token; // null, positional argument, or option with no value
}
//-------------------------------------------------------------------
// Terminate token, find next token, return pointer to current
//-------------------------------------------------------------------
char *GetNextToken ()
{
// Return NULL if no tokens
if (*NxtTokenPtr == '\0') return NULL;
// Save token pointer
char *token = NxtTokenPtr++;
// Advance to end of token
while (*NxtTokenPtr != SEPMARK) NxtTokenPtr++;
// If anything remains
if (*NxtTokenPtr != '\0') {
// Terminate current token
*NxtTokenPtr++ = '\0';
// Skip past extra separaters to start of next
while (*NxtTokenPtr == SEPMARK) NxtTokenPtr++;
}
// Strip leading and trailing quotes from token
if (token[0] == '\"') {
token++;
int n = strlen(token);
if ((n > 0) && (token[n-1] == '\"')) token[n-1] = '\0';
}
// Return address of current token
return token;
}