strlist: use a hash table

Use a hash table to enforce uniqueness in a string list. It is still
an ordered list, however, and can be walked in insertion order.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
This commit is contained in:
H. Peter Anvin (Intel) 2018-10-25 12:33:58 -07:00
parent c7922f95af
commit f7106d06e4
7 changed files with 108 additions and 162 deletions

View File

@ -75,7 +75,7 @@ struct forwrefinfo { /* info held on forward refs. */
};
static void parse_cmdline(int, char **, int);
static void assemble_file(const char *, StrList **);
static void assemble_file(const char *, StrList *);
static bool is_suppressed_warning(int severity);
static bool skip_this_pass(int severity);
static void nasm_verror_gnu(int severity, const char *fmt, va_list args);
@ -309,9 +309,12 @@ static void emit_dependencies(StrList *list)
{
FILE *deps;
int linepos, len;
StrList *l, *nl;
bool wmake = (quote_for_make == quote_for_wmake);
const char *wrapstr, *nulltarget;
struct strlist_entry *l;
if (!list)
return;
wrapstr = wmake ? " &\n " : " \\\n ";
nulltarget = wmake ? "\t%null\n" : "";
@ -328,7 +331,7 @@ static void emit_dependencies(StrList *list)
}
linepos = fprintf(deps, "%s :", depend_target);
list_for_each(l, list) {
list_for_each(l, list->head) {
char *file = quote_for_make(l->str);
len = strlen(file);
if (linepos + len > 62 && linepos > 1) {
@ -341,15 +344,16 @@ static void emit_dependencies(StrList *list)
}
fprintf(deps, "\n\n");
list_for_each_safe(l, nl, list) {
list_for_each(l, list->head) {
if (depend_emit_phony) {
char *file = quote_for_make(l->str);
fprintf(deps, "%s :\n%s\n", file, nulltarget);
nasm_free(file);
}
nasm_free(l);
}
strlist_free(list);
if (deps != stdout)
fclose(deps);
}
@ -409,8 +413,6 @@ static void timestamp(void)
int main(int argc, char **argv)
{
StrList **depend_ptr;
timestamp();
iflag_set_default_cpu(&cpu);
@ -494,7 +496,8 @@ int main(int argc, char **argv)
/* define some macros dependent of command-line */
define_macros_late();
depend_ptr = (depend_file || (operating_mode & OP_DEPEND)) ? &depend_list : NULL;
if (depend_file || (operating_mode & OP_DEPEND))
depend_list = strlist_allocate();
if (!depend_target)
depend_target = quote_for_make(outname);
@ -505,7 +508,7 @@ int main(int argc, char **argv)
if (depend_missing_ok)
preproc->include_path(NULL); /* "assume generated" */
preproc->reset(inname, 0, depend_ptr);
preproc->reset(inname, 0, depend_list);
ofile = NULL;
while ((line = preproc->getline()))
nasm_free(line);
@ -528,7 +531,7 @@ int main(int argc, char **argv)
location.known = false;
/* pass = 1; */
preproc->reset(inname, 3, depend_ptr);
preproc->reset(inname, 3, depend_list);
/* Revert all warnings to the default state */
memcpy(warning_state, warning_state_init, sizeof warning_state);
@ -570,7 +573,7 @@ int main(int argc, char **argv)
ofmt->init();
dfmt->init();
assemble_file(inname, depend_ptr);
assemble_file(inname, depend_list);
if (!terminate_after_phase) {
ofmt->cleanup();
@ -1379,7 +1382,7 @@ static void parse_cmdline(int argc, char **argv, int pass)
}
}
static void assemble_file(const char *fname, StrList **depend_ptr)
static void assemble_file(const char *fname, StrList *depend_list)
{
char *line;
insn output_ins;
@ -1431,7 +1434,7 @@ static void assemble_file(const char *fname, StrList **depend_ptr)
location.known = true;
ofmt->reset();
switch_segment(ofmt->section(NULL, pass2, &globalbits));
preproc->reset(fname, pass1, pass1 == 2 ? depend_ptr : NULL);
preproc->reset(fname, pass1, pass1 == 2 ? depend_list : NULL);
/* Revert all warnings to the default state */
memcpy(warning_state, warning_state_init, sizeof warning_state);

View File

@ -63,7 +63,7 @@ static void nop_init(void)
/* Nothing to do */
}
static void nop_reset(const char *file, int pass, StrList **deplist)
static void nop_reset(const char *file, int pass, StrList *deplist)
{
src_set(0, file);
nop_lineinc = 1;
@ -73,7 +73,7 @@ static void nop_reset(const char *file, int pass, StrList **deplist)
nasm_fatal_fl(ERR_NOFILE, "unable to open input file `%s'", file);
(void)pass; /* placate compilers */
nasm_add_string_to_strlist(deplist, file);
strlist_add_string(deplist, file);
}
static char *nop_getline(void)
@ -170,7 +170,7 @@ static void nop_pre_command(const char *what, char *string)
(void)string;
}
static void nop_include_path(char *path)
static void nop_include_path(const char *path)
{
(void)path;
}

View File

@ -91,7 +91,6 @@ typedef struct Blocks Blocks;
typedef struct Line Line;
typedef struct Include Include;
typedef struct Cond Cond;
typedef struct IncPath IncPath;
/*
* Note on the storage of both SMacro and MMacros: the hash table
@ -276,16 +275,6 @@ struct Include {
MMacro *mstk; /* stack of active macros/reps */
};
/*
* Include search path. This is simply a list of strings which get
* prepended, in turn, to the name of an include file, in an
* attempt to find the file if it's not in the current directory.
*/
struct IncPath {
IncPath *next;
char *path;
};
/*
* File real name hash, so we don't have to re-search the include
* path for every pass (and potentially more than that if a file
@ -397,10 +386,10 @@ static int LocalOffset = 0;
static Context *cstk;
static Include *istk;
static IncPath *ipath = NULL;
static StrList *ipath;
static int pass; /* HACK: pass 0 = generate dependencies only */
static StrList **dephead;
static StrList *deplist;
static uint64_t unique; /* unique identifier numbers */
@ -1509,43 +1498,37 @@ enum incopen_mode {
};
/* This is conducts a full pathname search */
static FILE *inc_fopen_search(const char *file, StrList **slpath,
static FILE *inc_fopen_search(const char *file, char **slpath,
enum incopen_mode omode, enum file_flags fmode)
{
FILE *fp;
char *prefix = "";
const IncPath *ip = ipath;
int len;
StrList *sl;
const char *prefix = "";
const struct strlist_entry *ip = ipath->head;
char *sp;
bool found;
while (1) {
sp = nasm_catfile(prefix, file);
len = strlen(sp) + 1;
sl = nasm_malloc(len + sizeof sl->next);
memcpy(sl->str, sp, len);
sl->next = NULL;
nasm_free(sp);
if (omode == INC_PROBE) {
fp = NULL;
found = nasm_file_exists(sl->str);
found = nasm_file_exists(sp);
} else {
fp = nasm_open_read(sl->str, fmode);
fp = nasm_open_read(sp, fmode);
found = (fp != NULL);
}
if (found) {
*slpath = sl;
*slpath = sp;
return fp;
}
nasm_free(sl);
nasm_free(sp);
if (!ip)
if (!ip) {
*slpath = NULL;
return NULL;
}
prefix = ip->path;
prefix = ip->str;
ip = ip->next;
}
}
@ -1555,12 +1538,11 @@ static FILE *inc_fopen_search(const char *file, StrList **slpath,
* considering the include path.
*/
static FILE *inc_fopen(const char *file,
StrList **dhead,
StrList *dhead,
const char **found_path,
enum incopen_mode omode,
enum file_flags fmode)
{
StrList *sl;
struct hash_insert hi;
void **hp;
char *path;
@ -1570,52 +1552,30 @@ static FILE *inc_fopen(const char *file,
if (hp) {
path = *hp;
if (path || omode != INC_NEEDED) {
nasm_add_string_to_strlist(dhead, path ? path : file);
strlist_add_string(dhead, path ? path : file);
}
} else {
/* Need to do the actual path search */
size_t file_len;
fp = inc_fopen_search(file, &path, omode, fmode);
sl = NULL;
fp = inc_fopen_search(file, &sl, omode, fmode);
file_len = strlen(file);
if (!sl) {
/* Store negative result for this file */
sl = nasm_malloc(file_len + 1 + sizeof sl->next);
memcpy(sl->str, file, file_len+1);
sl->next = NULL;
file = sl->str;
path = NULL;
} else {
path = sl->str;
file = strchr(path, '\0') - file_len;
}
hash_add(&hi, file, path); /* Positive or negative result */
/* Positive or negative result */
hash_add(&hi, nasm_strdup(file), path);
/*
* Add file to dependency path. The in_list() is needed
* in case the file was already added with %depend.
* Add file to dependency path.
*/
if (path || omode != INC_NEEDED)
nasm_add_to_strlist(dhead, sl);
strlist_add_string(dhead, file);
}
if (!path) {
if (omode == INC_NEEDED)
nasm_fatal("unable to open include file `%s'", file);
if (found_path)
*found_path = NULL;
return NULL;
} else {
if (!fp && omode != INC_PROBE)
fp = nasm_open_read(path, fmode);
}
if (!fp && omode != INC_PROBE)
fp = nasm_open_read(path, fmode);
if (found_path)
*found_path = path;
@ -2598,7 +2558,7 @@ static int do_directive(Token *tline, char **output)
p = t->text;
if (t->type != TOK_INTERNAL_STRING)
nasm_unquote_cstr(p, i);
nasm_add_string_to_strlist(dephead, p);
strlist_add_string(deplist, p);
free_tlist(origline);
return DIRECTIVE_FOUND;
@ -2622,7 +2582,7 @@ static int do_directive(Token *tline, char **output)
inc->next = istk;
inc->conds = NULL;
found_path = NULL;
inc->fp = inc_fopen(p, dephead, &found_path,
inc->fp = inc_fopen(p, deplist, &found_path,
pass == 0 ? INC_OPTIONAL : INC_NEEDED, NF_TEXT);
if (!inc->fp) {
/* -MG given but file not found */
@ -4972,7 +4932,7 @@ static void pp_verror(int severity, const char *fmt, va_list arg)
}
static void
pp_reset(const char *file, int apass, StrList **deplist)
pp_reset(const char *file, int apass, StrList *dep_list)
{
Token *t;
@ -4993,6 +4953,7 @@ pp_reset(const char *file, int apass, StrList **deplist)
nested_rep_count = 0;
init_macros();
unique = 0;
deplist = dep_list;
if (tasm_compatible_mode)
pp_add_stdmac(nasm_stdmac_tasm);
@ -5015,9 +4976,8 @@ pp_reset(const char *file, int apass, StrList **deplist)
*/
pass = apass > 2 ? 2 : apass;
dephead = deplist;
nasm_add_string_to_strlist(dephead, file);
strlist_add_string(deplist, file);
/*
* Define the __PASS__ macro. This is defined here unlike
* all the other builtins, because it is special -- it varies between
@ -5033,6 +4993,7 @@ pp_reset(const char *file, int apass, StrList **deplist)
static void pp_init(void)
{
hash_init(&FileHash, HASH_MEDIUM);
ipath = strlist_allocate();
}
static char *pp_getline(void)
@ -5296,36 +5257,20 @@ static void pp_cleanup(int pass)
ctx_pop();
src_set_fname(NULL);
if (pass == 0) {
IncPath *i;
free_llist(predef);
predef = NULL;
delete_Blocks();
freeTokens = NULL;
while ((i = ipath)) {
ipath = i->next;
if (i->path)
nasm_free(i->path);
nasm_free(i);
}
strlist_free(ipath);
}
}
static void pp_include_path(char *path)
static void pp_include_path(const char *path)
{
IncPath *i;
if (!path)
path = "";
i = nasm_malloc(sizeof(IncPath));
i->path = path ? nasm_strdup(path) : NULL;
i->next = NULL;
if (ipath) {
IncPath *j = ipath;
while (j->next)
j = j->next;
j->next = i;
} else {
ipath = i;
}
strlist_add_string(ipath, path);
}
static void pp_pre_include(char *fname)

View File

@ -336,7 +336,7 @@ struct preproc_ops {
* of the pass, an error reporting function, an evaluator
* function, and a listing generator to talk to.
*/
void (*reset)(const char *file, int pass, StrList **deplist);
void (*reset)(const char *file, int pass, StrList *deplist);
/*
* Called to fetch a line of preprocessed source. The line
@ -362,7 +362,7 @@ struct preproc_ops {
void (*pre_command)(const char *what, char *str);
/* Include path from command line */
void (*include_path)(char *path);
void (*include_path)(const char *path);
/* Unwind the macro stack when printing an error message */
void (*error_list_macros)(int severity);

View File

@ -1,6 +1,6 @@
/* ----------------------------------------------------------------------- *
*
* Copyright 1996-2016 The NASM Authors - All Rights Reserved
* Copyright 1996-2018 The NASM Authors - All Rights Reserved
* See the file AUTHORS included with the NASM distribution for
* the specific copyright holders.
*
@ -39,17 +39,22 @@
#define NASM_STRLIST_H
#include "compiler.h"
#include <string.h>
#include "nasmlib.h"
#include "hashtbl.h"
struct strlist_entry {
struct strlist_entry *next;
size_t len;
char str[1];
};
typedef struct string_list {
struct string_list *next;
char str[1];
struct hash_table hash;
struct strlist_entry *head, **tailp;
} StrList;
bool nasm_add_to_strlist(StrList **head, StrList *entry);
bool nasm_add_string_to_strlist(StrList **head, const char *str);
StrList safe_alloc *strlist_allocate(void);
bool strlist_add_string(StrList *list, const char *str);
void strlist_free(StrList *list);
#endif /* NASM_STRLIST_H */

View File

@ -1,6 +1,6 @@
/* ----------------------------------------------------------------------- *
*
* Copyright 1996-2016 The NASM Authors - All Rights Reserved
* Copyright 1996-2018 The NASM Authors - All Rights Reserved
* See the file AUTHORS included with the NASM distribution for
* the specific copyright holders.
*
@ -32,69 +32,62 @@
* ----------------------------------------------------------------------- */
/*
* strlist.c - simple linked list of strings
* strlist.c - list of unique, ordered strings
*/
#include "compiler.h"
#include <string.h>
#include "strlist.h"
static inline StrList *nasm_str_to_strlist(const char *str)
{
size_t l = strlen(str) + 1;
StrList *sl = nasm_malloc(l + sizeof sl->next);
memcpy(sl->str, str, l);
sl->next = NULL;
return sl;
}
/*
* Append a string list entry to a string list if and only if it isn't
* already there. Return true if it was added.
* Create a string list
*/
bool nasm_add_to_strlist(StrList **head, StrList *entry)
StrList *strlist_allocate(void)
{
StrList *list;
if (!head)
return false;
nasm_new(list);
hash_init(&list->hash, HASH_MEDIUM);
list->tailp = &list->head;
list = *head;
while (list) {
if (!strcmp(list->str, entry->str))
return false;
head = &list->next;
list = list->next;
}
*head = entry;
entry->next = NULL;
return true;
return list;
}
/*
* Append a string to a string list if and only if it isn't
* already there. Return true if it was added.
*/
bool nasm_add_string_to_strlist(StrList **head, const char *str)
bool strlist_add_string(StrList *list, const char *str)
{
StrList *list;
struct hash_insert hi;
struct strlist_entry *sl;
size_t l;
if (!head)
if (!list)
return false;
list = *head;
while (list) {
if (!strcmp(list->str, str))
return false;
head = &list->next;
list = list->next;
}
if (hash_find(&list->hash, str, &hi))
return false; /* Already present */
*head = nasm_str_to_strlist(str);
l = strlen(str);
sl = nasm_malloc(sizeof(struct strlist_entry) + l);
sl->len = l;
memcpy(sl->str, str, l+1);
sl->next = NULL;
*list->tailp = sl;
list->tailp = &sl->next;
hash_add(&hi, sl->str, (void *)sl);
return true;
}
/*
* Free a string list
*/
void strlist_free(StrList *list)
{
if (!list)
return;
hash_free_all(&list->hash, false);
nasm_free(list);
}

View File

@ -1965,7 +1965,7 @@ static void obj_write_file(void)
struct ExpDef *export;
int lname_idx;
ObjRecord *orp;
const StrList *depfile;
const struct strlist_entry *depfile;
const bool debuginfo = (dfmt == &borland_debug_form);
/*
@ -1988,7 +1988,7 @@ static void obj_write_file(void)
* Output file dependency information
*/
if (!obj_nodepend) {
list_for_each(depfile, depend_list) {
list_for_each(depfile, depend_list->head) {
uint32_t ts;
ts = obj_file_timestamp(depfile->str);