-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathmacro.c
161 lines (143 loc) · 3.43 KB
/
macro.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#include <string.h>
#include <lib.h>
#include <list.h>
#include <macro.h>
static struct list_head macrotable[MACRO_HASH_SIZE];
/* compute macro name hash value */
unsigned int mhash(char *name)
{
unsigned int hash, c;
hash = 0;
while (c = *name++)
hash = (hash + (c << 4 + c >> 4)) * 11;
return hash;
}
/* look up macro entry in macro table according to @name, @hash */
struct macro *lookup_hash_macro(char *name, unsigned int hash)
{
struct macro *macro;
list_for_each_entry(macro, tbl(hash), list) {
/* Macro is found. */
if (strcmp(macro->name, name) == 0)
return macro;
}
return NULL;
}
/* look up macro entry in macro table according to @name */
struct macro *lookup_macro(char *name)
{
unsigned int hash;
hash = mhash(name);
return lookup_hash_macro(name, hash);
}
struct macro *new_macro(char *name, char *text)
{
struct macro *macro;
macro = xmalloc(sizeof(*macro));
macro->name = strdup(name);
macro->text = strdup(text);
macro->hash = mhash(name);
list_init(¯o->list);
return macro;
}
/*
* The macro line lenth is valid! (3 < len < 256)
* And the line tail has no newline.
*/
struct macro *make_macro(char *line, int len)
{
struct macro *macro;
char macroname[128];
char macrotext[128];
int i, k, inquato = 0;
unsigned int hash;
/* get macro name */
for (k = i = 0; i < len; i++, k++) {
if (isspace(line[i]))
break;
macroname[k] = line[i];
}
macroname[k] = '\0';
/* skip whitespace: space or tab */
while (isspace(line[i])) /* isspace('\0') -> 0 */
i++;
if (i >= len)
text_errx("no macro text");
/* get macro text */
for (k = 0, inquato = 0; i < len; i++, k++) {
/* "..{blank}.." is valid */
if (isblank(line[i]) && !inquato)
break;
/* text reserve quota `"`. */
if (line[i] == '"')
inquato = ~inquato;
macrotext[k] = line[i];
}
macrotext[k] = '\0';
if (inquato || (i < len && !isspaceline(&line[i])))
text_errx("Format macro is invalid");
/* check whether this macro is already in macor table */
macro = lookup_macro(macroname);
if (macro) {
text_err("reduplicated macro");
/* using new macro text instead of old one */
free(macro->text);
macro->text = strdup(macrotext);
} else {
/* real macro allocing */
macro = new_macro(macroname, macrotext);
}
return macro;
}
void add_macro_table(struct macro *macro)
{
/* not add existed macro */
if (list_empty(¯o->list))
list_add(¯o->list, tbl(macro->hash));
}
/*
* @line is macro definition
*/
void add_macro(char *line, int len)
{
struct macro *macro;
int macrolen = len;
/* check macro format: ^macroname macrotext */
if (isspace(*line)) {
if (isspaceline(line))
return;
else
text_errx("Macro is invalid: redundant space");
}
/* `xy z` is shortest macro line */
if (len < 4)
text_errx("Macro is invalid: macro line is too short");
if (len > 256)
text_errx("Macro is invalid: macro line is too long");
/* elimite tail newline */
if (line[len - 1] == '\n') {
line[len - 1] = '\0';
macrolen = len - 1;
}
/* make it */
macro = make_macro(line, macrolen);
/* restore the elimited newline */
if (macrolen < len)
line[len - 1] = '\n';
/* add it to hash table */
add_macro_table(macro);
dbg("add macro hash:%8x name:%s text:%s",
macro->hash, macro->name, macro->text);
}
char *expand_macro(char *name)
{
struct macro *macro;
macro = lookup_macro(name);
return macro ? macro->text : NULL;
}
void init_macro(void)
{
int i;
for (i = 0; i < MACRO_HASH_SIZE; i++)
list_init(¯otable[i]);
}