Re: Non-Printable Characters in Strings

Luke-Jr <[email protected]> Tue, 10 Feb 2004 02:38:33 +0000
Newsgroups gmane.comp.lang.moo.general
Message-ID <[email protected]>
--Boundary-00=_pQEKAeI7P17FqXI
Content-Type: Text/Plain;
  charset="utf-8"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

=2D----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Attached is a patch for a vanilla LambdaMOO server to add support for C-sty=
le=20
escape codes, \### (octal), \^@ through \^_ (see ASCII chart for details on=
=20
range), \e, \s1 to \s4, \sf, \sg, \sr, and \su. Octet-based, but VBR length=
=20
numbers for \x##, \o###, and \d### are supported.
This patch does not address \<newline>, and such a sequence will continue t=
o=20
error. It has the potential for memory leaking since character 0x00 can be=
=20
used and the LambdaMOO server cannot properly handle it in strings (yet).
\### can easilly be changed to use decimal, but unless there are any=20
objections, I think octal is more logical. Note that hex is not an option,=
=20
since it would conflict with things such as \a or \b, which are C-style=20
escape codes.
As before, comments are more than welcome. :)

On Wednesday 28 January 2004 12:51 am, Luke-Jr wrote:
> Is C-style escaping of common characters (\n, \r, \t, \v, \x##, etc) a go=
od
> idea? Including C-style's \### which uses octal or should \### use decimal
> (or hex?)?
> Should the following string be permitted (it is currently not)? "this is a
> \ multiline string" or require the programmer to use \n?
> Would it be a good or bad idea to parse \^A through \^Z into character 0x=
01
> to 0x1A? What about parsing \e to 0x1B and \s1 to \s4 and \sf \sg \sr \su
> (seperator characters) to 0x1C to 0x1F?
=2D----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.3 (GNU/Linux)

iD8DBQFAKEQsZl/BHdU+lYMRAuVRAJ4yHURT+Dz5HCwffbuc5jUS4vay6wCdHXLr
Y7dP1hFXts9RBbYJwaTDWYY=3D
=3DyNH5
=2D----END PGP SIGNATURE-----

--Boundary-00=_pQEKAeI7P17FqXI
Content-Type: text/x-diff;
  charset="utf-8";
  name="unprintable-strings-proposal-01.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
	filename="unprintable-strings-proposal-01.patch"

diff -u MOO-1.8.1/list.c MOO-1.8.1.nonprintable-strings/list.c
--- MOO-1.8.1/list.c	2004-01-18 06:51:56.000000000 +0000
+++ MOO-1.8.1.nonprintable-strings/list.c	2004-02-10 02:29:48.337889840 +0000
@@ -288,17 +288,34 @@
 	break;
     case TYPE_STR:
 	{
-	    const char *str = v.v.str;
+	    const unsigned char *str = v.v.str;
 
 	    stream_add_char(s, '"');
 	    while (*str) {
 		switch (*str) {
-		case '"':
-		case '\\':
+		case '\a':	stream_add_string(s, "\\a");	str++;	break;
+		case '\b':	stream_add_string(s, "\\b");	str++;	break;
+		case '\f':	stream_add_string(s, "\\f");	str++;	break;
+		case '\n':	stream_add_string(s, "\\n");	str++;	break;
+		case '\r':	stream_add_string(s, "\\r");	str++;	break;
+		case '\t':	stream_add_string(s, "\\t");	str++;	break;
+		case '\v':	stream_add_string(s, "\\v");	str++;	break;
+		case '\0':	stream_add_string(s, "\\0");	str++;	break;
+		case 0x1B:	stream_add_string(s, "\\e");	str++;	break;
+		case '"':	case '\\':
 		    stream_add_char(s, '\\');
 		    /* fall thru */
 		default:
-		    stream_add_char(s, *str++);
+			if (isprint(*str))
+				stream_add_char(s, *str++);
+			else if (*str < 0x1B) {
+				stream_add_string(s, "\\^");
+				stream_add_char(s, *str++ + 'A' - 1);
+			} else if (*str < 0x20) {
+				stream_add_string(s, "\\s");
+				stream_add_char(s, "fgru"[*str++ - 0x1C]);
+			} else
+				stream_printf(s, "\\x%02x", *str++);
 		}
 	    }
 	    stream_add_char(s, '"');
diff -u MOO-1.8.1/parser.y MOO-1.8.1.nonprintable-strings/parser.y
--- MOO-1.8.1/parser.y	2004-01-18 06:51:56.000000000 +0000
+++ MOO-1.8.1.nonprintable-strings/parser.y	2004-02-10 02:20:36.524778184 +0000
@@ -922,13 +922,67 @@
 	while(1) {
 	    c = lex_getc();
 	    if (c == '"')
-		break;
-	    if (c == '\\')
-		c = lex_getc();
+			break;
 	    if (c == '\n' || c == EOF) {
-		yyerror("Missing quote");
-		break;
+			yyerror("Missing quote");
+			break;
 	    }
+	    if (c == '\\') {
+			int cnum = 0, count, cc;
+			c = lex_getc();
+	    	if (c == '\n' || c == EOF) {
+				yyerror("Missing quote");
+				break;
+		    }
+			if (isdigit(c)) {
+				lex_ungetc(c);
+				c = 'o';	// Render numbers as octal, by default
+			}
+			// The behavior of an unknown escaped character is undefined.
+			isupper(c) && (c = tolower(c));	// isupper is checked for compatibility
+			switch (c) {	/* C-Style */
+			case 'a':	c = '\a';	break;
+			case 'b':	c = '\b';	break;
+			case 'f':	c = '\f';	break;
+			case 'n':	c = '\n';	break;
+			case 'r':	c = '\r';	break;
+			case 't':	c = '\t';	break;
+			case 'v':	c = '\v';	break;
+			/* \0 is parsed as a digit below; if this is ever VBR #s, need a special case */
+#define BASE_ESCAPE(letter, base, length)												\
+			case letter:																\
+				for (count = 0; isxdigit(c = lex_getc()) && count < length; ++count)	\
+					cnum = cnum * base + (strindex("0123456789abcdef",					\
+							(const char *) &c, 0) - 1);									\
+				lex_ungetc(c);															\
+				c = count ? cnum : letter;												\
+				break;
+			BASE_ESCAPE('x', 16, 2)
+			BASE_ESCAPE('d', 10, 3)
+			BASE_ESCAPE('o', 8, 3)
+#undef BASE_ESCAPE
+			case 'e':	c = 0x1B;	// Escape
+			case 's':
+				cc = lex_getc();
+				isupper(cc) && (cc = tolower(cc));
+				switch (cc) {
+				case 'f':	case '1':	c = 0x1C;	break;	// File Seperator
+				case 'g':	case '2':	c = 0x1D;	break;	// Group Seperator
+				case 'r':	case '3':	c = 0x1E;	break;	// Record Seperator
+				case 'u':	case '4':	c = 0x1F;	break;	// Unit Seperator
+				default:
+					lex_ungetc(cc);
+				}
+				break;
+			case '^':	// Ctrl-style escaping A-Z
+				cc = lex_getc();
+				if (cc > 'A' - 2 && c < 'Z' + 6)
+					c = (islower(cc) ? toupper(cc) : cc) - 'A' + 1;
+				else
+					lex_ungetc(cc);
+				break;
+			}
+		}
 	    stream_add_char(token_stream, c);
 	}
 	yylval.string = alloc_string(reset_stream(token_stream));
Common subdirectories: MOO-1.8.1/pgperf and MOO-1.8.1.nonprintable-strings/pgperf

--Boundary-00=_pQEKAeI7P17FqXI--


-------------------------------------------------------
The SF.Net email is sponsored by EclipseCon 2004
Premiere Conference on Open Tools Development and Integration
See the breadth of Eclipse activity. February 3-5 in Anaheim, CA.
http://www.eclipsecon.org/osdn