Blame |
Last modification |
View Log
| Download
| RSS feed
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mhmt-types.h"
#include "mhmt-parsearg.h"
#include "mhmt-globals.h"
struct argtbl default_arg_table
[] =
{
{"d", ARG_MODE
, NULL
},
{"g", ARG_GREEDY
, NULL
},
{ARGSTR_MEGALZ
, ARG_PTYPE
, NULL
},
{ARGSTR_HRUM
, ARG_PTYPE
, NULL
},
{ARGSTR_HRUST
, ARG_PTYPE
, NULL
},
{ARGSTR_ZX7
, ARG_PTYPE
, NULL
},
{"zxh", ARG_ZXHEAD
, NULL
},
{ARGSTR_8
, ARG_WORD
, NULL
},
{ARGSTR_16
, ARG_WORD
, NULL
},
{"bend", ARG_BIGEND
, NULL
},
{ARGSTR_MW256
, ARG_MAXWIN
, NULL
},
{ARGSTR_MW512
, ARG_MAXWIN
, NULL
},
{ARGSTR_MW1024
, ARG_MAXWIN
, NULL
},
{ARGSTR_MW2048
, ARG_MAXWIN
, NULL
},
{ARGSTR_MW2176
, ARG_MAXWIN
, NULL
},
{ARGSTR_MW4096
, ARG_MAXWIN
, NULL
},
{ARGSTR_MW4352
, ARG_MAXWIN
, NULL
},
{ARGSTR_MW8192
, ARG_MAXWIN
, NULL
},
{ARGSTR_MW16384
, ARG_MAXWIN
, NULL
},
{ARGSTR_MW32768
, ARG_MAXWIN
, NULL
},
{ARGSTR_MW65536
, ARG_MAXWIN
, NULL
},
{ARGSTR_PB
, ARG_PREBIN
, NULL
},
{NULL
, 0, NULL
}
};
// main argument parser, sets fields of "struct globals wrk",
// tries to detect all erroneous arguments.
ULONG parse_args
(int argc
, char* argv
[])
{
struct argtbl argstore
[ARG_STORE_SIZE
+1]; // last element is always stop-value
struct argtbl
* arg
;
ULONG inarg_pos
; // position in argv[] array
ULONG storearg_pos
; // position in argstore[] array
ULONG files_num
; // number of filenames specified
char * temp_filename
;
ULONG last_arg_type
;
ULONG maxwin
;
ULONG i
;
for(i
=0;i
<ARG_STORE_SIZE
+1;i
++)
{
argstore
[i
].
name = NULL
;
argstore
[i
].
fname = NULL
;
argstore
[i
].
type = ARG_NOARG
;
}
if( argc
<2 )
{
printf("No arguments! Use \"mhmt -h\" or \"mhmt -help\" for help!\n");
return 0L;
}
// shortcut for help request
if( !cmp_str_nocase
( argv
[1]+1, "h" ) || !cmp_str_nocase
( argv
[1]+1, "help" ) )
return ARG_PARSER_SHOWHELP
;
inarg_pos
= 1;
storearg_pos
= 0;
files_num
= 0;
// first find all arguments beginning with "-"
while( inarg_pos
<(ULONG
)argc
&& *(argv
[inarg_pos
])=='-' )
{
arg
=match_arg
(argv
[inarg_pos
]+1); // search match...
if( arg
) // match!
{
if( storearg_pos
>=ARG_STORE_SIZE
)
{
printf("Too many arguments!\n");
return ARG_PARSER_ERROR
|ARG_PARSER_SHOWHELP
;
}
argstore
[storearg_pos
] = *arg
;
if( arg
->type
== ARG_PREBIN
)
{
if( inarg_pos
>=(ULONG
)(argc
-1) )
{
printf("\"-prebin\" has no filename!\n");
return ARG_PARSER_ERROR
|ARG_PARSER_SHOWHELP
;
}
inarg_pos
++;
argstore
[storearg_pos
].
fname = (char *)malloc( 1+strlen(argv
[inarg_pos
]) );
if( !argstore
[storearg_pos
].
fname )
{
printf("Cannot allocate memory for filename string!\n");
return ARG_PARSER_ERROR
;
}
strcpy( argstore
[storearg_pos
].
fname, argv
[inarg_pos
] );
}
storearg_pos
++;
}
else // argument does not match predefined set
{
printf("Wrong arguments!\n");
return ARG_PARSER_ERROR
|ARG_PARSER_SHOWHELP
;
}
inarg_pos
++;
}
// parse filenames then
while( inarg_pos
<(ULONG
)argc
)
{
if( files_num
>=2 ) // there should be no more than two filenames
{
printf("Too many filenames specified!\n");
return ARG_PARSER_ERROR
|ARG_PARSER_SHOWHELP
;
}
temp_filename
= (char *)malloc( 1+strlen(argv
[inarg_pos
]) );
if( !temp_filename
)
{
printf("Cannot allocate memory for filename string!\n");
return ARG_PARSER_ERROR
;
}
strcpy( temp_filename
, argv
[inarg_pos
] );
if( files_num
==0 )
wrk.
fname_in = temp_filename
;
else // only files_num==1, because of condition in the beginning of current "while" cycle
wrk.
fname_out = temp_filename
;
files_num
++;
inarg_pos
++;
}
if( !files_num
) // there must be at least 1 filename specified
{
printf("No filenames specified!\n");
return ARG_PARSER_ERROR
|ARG_PARSER_SHOWHELP
;
}
// now optional arguments (starting with "-") are stored in argstore[],
// all needed filenames are also copied, go proceed configuring with
// optional arguments
// sort argument array (in increasing .type order) to ensure correct parsing
sort_args
( argstore
, ARG_STORE_SIZE
);
storearg_pos
= 0;
last_arg_type
= ARG_INIT
; // there is no such value in argstore[].type
while( argstore
[storearg_pos
].
type != ARG_NOARG
)
{
if( last_arg_type
== argstore
[storearg_pos
].
type )
{
printf("Redundant arguments!\n");
return ARG_PARSER_ERROR
|ARG_PARSER_SHOWHELP
;
}
switch( argstore
[storearg_pos
].
type )
{
case ARG_MODE
:
wrk.
mode = 1; // set depack mode
break;
case ARG_GREEDY
:
if( wrk.
mode ) // since sorted, argument list causes parsing go from up to down in this "case" list
{
printf("No greedy mode specification for DEpacking!\n");
return ARG_PARSER_ERROR
;
}
wrk.
greedy = 1; // set greedy packing mode
break;
case ARG_PTYPE
:
if( !cmp_str_nocase
( argstore
[storearg_pos
].
name, ARGSTR_MEGALZ
) )
{
wrk.
packtype = PK_MLZ
;
wrk.
zxheader = 0;
wrk.
wordbit = 0;
wrk.
bigend = 0;
wrk.
fullbits = 0;
wrk.
maxwin = 4352;
}
else if( !cmp_str_nocase
( argstore
[storearg_pos
].
name, ARGSTR_HRUM
) )
{
wrk.
packtype = PK_HRM
;
wrk.
zxheader = 0; // by default, there is NO ZX-HEADER if only -hrm or -hst specified
wrk.
wordbit = 1;
wrk.
bigend = 0;
wrk.
fullbits = 1;
wrk.
maxwin = 4096;
}
else if( !cmp_str_nocase
( argstore
[storearg_pos
].
name, ARGSTR_HRUST
) )
{
wrk.
packtype = PK_HST
;
wrk.
zxheader = 0; // by default, there is NO ZX-HEADER if only -hrm or -hst specified
wrk.
wordbit = 1;
wrk.
bigend = 0;
wrk.
fullbits = 1;
wrk.
maxwin = 65536;
}
else if( !cmp_str_nocase
( argstore
[storearg_pos
].
name, ARGSTR_ZX7
) )
{
wrk.
packtype = PK_ZX7
;
wrk.
zxheader = 0;
wrk.
wordbit = 0;
wrk.
bigend = 0;
wrk.
fullbits = 0;
wrk.
maxwin = 2176;
}
else // there shouldn't be this case, but nevertheless...
{
printf("Impossible error #1! Press any key to continue or \"SPACE\" to exit... :-)\n");
return ARG_PARSER_ERROR
;
}
break;
case ARG_ZXHEAD
:
// ZX-header is not applicable for PK_MLZ type...
// also wrk.packtype has been already set before...
if( PK_MLZ
==wrk.
packtype )
{
printf("There couldn't be zx-header in megalz mode!\n");
return ARG_PARSER_ERROR
;
}
wrk.
zxheader = 1;
break;
case ARG_WORD
:
// whether bits must be grouped in words or in bytes
if( !cmp_str_nocase
( argstore
[storearg_pos
].
name, ARGSTR_8
) )
{
if( wrk.
zxheader ) // won't force byte-wise bits when there is a zx-header
{
printf("There can be only 16bit grouping of bits when ZX-header is active!\n");
return ARG_PARSER_ERROR
;
}
wrk.
wordbit = 0;
}
else if( !cmp_str_nocase
( argstore
[storearg_pos
].
name, ARGSTR_16
) )
{
wrk.
wordbit = 1;
}
else // there shouldn't be this case, but nevertheless...
{
printf("Impossible error #2! Press any key to continue or \"SPACE\" to exit... :-)\n");
return ARG_PARSER_ERROR
;
}
break;
case ARG_BIGEND
:
// whether word-grouped bits must be big- or little-endian arranged
if( wrk.
zxheader )
{
printf("There can be only little-endian arrangement of bits when ZX-header is active!\n");
return ARG_PARSER_ERROR
;
}
wrk.
bigend = 1;
break;
case ARG_MAXWIN
:
maxwin
= get_maxwin
( argstore
[storearg_pos
].
name );
if( !maxwin
) // there shouldn't be this case, but nevertheless...
{
printf("Impossible error #3! Press any key to continue or \"SPACE\" to exit... :-)\n");
return ARG_PARSER_ERROR
;
}
// wrk.maxwin is already initialized to the maximum value suitable for given packing type, so check new setting
if( maxwin
> wrk.
maxwin )
{
printf("Maximum window specified is too big for given packing type!\n");
return ARG_PARSER_ERROR
;
}
wrk.
maxwin = maxwin
;
break;
case ARG_PREBIN
:
wrk.
prebin = 1;
wrk.
fname_prebin = argstore
[storearg_pos
].
fname;
break;
default:
// once again impossible error: we shouldn't be here since "while" loop condition...
printf("Impossible error #4! Press any key to continue or \"SPACE\" to exit... :-)\n");
return ARG_PARSER_ERROR
;
break;
}
last_arg_type
= argstore
[storearg_pos
++].
type;
}
return ARG_PARSER_GO
;
}
// sort arguments
void sort_args
( struct argtbl
* args
, ULONG argsize
)
{
struct argtbl temp
;
LONG i
,j
;
// simple bubble sort since there are not too many arguments
for( i
=(argsize
-2); i
>=0; i
-- )
{
for( j
=0; j
<=i
; j
++ )
{
if( args
[j
].
type > args
[j
+1].
type )
{
temp
= args
[j
];
args
[j
] = args
[j
+1];
args
[j
+1] = temp
;
}
}
}
}
// get maxwin string into number, returns 0 if no match
LONG get_maxwin
( char * txtmaxwin
)
{
static char * strings
[] =
{
ARGSTR_MW256
,
ARGSTR_MW512
,
ARGSTR_MW1024
,
ARGSTR_MW2048
,
ARGSTR_MW4096
,
ARGSTR_MW4352
,
ARGSTR_MW8192
,
ARGSTR_MW16384
,
ARGSTR_MW32768
,
ARGSTR_MW65536
,
NULL
};
static LONG sizes
[] =
{
256,
512,
1024,
2048,
4096,
4352,
8192,
16384,
32768,
65536,
0
};
ULONG i
;
i
=0;
while( strings
[i
] )
{
if( !cmp_str_nocase
( strings
[i
], txtmaxwin
) )
{
return sizes
[i
];
}
i
++;
}
return 0;
}
// finds matching arg in default_arg_table,
// returns ptr to the found element or NULL if not found
struct argtbl
* match_arg
(char * argument
)
{
struct argtbl
* test_arg
= default_arg_table
;
while( test_arg
->name
&& cmp_str_nocase
(test_arg
->name
,argument
) )
test_arg
++;
return (test_arg
->name
)?test_arg
:NULL
;
}
// compares two char strings, ignoring case (uppercase by default)
// returns 0, if equal, -1 if left lower than right, and +1 otherwise
LONG cmp_str_nocase
(char * left
, char * right
)
{
LONG order
=0;
UBYTE leftchar
,rightchar
;
UBYTE leftadd
,rightadd
;
do
{
leftchar
= (UBYTE
)*left
;
rightchar
= (UBYTE
)*right
;
leftadd
= 0;
rightadd
= 0;
left
++;
right
++;
if( leftchar
>= (UBYTE
)'a' ) leftadd
= (UBYTE
)('A'-'a');
if( rightchar
>= (UBYTE
)'a' ) rightadd
= (UBYTE
)('A'-'a');
if( leftchar
> (UBYTE
)'z' ) leftadd
= 0;
if( rightchar
> (UBYTE
)'z' ) rightadd
= 0;
leftchar
+= leftadd
;
rightchar
+= rightadd
;
if( leftchar
<rightchar
) order
= (-1);
if( leftchar
>rightchar
) order
= (+1);
} while( (!order
) && leftchar
&& rightchar
);
return order
;
}