#include "config.h"
#ifdef _WIN32
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include <errno.h>
#include <ctype.h>
#include <string.h>
#include "dwgetopt.h"
#include "libdwarf_version.h"
typedef int boolean;
#define TRUE 1
#define FALSE 0
#define FAILED 1
static void OpenAllFiles(void);
static void WriteFileTrailers(void);
static void CloseAllFiles(void);
static void GenerateInitialFileLines(void);
static void GenerateOneSet(void);
#ifdef TRACE_ARRAY
static void PrintArray(void);
#endif
static boolean is_skippable_line(char *pLine);
static void ParseDefinitionsAndWriteOutput(void);
#define MAX_LINE_SIZE 1000
#define ARRAY_SIZE 300
#define MAX_NAME_LEN 64
typedef struct {
char name[MAX_NAME_LEN];
unsigned value;
unsigned 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 FILE *f_names_enum_h;
static FILE *f_names_new_h;
static char prefix[200] = "";
static const char *usage[] = {
"Usage: gennames <options>",
" -i input-table-path",
" -o output-table-path",
" -s use 'switch' in generation",
" -t use 'tables' in generation",
"",
};
static void
print_args(int argc, char *argv[])
{
int index;
printf("Arguments: ");
for (index = 1; index < argc; ++index) {
printf("%s ",argv[index]);
}
printf("\n");
}
char *program_name = 0;
static char *input_name = 0;
static char *output_name = 0;
static boolean use_switch = TRUE;
static boolean use_tables = FALSE;
static void
print_version(const char * name)
{
#ifdef _DEBUG
const char *acType = "Debug";
#else
const char *acType = "Release";
#endif
printf("%s [%s %s]\n",name,DW_VERSION_DATE_STR,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;
boolean usage_error = FALSE;
program_name = argv[0];
while ((c = dwgetopt(argc, argv, "i:o:st")) != EOF) {
switch (c) {
case 'i':
input_name = dwoptarg;
break;
case 'o':
output_name = dwoptarg;
break;
case 's':
use_switch = TRUE;
use_tables = FALSE;
break;
case 't':
use_switch = FALSE;
use_tables = TRUE;
break;
default:
usage_error = TRUE;
break;
}
}
if (usage_error || 1 == dwoptind || dwoptind != argc) {
print_usage_message(usage);
exit(FAILED);
}
}
int
main(int argc,char **argv)
{
print_version(argv[0]);
print_args(argc,argv);
process_args(argc,argv);
OpenAllFiles();
GenerateInitialFileLines();
ParseDefinitionsAndWriteOutput();
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,prefix,
array[i].name,
array[i].value);
}
}
#endif
static int
Compare(array_data *elem1,array_data *elem2)
{
if (elem1->value < elem2->value) {
return -1;
}
if (elem1->value > elem2->value) {
return 1;
}
if (elem1->original_position < elem2->original_position) {
return -1;
}
if (elem1->original_position > elem2->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 netlen = strlen(file) +strlen(base) + 2;
if (netlen >= BUFSIZ) {
printf("Error opening '%s/%s', name too long\n",base,file);
exit(1);
}
strcpy(path_name,base);
strcat(path_name,"/");
strcat(path_name,file);
f = fopen(path_name,direction);
if (!f) {
printf("Error opening '%s'\n",path_name);
exit(1);
}
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";
const char *names_enum_h = "dwarf_names_enum.h";
const char *names_new_h = "dwarf_names_new.h";
f_dwarf_in = open_path(input_name,dwarf_h,"r");
f_names_enum_h = open_path(output_name,names_enum_h,"w");
f_names_new_h = open_path(output_name,names_new_h,"w");
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_enum_h,"/* Automatically generated, do not edit. */\n");
fprintf(f_names_enum_h,"/* Generated sourcedate %s */\n",
DW_VERSION_DATE_STR);
fprintf(f_names_enum_h,"\n/* BEGIN FILE */\n\n");
fprintf(f_names_enum_h,"#ifndef __DWARF_NAMES_ENUM_H__\n");
fprintf(f_names_enum_h,"#define __DWARF_NAMES_ENUM_H__\n");
fprintf(f_names_new_h,"/* Automatically generated, do not edit. */\n");
fprintf(f_names_new_h,"/* Generated sourcedate %s */\n",
DW_VERSION_DATE_STR);
fprintf(f_names_new_h,"\n/* BEGIN FILE */\n\n");
fprintf(f_names_new_h,"/* define DWARF_PRINT_PREFIX before this\n");
fprintf(f_names_new_h," point if you wish to. */\n");
fprintf(f_names_new_h,"#ifndef DWARF_PRINT_PREFIX\n");
fprintf(f_names_new_h,"#define DWARF_PRINT_PREFIX dwarf_\n");
fprintf(f_names_new_h,"#endif\n");
fprintf(f_names_new_h,"#define dw_glue(x,y) x##y\n");
fprintf(f_names_new_h,"#define dw_glue2(x,y) dw_glue(x,y)\n");
fprintf(f_names_new_h,"#define DWPREFIX(x) dw_glue2(DWARF_PRINT_PREFIX,x)\n");
fprintf(f_names_h,"/* Generated routines, do not edit. */\n");
fprintf(f_names_h,"/* Generated sourcedate %s */\n",
DW_VERSION_DATE_STR);
fprintf(f_names_h,"\n/* BEGIN FILE */\n\n");
fprintf(f_names_h,"#ifndef DWARF_NAMES_H\n");
fprintf(f_names_h,"#define DWARF_NAMES_H\n\n");
fprintf(f_names_h,"#ifdef __cplusplus\n");
fprintf(f_names_h,"extern \"C\" {\n");
fprintf(f_names_h,"#endif /* __cplusplus */\n\n");
fprintf(f_names_c,"/* Generated routines, do not edit. */\n");
fprintf(f_names_c,"/* Generated sourcedate %s */\n",
DW_VERSION_DATE_STR);
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");
if (use_tables) {
fprintf(f_names_c,"typedef struct Names_Data {\n");
fprintf(f_names_c," const char *l_name; \n");
fprintf(f_names_c," unsigned value; \n");
fprintf(f_names_c,"} Names_Data;\n\n");
fprintf(f_names_c,"/* Use standard binary search to get entry */\n");
fprintf(f_names_c,"static int\nfind_entry(Names_Data *table,"
"const int last,unsigned value, const char **s_out)\n");
fprintf(f_names_c,"{\n");
fprintf(f_names_c," int low = 0;\n");
fprintf(f_names_c," int high = last;\n");
fprintf(f_names_c," int mid;\n");
fprintf(f_names_c," unsigned maxval = table[last-1].value;\n");
fprintf(f_names_c,"\n");
fprintf(f_names_c," if (value > maxval) {\n");
fprintf(f_names_c," return DW_DLV_NO_ENTRY;\n");
fprintf(f_names_c," }\n");
fprintf(f_names_c," while (low < high) {\n");
fprintf(f_names_c," mid = low + ((high - low) / 2);\n");
fprintf(f_names_c," if(mid == last) {\n");
fprintf(f_names_c," break;\n");
fprintf(f_names_c," }\n");
fprintf(f_names_c," if (table[mid].value < value) {\n");
fprintf(f_names_c," low = mid + 1;\n");
fprintf(f_names_c," }\n");
fprintf(f_names_c," else {\n");
fprintf(f_names_c," high = mid;\n");
fprintf(f_names_c," }\n");
fprintf(f_names_c," }\n");
fprintf(f_names_c,"\n");
fprintf(f_names_c," if (low < last && table[low].value == value) {\n");
fprintf(f_names_c," /* Found: low is the entry */\n");
fprintf(f_names_c," *s_out = table[low].l_name;\n");
fprintf(f_names_c," return DW_DLV_OK;\n");
fprintf(f_names_c," }\n");
fprintf(f_names_c," return DW_DLV_NO_ENTRY;\n");
fprintf(f_names_c,"}\n");
fprintf(f_names_c,"\n");
}
}
static void
WriteFileTrailers(void)
{
fprintf(f_names_enum_h,"#endif /* __DWARF_NAMES_ENUM_H__ */\n");
fprintf(f_names_enum_h,"\n/* END FILE */\n");
fprintf(f_names_new_h,"\n/* END FILE */\n");
fprintf(f_names_h,"\n#ifdef __cplusplus\n");
fprintf(f_names_h,"}\n");
fprintf(f_names_h,"#endif /* __cplusplus */\n\n");
fprintf(f_names_h,"#endif /* DWARF_NAMES_H */\n");
fprintf(f_names_h,"\n/* END FILE */\n");
fprintf(f_names_c,"\n/* END FILE */\n");
}
static void
CloseAllFiles(void)
{
fclose(f_dwarf_in);
fclose(f_names_enum_h);
fclose(f_names_new_h);
fclose(f_names_h);
fclose(f_names_c);
}
static void
GenerateOneSet(void)
{
unsigned u;
unsigned prev_value = 0;
size_t len;
char *prefix_id = prefix + prefix_root_len;
unsigned actual_array_count = 0;
#ifdef TRACE_ARRAY
printf("List before sorting:\n");
PrintArray();
#endif
qsort((void *)&group_array,array_count,sizeof(array_data),(compfn)Compare);
#ifdef TRACE_ARRAY
printf("\nList after sorting:\n");
PrintArray();
#endif
fprintf(f_names_enum_h,"\nenum Dwarf_%s_e {\n",prefix_id);
fprintf(f_names_new_h,"int DWPREFIX(get_%s_name) (unsigned int, const char **);\n",prefix_id);
fprintf(f_names_h,"extern int dwarf_get_%s_name(unsigned int /*val_in*/, const char ** /*s_out */);\n",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,const char ** s_out)\n",prefix_id);
fprintf(f_names_c,"{\n");
if (use_tables) {
fprintf(f_names_c," static Names_Data Dwarf_%s_n[] = {\n",prefix_id);
} else {
fprintf(f_names_c," switch (val) {\n");
}
for (u = 0; u < array_count; ++u) {
if (u > 0 && group_array[u].value == prev_value) {
fprintf(f_names_c,
" /* Skipping alternate spelling of value 0x%x. %s_%s */\n",
(unsigned)prev_value,
prefix,
group_array[u].name);
continue;
}
prev_value = group_array[u].value;
len = 39 - strlen(prefix);
fprintf(f_names_enum_h," %s_%-*s = 0x%04x",
prefix,(int)len,group_array[u].name,group_array[u].value);
fprintf(f_names_enum_h,(u + 1 < array_count) ? ",\n" : "\n");
if (use_tables) {
fprintf(f_names_c," {/* %3u */ \"%s_%s\", ",
actual_array_count,prefix,group_array[u].name);
fprintf(f_names_c," %s_%s}", prefix,group_array[u].name);
fprintf(f_names_c,(u + 1 < array_count) ? ",\n" : "\n");
} else {
fprintf(f_names_c," case %s_%s:\n",
prefix,group_array[u].name);
fprintf(f_names_c," *s_out = \"%s_%s\";\n",
prefix,group_array[u].name);
fprintf(f_names_c," return DW_DLV_OK;\n");
}
++actual_array_count;
}
fprintf(f_names_enum_h,"};\n");
if (use_tables) {
fprintf(f_names_c," };\n\n");
fprintf(f_names_c," const int last_entry = %d;\n",actual_array_count);
fprintf(f_names_c," /* find the entry */\n");
fprintf(f_names_c," int r = find_entry(Dwarf_%s_n,last_entry,val,s_out);\n",prefix_id);
fprintf(f_names_c," return r;\n");
fprintf(f_names_c,"}\n");
} else {
fprintf(f_names_c," }\n");
fprintf(f_names_c," return DW_DLV_NO_ENTRY;\n");
fprintf(f_names_c,"}\n");
}
array_count = 0;
}
static boolean
is_skippable_line(char *pLine)
{
boolean empty = TRUE;
for (; *pLine && empty; ++pLine) {
empty = isspace(*pLine);
}
return empty;
}
static void
safe_strncpy(char *out, unsigned out_len,
char *in,unsigned in_len)
{
if(in_len >= out_len) {
fprintf(stderr,"Impossible input line from dwarf.h. Giving up. \n");
fprintf(stderr,"Length %u is too large, limited to %u.\n",
in_len,out_len);
exit(1);
}
strncpy(out,in,in_len);
}
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(1);
}
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);
safe_strncpy(new_prefix,sizeof(new_prefix),name,prefix_len);
new_prefix[prefix_len] = 0;
if (strcmp(prefix,new_prefix)) {
if (pending) {
GenerateOneSet();
}
pending = TRUE;
strcpy(prefix,new_prefix);
}
if (array_count >= ARRAY_SIZE) {
printf("Too many entries for current group_array size of %d",ARRAY_SIZE);
exit(1);
}
++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(1);
}
strcpy(group_array[array_count].name,second_underscore);
group_array[array_count].value = v;
group_array[array_count].original_position = array_count;
++array_count;
}
}
if (pending) {
GenerateOneSet();
}
}