#include <config.h>
#include <stddef.h> /* NULL size_t */
#include <ctype.h> /* isspace() */
#include <errno.h> /* errno */
#include <stdio.h> /* fgets() fprintf() printf() sscanf() */
#include <stdlib.h> /* exit() qsort() strtoul() */
#include <string.h> /* strchr() strcmp() strcpy() strlen()
strncmp
() */
#include "libdwarf_private.h"
#include "dd_getopt.h"
#include "dwarf_safe_strcpy.h"
#include "dd_minimal.h"
void
dd_minimal_count_global_error(
void
) {}
static
void
OpenAllFiles(
void
);
static
void
WriteFileTrailers(
void
);
static
void
CloseAllFiles(
void
);
static
void
GenerateInitialFileLines(
void
);
static
void
GenerateOneSet(
void
);
static
void
WriteNameDeclarations(
void
);
#ifdef TRACE_ARRAY
static
void
PrintArray(
void
);
#endif /* TRACE_ARRAY */
static
int
is_skippable_line(
char
*pLine);
static
void
ParseDefinitionsAndWriteOutput(
void
);
#define MAX_LINE_SIZE 1000
#define ARRAY_SIZE 350
#define MAX_NAME_LEN 64
typedef
struct
{
char
ad_prefixname[MAX_NAME_LEN];
char
ad_name[MAX_NAME_LEN];
unsigned ad_value;
unsigned ad_original_position;
} array_data;
static
array_data group_array[ARRAY_SIZE];
static
unsigned array_count = 0;
typedef
int
(*compfn)(
const
void
*,
const
void
*);
static
int
Compare(array_data *,array_data *);
static
const
char
*prefix_root =
"DW_"
;
static
const
unsigned prefix_root_len = 3;
static
FILE
*f_dwarf_in;
static
FILE
*f_names_h;
static
FILE
*f_names_c;
static
char
prefix[200] =
""
;
static
const
char
*usage[] = {
"Usage: gennames <options>"
,
" -i <path/src/lib/libdwarf"
,
" -o output-table-path"
,
""
,
};
static
void
print_args(
int
argc,
char
*argv[])
{
int
index;
printf
(
"Arguments: "
);
for
(index = 1; index < argc; ++index) {
printf
(
"%s "
,argv[index]);
}
printf
(
"\n"
);
}
static
char
*program_name = 0;
static
char
*input_name = 0;
static
char
*output_name = 0;
static
void
print_version(
const
char
* name)
{
#ifdef _DEBUG
const
char
*acType =
"Debug"
;
#else
const
char
*acType =
"Release"
;
#endif /* _DEBUG */
printf
(
"%s [%s %s]\n"
,name,PACKAGE_VERSION,acType);
}
static
void
print_usage_message(
const
char
*options[])
{
int
index;
for
(index = 0; *options[index]; ++index) {
printf
(
"%s\n"
,options[index]);
}
}
static
void
process_args(
int
argc,
char
*argv[])
{
int
c = 0;
int
usage_error = FALSE;
program_name = argv[0];
while
((c = dwgetopt(argc, argv,
"i:o:"
)) != EOF) {
switch
(c) {
case
'i'
:
input_name = dwoptarg;
break
;
case
'o'
:
output_name = dwoptarg;
break
;
default
:
usage_error = TRUE;
break
;
}
}
if
(usage_error || 1 == dwoptind || dwoptind != argc) {
print_usage_message(usage);
exit
(EXIT_FAILURE);
}
}
int
main(
int
argc,
char
**argv)
{
print_version(argv[0]);
print_args(argc,argv);
process_args(argc,argv);
OpenAllFiles();
GenerateInitialFileLines();
ParseDefinitionsAndWriteOutput();
WriteNameDeclarations();
WriteFileTrailers();
CloseAllFiles();
return
0;
}
#ifdef TRACE_ARRAY
static
void
PrintArray(
void
)
{
int
i;
for
(i = 0; i < array_count; ++i) {
printf
(
"%d: Name %s_%s, Value 0x%04x\n"
,
i,grouparray[i].ad_prefixname,
grouparray[i].ad_name,
grouparray[i].ad_value);
}
}
#endif /* TRACE_ARRAY */
static
int
Compare(array_data *elem1,array_data *elem2)
{
if
(elem1->ad_value < elem2->ad_value) {
return
-1;
}
if
(elem1->ad_value > elem2->ad_value) {
return
1;
}
if
(elem1->ad_original_position < elem2->ad_original_position) {
return
-1;
}
if
(elem1->ad_original_position > elem2->ad_original_position) {
return
1;
}
return
0;
}
static
FILE
*
open_path(
const
char
*base,
const
char
*file,
const
char
*direction)
{
FILE
*f = 0;
static
char
path_name[BUFSIZ];
size_t
baselen =
strlen
(base) +1;
size_t
filelen =
strlen
(file) +1;
size_t
netlen = baselen + filelen;
if
(netlen >= BUFSIZ) {
printf
(
"Error opening '%s/%s', name too long\n"
,base,file);
exit
(EXIT_FAILURE);
}
_dwarf_safe_strcpy(path_name,BUFSIZ,
base,baselen-1);
_dwarf_safe_strcpy(path_name+baselen-1,BUFSIZ -baselen,
"/"
,1);
_dwarf_safe_strcpy(path_name+baselen,BUFSIZ -baselen -1,
file,filelen-1);
f =
fopen
(path_name,direction);
if
(!f) {
printf
(
"Error opening '%s'\n"
,path_name);
exit
(EXIT_FAILURE);
}
return
f;
}
static
void
OpenAllFiles(
void
)
{
const
char
*dwarf_h =
"dwarf.h"
;
const
char
*names_h =
"dwarf_names.h"
;
const
char
*names_c =
"dwarf_names.c"
;
f_dwarf_in = open_path(input_name,dwarf_h,
"r"
);
f_names_h = open_path(output_name,names_h,
"w"
);
f_names_c = open_path(output_name,names_c,
"w"
);
}
static
void
GenerateInitialFileLines(
void
)
{
fprintf
(f_names_c,
"/* Generated routines, do not edit. */\n"
);
fprintf
(f_names_c,
"/* Generated for source version %s */\n"
,
PACKAGE_VERSION);
fprintf
(f_names_c,
"\n/* BEGIN FILE */\n\n"
);
fprintf
(f_names_c,
"#include \"dwarf.h\"\n\n"
);
fprintf
(f_names_c,
"#include \"libdwarf.h\"\n\n"
);
}
static
void
WriteFileTrailers(
void
)
{
fprintf
(f_names_c,
"\n/* END FILE */\n"
);
}
static
void
CloseAllFiles(
void
)
{
fclose
(f_dwarf_in);
fclose
(f_names_h);
fclose
(f_names_c);
}
struct
NameEntry {
char
ne_name[MAX_NAME_LEN];
};
#define MAX_NAMES 200
static
struct
NameEntry nameentries[MAX_NAMES];
static
int
curnameentry;
static
int
CompareName(
struct
NameEntry *elem1,
struct
NameEntry *elem2)
{
char
*cpl = elem1->ne_name;
char
*cpr = elem2->ne_name;
for
( ; *cpl && *cpr; ++cpl,++cpr) {
unsigned
char
l = *cpl;
unsigned
char
r = *cpr;
unsigned
char
l1 = 0;
unsigned
char
r1 = 0;
if
(l == r) {
continue
;
}
if
(l <=
'z'
&& l >=
'a'
) {
l1 = l -
'a'
+
'A'
;
l = l1;
}
if
(r <=
'z'
&& r >=
'a'
) {
r1 = r -
'a'
+
'A'
;
r = r1;
}
if
(l < r) {
return
-1;
}
if
(l > r) {
return
1;
}
continue
;
}
if
(*cpl < *cpr) {
return
-1;
}
if
(*cpl > *cpr) {
return
1;
}
return
0;
}
static
void
WriteNameDeclarations(
void
)
{
int
i = 0;
qsort
((
void
*)&nameentries,curnameentry,
sizeof
(
struct
NameEntry),(compfn)CompareName);
for
( ; i < curnameentry;++i) {
fprintf
(f_names_h,
"DW_API int dwarf_get_%s_name"
"(unsigned int /*val_in*/,\n"
,nameentries[i].ne_name);
fprintf
(f_names_h,
" const char ** /*s_out */);\n"
);
}
}
static
void
SaveNameDeclaration(
char
*prefix_id)
{
unsigned
long
length = 0;
if
(curnameentry >= MAX_NAMES) {
printf
(
"FAIL gennames. Exceeded limit of declarations %d "
"when given %s\n"
,curnameentry,prefix_id);
exit
(EXIT_FAILURE);
}
length =
strlen
(prefix_id);
if
(length >= MAX_NAME_LEN) {
printf
(
"FAIL gennames. Exceeded limit of declaration "
"name length at %ul "
"when given %s\n"
,curnameentry,prefix_id);
exit
(EXIT_FAILURE);
}
strcpy
(nameentries[curnameentry].ne_name,prefix_id);
++curnameentry;
}
static
void
GenerateOneSet(
void
)
{
unsigned u;
unsigned prev_value = 0;
char
* prev_name =
""
;
char
*prefix_id = prefix + prefix_root_len;
#ifdef TRACE_ARRAY
printf
(
"List before sorting:\n"
);
PrintArray();
#endif /* TRACE_ARRAY */
qsort
((
void
*)&group_array,array_count,
sizeof
(array_data),(compfn)Compare);
#ifdef TRACE_ARRAY
printf
(
"\nList after sorting:\n"
);
PrintArray();
#endif /* TRACE_ARRAY */
SaveNameDeclaration(prefix_id);
fprintf
(f_names_c,
"/* ARGSUSED */\n"
);
fprintf
(f_names_c,
"int\n"
);
fprintf
(f_names_c,
"dwarf_get_%s_name (unsigned int val,\n"
,
prefix_id);
fprintf
(f_names_c,
" const char ** s_out)\n"
);
fprintf
(f_names_c,
"{\n"
);
fprintf
(f_names_c,
" switch (val) {\n"
);
for
(u = 0; u < array_count; ++u) {
if
(u > 0 && group_array[u].ad_value == prev_value) {
fprintf
(f_names_c,
" /* Skipping alternate spelling of value\n"
);
fprintf
(f_names_c,
" 0x%x. %s_%s */\n"
,
(unsigned)prev_value,
prefix,
group_array[u].ad_name);
printf
(
"0x%04x: Skip "
"%s_%s Keep %s_%s\n"
,
(unsigned)prev_value,
prefix,
group_array[u].ad_name,
prefix,prev_name);
continue
;
}
prev_value = group_array[u].ad_value;
prev_name = group_array[u].ad_name;
fprintf
(f_names_c,
" case %s_%s:\n"
,
prefix,group_array[u].ad_name);
fprintf
(f_names_c,
" *s_out = \"%s_%s\";\n"
,
prefix,group_array[u].ad_name);
fprintf
(f_names_c,
" return DW_DLV_OK;\n"
);
}
fprintf
(f_names_c,
" default: break;\n"
);
fprintf
(f_names_c,
" }\n"
);
fprintf
(f_names_c,
" return DW_DLV_NO_ENTRY;\n"
);
fprintf
(f_names_c,
"}\n"
);
array_count = 0;
}
static
int
is_skippable_line(
char
*pLine)
{
int
empty = TRUE;
for
(; *pLine && empty; ++pLine) {
empty =
isspace
(*pLine);
}
return
empty;
}
static
void
ParseDefinitionsAndWriteOutput(
void
)
{
char
new_prefix[64];
char
*second_underscore = NULL;
char
type[1000];
char
name[1000];
char
value[1000];
char
extra[1000];
char
line_in[MAX_LINE_SIZE];
int
pending = FALSE;
int
prefix_len = 0;
while
(!
feof
(f_dwarf_in)) {
char
*fgbad = 0;
errno
= 0;
fgbad =
fgets
(line_in,
sizeof
(line_in),f_dwarf_in);
if
(!fgbad) {
if
(
feof
(f_dwarf_in)) {
break
;
}
fprintf
(stderr,
"Error reading dwarf.h!. Errno %d\n"
,
errno
);
exit
(EXIT_FAILURE);
}
if
(is_skippable_line(line_in)) {
continue
;
}
sscanf
(line_in,
"%s %s %s %s"
,type,name,value,extra);
if
(
strcmp
(type,
"#define"
) ||
strncmp
(name,prefix_root,prefix_root_len)) {
continue
;
}
second_underscore =
strchr
(name + prefix_root_len,
'_'
);
prefix_len = (
int
)(second_underscore - name);
_dwarf_safe_strcpy(new_prefix,
sizeof
(new_prefix),
name,prefix_len);
if
(
strcmp
(prefix,new_prefix)) {
if
(pending) {
GenerateOneSet();
}
pending = TRUE;
_dwarf_safe_strcpy(prefix,
sizeof
(prefix),
new_prefix,
strlen
(new_prefix));
}
if
(array_count >= ARRAY_SIZE) {
printf
(
"Too many entries for current "
"group_array size of %d"
,ARRAY_SIZE);
exit
(EXIT_FAILURE);
}
if
(!second_underscore) {
printf
(
"Line has no underscore %s\n"
,line_in);
continue
;
}
++second_underscore;
{
unsigned
long
v =
strtoul
(value,NULL,16);
if
(
strlen
(second_underscore) >= MAX_NAME_LEN) {
printf
(
"Too long a name %s for max len %d\n"
,
second_underscore,MAX_NAME_LEN);
exit
(EXIT_FAILURE);
}
_dwarf_safe_strcpy(group_array[array_count].ad_name,
MAX_NAME_LEN,second_underscore,
strlen
(second_underscore));
group_array[array_count].ad_value = v;
group_array[array_count].ad_original_position =
array_count;
++array_count;
}
}
if
(pending) {
GenerateOneSet();
}
}