| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
/* |
|
2
|
|
|
|
|
|
|
* eshu.h — Core types, config, and public API for Eshu indentation fixer |
|
3
|
|
|
|
|
|
|
* |
|
4
|
|
|
|
|
|
|
* Pure C, no Perl dependencies. |
|
5
|
|
|
|
|
|
|
*/ |
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
#ifndef ESHU_H |
|
8
|
|
|
|
|
|
|
#define ESHU_H |
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
#include |
|
11
|
|
|
|
|
|
|
#include |
|
12
|
|
|
|
|
|
|
#include |
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
/* ══════════════════════════════════════════════════════════════════ |
|
15
|
|
|
|
|
|
|
* Language enum |
|
16
|
|
|
|
|
|
|
* ══════════════════════════════════════════════════════════════════ */ |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
enum eshu_lang { |
|
19
|
|
|
|
|
|
|
ESHU_LANG_C = 0, |
|
20
|
|
|
|
|
|
|
ESHU_LANG_PERL = 1, |
|
21
|
|
|
|
|
|
|
ESHU_LANG_XS = 2, |
|
22
|
|
|
|
|
|
|
ESHU_LANG_XML = 3, |
|
23
|
|
|
|
|
|
|
ESHU_LANG_HTML = 4, |
|
24
|
|
|
|
|
|
|
ESHU_LANG_CSS = 5 |
|
25
|
|
|
|
|
|
|
}; |
|
26
|
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
/* ══════════════════════════════════════════════════════════════════ |
|
28
|
|
|
|
|
|
|
* Scanner state |
|
29
|
|
|
|
|
|
|
* ══════════════════════════════════════════════════════════════════ */ |
|
30
|
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
enum eshu_state { |
|
32
|
|
|
|
|
|
|
ESHU_CODE, |
|
33
|
|
|
|
|
|
|
ESHU_STRING_DQ, |
|
34
|
|
|
|
|
|
|
ESHU_STRING_SQ, |
|
35
|
|
|
|
|
|
|
ESHU_CHAR_LIT, |
|
36
|
|
|
|
|
|
|
ESHU_COMMENT_LINE, |
|
37
|
|
|
|
|
|
|
ESHU_COMMENT_BLOCK, |
|
38
|
|
|
|
|
|
|
ESHU_PREPROCESSOR, |
|
39
|
|
|
|
|
|
|
/* Perl-specific states */ |
|
40
|
|
|
|
|
|
|
ESHU_HEREDOC, |
|
41
|
|
|
|
|
|
|
ESHU_HEREDOC_INDENT, |
|
42
|
|
|
|
|
|
|
ESHU_REGEX, |
|
43
|
|
|
|
|
|
|
ESHU_QW, |
|
44
|
|
|
|
|
|
|
ESHU_QQ, |
|
45
|
|
|
|
|
|
|
ESHU_Q, |
|
46
|
|
|
|
|
|
|
ESHU_POD, |
|
47
|
|
|
|
|
|
|
/* XML/HTML-specific states */ |
|
48
|
|
|
|
|
|
|
ESHU_XML_TAG, |
|
49
|
|
|
|
|
|
|
ESHU_XML_COMMENT, |
|
50
|
|
|
|
|
|
|
ESHU_XML_CDATA, |
|
51
|
|
|
|
|
|
|
ESHU_XML_PI, |
|
52
|
|
|
|
|
|
|
ESHU_XML_DOCTYPE, |
|
53
|
|
|
|
|
|
|
ESHU_XML_ATTR_DQ, |
|
54
|
|
|
|
|
|
|
ESHU_XML_ATTR_SQ, |
|
55
|
|
|
|
|
|
|
ESHU_XML_VERBATIM, |
|
56
|
|
|
|
|
|
|
/* CSS-specific states */ |
|
57
|
|
|
|
|
|
|
ESHU_CSS_STRING_DQ, |
|
58
|
|
|
|
|
|
|
ESHU_CSS_STRING_SQ, |
|
59
|
|
|
|
|
|
|
ESHU_CSS_COMMENT, |
|
60
|
|
|
|
|
|
|
ESHU_CSS_URL |
|
61
|
|
|
|
|
|
|
}; |
|
62
|
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
/* ══════════════════════════════════════════════════════════════════ |
|
64
|
|
|
|
|
|
|
* Configuration |
|
65
|
|
|
|
|
|
|
* ══════════════════════════════════════════════════════════════════ */ |
|
66
|
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
typedef struct { |
|
68
|
|
|
|
|
|
|
char indent_char; /* '\t' or ' ' */ |
|
69
|
|
|
|
|
|
|
int indent_width; /* spaces per level (ignored for tabs) */ |
|
70
|
|
|
|
|
|
|
int indent_pp; /* indent preprocessor directives? */ |
|
71
|
|
|
|
|
|
|
int lang; /* eshu_lang enum value */ |
|
72
|
|
|
|
|
|
|
int range_start; /* first line to reindent (1-based, 0=all) */ |
|
73
|
|
|
|
|
|
|
int range_end; /* last line to reindent (1-based, 0=all) */ |
|
74
|
|
|
|
|
|
|
} eshu_config_t; |
|
75
|
|
|
|
|
|
|
|
|
76
|
271
|
|
|
|
|
|
static eshu_config_t eshu_default_config(void) { |
|
77
|
|
|
|
|
|
|
eshu_config_t c; |
|
78
|
271
|
|
|
|
|
|
c.indent_char = '\t'; |
|
79
|
271
|
|
|
|
|
|
c.indent_width = 1; |
|
80
|
271
|
|
|
|
|
|
c.indent_pp = 0; |
|
81
|
271
|
|
|
|
|
|
c.lang = ESHU_LANG_C; |
|
82
|
271
|
|
|
|
|
|
c.range_start = 0; |
|
83
|
271
|
|
|
|
|
|
c.range_end = 0; |
|
84
|
271
|
|
|
|
|
|
return c; |
|
85
|
|
|
|
|
|
|
} |
|
86
|
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
/* Check if a line number is within the configured range (or range is disabled) */ |
|
88
|
7176
|
|
|
|
|
|
static int eshu_in_range(const eshu_config_t *cfg, int line_num) { |
|
89
|
7176
|
100
|
|
|
|
|
if (cfg->range_start == 0) return 1; /* no range = all lines */ |
|
90
|
9
|
100
|
|
|
|
|
return line_num >= cfg->range_start && line_num <= cfg->range_end; |
|
|
|
100
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
} |
|
92
|
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
/* ══════════════════════════════════════════════════════════════════ |
|
94
|
|
|
|
|
|
|
* Dynamic buffer |
|
95
|
|
|
|
|
|
|
* ══════════════════════════════════════════════════════════════════ */ |
|
96
|
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
typedef struct { |
|
98
|
|
|
|
|
|
|
char *data; |
|
99
|
|
|
|
|
|
|
size_t len; |
|
100
|
|
|
|
|
|
|
size_t cap; |
|
101
|
|
|
|
|
|
|
} eshu_buf_t; |
|
102
|
|
|
|
|
|
|
|
|
103
|
271
|
|
|
|
|
|
static void eshu_buf_init(eshu_buf_t *b, size_t initial) { |
|
104
|
271
|
50
|
|
|
|
|
b->cap = initial > 0 ? initial : 4096; |
|
105
|
271
|
|
|
|
|
|
b->data = (char *)malloc(b->cap); |
|
106
|
271
|
|
|
|
|
|
b->len = 0; |
|
107
|
271
|
|
|
|
|
|
} |
|
108
|
|
|
|
|
|
|
|
|
109
|
23110
|
|
|
|
|
|
static void eshu_buf_ensure(eshu_buf_t *b, size_t extra) { |
|
110
|
23110
|
50
|
|
|
|
|
while (b->len + extra > b->cap) { |
|
111
|
0
|
|
|
|
|
|
b->cap *= 2; |
|
112
|
0
|
|
|
|
|
|
b->data = (char *)realloc(b->data, b->cap); |
|
113
|
|
|
|
|
|
|
} |
|
114
|
23110
|
|
|
|
|
|
} |
|
115
|
|
|
|
|
|
|
|
|
116
|
16490
|
|
|
|
|
|
static void eshu_buf_putc(eshu_buf_t *b, char c) { |
|
117
|
16490
|
|
|
|
|
|
eshu_buf_ensure(b, 1); |
|
118
|
16490
|
|
|
|
|
|
b->data[b->len++] = c; |
|
119
|
16490
|
|
|
|
|
|
} |
|
120
|
|
|
|
|
|
|
|
|
121
|
6620
|
|
|
|
|
|
static void eshu_buf_write(eshu_buf_t *b, const char *s, size_t n) { |
|
122
|
6620
|
|
|
|
|
|
eshu_buf_ensure(b, n); |
|
123
|
6620
|
|
|
|
|
|
memcpy(b->data + b->len, s, n); |
|
124
|
6620
|
|
|
|
|
|
b->len += n; |
|
125
|
6620
|
|
|
|
|
|
} |
|
126
|
|
|
|
|
|
|
|
|
127
|
0
|
|
|
|
|
|
static void eshu_buf_free(eshu_buf_t *b) { |
|
128
|
0
|
0
|
|
|
|
|
if (b->data) free(b->data); |
|
129
|
0
|
|
|
|
|
|
b->data = NULL; |
|
130
|
0
|
|
|
|
|
|
b->len = 0; |
|
131
|
0
|
|
|
|
|
|
b->cap = 0; |
|
132
|
0
|
|
|
|
|
|
} |
|
133
|
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
/* ══════════════════════════════════════════════════════════════════ |
|
135
|
|
|
|
|
|
|
* Line extraction helper |
|
136
|
|
|
|
|
|
|
* ══════════════════════════════════════════════════════════════════ */ |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
/* Find end of current line. Returns pointer to '\n' or to the |
|
139
|
|
|
|
|
|
|
* terminating NUL if no newline. */ |
|
140
|
7535
|
|
|
|
|
|
static const char * eshu_find_eol(const char *p) { |
|
141
|
184730
|
50
|
|
|
|
|
while (*p && *p != '\n') |
|
|
|
100
|
|
|
|
|
|
|
142
|
177195
|
|
|
|
|
|
p++; |
|
143
|
7535
|
|
|
|
|
|
return p; |
|
144
|
|
|
|
|
|
|
} |
|
145
|
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
/* Return pointer to first non-whitespace char in line */ |
|
147
|
9109
|
|
|
|
|
|
static const char * eshu_skip_leading_ws(const char *p) { |
|
148
|
22478
|
100
|
|
|
|
|
while (*p == ' ' || *p == '\t') |
|
|
|
100
|
|
|
|
|
|
|
149
|
13369
|
|
|
|
|
|
p++; |
|
150
|
9109
|
|
|
|
|
|
return p; |
|
151
|
|
|
|
|
|
|
} |
|
152
|
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
/* ══════════════════════════════════════════════════════════════════ |
|
154
|
|
|
|
|
|
|
* Trim trailing whitespace |
|
155
|
|
|
|
|
|
|
* ══════════════════════════════════════════════════════════════════ */ |
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
/* Return length of content with trailing whitespace removed */ |
|
158
|
6620
|
|
|
|
|
|
static int eshu_trimmed_len(const char *content, int len) { |
|
159
|
6641
|
50
|
|
|
|
|
while (len > 0 && (content[len - 1] == ' ' || content[len - 1] == '\t')) |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
160
|
21
|
|
|
|
|
|
len--; |
|
161
|
6620
|
|
|
|
|
|
return len; |
|
162
|
|
|
|
|
|
|
} |
|
163
|
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
/* Write content to buffer with trailing whitespace stripped */ |
|
165
|
6620
|
|
|
|
|
|
static void eshu_buf_write_trimmed(eshu_buf_t *b, const char *s, int n) { |
|
166
|
6620
|
|
|
|
|
|
n = eshu_trimmed_len(s, n); |
|
167
|
6620
|
50
|
|
|
|
|
if (n > 0) |
|
168
|
6620
|
|
|
|
|
|
eshu_buf_write(b, s, (size_t)n); |
|
169
|
6620
|
|
|
|
|
|
} |
|
170
|
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
/* ══════════════════════════════════════════════════════════════════ |
|
172
|
|
|
|
|
|
|
* Emit indentation |
|
173
|
|
|
|
|
|
|
* ══════════════════════════════════════════════════════════════════ */ |
|
174
|
|
|
|
|
|
|
|
|
175
|
5995
|
|
|
|
|
|
static void eshu_emit_indent(eshu_buf_t *out, int depth, |
|
176
|
|
|
|
|
|
|
const eshu_config_t *cfg) { |
|
177
|
|
|
|
|
|
|
int i; |
|
178
|
5995
|
50
|
|
|
|
|
if (depth < 0) depth = 0; |
|
179
|
5995
|
100
|
|
|
|
|
if (cfg->indent_char == '\t') { |
|
180
|
14704
|
100
|
|
|
|
|
for (i = 0; i < depth; i++) |
|
181
|
8724
|
|
|
|
|
|
eshu_buf_putc(out, '\t'); |
|
182
|
|
|
|
|
|
|
} else { |
|
183
|
15
|
|
|
|
|
|
int n = depth * cfg->indent_width; |
|
184
|
35
|
100
|
|
|
|
|
for (i = 0; i < n; i++) |
|
185
|
20
|
|
|
|
|
|
eshu_buf_putc(out, ' '); |
|
186
|
|
|
|
|
|
|
} |
|
187
|
5995
|
|
|
|
|
|
} |
|
188
|
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
#endif /* ESHU_H */ |