Subversion Repositories pentevo

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
969 dimkam 1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <string.h>
4
 
5
#include "mhmt-types.h"
6
#include "mhmt-parsearg.h"
7
#include "mhmt-globals.h"
8
 
9
 
10
struct argtbl default_arg_table[] =
11
{
12
        {"d",            ARG_MODE,   NULL},
13
 
14
        {"g",            ARG_GREEDY, NULL},
15
 
16
        {ARGSTR_MEGALZ,  ARG_PTYPE,  NULL},
17
        {ARGSTR_HRUM,    ARG_PTYPE,  NULL},
18
        {ARGSTR_HRUST,   ARG_PTYPE,  NULL},
19
        {ARGSTR_ZX7,     ARG_PTYPE,  NULL},
20
 
21
        {"zxh",          ARG_ZXHEAD, NULL},
22
 
23
        {ARGSTR_8,       ARG_WORD,   NULL},
24
        {ARGSTR_16,      ARG_WORD,   NULL},
25
 
26
        {"bend",         ARG_BIGEND, NULL},
27
 
28
        {ARGSTR_MW256,   ARG_MAXWIN, NULL},
29
        {ARGSTR_MW512,   ARG_MAXWIN, NULL},
30
        {ARGSTR_MW1024,  ARG_MAXWIN, NULL},
31
        {ARGSTR_MW2048,  ARG_MAXWIN, NULL},
32
        {ARGSTR_MW2176,  ARG_MAXWIN, NULL},
33
        {ARGSTR_MW4096,  ARG_MAXWIN, NULL},
34
        {ARGSTR_MW4352,  ARG_MAXWIN, NULL},
35
        {ARGSTR_MW8192,  ARG_MAXWIN, NULL},
36
        {ARGSTR_MW16384, ARG_MAXWIN, NULL},
37
        {ARGSTR_MW32768, ARG_MAXWIN, NULL},
38
        {ARGSTR_MW65536, ARG_MAXWIN, NULL},
39
 
40
        {ARGSTR_PB,      ARG_PREBIN, NULL},
41
 
42
        {NULL,           0,          NULL}
43
};
44
 
45
 
46
 
47
// main argument parser, sets fields of "struct globals wrk",
48
// tries to detect all erroneous arguments.
49
ULONG parse_args(int argc, char* argv[])
50
{
51
        struct argtbl argstore[ARG_STORE_SIZE+1]; // last element is always stop-value
52
 
53
 
54
 
55
        struct argtbl * arg;
56
 
57
        ULONG inarg_pos; // position in argv[] array
58
        ULONG storearg_pos; // position in argstore[] array
59
 
60
        ULONG files_num; // number of filenames specified
61
 
62
        char * temp_filename;
63
 
64
        ULONG last_arg_type;
65
 
66
        ULONG maxwin;
67
 
68
 
69
        ULONG i;
70
        for(i=0;i<ARG_STORE_SIZE+1;i++)
71
        {
72
                argstore[i].name  = NULL;
73
                argstore[i].fname = NULL;
74
                argstore[i].type  = ARG_NOARG;
75
        }
76
 
77
 
78
        if( argc<2 )
79
        {
80
                printf("No arguments! Use \"mhmt -h\" or \"mhmt -help\" for help!\n");
81
                return 0L;
82
        }
83
 
84
        // shortcut for help request
85
        if( !cmp_str_nocase( argv[1]+1, "h" ) || !cmp_str_nocase( argv[1]+1, "help" ) )
86
                return ARG_PARSER_SHOWHELP;
87
 
88
 
89
        inarg_pos = 1;
90
        storearg_pos = 0;
91
        files_num = 0;
92
 
93
        // first find all arguments beginning with "-"
94
        while( inarg_pos<(ULONG)argc && *(argv[inarg_pos])=='-' )
95
        {
96
                arg=match_arg(argv[inarg_pos]+1); // search match...
97
                if( arg ) // match!
98
                {
99
                        if( storearg_pos>=ARG_STORE_SIZE )
100
                        {
101
                                printf("Too many arguments!\n");
102
                                return ARG_PARSER_ERROR|ARG_PARSER_SHOWHELP;
103
                        }
104
 
105
                        argstore[storearg_pos] = *arg;
106
 
107
                        if( arg->type == ARG_PREBIN )
108
                        {
109
                                if( inarg_pos>=(ULONG)(argc-1) )
110
                                {
111
                                        printf("\"-prebin\" has no filename!\n");
112
                                        return ARG_PARSER_ERROR|ARG_PARSER_SHOWHELP;
113
                                }
114
 
115
                                inarg_pos++;
116
 
117
                                argstore[storearg_pos].fname = (char *)malloc( 1+strlen(argv[inarg_pos]) );
118
                                if( !argstore[storearg_pos].fname )
119
                                {
120
                                        printf("Cannot allocate memory for filename string!\n");
121
                                        return ARG_PARSER_ERROR;
122
                                }
123
 
124
                                strcpy( argstore[storearg_pos].fname, argv[inarg_pos] );
125
                        }
126
 
127
                        storearg_pos++;
128
                }
129
                else // argument does not match predefined set
130
                {
131
                        printf("Wrong arguments!\n");
132
                        return ARG_PARSER_ERROR|ARG_PARSER_SHOWHELP;
133
                }
134
 
135
                inarg_pos++;
136
        }
137
 
138
        // parse filenames then
139
        while( inarg_pos<(ULONG)argc )
140
        {
141
                if( files_num>=2 ) // there should be no more than two filenames
142
                {
143
                        printf("Too many filenames specified!\n");
144
                        return ARG_PARSER_ERROR|ARG_PARSER_SHOWHELP;
145
                }
146
 
147
                temp_filename = (char *)malloc( 1+strlen(argv[inarg_pos]) );
148
                if( !temp_filename )
149
                {
150
                        printf("Cannot allocate memory for filename string!\n");
151
                        return ARG_PARSER_ERROR;
152
                }
153
 
154
                strcpy( temp_filename, argv[inarg_pos] );
155
 
156
                if( files_num==0 )
157
                        wrk.fname_in = temp_filename;
158
                else // only files_num==1, because of condition in the beginning of current "while" cycle
159
                        wrk.fname_out = temp_filename;
160
 
161
                files_num++;
162
                inarg_pos++;
163
        }
164
 
165
        if( !files_num ) // there must be at least 1 filename specified
166
        {
167
                printf("No filenames specified!\n");
168
                return ARG_PARSER_ERROR|ARG_PARSER_SHOWHELP;
169
        }
170
 
171
 
172
        // now optional arguments (starting with "-") are stored in argstore[],
173
        // all needed filenames are also copied, go proceed configuring with
174
        // optional arguments
175
 
176
        // sort argument array (in increasing .type order) to ensure correct parsing
177
        sort_args( argstore, ARG_STORE_SIZE );
178
 
179
        storearg_pos = 0;
180
        last_arg_type = ARG_INIT; // there is no such value in argstore[].type
181
        while( argstore[storearg_pos].type != ARG_NOARG )
182
        {
183
                if( last_arg_type == argstore[storearg_pos].type )
184
                {
185
                        printf("Redundant arguments!\n");
186
                        return ARG_PARSER_ERROR|ARG_PARSER_SHOWHELP;
187
                }
188
 
189
                switch( argstore[storearg_pos].type )
190
                {
191
                case ARG_MODE:
192
                        wrk.mode = 1; // set depack mode
193
                        break;
194
 
195
                case ARG_GREEDY:
196
                        if( wrk.mode ) // since sorted, argument list causes parsing go from up to down in this "case" list
197
                        {
198
                                printf("No greedy mode specification for DEpacking!\n");
199
                                return ARG_PARSER_ERROR;
200
                        }
201
                        wrk.greedy = 1; // set greedy packing mode
202
                        break;
203
 
204
                case ARG_PTYPE:
205
                        if( !cmp_str_nocase( argstore[storearg_pos].name, ARGSTR_MEGALZ ) )
206
                        {
207
                                wrk.packtype = PK_MLZ;
208
                                wrk.zxheader = 0;
209
                                wrk.wordbit  = 0;
210
                                wrk.bigend   = 0;
211
                                wrk.fullbits = 0;
212
                                wrk.maxwin   = 4352;
213
                        }
214
                        else if( !cmp_str_nocase( argstore[storearg_pos].name, ARGSTR_HRUM ) )
215
                        {
216
                                wrk.packtype = PK_HRM;
217
                                wrk.zxheader = 0; // by default, there is NO ZX-HEADER if only -hrm or -hst specified
218
                                wrk.wordbit  = 1;
219
                                wrk.bigend   = 0;
220
                                wrk.fullbits = 1;
221
                                wrk.maxwin   = 4096;
222
                        }
223
                        else if( !cmp_str_nocase( argstore[storearg_pos].name, ARGSTR_HRUST ) )
224
                        {
225
                                wrk.packtype = PK_HST;
226
                                wrk.zxheader = 0; // by default, there is NO ZX-HEADER if only -hrm or -hst specified
227
                                wrk.wordbit  = 1;
228
                                wrk.bigend   = 0;
229
                                wrk.fullbits = 1;
230
                                wrk.maxwin   = 65536;
231
                        }
232
                        else if( !cmp_str_nocase( argstore[storearg_pos].name, ARGSTR_ZX7 ) )
233
                        {
234
                                wrk.packtype = PK_ZX7;
235
                                wrk.zxheader = 0;
236
                                wrk.wordbit  = 0;
237
                                wrk.bigend   = 0;
238
                                wrk.fullbits = 0;
239
                                wrk.maxwin   = 2176;
240
                        }
241
                        else // there shouldn't be this case, but nevertheless...
242
                        {
243
                                printf("Impossible error #1! Press any key to continue or \"SPACE\" to exit... :-)\n");
244
                                return ARG_PARSER_ERROR;
245
                        }
246
                        break;
247
 
248
                case ARG_ZXHEAD:
249
                        // ZX-header is not applicable for PK_MLZ type...
250
                        // also wrk.packtype has been already set before...
251
                        if( PK_MLZ==wrk.packtype )
252
                        {
253
                                printf("There couldn't be zx-header in megalz mode!\n");
254
                                return ARG_PARSER_ERROR;
255
                        }
256
                        wrk.zxheader = 1;
257
                        break;
258
 
259
                case ARG_WORD:
260
                        // whether bits must be grouped in words or in bytes
261
                        if( !cmp_str_nocase( argstore[storearg_pos].name, ARGSTR_8 ) )
262
                        {
263
                                if( wrk.zxheader ) // won't force byte-wise bits when there is a zx-header
264
                                {
265
                                        printf("There can be only 16bit grouping of bits when ZX-header is active!\n");
266
                                        return ARG_PARSER_ERROR;
267
                                }
268
                                wrk.wordbit = 0;
269
                        }
270
                        else if( !cmp_str_nocase( argstore[storearg_pos].name, ARGSTR_16 ) )
271
                        {
272
                                wrk.wordbit = 1;
273
                        }
274
                        else // there shouldn't be this case, but nevertheless...
275
                        {
276
                                printf("Impossible error #2! Press any key to continue or \"SPACE\" to exit... :-)\n");
277
                                return ARG_PARSER_ERROR;
278
                        }
279
                        break;
280
 
281
                case ARG_BIGEND:
282
                        // whether word-grouped bits must be big- or little-endian arranged
283
                        if( wrk.zxheader )
284
                        {
285
                                printf("There can be only little-endian arrangement of bits when ZX-header is active!\n");
286
                                return ARG_PARSER_ERROR;
287
                        }
288
                        wrk.bigend = 1;
289
                        break;
290
 
291
                case ARG_MAXWIN:
292
                        maxwin = get_maxwin( argstore[storearg_pos].name );
293
                        if( !maxwin ) // there shouldn't be this case, but nevertheless...
294
                        {
295
                                printf("Impossible error #3! Press any key to continue or \"SPACE\" to exit... :-)\n");
296
                                return ARG_PARSER_ERROR;
297
                        }
298
 
299
                        // wrk.maxwin is already initialized to the maximum value suitable for given packing type, so check new setting
300
                        if( maxwin > wrk.maxwin )
301
                        {
302
                                printf("Maximum window specified is too big for given packing type!\n");
303
                                return ARG_PARSER_ERROR;
304
                        }
305
                        wrk.maxwin = maxwin;
306
                        break;
307
 
308
                case ARG_PREBIN:
309
                        wrk.prebin = 1;
310
                        wrk.fname_prebin = argstore[storearg_pos].fname;
311
                        break;
312
 
313
                default:
314
                        // once again impossible error: we shouldn't be here since "while" loop condition...
315
                        printf("Impossible error #4! Press any key to continue or \"SPACE\" to exit... :-)\n");
316
                        return ARG_PARSER_ERROR;
317
                        break;
318
                }
319
 
320
 
321
                last_arg_type = argstore[storearg_pos++].type;
322
        }
323
 
324
 
325
        return ARG_PARSER_GO;
326
}
327
 
328
 
329
// sort arguments
330
void sort_args( struct argtbl * args, ULONG argsize )
331
{
332
        struct argtbl temp;
333
        LONG i,j;
334
 
335
        // simple bubble sort since there are not too many arguments
336
        for( i=(argsize-2); i>=0; i-- )
337
        {
338
                for( j=0; j<=i; j++ )
339
                {
340
                        if( args[j].type > args[j+1].type )
341
                        {
342
                                temp      = args[j];
343
                                args[j]   = args[j+1];
344
                                args[j+1] = temp;
345
                        }
346
                }
347
        }
348
}
349
 
350
 
351
// get maxwin string into number, returns 0 if no match
352
LONG get_maxwin( char * txtmaxwin )
353
{
354
        static char * strings[] =
355
        {
356
                ARGSTR_MW256,
357
                ARGSTR_MW512,
358
                ARGSTR_MW1024,
359
                ARGSTR_MW2048,
360
                ARGSTR_MW4096,
361
                ARGSTR_MW4352,
362
                ARGSTR_MW8192,
363
                ARGSTR_MW16384,
364
                ARGSTR_MW32768,
365
                ARGSTR_MW65536,
366
                NULL
367
        };
368
 
369
        static LONG sizes[] =
370
        {
371
                256,
372
                512,
373
                1024,
374
                2048,
375
                4096,
376
                4352,
377
                8192,
378
                16384,
379
                32768,
380
                65536,
381
 
382
        };
383
 
384
        ULONG i;
385
 
386
 
387
        i=0;
388
        while( strings[i] )
389
        {
390
                if( !cmp_str_nocase( strings[i], txtmaxwin ) )
391
                {
392
                        return sizes[i];
393
                }
394
 
395
                i++;
396
        }
397
 
398
        return 0;
399
}
400
 
401
 
402
 
403
 
404
 
405
// finds matching arg in default_arg_table,
406
// returns ptr to the found element or NULL if not found
407
struct argtbl * match_arg(char * argument)
408
{
409
        struct argtbl * test_arg = default_arg_table;
410
 
411
 
412
        while( test_arg->name && cmp_str_nocase(test_arg->name,argument) )
413
                test_arg++;
414
 
415
        return (test_arg->name)?test_arg:NULL;
416
}
417
 
418
 
419
// compares two char strings, ignoring case (uppercase by default)
420
// returns 0, if equal, -1 if left lower than right, and +1 otherwise
421
LONG cmp_str_nocase(char * left, char * right)
422
{
423
 
424
        LONG order=0;
425
 
426
        UBYTE leftchar,rightchar;
427
        UBYTE leftadd,rightadd;
428
 
429
        do
430
        {
431
                leftchar  = (UBYTE)*left;
432
                rightchar = (UBYTE)*right;
433
 
434
                leftadd  = 0;
435
                rightadd = 0;
436
 
437
                left++;
438
                right++;
439
 
440
                if( leftchar  >= (UBYTE)'a' ) leftadd  = (UBYTE)('A'-'a');
441
                if( rightchar >= (UBYTE)'a' ) rightadd = (UBYTE)('A'-'a');
442
 
443
                if( leftchar  > (UBYTE)'z' ) leftadd  = 0;
444
                if( rightchar > (UBYTE)'z' ) rightadd = 0;
445
 
446
                leftchar  += leftadd;
447
                rightchar += rightadd;
448
 
449
                if( leftchar<rightchar ) order = (-1);
450
                if( leftchar>rightchar ) order = (+1);
451
 
452
        } while( (!order) && leftchar && rightchar );
453
 
454
        return order;
455
}
456