FreeCalypso > hg > falcon-mail-tools
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/f-demime/ptext_in.c Sat May 06 06:14:03 2023 +0000 @@ -0,0 +1,240 @@ +/* + * This module implements transformations that are specific to text/plain. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include "defs.h" + +extern void (*dec_outf)(); +extern FILE *tempfile; +extern int text_is_utf8; + +int ptext_has_backslash, ptext_has_linesplit; + +static enum { + FPS_GROUND, + FPS_CR, + FPS_UTF8 +} first_pass_state; +static u_char utf8_buf[4]; +static unsigned utf8_nbytes, utf8_wptr, unicode; +static unsigned out_line_len, trailing_newline; + +static void +unit_output(str) + char *str; +{ + unsigned newlen; + + newlen = strlen(str); + if (out_line_len + newlen >= OUTPUT_LINE_MAX) + putc('\\', tempfile); + putc('\n', tempfile); + out_line_len = 0; + ptext_has_linesplit = 1; + } + fputs(str, tempfile); + out_line_len += newlen; + trailing_newline = 0; +} + +static void +newline_out() +{ + putc('\n', tempfile); + out_line_len = 0; + trailing_newline++; + if (trailing_newline > 2) + trailing_newline = 2; +} + +static void +direct_output(ch) +{ + char buf[2]; + + buf[0] = ch; + buf[1] = '\0'; + unit_output(buf); +} + +static void +simple_escape(ch) +{ + char buf[3]; + + buf[0] = '\\'; + buf[1] = ch; + buf[2] = '\0'; + unit_output(buf); +} + +static void +hex_escape(ch) +{ + char buf[5]; + + sprintf(buf, "\\x%02X", ch); + unit_output(buf); +} + +static void +regular_byte(ch) +{ + if (ch == '\\') { + ptext_has_backslash = 1; + simple_escape(ch); + return; + } + if (ch >= ' ' && ch <= '~') { + direct_output(ch); + return; + } + switch (ch) { + case 0x07: + simple_escape('a'); + return; + case 0x08': + simple_escape('b'); + return; + case 0x09: + direct_output(ch); + return; + case 0x0B: + simple_escape('v'); + return; + case 0x0C: + simple_escape('f'); + return; + case 0x0D: + simple_escape('r'); + return; + case 0x1B: + simple_escape('e'); + return; + } + hex_escape(ch); +} + +static int +utf8_collect() +{ + switch (utf8_nbytes) { + case 2: + unicode = ((utf8_buf[0] & 0x1F) << 6) | (utf8_buf[1] & 0x3F); + return(1); + case 3: + unicode = ((utf8_buf[0] & 0x0F) << 12) | + ((utf8_buf[1] & 0x3F) << 6) | (utf8_buf[2] & 0x3F); + if (unicode & 0xF800) + return(1); + else + return(0); + case 4: + unicode = ((utf8_buf[0] & 0x07) << 18) | + ((utf8_buf[1] & 0x3F) << 12) | + ((utf8_buf[2] & 0x3F) << 6) | (utf8_buf[3] & 0x3F); + if (unicode & 0x1F0000) + return(1); + else + return(0); + default: + return(0); + } +} + +static void +unicode_out() +{ + char buf[9]; + + if (unicode >= 0x10000) + sprintf(buf, "\\U%06u", unicode); + else + sprintf(buf, "\\u%04u", unicode); + unit_output(buf); +} + +static void +flush_first_pass_state() +{ + unsigned n; + + switch (first_pass_state) { + case FPS_CR: + regular_byte('\r'); + break; + case FPS_UTF8: + for (n = 0; n < utf8_wptr; n++) + regular_byte(utf8_buf[n]); + break; + } + first_pass_state = FPS_GROUND; +} + +static void +first_pass(ch) +{ + if (first_pass_state == FPS_CR && ch == '\n') { + first_pass_state = FPS_GROUND; + newline_out(); + return; + } + if (first_pass_state == FPS_UTF8 && ch >= 0x80 && ch <= 0xBF) { + utf8_buf[utf8_wptr++] = ch; + if (utf8_wptr < utf8_nbytes) + return; + if (utf8_collect()) { + first_pass_state = FPS_GROUND; + unicode_out(); + return; + } + } + flush_first_pass_state(); + switch (ch) { + case '\n': + newline_out(); + return; + case '\r': + first_pass_state = FPS_CR; + return; + } + if (!text_is_utf8 || ch < 0xC2 || ch > 0xF7) { + regular_byte(ch); + return; + } + first_pass_state = FPS_UTF8; + utf8_buf[0] = ch; + utf8_wptr = 1; + if (ch < 0xE0) + utf8_nbytes = 2; + else if (ch < 0xF0) + utf8_nbytes = 3; + else + utf8_nbytes = 4; +} + +void +ptext_conv_init() +{ + dec_outf = first_pass; + ptext_has_backslash = 0; + ptext_has_linesplit = 0; + first_pass_state = FPS_GROUND; + out_line_len = 0; + trailing_newline = 1; +} + +void +ptext_conv_finish() +{ + flush_first_pass_state(); + while (trailing_newline < 2) { + putc('\n', tempfile); + trailing_newline++; + } +}