// stringutil.cpp -- string utilities // // $Id: stringutil.cpp,v 1.24 2000/09/28 18:14:50 sdennis Exp $ // // MUX 2.0 // Portions are derived from MUX 1.6. Portions are original work. // // Copyright (C) 1998 through 2000 Solid Vertical Domains, Ltd. All // rights not explicitly given are reserved. Permission is given to // use this code for building and hosting text-based game servers. // Permission is given to use this code for other non-commercial // purposes. To use this code for commercial purposes other than // building/hosting text-based game servers, contact the author at // Stephen Dennis <sdennis@svdltd.com> for another license. // #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "mudconf.h" #include "alloc.h" #include "ansi.h" char Tiny_IsASCII[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F }; char Tiny_IsPrint[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F }; char Tiny_IsDigit[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 3 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F }; char Tiny_IsAlpha[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 5 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F }; char Tiny_IsAlphaNumeric[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 3 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 5 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F }; char Tiny_IsUpper[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 5 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F }; char Tiny_IsLower[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F }; char Tiny_IsSpace[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, // 0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F }; // Valid characters for an attribute name are letters, // numbers, and characters from the set // {'?!`/-_.@#$^&~=+<>()%}. The first character in an // attribute name must be a letter, and lower-case // letters are turned into uppercase before being used, // but lower-case letters are valid input and the check // for the first character is handled seperately. // char Tiny_IsAttributeNameCharacter[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, // 2 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, // 3 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, // 5 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F }; // Valid characters for an object name are all printable // characters except those from the set {=&|}. // char Tiny_IsObjectNameCharacter[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, // 3 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F }; // Valid characters for a player name are all alphanumeric plus // {`$_-.,'} plus SPACE depending on configuration. // char Tiny_IsPlayerNameCharacter[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, // 2 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 3 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, // 5 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F }; // Characters which should be escaped for the secure() // function: '%$\[](){},;'. // char Tiny_IsSecureCharacter[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, // 2 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // 3 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, // 5 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F }; // Characters which should be escaped for the escape() // function: '%\[]{};'. // char Tiny_IsEscapeCharacter[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // 3 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, // 5 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F }; char ANSI_TokenTerminatorTable[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 5 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F }; unsigned char Tiny_ToUpper[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, // 0 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, // 1 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, // 2 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, // 3 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, // 4 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, // 5 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, // 6 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, // 7 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, // 8 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, // 9 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, // A 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, // B 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, // C 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, // D 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, // E 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF // F }; unsigned char Tiny_ToLower[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, // 0 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, // 1 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, // 2 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, // 3 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, // 4 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, // 5 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, // 6 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, // 7 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, // 8 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, // 9 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, // A 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, // B 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, // C 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, // D 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, // E 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF // F }; // ANSI_lex - This function parses a string and returns two token types. // The type identifies the token type of length nLengthToken0. nLengthToken1 // may also be present and is a token of the -other- type. // int ANSI_lex(int nString, const char *pString, int *nLengthToken0, int *nLengthToken1) { *nLengthToken0 = 0; *nLengthToken1 = 0; const char *p = pString; for (;;) { // Look for an ESC_CHAR // p = strchr(p, ESC_CHAR); if (!p) { // This is the most common case by far. // *nLengthToken0 = nString; return TOKEN_TEXT_ANSI; } // We have an ESC_CHAR. Let's look at the next character. // if (p[1] != '[') { // Could be a '\0' or another non-'[' character. // Move the pointer to position ourselves over it. // And continue looking for an ESC_CHAR. // p = p + 1; continue; } // We found the beginning of an ANSI sequence. // Find the terminating character. // const char *q = p+2; while (ANSI_TokenTerminatorTable[*q] == 0) { q++; } if (q[0] == '\0') { // There was no good terminator. Treat everything like text. // Also, we are at the end of the string, so just return. // *nLengthToken0 = q - pString; return TOKEN_TEXT_ANSI; } else { // We found an ANSI sequence. // if (p == pString) { // The ANSI sequence started it. // *nLengthToken0 = q - pString + 1; return TOKEN_ANSI; } else { // We have TEXT followed by an ANSI sequence. // *nLengthToken0 = p - pString; *nLengthToken1 = q - p + 1; return TOKEN_TEXT_ANSI; } } } } char *strip_ansi(const char *szString, unsigned int *pnString) { static char Buffer[LBUF_SIZE]; char *pBuffer = Buffer; const char *pString = szString; if (!pString) { if (pnString) { *pnString = 0; } *pBuffer = '\0'; return Buffer; } int nString = strlen(szString); while (nString) { int nTokenLength0; int nTokenLength1; int iType = ANSI_lex(nString, pString, &nTokenLength0, &nTokenLength1); if (iType == TOKEN_TEXT_ANSI) { memcpy(pBuffer, pString, nTokenLength0); pBuffer += nTokenLength0; int nSkipLength = nTokenLength0 + nTokenLength1; nString -= nSkipLength; pString += nSkipLength; } else { // TOKEN_ANSI // nString -= nTokenLength0; pString += nTokenLength0; } } if (pnString) { *pnString = pBuffer - Buffer; } *pBuffer = '\0'; return Buffer; } #define ANSI_COLOR_INDEX_BLACK 0 #define ANSI_COLOR_INDEX_RED 1 #define ANSI_COLOR_INDEX_GREEN 2 #define ANSI_COLOR_INDEX_YELLOW 3 #define ANSI_COLOR_INDEX_BLUE 4 #define ANSI_COLOR_INDEX_MAGENTA 5 #define ANSI_COLOR_INDEX_CYAN 6 #define ANSI_COLOR_INDEX_WHITE 7 #define ANSI_COLOR_INDEX_DEFAULT 9 ANSI_ColorState acsRestingStates[2] = { {TRUE, FALSE, FALSE, FALSE, FALSE, ANSI_COLOR_INDEX_DEFAULT, ANSI_COLOR_INDEX_DEFAULT}, {FALSE, FALSE, FALSE, FALSE, FALSE, ANSI_COLOR_INDEX_WHITE, ANSI_COLOR_INDEX_DEFAULT} }; void ANSI_InitColorState(ANSI_ColorState *acsCurrent, BOOL bNoBleed) { int iRestingState = bNoBleed ? 1 : 0; memcpy(acsCurrent, acsRestingStates + iRestingState, sizeof(ANSI_ColorState)); } void ANSI_Parse_m(ANSI_ColorState *pacsCurrent, int nANSI, const char *pANSI, BOOL *pbSawNormal) { // if the last character isn't an 'm', then it's an ANSI sequence we // don't support, yet. TODO: There should be a ANSI_Parse() function // that calls into this one -only- if there's an 'm', but since 'm' // is the only command this game understands at the moment, it's easier // to put the test here. // if (pANSI[nANSI-1] != 'm') { return; } // Process entire string and update the current color state structure. // while (nANSI) { // Process the next attribute phrase (terminated by ';' or 'm' // typically). // const char *p = pANSI; while (Tiny_IsDigit[(unsigned int)*p]) { p++; } int nLen = p - pANSI + 1; if (p[0] == 'm' || p[0] == ';') { // We have an attribute. // if (nLen == 2) { int iCode = pANSI[0] - '0'; switch (iCode) { case 0: // Normal. // ANSI_InitColorState(pacsCurrent, FALSE); *pbSawNormal = TRUE; break; case 1: // High Intensity. // pacsCurrent->bHighlite = TRUE; pacsCurrent->bNormal = FALSE; break; case 2: // Low Intensity. // pacsCurrent->bHighlite = FALSE; pacsCurrent->bNormal = FALSE; break; case 4: // Underline. // pacsCurrent->bUnder = TRUE; pacsCurrent->bNormal = FALSE; break; case 5: // Blinking. // pacsCurrent->bBlink = TRUE; pacsCurrent->bNormal = FALSE; break; case 7: // Reverse Video // pacsCurrent->bInverse = TRUE; pacsCurrent->bNormal = FALSE; break; } } else if (nLen == 3) { int iCode0 = pANSI[0] - '0'; int iCode1 = pANSI[1] - '0'; if (iCode0 == 3) { // Foreground Color // if (iCode1 <= 7) { pacsCurrent->iForeground = iCode1; pacsCurrent->bNormal = FALSE; } } else if (iCode0 == 4) { // Background Color // if (iCode1 <= 7) { pacsCurrent->iBackground = iCode1; pacsCurrent->bNormal = FALSE; } } } } pANSI += nLen; nANSI -= nLen; } } // The following is really 30 (E[0mE[1mE[4mE[5mE[7mE[33mE[43m) but we are // being conservative. // #define ANSI_MAXIMUM_BINARY_TRANSITION_LENGTH 60 // Generate the minimal ANSI sequence that will transition from one color state // to another. // char *ANSI_TransitionColorBinary(ANSI_ColorState *acsCurrent, ANSI_ColorState *acsNext, int *nTransition, BOOL bNoBleed) { static char Buffer[ANSI_MAXIMUM_BINARY_TRANSITION_LENGTH+1]; if (memcmp(acsCurrent, acsNext, sizeof(ANSI_ColorState)) == 0) { *nTransition = 0; Buffer[0] = '\0'; return Buffer; } ANSI_ColorState tmp = *acsCurrent; char *p = Buffer; if (acsNext->bNormal && bNoBleed) { // We can't really go back to normal. We have'ta go to a white // foreground. // ANSI_InitColorState(acsNext, TRUE); } // Do we need to go through the normal state? // if ( tmp.bHighlite && !acsNext->bHighlite || tmp.bUnder && !acsNext->bUnder || tmp.bBlink && !acsNext->bBlink || tmp.bInverse && !acsNext->bInverse || ( tmp.iBackground != ANSI_COLOR_INDEX_DEFAULT && acsNext->iBackground == ANSI_COLOR_INDEX_DEFAULT) || ( tmp.iForeground != ANSI_COLOR_INDEX_DEFAULT && acsNext->iForeground == ANSI_COLOR_INDEX_DEFAULT)) { memcpy(p, ANSI_NORMAL, sizeof(ANSI_NORMAL)-1); p += sizeof(ANSI_NORMAL)-1; ANSI_InitColorState(&tmp, FALSE); } if (tmp.bHighlite != acsNext->bHighlite) { memcpy(p, ANSI_HILITE, sizeof(ANSI_HILITE)-1); p += sizeof(ANSI_HILITE)-1; } if (tmp.bUnder != acsNext->bUnder) { memcpy(p, ANSI_UNDER, sizeof(ANSI_UNDER)-1); p += sizeof(ANSI_UNDER)-1; } if (tmp.bBlink != acsNext->bBlink) { memcpy(p, ANSI_BLINK, sizeof(ANSI_BLINK)-1); p += sizeof(ANSI_BLINK)-1; } if (tmp.bInverse != acsNext->bInverse) { memcpy(p, ANSI_INVERSE, sizeof(ANSI_INVERSE)-1); p += sizeof(ANSI_INVERSE)-1; } if (tmp.iForeground != acsNext->iForeground) { memcpy(p, ANSI_FOREGROUND, sizeof(ANSI_FOREGROUND)-1); p += sizeof(ANSI_FOREGROUND)-1; *p++ = acsNext->iForeground + '0'; *p++ = ANSI_ATTR_CMD; } if (tmp.iBackground != acsNext->iBackground) { memcpy(p, ANSI_BACKGROUND, sizeof(ANSI_BACKGROUND)-1); p += sizeof(ANSI_BACKGROUND)-1; *p++ = acsNext->iBackground + '0'; *p++ = ANSI_ATTR_CMD; } *p = '\0'; *nTransition = p - Buffer; return Buffer; } // The following is really 21 (%cn%ch%cu%ci%cf%cR%cr) but we are being conservative // #define ANSI_MAXIMUM_ESCAPE_TRANSITION_LENGTH 42 // Generate the minimal MU ANSI %-sequence that will transition from one color state // to another. // char *ANSI_TransitionColorEscape(ANSI_ColorState *acsCurrent, ANSI_ColorState *acsNext, int *nTransition) { static char Buffer[ANSI_MAXIMUM_ESCAPE_TRANSITION_LENGTH+1]; static char cForegroundColors[9] = "xrgybmcw"; static char cBackgroundColors[9] = "XRGYBMCW"; if (memcmp(acsCurrent, acsNext, sizeof(ANSI_ColorState)) == 0) { *nTransition = 0; Buffer[0] = '\0'; return Buffer; } ANSI_ColorState tmp = *acsCurrent; char *p = Buffer; // Do we need to go through the normal state? // if ( tmp.bBlink && !acsNext->bBlink || tmp.bHighlite && !acsNext->bHighlite || tmp.bInverse && !acsNext->bInverse || ( tmp.iBackground != ANSI_COLOR_INDEX_DEFAULT && acsNext->iBackground == ANSI_COLOR_INDEX_DEFAULT) || ( tmp.iForeground != ANSI_COLOR_INDEX_DEFAULT && acsNext->iForeground == ANSI_COLOR_INDEX_DEFAULT)) { memcpy(p, "%cn", 3); p += 3; ANSI_InitColorState(&tmp, FALSE); } if (tmp.bHighlite != acsNext->bHighlite) { memcpy(p, "%ch", 3); p += 3; } if (tmp.bUnder != acsNext->bUnder) { memcpy(p, "%cu", 3); p += 3; } if (tmp.bBlink != acsNext->bBlink) { memcpy(p, "%cf", 3); p += 3; } if (tmp.bInverse != acsNext->bInverse) { memcpy(p, "%ci", 3); p += 3; } if (tmp.iForeground != acsNext->iForeground) { memcpy(p, "%c", 2); p += 2; *p++ = cForegroundColors[acsNext->iForeground]; } if (tmp.iBackground != acsNext->iBackground) { memcpy(p, "%c", 2); p += 2; *p++ = cBackgroundColors[acsNext->iBackground]; } *p = '\0'; *nTransition = p - Buffer; return Buffer; } void ANSI_String_Init(struct ANSI_Context *pContext, const char *szString, BOOL bNoBleed) { ANSI_InitColorState(&(pContext->acsCurrent), bNoBleed); pContext->acsPrevious = pContext->acsCurrent; pContext->acsFinal = pContext->acsCurrent; pContext->pString = szString; pContext->nString = strlen(szString); pContext->bNoBleed = bNoBleed; pContext->bSawNormal = FALSE; } void ANSI_String_Skip(struct ANSI_Context *pContext, int maxVisualWidth, int *pnVisualWidth) { *pnVisualWidth = 0; while (pContext->nString) { int nTokenLength0; int nTokenLength1; int iType = ANSI_lex(pContext->nString, pContext->pString, &nTokenLength0, &nTokenLength1); if (iType == TOKEN_TEXT_ANSI) { // Process TEXT // int nTextToSkip = maxVisualWidth - *pnVisualWidth; if (nTokenLength0 > nTextToSkip) { // We have reached the limits of the field // *pnVisualWidth += nTextToSkip; pContext->pString += nTextToSkip; pContext->nString -= nTextToSkip; return; } pContext->pString += nTokenLength0; pContext->nString -= nTokenLength0; *pnVisualWidth += nTokenLength0; pContext->acsPrevious = pContext->acsCurrent; if (nTokenLength1) { // Process ANSI // ANSI_Parse_m(&(pContext->acsCurrent), nTokenLength1, pContext->pString, &(pContext->bSawNormal)); pContext->pString += nTokenLength1; pContext->nString -= nTokenLength1; } } else { // Process ANSI // ANSI_Parse_m(&(pContext->acsCurrent), nTokenLength0, pContext->pString, &(pContext->bSawNormal)); pContext->nString -= nTokenLength0; pContext->pString += nTokenLength0; } } } // ANSI_String_Copy -- Copy characters into a buffer starting at // pField0 with maximum size of nField. Truncate the string if it would // overflow the buffer -or- if it would have a visual with of greater // than maxVisualWidth. Returns the number of ANSI-encoded characters // copied to. Also, the visual width produced by this is returned in // *pnVisualWidth. // // There are three ANSI color states that we deal with in this routine: // // 1. acsPrevious is the color state at the current end of the field. // It has already been encoded into the field. // // 2. acsCurrent is the color state that the current TEXT will be shown // with. It hasn't been encoded into the field, yet, and if we don't // have enough room for at least one character of TEXT, then it may // never be encoded into the field. // // 3. acsFinal is the required color state at the end. This is usually // the normal state or in the case of NOBLEED, it's a specific (and // somewhate arbitrary) foreground/background combination. // int ANSI_String_Copy ( struct ANSI_Context *pC, int nField, char *pField0, int maxVisualWidth, int *pnVisualWidth ) { *pnVisualWidth = 0; char *pField = pField0; while (pC->nString) { int nTokenLength0; int nTokenLength1; int iType = ANSI_lex(pC->nString, pC->pString, &nTokenLength0, &nTokenLength1); if (iType == TOKEN_TEXT_ANSI) { // We have a TEXT+[ANSI] phrase. The text length is given // by nTokenLength0, and the ANSI characters that follow // (if present) are of length nTokenLength1. // // Process TEXT part first. // // TODO: If there is a maximum size for the transitions, // and we have gobs of space, don't bother calculating // sizes so carefully. It might be faster // nFieldEffective is used to allocate and plan space for // the rest of the physical field (given by the current // nField length). // int nFieldEffective = nField - 1; // Leave room for '\0'. // If we lay down -any- of the TEXT part, we need to make // sure we always leave enough room to get back to the // required final ANSI color state. // int nTransitionFinal = 0; if (memcmp(&(pC->acsCurrent), &(pC->acsFinal), sizeof(ANSI_ColorState)) != 0) { // The color state of the TEXT isn't the final state, // so how much room will the transition back to the // final state take? // ANSI_TransitionColorBinary(&(pC->acsCurrent), &(pC->acsFinal), &nTransitionFinal, pC->bNoBleed); nFieldEffective -= nTransitionFinal; } // If we lay down -any- of the TEXT part, it needs to be // the right color. // int nTransition = 0; char *pTransition = ANSI_TransitionColorBinary(&(pC->acsPrevious), &(pC->acsCurrent), &nTransition, pC->bNoBleed); nFieldEffective -= nTransition; // If we find that there is no room for any of the TEXT, // then we're done. // // TODO: The visual width test can be done further up to save time. // if (nFieldEffective <= nTokenLength0 || *pnVisualWidth + nTokenLength0 > maxVisualWidth) { // We have reached the limits of the field. // if (nFieldEffective > 0) { // There was enough physical room in the field, but // we would have exceeded the maximum visual width // if we used all the text. // if (nTransition) { // Encode the TEXT color. // memcpy(pField, pTransition, nTransition); pField += nTransition; } // Place just enough of the TEXT in the field. // int nTextToAdd = maxVisualWidth - *pnVisualWidth; if (nTextToAdd < nFieldEffective) { nFieldEffective = nTextToAdd; } memcpy(pField, pC->pString, nFieldEffective); pField += nFieldEffective; pC->pString += nFieldEffective; pC->nString -= nFieldEffective; *pnVisualWidth += nFieldEffective; pC->acsPrevious = pC->acsCurrent; } if (nTransitionFinal) { char *pTransitionFinal = ANSI_TransitionColorBinary(&(pC->acsPrevious), &(pC->acsFinal), &nTransitionFinal, pC->bNoBleed); memcpy(pField, pTransitionFinal, nTransitionFinal); pField += nTransitionFinal; } *pField = '\0'; return pField - pField0; } if (nTransition) { memcpy(pField, pTransition, nTransition); pField += nTransition; nField -= nTransition; } memcpy(pField, pC->pString, nTokenLength0); pField += nTokenLength0; nField -= nTokenLength0; pC->pString += nTokenLength0; pC->nString -= nTokenLength0; *pnVisualWidth += nTokenLength0; pC->acsPrevious = pC->acsCurrent; if (nTokenLength1) { // Process ANSI // ANSI_Parse_m(&(pC->acsCurrent), nTokenLength1, pC->pString, &(pC->bSawNormal)); pC->pString += nTokenLength1; pC->nString -= nTokenLength1; } } else { // Process ANSI // ANSI_Parse_m(&(pC->acsCurrent), nTokenLength0, pC->pString, &(pC->bSawNormal)); pC->nString -= nTokenLength0; pC->pString += nTokenLength0; } } int nTransition = 0; char *pTransition = ANSI_TransitionColorBinary(&(pC->acsPrevious), &(pC->acsFinal), &nTransition, pC->bNoBleed); if (nTransition) { memcpy(pField, pTransition, nTransition); pField += nTransition; } *pField = '\0'; return pField - pField0; } // Take an ANSI string and fit as much of the information as possible // into a field of size nField. Truncate text. Also make sure that no color // leaks out of the field. // int ANSI_TruncateToField(const char *szString, int nField, char *pField0, int maxVisualWidth, int *pnVisualWidth, BOOL bNoBleed) { if (!szString) { pField0[0] = '\0'; return 0; } struct ANSI_Context state; ANSI_String_Init(&state, szString, bNoBleed); return ANSI_String_Copy(&state, nField, pField0, maxVisualWidth, pnVisualWidth); } char *normal_to_white(const char *szString) { static char Buffer[LBUF_SIZE]; int nVisualWidth; ANSI_TruncateToField(szString, sizeof(Buffer), Buffer, sizeof(Buffer), &nVisualWidth, TRUE); return Buffer; } char MU_EscapeChar[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, // 0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // 2 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, // 5 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F }; // Convert raw character sequences into MUX substitutions (type = 1) // or strips them (type = 0). // char *translate_string(const char *szString, int bConvert) { static char szTranslatedString[LBUF_SIZE]; char *pTranslatedString = szTranslatedString; const char *pString = szString; if (!szString) { *pTranslatedString = '\0'; return szTranslatedString; } int nString = strlen(szString); ANSI_ColorState acsCurrent; ANSI_ColorState acsPrevious; ANSI_InitColorState(&acsCurrent, FALSE); acsPrevious = acsCurrent; BOOL bSawNormal = FALSE; while (nString) { int nTokenLength0; int nTokenLength1; int iType = ANSI_lex(nString, pString, &nTokenLength0, &nTokenLength1); if (iType == TOKEN_TEXT_ANSI) { // Process TEXT // int nTransition = 0; if (bConvert) { char *pTransition = ANSI_TransitionColorEscape(&acsPrevious, &acsCurrent, &nTransition); safe_str(pTransition, szTranslatedString, &pTranslatedString); } nString -= nTokenLength0; while (nTokenLength0--) { int ch = *pString++; if (MU_EscapeChar[ch] == 0) { // Common case: mundane character. // safe_chr(ch, szTranslatedString, &pTranslatedString); continue; } // Handle special characters. '\0' doesn't occur because // nLengthToken0 controls us. // if (ch <= '(') { // LF, CR, SP, %, ( // if (ch <= '\r') { // LF CR // if (ch == '\n') { if (bConvert) safe_str("%r", szTranslatedString, &pTranslatedString); else safe_chr(' ', szTranslatedString, &pTranslatedString); } // Ignore CR on purpose. // } else { // SP % ( // if (ch == ' ') { // The following can look one ahead off the end of the // current token (and even at the '\0' at the end of the // string, but this is acceptable. An extra look will // always see either ESC from the next ANSI sequence, // or the '\0' on the end of the string. No harm done. // if (pString[0] == ' ' && bConvert) safe_str("%b", szTranslatedString, &pTranslatedString); else safe_chr(' ', szTranslatedString, &pTranslatedString); } else if (ch == '%') { if (bConvert) safe_str("%%", szTranslatedString, &pTranslatedString); else safe_chr('%', szTranslatedString, &pTranslatedString); } else { // ( // if (bConvert) safe_str("%(", szTranslatedString, &pTranslatedString); else safe_chr('(', szTranslatedString, &pTranslatedString); } } } else { // ) [ \ ] { } // if (ch <= '\\') { // ) [ \ // if (ch == ')') { if (bConvert) safe_str("%)", szTranslatedString, &pTranslatedString); else safe_chr(')', szTranslatedString, &pTranslatedString); } else if (ch == '[') { if (bConvert) safe_str("%[", szTranslatedString, &pTranslatedString); else safe_chr('[', szTranslatedString, &pTranslatedString); } else { // \ // if (bConvert) safe_str("\\\\", szTranslatedString, &pTranslatedString); else safe_chr('\\', szTranslatedString, &pTranslatedString); } } else { // ] { } // if (ch == ']') { if (bConvert) safe_str("%]", szTranslatedString, &pTranslatedString); else safe_chr(']', szTranslatedString, &pTranslatedString); } else if (ch == '{') { if (bConvert) safe_str("%{", szTranslatedString, &pTranslatedString); else safe_chr('{', szTranslatedString, &pTranslatedString); } else { // } // if (bConvert) safe_str("%}", szTranslatedString, &pTranslatedString); else safe_chr('}', szTranslatedString, &pTranslatedString); } } } } acsPrevious = acsCurrent; if (nTokenLength1) { // Process ANSI // ANSI_Parse_m(&acsCurrent, nTokenLength1, pString, &bSawNormal); pString += nTokenLength1; nString -= nTokenLength1; } } else { // Process ANSI // ANSI_Parse_m(&acsCurrent, nTokenLength0, pString, &bSawNormal); nString -= nTokenLength0; pString += nTokenLength0; } } *pTranslatedString = '\0'; return szTranslatedString; } /* * capitalizes an entire string */ char *upcasestr(char *s) { if (s) { _strupr(s); } return s; } /* * --------------------------------------------------------------------------- * * munge_space: Compress multiple spaces to one space, also remove leading and * * trailing spaces. */ char *munge_space(char *string) { char *buffer, *p, *q; buffer = alloc_lbuf("munge_space"); p = string; q = buffer; if (p) { // Remove initial spaces. // while (Tiny_IsSpace[(unsigned char)*p]) p++; while (*p) { while (*p && !Tiny_IsSpace[(unsigned char)*p]) *q++ = *p++; while (Tiny_IsSpace[(unsigned char)*p]) { p++; } if (*p) *q++ = ' '; } } // Remove terminal spaces and terminate string. // *q = '\0'; return buffer; } /* * --------------------------------------------------------------------------- * * trim_spaces: Remove leading and trailing spaces. */ char *trim_spaces(char *string) { char *buffer, *p, *q; buffer = alloc_lbuf("trim_spaces"); p = string; q = buffer; if (p) { // Remove initial spaces. // while (Tiny_IsSpace[(unsigned char)*p]) p++; while (*p) { // Copy non-space characters. // while (*p && !Tiny_IsSpace[(unsigned char)*p]) *q++ = *p++; // Compress spaces. // while (Tiny_IsSpace[(unsigned char)*p]) p++; // Leave one space. // if (*p) { *q++ = ' '; } } } // Terminate string. // *q = '\0'; return buffer; } /* * --------------------------------------------------------------------------- * * grabto: Return portion of a string up to the indicated character. Also * * returns a modified pointer to the string ready for another call. */ char *grabto(char **str, char targ) { char *savec, *cp; if (!str || !*str || !**str) return NULL; savec = cp = *str; while (*cp && *cp != targ) cp++; if (*cp) *cp++ = '\0'; *str = cp; return savec; } int string_compare(const char *s1, const char *s2) { #ifndef STANDALONE if (!mudconf.space_compress) { return _stricmp(s1, s2); } else { #endif while (Tiny_IsSpace[(unsigned char)*s1]) s1++; while (Tiny_IsSpace[(unsigned char)*s2]) s2++; while (*s1 && *s2 && ( (Tiny_ToLower[(unsigned char)*s1] == Tiny_ToLower[(unsigned char)*s2]) || (Tiny_IsSpace[(unsigned char)*s1] && Tiny_IsSpace[(unsigned char)*s2]))) { if (Tiny_IsSpace[(unsigned char)*s1] && Tiny_IsSpace[(unsigned char)*s2]) { // skip all other spaces. // do { s1++; } while (Tiny_IsSpace[(unsigned char)*s1]); do { s2++; } while (Tiny_IsSpace[(unsigned char)*s2]); } else { s1++; s2++; } } if ((*s1) && (*s2)) return 1; if (Tiny_IsSpace[(unsigned char)*s1]) { while (Tiny_IsSpace[(unsigned char)*s1]) s1++; return *s1; } if (Tiny_IsSpace[(unsigned char)*s2]) { while (Tiny_IsSpace[(unsigned char)*s2]) s2++; return *s2; } if ((*s1) || (*s2)) return 1; return 0; #ifndef STANDALONE } #endif } int string_prefix(const char *string, const char *prefix) { int count = 0; while (*string && *prefix && (Tiny_ToLower[(unsigned char)*string] == Tiny_ToLower[(unsigned char)*prefix])) { string++, prefix++, count++; } if (*prefix == '\0') { // Matched all of prefix. // return count; } else { return 0; } } /* * accepts only nonempty matches starting at the beginning of a word */ const char *string_match(const char *src, const char *sub) { if ((*sub != '\0') && (src)) { while (*src) { if (string_prefix(src, sub)) { return src; } // else scan to beginning of next word // while (Tiny_IsAlphaNumeric[(unsigned char)*src]) { src++; } while (*src && !Tiny_IsAlphaNumeric[(unsigned char)*src]) { src++; } } } return 0; } /* * --------------------------------------------------------------------------- * * replace_string: Returns an lbuf containing string STRING with all occurances * * of OLD replaced by NEW. OLD and NEW may be different lengths. * * (mitch 1 feb 91) */ char *replace_string(const char *old, const char *new0, const char *string) { char *result, *r, *s; int olen; if (!string) { return NULL; } s = (char *)string; olen = strlen(old); r = result = alloc_lbuf("replace_string"); while (*s) { // Find next occurrence of the first character of OLD string. // char *p = strchr(s, old[0]); if (p) { // Copy up to the next occurrence of the first char of OLD. // int n = p - s; if (n) { safe_copy_buf(s, n, result, &r, LBUF_SIZE-1); s += n; } // If we are really at an complete OLD, append NEW to the result // and bump the input string past the occurrence of OLD. // Otherwise, copy the character and try matching again. // if (!strncmp(old, s, olen)) { safe_str((char *)new0, result, &r); s += olen; } else { safe_chr(*s, result, &r); s++; } } else { // Finish copying source string. No matches. No further // work to perform. // safe_str(s, result, &r); break; } } *r = '\0'; return result; } /* * Returns string STRING with all occurances * of OLD replaced by NEW. OLD * and NEW may be different lengths. Modifies string, so: Note - STRING must * already be allocated large enough to handle the new size. (mitch 1 feb 91) */ char *replace_string_inplace(const char *old, const char *new0, char *string) { char *s; s = replace_string(old, new0, string); StringCopy(string, s); free_lbuf(s); return string; } /* * returns the number of identical characters in the two strings */ int prefix_match(const char *s1, const char *s2) { int count = 0; while (*s1 && *s2 && (Tiny_ToLower[(unsigned char)*s1] == Tiny_ToLower[(unsigned char)*s2])) { s1++, s2++, count++; } // If the whole string matched, count the null. (Yes really.) // if (!*s1 && !*s2) { count++; } return count; } int minmatch(char *str, char *target, int min) { while (*str && *target && (Tiny_ToLower[(unsigned char)*str] == Tiny_ToLower[(unsigned char)*target])) { str++; target++; min--; } if (*str) return 0; if (!*target) return 1; return ((min <= 0) ? 1 : 0); } // -------------------------------------------------------------------------- // StringCloneLen: allocate memory and copy string // char *StringCloneLen(const char *str, unsigned int nStr) { char *buff = (char *)MEMALLOC(nStr+1); if (ISOUTOFMEMORY(buff)) { return 0; } memcpy(buff, str, nStr); buff[nStr] = '\0'; return buff; } // -------------------------------------------------------------------------- // StringClone: allocate memory and copy string // char *StringClone(const char *str) { return StringCloneLen(str, strlen(str)); } // -------------------------------------------------------------------------- // BufferCloneLen: allocate memory and copy buffer // char *BufferCloneLen(const char *pBuffer, unsigned int nBuffer) { char *buff = (char *)MEMALLOC(nBuffer); if (ISOUTOFMEMORY(buff)) { return 0; } memcpy(buff, pBuffer, nBuffer); return buff; } /* * --------------------------------------------------------------------------- * * safe_copy_str, safe_copy_chr - Copy buffers, watching for overflows. */ void safe_copy_str(const char *src, char *buff, char **bufp, int nSizeOfBuffer) { if (src == NULL) return; char *tp = *bufp; int left = (buff + nSizeOfBuffer) - tp; while (*src && left > 0) { *tp++ = *src++; left--; } *bufp = tp; } int safe_copy_buf(const char *src, int nLen, char *buff, char **bufp, int nSizeOfBuffer) { int left = (buff + nSizeOfBuffer) - *bufp; if (left < nLen) { nLen = left; } memcpy(*bufp, src, nLen); *bufp += nLen; return nLen; } int matches_exit_from_list(char *str, char *pattern) { char *s; while (*pattern) { for (s = str; /* * check out this one */ ( *s && (Tiny_ToLower[(unsigned char)*s] == Tiny_ToLower[(unsigned char)*pattern]) && *pattern && (*pattern != EXIT_DELIMITER)); s++, pattern++) ; /* * Did we match it all? */ if (*s == '\0') { /* * Make sure nothing afterwards */ while (Tiny_IsSpace[(unsigned char)*pattern]) pattern++; /* * Did we get it? */ if (!*pattern || (*pattern == EXIT_DELIMITER)) return 1; } /* * We didn't get it, find next string to test */ while (*pattern && *pattern++ != EXIT_DELIMITER) ; while (Tiny_IsSpace[(unsigned char)*pattern]) pattern++; } return 0; } char Digits100[201] = "001020304050607080900111213141516171819102122232425262728292\ 031323334353637383930414243444546474849405152535455565758595\ 061626364656667686960717273747576777879708182838485868788898\ 09192939495969798999"; int Tiny_ltoa(long val, char *buf) { char *p = buf; if (val < 0) { *p++ = '-'; val = -val; } unsigned int uval = (unsigned int)val; char *q = p; char *z; while (uval > 99) { z = Digits100 + ((uval % 100) << 1); uval /= 100; *p++ = *z; *p++ = *(z+1); } z = Digits100 + (uval << 1); *p++ = *z; if (uval > 9) { *p++ = *(z+1); } int nLength = p - buf; *p-- = '\0'; // The digits are in reverse order with a possible leading '-' // if the value was negative. q points to the first digit, // and p points to the last digit. // while (q < p) { // Swap characters are *p and *q // char temp = *p; *p = *q; *q = temp; // Move p and first digit towards the middle. // --p; ++q; // Stop when we reach or pass the middle. // } return nLength; } char *Tiny_ltoa_t(long val) { static char buff[12]; Tiny_ltoa(val, buff); return buff; } void safe_ltoa(long val, char *buff, char **bufc, int size) { static char temp[12]; int n = Tiny_ltoa(val, temp); safe_copy_buf(temp, n, buff, bufc, size); } int Tiny_i64toa(INT64 val, char *buf) { char *p = buf; if (val < 0) { *p++ = '-'; val = -val; } char *q = p; char *z; while (val > 99) { z = Digits100 + ((val % 100) << 1); val /= 100; *p++ = *z; *p++ = *(z+1); } z = Digits100 + (val << 1); *p++ = *z; if (val > 9) { *p++ = *(z+1); } int nLength = p - buf; *p-- = '\0'; // The digits are in reverse order with a possible leading '-' // if the value was negative. q points to the first digit, // and p points to the last digit. // while (q < p) { // Swap characters are *p and *q // char temp = *p; *p = *q; *q = temp; // Move p and first digit towards the middle. // --p; ++q; // Stop when we reach or pass the middle. // } return nLength; } char *Tiny_i64toa_t(INT64 val) { static char buff[22]; Tiny_i64toa(val, buff); return buff; } long Tiny_atol(const char *pString) { long sum; int c; int LeadingCharacter; // Leading whitespace // while (Tiny_IsSpace[(unsigned char)*pString]) pString++; // Possible sign // LeadingCharacter = c = *pString++; if (c == '-' || c == '+') { c = *pString++; } sum = 0; // Convert ASCII digits // while (Tiny_IsDigit[(unsigned int)c]) { sum = 10 * sum + (c - '0'); c = *pString++; } // Interpret sign // if (LeadingCharacter == '-') { sum = -sum; } return sum; } INT64 Tiny_atoi64(const char *pString) { INT64 sum; int c; int LeadingCharacter; // Leading whitespace // while (Tiny_IsSpace[(unsigned char)*pString]) pString++; // Possible sign // LeadingCharacter = c = *pString++; if (c == '-' || c == '+') { c = *pString++; } sum = 0; // Convert ASCII digits // while (Tiny_IsDigit[(unsigned int)c]) { sum = 10 * sum + (c - '0'); c = *pString++; } // Interpret sign // if (LeadingCharacter == '-') { sum = -sum; } return sum; } // Tiny_StrTokString, Tiny_StrTokControl, Tiny_StrTokParse. // // These three functions work together to replace the functionality of the // strtok() C runtime library function. Call Tiny_StrTokString() first with // the string to parse, then Tiny_StrTokControl() with the control // characters, and finally Tiny_StrTokParse() to parse out the tokens. // // You may call Tiny_StrTokControl() to change the set of control characters // between Tiny_StrTokParse() calls, however keep in mind that the parsing // may not occur how you intend it to as Tiny_StrTokParse() does not // consume -all- of the controlling delimiters that seperate two tokens. // It consumes only the first one. // void Tiny_StrTokString(TINY_STRTOK_STATE *tts, char *arg_pString) { if (!tts || !arg_pString) return; // Remember the string to parse. // tts->pString = arg_pString; } void Tiny_StrTokControl(TINY_STRTOK_STATE *tts, char *pControl) { if (!tts || !pControl) return; // No character is a control character. // memset(tts->aControl, 0, sizeof(tts->aControl)); // The NUL character is always a control character. // tts->aControl[0] = 1; // Record the user-specified control characters. // while (*pControl) { tts->aControl[(unsigned char)*pControl] = 1; pControl++; } } char *Tiny_StrTokParseLEN(TINY_STRTOK_STATE *tts, int *pnLen) { *pnLen = 0; if (!tts) { return NULL; } char *p = tts->pString; if (!p) { return NULL; } // Skip over leading control characters except for the NUL character. // while (tts->aControl[(unsigned char)*p] && *p) { p++; } char *pReturn = p; // Skip over non-control characters. // while (tts->aControl[(unsigned char)*p] == 0) { p++; } // What is the length of this token? // *pnLen = p - pReturn; // Terminate the token with a NUL. // if (p[0]) { // We found a non-NUL delimiter, so the next call will begin parsing // on the character after this one. // tts->pString = p+1; } else { // We hit the end of the string, so the end of the string is where // the next call will begin. // tts->pString = p; } // Did we find a token? // if (*pnLen > 0) { return pReturn; } else { return NULL; } } char *Tiny_StrTokParse(TINY_STRTOK_STATE *tts) { int nLen; char *p = Tiny_StrTokParseLEN(tts, &nLen); if (p) { p[nLen] = '\0'; } return p; } // This function will filter out any characters in the the set from // the string. // char *RemoveSetOfCharacters(char *pString, char *pSetToRemove) { static char Buffer[LBUF_SIZE]; char *pBuffer = Buffer; int nLen; int nLeft = sizeof(Buffer) - 1; char *p; TINY_STRTOK_STATE tts; Tiny_StrTokString(&tts, pString); Tiny_StrTokControl(&tts, pSetToRemove); for ( p = Tiny_StrTokParseLEN(&tts, &nLen); p && nLeft; p = Tiny_StrTokParseLEN(&tts, &nLen)) { if (nLeft < nLen) { nLen = nLeft; } memcpy(pBuffer, p, nLen); pBuffer += nLen; nLeft -= nLen; } *pBuffer = '\0'; return Buffer; } void DbrefToBuffer_Init(DTB *p, char *arg_buff, char **arg_bufc) { p->bFirst = 1; p->buff = arg_buff; p->bufc = arg_bufc; p->nBufferAvailable = LBUF_SIZE - (*arg_bufc - arg_buff) - 1; } int DbrefToBuffer_Add(DTB *pContext, int i) { char smbuf[SBUF_SIZE]; char *p = smbuf; if (pContext->bFirst) { pContext->bFirst = 0; } else { *p++ = ' '; } *p++ = '#'; p += Tiny_ltoa(i, p); int nLen = p - smbuf; if (nLen > pContext->nBufferAvailable) { // Out of room. // return 0; } memcpy(*(pContext->bufc), smbuf, nLen); *(pContext->bufc) += nLen; pContext->nBufferAvailable -= nLen; return 1; } void DbrefToBuffer_Final(DTB *pContext) { **(pContext->bufc) = '\0'; } #ifndef WIN32 // _stricmp - Compare two strings ignoring case. // int _stricmp(const char *a, const char *b) { return strcasecmp(a,b); } // _stricmp - Compare two strings ignoring case. // int _strnicmp(const char *a, const char *b, int n) { return strncasecmp(a,b,n); } // _strlwr - Convert string to all lower case. // void _strlwr(char *a) { while (*a) { *a = Tiny_ToLower[(unsigned char)*a]; a++; } } // _strupr - Convert string to all upper case. // void _strupr(char *a) { while (*a) { *a = Tiny_ToUpper[(unsigned char)*a]; a++; } } #endif // WIN32 #ifdef WIN32 #define VSNPRINTF _vsnprintf #else // WIN32 #ifdef NEED_VSPRINTF_DCL extern char *vsprintf(char *, char *, va_list); #endif #define VSNPRINTF vsnprintf #endif // WIN32 // Tiny_vsnprintf - Is an sprintf-like function that will not overflow // a buffer of specific size. The size is give by count, and count // should be chosen to include the '\0' termination. // // Returns: A number from 0 to count-1 that is the string length of // the returned (possibly truncated) buffer. // int DCL_CDECL Tiny_vsnprintf(char *buff, int count, const char *fmt, va_list va) { // From the manuals: // // vsnprintf returns the number of characters written, not // including the terminating '\0' character. // // It returns a -1 if an output error occurs. // // It can return a number larger than the size of the buffer // on some systems to indicate how much space it -would- have taken // if not limited by the request. // // On Win32, it can fill the buffer completely without a // null-termination and return -1. // To favor the Unix case, if there is an output error, but // vsnprint doesn't touch the buffer, we avoid undefined trash by // null-terminating the buffer to zero-length before the call. // Not sure that this happens, but it's a cheap precaution. // buff[0] = '\0'; // If Unix version does start touching the buffer, null-terminates, // and returns -1, we are still safe. However, if Unix version // touches the buffer writes garbage, and then returns -1, we may // pass garbage, but this possibility seems very unlikely. // int len = VSNPRINTF(buff, count, fmt, va); if (len < 0 || len > count-1) { if (buff[0] == '\0') { // vsnprintf did not touch the buffer. // len = 0; } else { len = count-1; } } buff[len] = '\0'; return len; } #ifdef MUX21 // Method: Boyer-Moore-Horspool // // This method is a simplification of the Boyer-Moore String Searching // Algorithm, but a useful one. It does not require as much temporary // storage, and the setup costs are not as high as the full Boyer-Moore. // // If we were searching megabytes of data instead of 8KB at most, then // the full Boyer-Moore would make more sense. // #define BMH_LARGE 32767 void BMH_Prepare(BMH_State *bmhState, int nPat, char *pPat) { int k; for (k = 0; k < 128; k++) { bmhState->m_d[k] = nPat; } for (k = 0; k < nPat - 1; k++) { bmhState->m_d[pPat[k]] = nPat - k - 1; } char chLastPat = pPat[nPat-1]; bmhState->m_d[chLastPat] = BMH_LARGE; bmhState->m_skip2 = nPat; for (int i = 0; i < nPat-1; ++i) { if (pPat[i] == chLastPat) { bmhState->m_skip2 = nPat - i - 1; } } } int BMH_Execute(BMH_State *bmhs, int nPat, char *pPat, int nSrc, char *pSrc) { for (int i = nPat-1; i < nSrc; i += bmhState->m_skip2) { while ((i += bmhState->m_d[(unsigned char)(pSrc[i])]) < nSrc) { ; // Nothing. } if (i < BMH_LARGE) { break; } i -= BMH_LARGE; int j = nPat - 1; char *s = pSrc + (i - j); while (--j >= 0 && s[j] == pPat[j]) { ; // Nothing. } if (j < 0) { return s-pSrc; } } return -1; } int BMH_StringSearch(int nPat, char *pPat, int nSrc, char *pSrc) { BMH_State bmhs; BMH_Prepare(&bmhs, nPat, pPat); return BMH_Execute(&bmhs, nPat, pPat, nSrc, pSrc); } void BMH_PrepareI(BMH_State *bmhs, int nPat, char *pPat) { int k; for (k = 0; k < 128; k++) { bmhState->m_d[k] = nPat; } for (k = 0; k < nPat - 1; k++) { bmhState->m_d[Tiny_ToUpper[(unsigned char)pPat[k]]] = nPat - k - 1; bmhState->m_d[Tiny_ToLower[(unsigned char)pPat[k]]] = nPat - k - 1; } char chLastPat = pPat[nPat-1]; bmhState->m_d[Tiny_ToUpper[(unsigned char)chLastPat]] = BMH_LARGE; bmhState->m_d[Tiny_ToLower[(unsigned char)chLastPat]] = BMH_LARGE; bmhState->m_skip2 = nPat; for (int i = 0; i < nPat-1; ++i) { if (pPat[i] == chLastPat) { bmhState->m_skip2 = nPat - i - 1; } } } int BMH_ExecuteI(BMH_State *bmhs, int nPat, char *pPat, int nSrc, char *pSrc) { for (int i = nPat-1; i < nSrc; i += bmhState->m_skip2) { while ((i += bmhState->m_d[(unsigned char)(pSrc[i])]) < nSrc) { ; // Nothing. } if (i < BMH_LARGE) { break; } i -= BMH_LARGE; int j = nPat - 1; char *s = pSrc + (i - j); while ( --j >= 0 && Tiny_ToUpper[(unsigned char)s[j]] == Tiny_ToUpper[(unsigned char)pPat[j]]) { ; // Nothing. } if (j < 0) { return s-pSrc; } } return -1; } int BMH_StringSearchI(int nPat, char *pPat, int nSrc, char *pSrc) { BMH_State *bmhs; BMH_PrepareI(&bmhs, nPat, pPat); return BMH_ExecuteI(&bmhs, nPat, pPat, nSrc, pSrc); } #endif // MUX21