/* cmdarg.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */
/* */
/* AS-Portierung */
/* */
/* Verarbeitung Kommandozeilenparameter */
/* */
/* Historie: 4. 5.1996 Grundsteinlegung */
/* 1. 6.1996 Empty-Funktion */
/* 17. 4.1999 Key-Files in Kommandozeile */
/* 3. 8.2000 added command line args as slashes */
/* */
/*****************************************************************************/
#include "stdinc.h"
#include <string.h>
#include <ctype.h>
#include "strutil.h"
#include "stringlists.h"
#include "nls.h"
#include "nlmessages.h"
#include "cmdarg.rsc"
#ifdef _USE_MSH
# include "cmdarg.msh"
#endif
#include "cmdarg.h"
/* --------------------------------------------------------------- */
TMsgCat MsgCat
;
static as_cmd_rec_t
*sum_cmd_recs
= NULL
;
static size_t sum_cmd_rec_cnt
= 0;
/* --------------------------------------------------------------- */
static as_cmd_result_t ProcessFile
(const char *Name_O
,
const as_cmd_rec_t
*p_cmd_recs
, size_t cmd_rec_cnt
,
as_cmd_results_t
*p_results
);
static as_cmd_result_t cmd_write_help
(Boolean negate
, const char *p_arg
, as_cmd_results_t
*p_results
)
{
UNUSED
(p_arg
);
if (negate
)
return e_cmd_err
;
p_results
->write_help_exit
= True
;
return e_cmd_ok
;
}
static as_cmd_result_t cmd_write_version
(Boolean negate
, const char *p_arg
, as_cmd_results_t
*p_results
)
{
UNUSED
(p_arg
);
if (negate
)
return e_cmd_err
;
p_results
->write_version_exit
= True
;
return e_cmd_ok
;
}
static as_cmd_result_t ProcessParam
(const as_cmd_rec_t
*p_cmd_recs
, size_t cmd_rec_cnt
, const char *O_Param
,
const char *O_Next
, Boolean AllowLink
,
as_cmd_results_t
*p_results
)
{
size_t Start
;
Boolean Negate
;
size_t z
, Search
;
as_cmd_result_t TempRes
;
String Param
, Next
;
strmaxcpy
(Param
, O_Param
, STRINGSIZE
);
strmaxcpy
(Next
, O_Next
, STRINGSIZE
);
if ((*Next
== '-')
|| (*Next
== '+')
#ifdef SLASHARGS
|| (*Next
== '/')
#endif
|| (*Next
== '@'))
*Next
= '\0';
if (*Param
== '@')
{
if (AllowLink
)
{
return ProcessFile
(Param
+ 1, p_cmd_recs
, cmd_rec_cnt
, p_results
);
}
else
{
fprintf(stderr
, "%s\n", catgetmessage
(&MsgCat
, Num_ErrMsgNoKeyInFile
));
strmaxcpy
(p_results
->error_arg
, O_Param
, sizeof(p_results
->error_arg
));
return e_cmd_err
;
}
}
if ((*Param
== '-')
#ifdef SLASHARGS
|| (*Param
== '/')
#endif
|| (*Param
== '+'))
{
Negate
= (*Param
== '+');
Start
= 1;
if (Param
[Start
] == '#')
{
for (z
= Start
+ 1; z
< (size_t)strlen(Param
); z
++)
Param
[z
] = as_toupper
(Param
[z
]);
Start
++;
}
else if (Param
[Start
] == '~')
{
for (z
= Start
+ 1; z
< (size_t)strlen(Param
); z
++)
Param
[z
] = as_tolower
(Param
[z
]);
Start
++;
}
TempRes
= e_cmd_ok
;
Search
= 0;
for (Search
= 0; Search
< cmd_rec_cnt
; Search
++)
if ((strlen(p_cmd_recs
[Search
].
p_ident) > 1) && (!as_strcasecmp
(Param
+ Start
, p_cmd_recs
[Search
].
p_ident)))
break;
if (Search
< cmd_rec_cnt
)
TempRes
= p_cmd_recs
[Search
].
callback(Negate
, Next
);
else if (!as_strcasecmp
(Param
+ Start
, "help"))
TempRes
= cmd_write_help
(Negate
, Next
, p_results
);
else if (!as_strcasecmp
(Param
+ Start
, "version"))
TempRes
= cmd_write_version
(Negate
, Next
, p_results
);
else
{
for (z
= Start
; z
< (size_t)strlen(Param
); z
++)
if (TempRes
!= e_cmd_err
)
{
Search
= 0;
for (Search
= 0; Search
< cmd_rec_cnt
; Search
++)
if ((strlen(p_cmd_recs
[Search
].
p_ident) == 1) && (p_cmd_recs
[Search
].
p_ident[0] == Param
[z
]))
break;
if (Search
>= cmd_rec_cnt
)
TempRes
= e_cmd_err
;
else
{
switch (p_cmd_recs
[Search
].
callback(Negate
, Next
))
{
case e_cmd_err
:
TempRes
= e_cmd_err
;
break;
case e_cmd_arg
:
TempRes
= e_cmd_arg
;
break;
case e_cmd_ok
:
break;
case e_cmd_file
:
break; /** **/
}
}
}
}
if (TempRes
== e_cmd_err
)
strmaxcpy
(p_results
->error_arg
, Param
, sizeof(p_results
->error_arg
));
return TempRes
;
}
else
return e_cmd_file
;
}
static as_cmd_result_t DecodeLine
(const as_cmd_rec_t
*p_cmd_recs
, int cmd_rec_cnt
, char *OneLine
,
as_cmd_results_t
*p_results
)
{
int z
;
char *EnvStr
[256], *start
, *p
;
int EnvCnt
= 0;
KillPrefBlanks
(OneLine
);
if ((*OneLine
!= '\0') && (*OneLine
!= ';'))
{
start
= OneLine
;
while (*start
!= '\0')
{
EnvStr
[EnvCnt
++] = start
;
p
= strchr(start
, ' ');
if (!p
)
p
= strchr(start
, '\t');
if (p
)
{
*p
= '\0';
start
= p
+ 1;
while (as_isspace
(*start
))
start
++;
}
else
start
+= strlen(start
);
}
EnvStr
[EnvCnt
] = start
;
for (z
= 0; z
< EnvCnt
; z
++)
{
switch (ProcessParam
(p_cmd_recs
, cmd_rec_cnt
, EnvStr
[z
], EnvStr
[z
+ 1], False
, p_results
))
{
case e_cmd_file
:
AddStringListLast
(&p_results
->file_arg_list
, EnvStr
[z
]);
break;
case e_cmd_err
:
strmaxcpy
(p_results
->error_arg
, EnvStr
[z
], sizeof(p_results
->error_arg
));
p_results
->error_arg_in_env
= True
;
return e_cmd_err
;
case e_cmd_arg
:
z
++;
break;
case e_cmd_ok
:
break;
}
}
}
return e_cmd_ok
;
}
/*!------------------------------------------------------------------------
* \fn ProcessFile(const char *Name_O,
const as_cmd_rec_t *p_cmd_recs, size_t cmd_rec_cnt,
as_cmd_results_t *p_results)
* \brief process arguments from file
* \param Name_O file's name
* \param p_cmd_recs, cmd_rec_cnt argument defintions
* \param p_results result buffer
* \return e_cmd_ok or e_cmd_err
* ------------------------------------------------------------------------ */
static as_cmd_result_t ProcessFile
(const char *Name_O
,
const as_cmd_rec_t
*p_cmd_recs
, size_t cmd_rec_cnt
,
as_cmd_results_t
*p_results
)
{
FILE
*KeyFile
;
String Name
, OneLine
;
as_cmd_result_t ret
= e_cmd_ok
;
strmaxcpy
(Name
, Name_O
, STRINGSIZE
);
KillPrefBlanks
(OneLine
);
KeyFile
= fopen(Name
, "r");
if (!KeyFile
)
{
strmaxcpy
(p_results
->error_arg
, catgetmessage
(&MsgCat
, Num_ErrMsgKeyFileNotFound
), sizeof(p_results
->error_arg
));
ret
= e_cmd_err
;
}
while (!feof(KeyFile
) && (ret
== e_cmd_ok
))
{
errno
= 0;
ReadLn
(KeyFile
, OneLine
);
if ((errno
!= 0) && !feof(KeyFile
))
{
strmaxcpy
(p_results
->error_arg
, catgetmessage
(&MsgCat
, Num_ErrMsgKeyFileError
), sizeof(p_results
->error_arg
));
ret
= e_cmd_err
;
}
ret
= DecodeLine
(p_cmd_recs
, cmd_rec_cnt
, OneLine
, p_results
);
}
fclose(KeyFile
);
return ret
;
}
static int cmd_compare
(const void *p1
, const void *p2
)
{
const as_cmd_rec_t
*p_rec1
= (const as_cmd_rec_t
*)p1
,
*p_rec2
= (const as_cmd_rec_t
*)p2
;
int cmp_res
= strcmp(p_rec1
->p_ident
, p_rec2
->p_ident
);
if (!cmp_res
&& (p_rec1
!= p_rec2
))
fprintf(stderr
, "cmd_arg: option '%s' present twice\n", p_rec1
->p_ident
);
return cmp_res
;
}
/*!------------------------------------------------------------------------
* \fn as_cmd_register(const as_cmd_rec_t *p_add_recs, size_t add_rec_cnt)
* \brief extend command record list
* \param p_add_recs, add_rec_cnt records to add
* ------------------------------------------------------------------------ */
void as_cmd_register
(const as_cmd_rec_t
*p_add_recs
, size_t add_rec_cnt
)
{
as_cmd_rec_t
*p_new_sum_recs
;
if (sum_cmd_recs
)
p_new_sum_recs
= (as_cmd_rec_t
*)realloc(sum_cmd_recs
, sizeof(*p_new_sum_recs
) * (sum_cmd_rec_cnt
+ add_rec_cnt
));
else
p_new_sum_recs
= (as_cmd_rec_t
*)malloc(sizeof(*p_new_sum_recs
) * (sum_cmd_rec_cnt
+ add_rec_cnt
));
if (p_new_sum_recs
)
{
memcpy(&p_new_sum_recs
[sum_cmd_rec_cnt
], p_add_recs
, sizeof(*p_new_sum_recs
) * add_rec_cnt
);
sum_cmd_rec_cnt
+= add_rec_cnt
;
sum_cmd_recs
= p_new_sum_recs
;
qsort(p_new_sum_recs
, sum_cmd_rec_cnt
, sizeof(*p_new_sum_recs
), cmd_compare
);
}
}
/*!------------------------------------------------------------------------
* \fn as_cmd_process(int argc, char **argv,
const char *p_env_name, as_cmd_results_t *p_results)
* \brief arguments from command line and environment
* \param argc command line arg count as handed to main()
* \param argv command line args as handed to main()
* \param p_env_name environment variable to draw additional args from
* \param p_file_arg_list gets populated with file arguments
* \return e_cmd_ok, or e_cmd_err on faulty arg
* ------------------------------------------------------------------------ */
const char *argv0
;
as_cmd_result_t as_cmd_process
(int argc
, char **argv
,
const char *p_env_name
, as_cmd_results_t
*p_results
)
{
int z
;
String EnvLine
;
char *pEnv
;
Boolean skip_next
;
p_results
->file_arg_list
= NULL
;
p_results
->write_help_exit
=
p_results
->write_version_exit
= False
;
p_results
->error_arg_in_env
= False
;
p_results
->error_arg
[0] = '\0';
pEnv
= getenv(p_env_name
);
strmaxcpy
(EnvLine
, pEnv
? pEnv
: "", STRINGSIZE
);
if (EnvLine
[0] == '@')
{
if (e_cmd_err
== ProcessFile
(EnvLine
+ 1, sum_cmd_recs
, sum_cmd_rec_cnt
, p_results
))
return e_cmd_err
;
}
else
{
if (e_cmd_err
== DecodeLine
(sum_cmd_recs
, sum_cmd_rec_cnt
, EnvLine
, p_results
))
return e_cmd_err
;
}
argv0
= argv
[0];
skip_next
= False
;
for (z
= 1; z
< argc
; z
++)
{
if (skip_next
)
{
skip_next
= False
;
continue;
}
switch (ProcessParam
(sum_cmd_recs
, sum_cmd_rec_cnt
, argv
[z
], (z
+ 1 < argc
) ? argv
[z
+ 1] : "",
True
, p_results
))
{
case e_cmd_err
:
p_results
->error_arg_in_env
= False
;
strmaxcpy
(p_results
->error_arg
, argv
[z
], sizeof(p_results
->error_arg
));
return e_cmd_err
;
case e_cmd_ok
:
break;
case e_cmd_arg
:
skip_next
= True
;
break;
case e_cmd_file
:
AddStringListLast
(&p_results
->file_arg_list
, argv
[z
]);
break;
}
}
return e_cmd_ok
;
}
const char *as_cmdarg_get_executable_name
(void)
{
const char *pos
;
pos
= strrchr(argv0
, '/');
return (pos
) ? pos
+ 1 : argv0
;
}
void as_cmdarg_init
(char *ProgPath
)
{
#ifdef _USE_MSH
msg_catalog_open_buffer
(&MsgCat
, cmdarg_msh_data
, sizeof(cmdarg_msh_data
), MsgId1
, MsgId2
);
UNUSED
(ProgPath
);
#else
msg_catalog_open_file
(&MsgCat
, "cmdarg.msg", ProgPath
, MsgId1
, MsgId2
);
#endif
}