File Coverage

include/eshu.h
Criterion Covered Total %
statement 54 62 87.1
branch 27 36 75.0
condition n/a
subroutine n/a
pod n/a
total 81 98 82.6


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 */