Skip to content

Commit 6f63efa

Browse files
committed
Fix inliner string escaping
This adds proper backslash escaping in inliner.c to prevent unmatched quotes when processing strings with escaped characters and integrates norm-lf preprocessing into the build pipeline. The key fix is in write_line() which now properly escapes backslashes before quotes, preventing corruption like: Input: printf("Hello \"world\"\n"); Before: __c("printf(\"Hello \"world\"\n\");"); // Corrupted! After: __c("printf(\"Hello \\\"world\\\"\\n\");"); // Correct! Close #141
1 parent ea1b6ab commit 6f63efa

File tree

3 files changed

+102
-4
lines changed

3 files changed

+102
-4
lines changed

Makefile

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,16 @@ $(OUT)/%.o: %.c
106106
$(Q)$(CC) -o $@ $(CFLAGS) -c -MMD -MF $@.d $<
107107

108108
SHELL_HACK := $(shell mkdir -p $(OUT) $(OUT)/$(SRCDIR) $(OUT)/tests)
109-
$(OUT)/libc.inc: $(OUT)/inliner $(LIBDIR)/c.c
109+
110+
$(OUT)/norm-lf: tools/norm-lf.c
111+
$(VECHO) " CC+LD\t$@\n"
112+
$(Q)$(CC) $(CFLAGS) -o $@ $^
113+
114+
$(OUT)/libc.inc: $(OUT)/inliner $(OUT)/norm-lf $(LIBDIR)/c.c
110115
$(VECHO) " GEN\t$@\n"
111-
$(Q)$(OUT)/inliner $(LIBDIR)/c.c $@
116+
$(Q)$(OUT)/norm-lf $(LIBDIR)/c.c $(OUT)/c.normalized.c
117+
$(Q)$(OUT)/inliner $(OUT)/c.normalized.c $@
118+
$(Q)$(RM) $(OUT)/c.normalized.c
112119

113120
$(OUT)/inliner: tools/inliner.c
114121
$(VECHO) " CC+LD\t$@\n"
@@ -146,7 +153,7 @@ clean:
146153
-$(RM) $(OUT)/libc.inc
147154

148155
distclean: clean
149-
-$(RM) $(OUT)/inliner $(OUT)/target $(SRCDIR)/codegen.c config $(BUILD_SESSION)
156+
-$(RM) $(OUT)/inliner $(OUT)/norm-lf $(OUT)/target $(SRCDIR)/codegen.c config $(BUILD_SESSION)
150157
-$(RM) DOM.dot CFG.dot
151158

152159
-include $(deps)

tools/inliner.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
* The inliner is used at build-time, and developers can use the
1111
* "inline C" feature to implement target-specific parts such as
1212
* C runtime and essential libraries.
13+
*
14+
* Note: Input files are preprocessed by norm-lf tool to ensure
15+
* consistent LF (Unix) line endings before processing.
1316
*/
1417

1518
#include <stdbool.h>
@@ -110,7 +113,10 @@ void write_line(char *src)
110113
{
111114
write_str(" __c(\"");
112115
for (int i = 0; src[i]; i++) {
113-
if (src[i] == '\"') {
116+
if (src[i] == '\\') {
117+
write_char('\\');
118+
write_char('\\');
119+
} else if (src[i] == '\"') {
114120
write_char('\\');
115121
write_char('\"');
116122
} else if (src[i] != '\n') {

tools/norm-lf.c

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* Convert all line endings to LF (Unix style)
3+
*
4+
* This tool ensures consistent line endings before processing with inliner.
5+
* It converts CR-only (old Mac) and CRLF (Windows) to LF (Unix).
6+
*/
7+
8+
#include <stdbool.h>
9+
#include <stdio.h>
10+
#include <stdlib.h>
11+
12+
int main(int argc, char *argv[])
13+
{
14+
if (argc != 3) {
15+
fprintf(stderr, "Usage: %s <input> <output>\n", argv[0]);
16+
return 1;
17+
}
18+
19+
FILE *input = fopen(argv[1], "rb");
20+
if (!input) {
21+
fprintf(stderr, "Error: Cannot open input file '%s'\n", argv[1]);
22+
return 1;
23+
}
24+
25+
FILE *output = fopen(argv[2], "wb");
26+
if (!output) {
27+
fprintf(stderr, "Error: Cannot create output file '%s'\n", argv[2]);
28+
fclose(input);
29+
return 1;
30+
}
31+
32+
int c;
33+
int prev_cr = 0;
34+
bool has_crlf = false;
35+
bool has_lf = false;
36+
bool has_cr_only = false;
37+
38+
while ((c = fgetc(input)) != EOF) {
39+
if (c == '\r') {
40+
/* Mark that we saw a CR, but don't output it yet */
41+
prev_cr = 1;
42+
} else if (c == '\n') {
43+
if (prev_cr) {
44+
/* CRLF sequence - output single LF */
45+
has_crlf = true;
46+
} else {
47+
/* LF only */
48+
has_lf = true;
49+
}
50+
fputc('\n', output);
51+
prev_cr = 0;
52+
} else {
53+
if (prev_cr) {
54+
/* CR not followed by LF - convert to LF */
55+
fputc('\n', output);
56+
has_cr_only = true;
57+
}
58+
fputc(c, output);
59+
prev_cr = 0;
60+
}
61+
}
62+
63+
/* Handle CR at end of file */
64+
if (prev_cr) {
65+
fputc('\n', output);
66+
has_cr_only = true;
67+
}
68+
69+
fclose(input);
70+
fclose(output);
71+
72+
/* Report what was found and converted */
73+
if (has_cr_only) {
74+
fprintf(stderr,
75+
"Warning: Converted CR-only line endings to LF in '%s'\n",
76+
argv[1]);
77+
}
78+
if ((has_crlf && has_lf) || (has_crlf && has_cr_only) ||
79+
(has_lf && has_cr_only)) {
80+
fprintf(stderr, "Warning: Converted mixed line endings to LF in '%s'\n",
81+
argv[1]);
82+
}
83+
84+
return 0;
85+
}

0 commit comments

Comments
 (0)