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++;
+	}
+}