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