comparison f-demime/ptext_in.c @ 0:7e0d08176f32

f-demime starting code
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 06 May 2023 06:14:03 +0000
parents
children 05651a1b8ba8
comparison
equal deleted inserted replaced
-1:000000000000 0:7e0d08176f32
1 /*
2 * This module implements transformations that are specific to text/plain.
3 */
4
5 #include <sys/types.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <strings.h>
10 #include "defs.h"
11
12 extern void (*dec_outf)();
13 extern FILE *tempfile;
14 extern int text_is_utf8;
15
16 int ptext_has_backslash, ptext_has_linesplit;
17
18 static enum {
19 FPS_GROUND,
20 FPS_CR,
21 FPS_UTF8
22 } first_pass_state;
23 static u_char utf8_buf[4];
24 static unsigned utf8_nbytes, utf8_wptr, unicode;
25 static unsigned out_line_len, trailing_newline;
26
27 static void
28 unit_output(str)
29 char *str;
30 {
31 unsigned newlen;
32
33 newlen = strlen(str);
34 if (out_line_len + newlen >= OUTPUT_LINE_MAX)
35 putc('\\', tempfile);
36 putc('\n', tempfile);
37 out_line_len = 0;
38 ptext_has_linesplit = 1;
39 }
40 fputs(str, tempfile);
41 out_line_len += newlen;
42 trailing_newline = 0;
43 }
44
45 static void
46 newline_out()
47 {
48 putc('\n', tempfile);
49 out_line_len = 0;
50 trailing_newline++;
51 if (trailing_newline > 2)
52 trailing_newline = 2;
53 }
54
55 static void
56 direct_output(ch)
57 {
58 char buf[2];
59
60 buf[0] = ch;
61 buf[1] = '\0';
62 unit_output(buf);
63 }
64
65 static void
66 simple_escape(ch)
67 {
68 char buf[3];
69
70 buf[0] = '\\';
71 buf[1] = ch;
72 buf[2] = '\0';
73 unit_output(buf);
74 }
75
76 static void
77 hex_escape(ch)
78 {
79 char buf[5];
80
81 sprintf(buf, "\\x%02X", ch);
82 unit_output(buf);
83 }
84
85 static void
86 regular_byte(ch)
87 {
88 if (ch == '\\') {
89 ptext_has_backslash = 1;
90 simple_escape(ch);
91 return;
92 }
93 if (ch >= ' ' && ch <= '~') {
94 direct_output(ch);
95 return;
96 }
97 switch (ch) {
98 case 0x07:
99 simple_escape('a');
100 return;
101 case 0x08':
102 simple_escape('b');
103 return;
104 case 0x09:
105 direct_output(ch);
106 return;
107 case 0x0B:
108 simple_escape('v');
109 return;
110 case 0x0C:
111 simple_escape('f');
112 return;
113 case 0x0D:
114 simple_escape('r');
115 return;
116 case 0x1B:
117 simple_escape('e');
118 return;
119 }
120 hex_escape(ch);
121 }
122
123 static int
124 utf8_collect()
125 {
126 switch (utf8_nbytes) {
127 case 2:
128 unicode = ((utf8_buf[0] & 0x1F) << 6) | (utf8_buf[1] & 0x3F);
129 return(1);
130 case 3:
131 unicode = ((utf8_buf[0] & 0x0F) << 12) |
132 ((utf8_buf[1] & 0x3F) << 6) | (utf8_buf[2] & 0x3F);
133 if (unicode & 0xF800)
134 return(1);
135 else
136 return(0);
137 case 4:
138 unicode = ((utf8_buf[0] & 0x07) << 18) |
139 ((utf8_buf[1] & 0x3F) << 12) |
140 ((utf8_buf[2] & 0x3F) << 6) | (utf8_buf[3] & 0x3F);
141 if (unicode & 0x1F0000)
142 return(1);
143 else
144 return(0);
145 default:
146 return(0);
147 }
148 }
149
150 static void
151 unicode_out()
152 {
153 char buf[9];
154
155 if (unicode >= 0x10000)
156 sprintf(buf, "\\U%06u", unicode);
157 else
158 sprintf(buf, "\\u%04u", unicode);
159 unit_output(buf);
160 }
161
162 static void
163 flush_first_pass_state()
164 {
165 unsigned n;
166
167 switch (first_pass_state) {
168 case FPS_CR:
169 regular_byte('\r');
170 break;
171 case FPS_UTF8:
172 for (n = 0; n < utf8_wptr; n++)
173 regular_byte(utf8_buf[n]);
174 break;
175 }
176 first_pass_state = FPS_GROUND;
177 }
178
179 static void
180 first_pass(ch)
181 {
182 if (first_pass_state == FPS_CR && ch == '\n') {
183 first_pass_state = FPS_GROUND;
184 newline_out();
185 return;
186 }
187 if (first_pass_state == FPS_UTF8 && ch >= 0x80 && ch <= 0xBF) {
188 utf8_buf[utf8_wptr++] = ch;
189 if (utf8_wptr < utf8_nbytes)
190 return;
191 if (utf8_collect()) {
192 first_pass_state = FPS_GROUND;
193 unicode_out();
194 return;
195 }
196 }
197 flush_first_pass_state();
198 switch (ch) {
199 case '\n':
200 newline_out();
201 return;
202 case '\r':
203 first_pass_state = FPS_CR;
204 return;
205 }
206 if (!text_is_utf8 || ch < 0xC2 || ch > 0xF7) {
207 regular_byte(ch);
208 return;
209 }
210 first_pass_state = FPS_UTF8;
211 utf8_buf[0] = ch;
212 utf8_wptr = 1;
213 if (ch < 0xE0)
214 utf8_nbytes = 2;
215 else if (ch < 0xF0)
216 utf8_nbytes = 3;
217 else
218 utf8_nbytes = 4;
219 }
220
221 void
222 ptext_conv_init()
223 {
224 dec_outf = first_pass;
225 ptext_has_backslash = 0;
226 ptext_has_linesplit = 0;
227 first_pass_state = FPS_GROUND;
228 out_line_len = 0;
229 trailing_newline = 1;
230 }
231
232 void
233 ptext_conv_finish()
234 {
235 flush_first_pass_state();
236 while (trailing_newline < 2) {
237 putc('\n', tempfile);
238 trailing_newline++;
239 }
240 }