mux/src/stringutil.cpp

Go to the documentation of this file.
00001 // stringutil.cpp -- string utilities.
00002 //
00003 // $Id: stringutil.cpp,v 1.75 2006/09/11 23:57:47 sdennis Exp $
00004 //
00005 // MUX 2.4
00006 // Copyright (C) 1998 through 2004 Solid Vertical Domains, Ltd. All
00007 // rights not explicitly given are reserved.
00008 //
00009 #include "copyright.h"
00010 #include "autoconf.h"
00011 #include "config.h"
00012 #include "externs.h"
00013 
00014 #include "ansi.h"
00015 #include "pcre.h"
00016 
00017 const bool mux_isprint[256] =
00018 {
00019 //  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
00020 //
00021     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 0
00022     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 1
00023     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 2
00024     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 3
00025     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 4
00026     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 5
00027     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 6
00028     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,  // 7
00029 
00030     0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0,  // 8
00031     0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1,  // 9
00032     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // A
00033     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // B
00034     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // C
00035     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // D
00036     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // E
00037     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1   // F
00038 };
00039 
00040 const bool mux_isdigit[256] =
00041 {
00042 //  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
00043 //
00044     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 0
00045     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 1
00046     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 2
00047     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,  // 3
00048     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 4
00049     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 5
00050     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 6
00051     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 7
00052 
00053     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 8
00054     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 9
00055     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // A
00056     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // B
00057     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // C
00058     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // D
00059     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // E
00060     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0   // F
00061 };
00062 
00063 const bool mux_ishex[256] =
00064 {
00065 //  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
00066 //
00067     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 0
00068     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 1
00069     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 2
00070     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,  // 3
00071     0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 4
00072     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 5
00073     0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 6
00074     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 7
00075 
00076     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 8
00077     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 9
00078     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // A
00079     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // B
00080     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // C
00081     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // D
00082     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // E
00083     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0   // F
00084 };
00085 
00086 const bool mux_isazAZ[256] =
00087 {
00088 //  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
00089 //
00090     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 0
00091     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 1
00092     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 2
00093     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 3
00094     0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 4
00095     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,  // 5
00096     0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 6
00097     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,  // 7
00098 
00099     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 8
00100     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 9
00101     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // A
00102     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // B
00103     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // C
00104     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // D
00105     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // E
00106     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0   // F
00107 };
00108 
00109 const bool mux_isalpha[256] =
00110 {
00111 //  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
00112 //
00113     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 0
00114     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 1
00115     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 2
00116     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 3
00117     0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 4
00118     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,  // 5
00119     0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 6
00120     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,  // 7
00121 
00122     0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0,  // 8
00123     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1,  // 9
00124     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,  // A
00125     0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,  // B
00126     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // C
00127     1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,  // D
00128     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // E
00129     1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0   // F
00130 };
00131 
00132 const bool mux_isalnum[256] =
00133 {
00134 //  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
00135 //
00136     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 0
00137     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 1
00138     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 2
00139     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,  // 3
00140     0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 4
00141     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,  // 5
00142     0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 6
00143     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,  // 7
00144 
00145     0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0,  // 8
00146     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1,  // 9
00147     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,  // A
00148     0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,  // B
00149     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // C
00150     1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,  // D
00151     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // E
00152     1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0   // F
00153 };
00154 
00155 const bool mux_isupper[256] =
00156 {
00157 //  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
00158 //
00159     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 0
00160     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 1
00161     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 2
00162     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 3
00163     0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 4
00164     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,  // 5
00165     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 6
00166     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 7
00167 
00168     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0,  // 8
00169     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  // 9
00170     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // A
00171     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // B
00172     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // C
00173     1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0,  // D
00174     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // E
00175     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0   // F
00176 };
00177 
00178 const bool mux_islower[256] =
00179 {
00180 //  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
00181 //
00182     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 0
00183     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 1
00184     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 2
00185     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 3
00186     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 4
00187     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 5
00188     0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 6
00189     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,  // 7
00190 
00191     0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 8
00192     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0,  // 9
00193     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,  // A
00194     0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,  // B
00195     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // C
00196     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  // D
00197     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // E
00198     1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0   // F
00199 };
00200 
00201 const bool mux_isspace[256] =
00202 {
00203 //  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
00204 //
00205     0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,  // 0
00206     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 1
00207     1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 2
00208     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 3
00209     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 4
00210     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 5
00211     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 6
00212     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 7
00213 
00214     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 8
00215     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 9
00216     1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // A
00217     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // B
00218     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // C
00219     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // D
00220     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // E
00221     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0   // F
00222 };
00223 
00224 // The first character of an attribute name must be either alphabetic,
00225 // '_', '#', '.', or '~'. It's handled by the following table.
00226 //
00227 // Characters thereafter may be letters, numbers, and characters from
00228 // the set {'?!`/-_.@#$^&~=+<>()}. Lower-case letters are turned into
00229 // uppercase before being used, but lower-case letters are valid input.
00230 //
00231 bool mux_AttrNameInitialSet[256] =
00232 {
00233 //  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
00234 //
00235     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 0
00236     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 1
00237     0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,  // 2
00238     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 3
00239     0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 4
00240     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,  // 5
00241     0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 6
00242     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0,  // 7
00243 
00244     0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0,  // 8
00245     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1,  // 9
00246     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,  // A
00247     0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,  // B
00248     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // C
00249     1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,  // D
00250     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // E
00251     1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0   // F
00252 };
00253 
00254 bool mux_AttrNameSet[256] =
00255 {
00256 //  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
00257 //
00258     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 0
00259     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 1
00260     0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1,  // 2
00261     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1,  // 3
00262     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 4
00263     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,  // 5
00264     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 6
00265     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0,  // 7
00266 
00267     0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0,  // 8
00268     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1,  // 9
00269     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,  // A
00270     0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,  // B
00271     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // C
00272     1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,  // D
00273     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // E
00274     1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0   // F
00275 };
00276 
00277 // Valid characters for an object name are all printable
00278 // characters except those from the set {=&|}.
00279 //
00280 const bool mux_ObjectNameSet[256] =
00281 {
00282 //  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
00283 //
00284     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 0
00285     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 1
00286     1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 2
00287     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1,  // 3
00288     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 4
00289     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 5
00290     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 6
00291     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0,  // 7
00292 
00293     0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0,  // 8
00294     0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1,  // 9
00295     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // A
00296     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // B
00297     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // C
00298     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // D
00299     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // E
00300     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0   // F
00301 };
00302 
00303 // Valid characters for a player name are all alphanumeric plus
00304 // {`$_-.,'} plus SPACE depending on configuration.
00305 //
00306 bool mux_PlayerNameSet[256] =
00307 {
00308 //  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
00309 //
00310     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 0
00311     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 1
00312     1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0,  // 2
00313     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,  // 3
00314     0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 4
00315     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,  // 5
00316     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 6
00317     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,  // 7
00318 
00319     0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0,  // 8
00320     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1,  // 9
00321     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,  // A
00322     0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,  // B
00323     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // C
00324     1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,  // D
00325     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // E
00326     1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0   // F
00327 };
00328 
00329 // Characters which should be escaped for the secure()
00330 // function: '%$\[](){},;'.
00331 //
00332 const bool mux_issecure[256] =
00333 {
00334 //  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
00335 //
00336     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 0
00337     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 1
00338     0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0,  // 2
00339     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,  // 3
00340     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 4
00341     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0,  // 5
00342     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 6
00343     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0,  // 7
00344 
00345     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 8
00346     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 9
00347     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // A
00348     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // B
00349     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // C
00350     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // D
00351     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // E
00352     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0   // F
00353 };
00354 
00355 // Characters which should be escaped for the escape()
00356 // function: '%\[]{};,()^$'.
00357 //
00358 const bool mux_isescape[256] =
00359 {
00360 //  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
00361 //
00362     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 0
00363     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 1
00364     0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0,  // 2
00365     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,  // 3
00366     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 4
00367     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,  // 5
00368     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 6
00369     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0,  // 7
00370 
00371     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 8
00372     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 9
00373     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // A
00374     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // B
00375     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // C
00376     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // D
00377     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // E
00378     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0   // F
00379 };
00380 
00381 const bool ANSI_TokenTerminatorTable[256] =
00382 {
00383 //  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
00384 //
00385     1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 0
00386     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 1
00387     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 2
00388     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 3
00389     0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 4
00390     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,  // 5
00391     0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 6
00392     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,  // 7
00393 
00394     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 8
00395     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 9
00396     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // A
00397     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // B
00398     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // C
00399     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // D
00400     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // E
00401     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0   // F
00402 };
00403 
00404 const unsigned char mux_hex2dec[256] =
00405 {
00406 //  0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
00407 //
00408     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 0
00409     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 1
00410     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 2
00411     0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  0,  0,  0,  0,  0,  0,  // 3
00412     0, 10, 11, 12, 13, 14, 15,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 4
00413     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 5
00414     0, 10, 11, 12, 13, 14, 15,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 6
00415     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 7
00416 
00417     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 8
00418     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // A
00419     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // B
00420     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // C
00421     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // D
00422     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // E
00423     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0   // F
00424 };
00425 
00426 const unsigned char mux_toupper[256] =
00427 {
00428 //   0     1     2     3     4     5     6     7     8     9     A     B     C     D     E     F
00429 //
00430     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, // 0
00431     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, // 1
00432     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, // 2
00433     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, // 3
00434     0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, // 4
00435     0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, // 5
00436     0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, // 6
00437     0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, // 7
00438 
00439     0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, // 8
00440     0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x8A, 0x9B, 0x8C, 0x9D, 0x8E, 0x9F, // 9
00441     0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, // A
00442     0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, // B
00443     0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, // C
00444     0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, // D
00445     0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, // E
00446     0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xF7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xFF  // F
00447 };
00448 
00449 const unsigned char mux_tolower[256] =
00450 {
00451 //   0     1     2     3     4     5     6     7     8     9     A     B     C     D     E     F
00452 //
00453     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, // 0
00454     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, // 1
00455     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, // 2
00456     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, // 3
00457     0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, // 4
00458     0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, // 5
00459     0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, // 6
00460     0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, // 7
00461 
00462     0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x9A, 0x8B, 0x9C, 0x8D, 0x9E, 0x8F, // 8
00463     0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0xFF, // 9
00464     0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, // A
00465     0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, // B
00466     0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, // C
00467     0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xD7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xDF, // D
00468     0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, // E
00469     0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF  // F
00470 };
00471 
00472 const unsigned char mux_StripAccents[256] =
00473 {
00474 //   0     1     2     3     4     5     6     7     8     9     A     B     C     D     E     F
00475 //
00476     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, // 0
00477     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, // 1
00478     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, // 2
00479     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, // 3
00480     0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, // 4
00481     0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, // 5
00482     0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, // 6
00483     0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, // 7
00484 
00485     0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, // 8
00486     0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, // 9
00487     0xA0, 0x21, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0x22, 0xAC, 0xAD, 0xAE, 0xAF, // A
00488     0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0x22, 0xBC, 0xBD, 0xBE, 0x3F, // B
00489     0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0xC6, 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, // C
00490     0x44, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0xD7, 0x4F, 0x55, 0x55, 0x55, 0x55, 0x59, 0x50, 0x42, // D
00491     0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0xE6, 0x63, 0x65, 0x65, 0x65, 0x65, 0x69, 0x69, 0x69, 0x69, // E
00492     0x6F, 0x6E, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0xF7, 0x6F, 0x75, 0x75, 0x75, 0x75, 0x79, 0x70, 0x79, // F
00493 };
00494 
00495 // ANSI_lex - This function parses a string and returns two token types.
00496 // The type identifies the token type of length nLengthToken0. nLengthToken1
00497 // may also be present and is a token of the -other- type.
00498 //
00499 int ANSI_lex(int nString, const char *pString, int *nLengthToken0, int *nLengthToken1)
00500 {
00501     *nLengthToken0 = 0;
00502     *nLengthToken1 = 0;
00503 
00504     const char *p = pString;
00505 
00506     for (;;)
00507     {
00508         // Look for an ESC_CHAR
00509         //
00510         p = strchr(p, ESC_CHAR);
00511         if (!p)
00512         {
00513             // This is the most common case by far.
00514             //
00515             *nLengthToken0 = nString;
00516             return TOKEN_TEXT_ANSI;
00517         }
00518 
00519         // We have an ESC_CHAR. Let's look at the next character.
00520         //
00521         if (p[1] != '[')
00522         {
00523             // Could be a '\0' or another non-'[' character.
00524             // Move the pointer to position ourselves over it.
00525             // And continue looking for an ESC_CHAR.
00526             //
00527             p = p + 1;
00528             continue;
00529         }
00530 
00531         // We found the beginning of an ANSI sequence.
00532         // Find the terminating character.
00533         //
00534         const char *q = p+2;
00535         while (ANSI_TokenTerminatorTable[(unsigned char)*q] == 0)
00536         {
00537             q++;
00538         }
00539         if (q[0] == '\0')
00540         {
00541             // There was no good terminator. Treat everything like text.
00542             // Also, we are at the end of the string, so just return.
00543             //
00544             *nLengthToken0 = q - pString;
00545             return TOKEN_TEXT_ANSI;
00546         }
00547         else
00548         {
00549             // We found an ANSI sequence.
00550             //
00551             if (p == pString)
00552             {
00553                 // The ANSI sequence started it.
00554                 //
00555                 *nLengthToken0 = q - pString + 1;
00556                 return TOKEN_ANSI;
00557             }
00558             else
00559             {
00560                 // We have TEXT followed by an ANSI sequence.
00561                 //
00562                 *nLengthToken0 = p - pString;
00563                 *nLengthToken1 = q - p + 1;
00564                 return TOKEN_TEXT_ANSI;
00565             }
00566         }
00567     }
00568 }
00569 
00570 char *strip_ansi(const char *szString, size_t *pnString)
00571 {
00572     static char Buffer[LBUF_SIZE];
00573     char *pBuffer = Buffer;
00574 
00575     const char *pString = szString;
00576     if (!pString)
00577     {
00578         if (pnString)
00579         {
00580             *pnString = 0;
00581         }
00582         *pBuffer = '\0';
00583         return Buffer;
00584     }
00585     size_t nString = strlen(szString);
00586 
00587     while (nString)
00588     {
00589         int nTokenLength0;
00590         int nTokenLength1;
00591         int iType = ANSI_lex(nString, pString, &nTokenLength0, &nTokenLength1);
00592 
00593         if (iType == TOKEN_TEXT_ANSI)
00594         {
00595             memcpy(pBuffer, pString, nTokenLength0);
00596             pBuffer += nTokenLength0;
00597 
00598             int nSkipLength = nTokenLength0 + nTokenLength1;
00599             nString -= nSkipLength;
00600             pString += nSkipLength;
00601         }
00602         else
00603         {
00604             // TOKEN_ANSI
00605             //
00606             nString -= nTokenLength0;
00607             pString += nTokenLength0;
00608         }
00609     }
00610     if (pnString)
00611     {
00612         *pnString = pBuffer - Buffer;
00613     }
00614     *pBuffer = '\0';
00615     return Buffer;
00616 }
00617 
00618 char *strip_accents(const char *szString, size_t *pnString)
00619 {
00620     static char Buffer[LBUF_SIZE];
00621     char *pBuffer = Buffer;
00622 
00623     const char *pString = szString;
00624     if (pString)
00625     {
00626         while (*pString)
00627         {
00628             *pBuffer = mux_StripAccents(*pString);
00629             pBuffer++;
00630             pString++;
00631         }
00632     }
00633     if (pnString)
00634     {
00635         *pnString = pBuffer - Buffer;
00636     }
00637     *pBuffer = '\0';
00638     return Buffer;
00639 }
00640 
00641 #define ANSI_COLOR_INDEX_BLACK     0
00642 #define ANSI_COLOR_INDEX_RED       1
00643 #define ANSI_COLOR_INDEX_GREEN     2
00644 #define ANSI_COLOR_INDEX_YELLOW    3
00645 #define ANSI_COLOR_INDEX_BLUE      4
00646 #define ANSI_COLOR_INDEX_MAGENTA   5
00647 #define ANSI_COLOR_INDEX_CYAN      6
00648 #define ANSI_COLOR_INDEX_WHITE     7
00649 #define ANSI_COLOR_INDEX_DEFAULT   8
00650 
00651 static const ANSI_ColorState acsRestingStates[3] =
00652 {
00653     {true,  false, false, false, false, ANSI_COLOR_INDEX_DEFAULT, ANSI_COLOR_INDEX_DEFAULT},
00654     {false, false, false, false, false, ANSI_COLOR_INDEX_WHITE,   ANSI_COLOR_INDEX_DEFAULT},
00655     {true,  false, false, false, false, ANSI_COLOR_INDEX_DEFAULT, ANSI_COLOR_INDEX_DEFAULT}
00656 };
00657 
00658 static void ANSI_Parse_m(ANSI_ColorState *pacsCurrent, int nANSI, const char *pANSI,
00659                   bool *pbSawNormal)
00660 {
00661     // If the last character isn't an 'm', then it's an ANSI sequence we
00662     // don't support, yet. TODO: There should be a ANSI_Parse() function
00663     // that calls into this one -only- if there's an 'm', but since 'm'
00664     // is the only command this game understands at the moment, it's easier
00665     // to put the test here.
00666     //
00667     if (pANSI[nANSI-1] != 'm')
00668     {
00669         return;
00670     }
00671 
00672     // Process entire string and update the current color state structure.
00673     //
00674     while (nANSI)
00675     {
00676         // Process the next attribute phrase (terminated by ';' or 'm'
00677         // typically).
00678         //
00679         const char *p = pANSI;
00680         while (mux_isdigit(*p))
00681         {
00682             p++;
00683         }
00684         size_t nLen = p - pANSI + 1;
00685         if (p[0] == 'm' || p[0] == ';')
00686         {
00687             // We have an attribute.
00688             //
00689             if (nLen == 2)
00690             {
00691                 int iCode = pANSI[0] - '0';
00692                 switch (iCode)
00693                 {
00694                 case 0:
00695                     // Normal.
00696                     //
00697                     *pacsCurrent = acsRestingStates[ANSI_ENDGOAL_NORMAL];
00698                     *pbSawNormal = true;
00699                     break;
00700 
00701                 case 1:
00702                     // High Intensity.
00703                     //
00704                     pacsCurrent->bHighlite = true;
00705                     pacsCurrent->bNormal = false;
00706                     break;
00707 
00708                 case 2:
00709                     // Low Intensity.
00710                     //
00711                     pacsCurrent->bHighlite = false;
00712                     pacsCurrent->bNormal = false;
00713                     break;
00714 
00715                 case 4:
00716                     // Underline.
00717                     //
00718                     pacsCurrent->bUnder = true;
00719                     pacsCurrent->bNormal = false;
00720                     break;
00721 
00722                 case 5:
00723                     // Blinking.
00724                     //
00725                     pacsCurrent->bBlink = true;
00726                     pacsCurrent->bNormal = false;
00727                     break;
00728 
00729                 case 7:
00730                     // Reverse Video
00731                     //
00732                     pacsCurrent->bInverse = true;
00733                     pacsCurrent->bNormal = false;
00734                     break;
00735                 }
00736             }
00737             else if (nLen == 3)
00738             {
00739                 int iCode0 = pANSI[0] - '0';
00740                 int iCode1 = pANSI[1] - '0';
00741                 if (iCode0 == 3)
00742                 {
00743                     // Foreground Color
00744                     //
00745                     if (iCode1 <= 7)
00746                     {
00747                         pacsCurrent->iForeground = iCode1;
00748                         pacsCurrent->bNormal = false;
00749                     }
00750                 }
00751                 else if (iCode0 == 4)
00752                 {
00753                     // Background Color
00754                     //
00755                     if (iCode1 <= 7)
00756                     {
00757                         pacsCurrent->iBackground = iCode1;
00758                         pacsCurrent->bNormal = false;
00759                     }
00760                 }
00761             }
00762         }
00763         pANSI += nLen;
00764         nANSI -= nLen;
00765     }
00766 }
00767 
00768 // The following is really 30 (E[0mE[1mE[4mE[5mE[7mE[33mE[43m) but we are
00769 // being conservative.
00770 //
00771 #define ANSI_MAXIMUM_BINARY_TRANSITION_LENGTH 60
00772 
00773 // Generate the minimal ANSI sequence that will transition from one color state
00774 // to another.
00775 //
00776 static char *ANSI_TransitionColorBinary
00777 (
00778     ANSI_ColorState *acsCurrent,
00779     const ANSI_ColorState *pcsNext,
00780     int *nTransition,
00781     int  iEndGoal
00782 )
00783 {
00784     static char Buffer[ANSI_MAXIMUM_BINARY_TRANSITION_LENGTH+1];
00785 
00786     if (memcmp(acsCurrent, pcsNext, sizeof(ANSI_ColorState)) == 0)
00787     {
00788         *nTransition = 0;
00789         Buffer[0] = '\0';
00790         return Buffer;
00791     }
00792     ANSI_ColorState tmp = *acsCurrent;
00793     char *p = Buffer;
00794 
00795     if (pcsNext->bNormal)
00796     {
00797         // With NOBLEED, we can't stay in the normal mode. We must eventually
00798         // be on a white foreground.
00799         //
00800         pcsNext = &acsRestingStates[iEndGoal];
00801     }
00802 
00803     // Do we need to go through the normal state?
00804     //
00805     if (  tmp.bHighlite && !pcsNext->bHighlite
00806        || tmp.bUnder    && !pcsNext->bUnder
00807        || tmp.bBlink    && !pcsNext->bBlink
00808        || tmp.bInverse  && !pcsNext->bInverse
00809        || (  tmp.iBackground != ANSI_COLOR_INDEX_DEFAULT
00810           && pcsNext->iBackground == ANSI_COLOR_INDEX_DEFAULT)
00811        || (  tmp.iForeground != ANSI_COLOR_INDEX_DEFAULT
00812           && pcsNext->iForeground == ANSI_COLOR_INDEX_DEFAULT))
00813     {
00814         memcpy(p, ANSI_NORMAL, sizeof(ANSI_NORMAL)-1);
00815         p += sizeof(ANSI_NORMAL)-1;
00816         tmp = acsRestingStates[ANSI_ENDGOAL_NORMAL];
00817     }
00818     if (tmp.bHighlite != pcsNext->bHighlite)
00819     {
00820         memcpy(p, ANSI_HILITE, sizeof(ANSI_HILITE)-1);
00821         p += sizeof(ANSI_HILITE)-1;
00822     }
00823     if (tmp.bUnder != pcsNext->bUnder)
00824     {
00825         memcpy(p, ANSI_UNDER, sizeof(ANSI_UNDER)-1);
00826         p += sizeof(ANSI_UNDER)-1;
00827     }
00828     if (tmp.bBlink != pcsNext->bBlink)
00829     {
00830         memcpy(p, ANSI_BLINK, sizeof(ANSI_BLINK)-1);
00831         p += sizeof(ANSI_BLINK)-1;
00832     }
00833     if (tmp.bInverse != pcsNext->bInverse)
00834     {
00835         memcpy(p, ANSI_INVERSE, sizeof(ANSI_INVERSE)-1);
00836         p += sizeof(ANSI_INVERSE)-1;
00837     }
00838     if (tmp.iForeground != pcsNext->iForeground)
00839     {
00840         memcpy(p, ANSI_FOREGROUND, sizeof(ANSI_FOREGROUND)-1);
00841         p += sizeof(ANSI_FOREGROUND)-1;
00842         *p++ = pcsNext->iForeground + '0';
00843         *p++ = ANSI_ATTR_CMD;
00844     }
00845     if (tmp.iBackground != pcsNext->iBackground)
00846     {
00847         memcpy(p, ANSI_BACKGROUND, sizeof(ANSI_BACKGROUND)-1);
00848         p += sizeof(ANSI_BACKGROUND)-1;
00849         *p++ = pcsNext->iBackground + '0';
00850         *p++ = ANSI_ATTR_CMD;
00851     }
00852     *p = '\0';
00853     *nTransition = p - Buffer;
00854     return Buffer;
00855 }
00856 
00857 // The following is really 21 (%xn%xh%xu%xi%xf%xR%xr) but we are being conservative
00858 //
00859 #define ANSI_MAXIMUM_ESCAPE_TRANSITION_LENGTH 42
00860 
00861 // Generate the minimal MU ANSI %-sequence that will transition from one color state
00862 // to another.
00863 //
00864 static char *ANSI_TransitionColorEscape
00865 (
00866     ANSI_ColorState *acsCurrent,
00867     ANSI_ColorState *acsNext,
00868     int *nTransition
00869 )
00870 {
00871     static char Buffer[ANSI_MAXIMUM_ESCAPE_TRANSITION_LENGTH+1];
00872     static const char cForegroundColors[9] = "xrgybmcw";
00873     static const char cBackgroundColors[9] = "XRGYBMCW";
00874 
00875     if (memcmp(acsCurrent, acsNext, sizeof(ANSI_ColorState)) == 0)
00876     {
00877         *nTransition = 0;
00878         Buffer[0] = '\0';
00879         return Buffer;
00880     }
00881     ANSI_ColorState tmp = *acsCurrent;
00882     int  i = 0;
00883 
00884     // Do we need to go through the normal state?
00885     //
00886     if (  tmp.bBlink    && !acsNext->bBlink
00887        || tmp.bHighlite && !acsNext->bHighlite
00888        || tmp.bInverse  && !acsNext->bInverse
00889        || (  tmp.iBackground != ANSI_COLOR_INDEX_DEFAULT
00890           && acsNext->iBackground == ANSI_COLOR_INDEX_DEFAULT)
00891        || (  tmp.iForeground != ANSI_COLOR_INDEX_DEFAULT
00892           && acsNext->iForeground == ANSI_COLOR_INDEX_DEFAULT))
00893     {
00894         Buffer[i  ] = '%';
00895         Buffer[i+1] = 'x';
00896         Buffer[i+2] = 'n';
00897         i = i + 3;
00898         tmp = acsRestingStates[ANSI_ENDGOAL_NORMAL];
00899     }
00900     if (tmp.bHighlite != acsNext->bHighlite)
00901     {
00902         Buffer[i  ] = '%';
00903         Buffer[i+1] = 'x';
00904         Buffer[i+2] = 'h';
00905         i = i + 3;
00906     }
00907     if (tmp.bUnder != acsNext->bUnder)
00908     {
00909         Buffer[i  ] = '%';
00910         Buffer[i+1] = 'x';
00911         Buffer[i+2] = 'u';
00912         i = i + 3;
00913     }
00914     if (tmp.bBlink != acsNext->bBlink)
00915     {
00916         Buffer[i  ] = '%';
00917         Buffer[i+1] = 'x';
00918         Buffer[i+2] = 'f';
00919         i = i + 3;
00920     }
00921     if (tmp.bInverse != acsNext->bInverse)
00922     {
00923         Buffer[i  ] = '%';
00924         Buffer[i+1] = 'x';
00925         Buffer[i+2] = 'i';
00926         i = i + 3;
00927     }
00928     if (tmp.iForeground != acsNext->iForeground)
00929     {
00930         Buffer[i  ] = '%';
00931         Buffer[i+1] = 'x';
00932         Buffer[i+2] = cForegroundColors[acsNext->iForeground];
00933         i = i + 3;
00934     }
00935     if (tmp.iBackground != acsNext->iBackground)
00936     {
00937         Buffer[i  ] = '%';
00938         Buffer[i+1] = 'x';
00939         Buffer[i+2] = cBackgroundColors[acsNext->iBackground];
00940         i = i + 3;
00941     }
00942     Buffer[i] = '\0';
00943     *nTransition = i;
00944     return Buffer;
00945 }
00946 
00947 void ANSI_String_In_Init
00948 (
00949     struct ANSI_In_Context *pacIn,
00950     const char *szString,
00951     int        iEndGoal
00952 )
00953 {
00954     pacIn->m_acs = acsRestingStates[iEndGoal];
00955     pacIn->m_p   = szString;
00956     pacIn->m_n   = strlen(szString);
00957     pacIn->m_bSawNormal = false;
00958 }
00959 
00960 void ANSI_String_Out_Init
00961 (
00962     struct ANSI_Out_Context *pacOut,
00963     char *pField,
00964     int   nField,
00965     int   vwMax,
00966     int   iEndGoal
00967 )
00968 {
00969     pacOut->m_acs      = acsRestingStates[ANSI_ENDGOAL_NORMAL];
00970     pacOut->m_bDone    = false;
00971     pacOut->m_iEndGoal = iEndGoal;
00972     pacOut->m_n        = 0;
00973     pacOut->m_nMax     = nField;
00974     pacOut->m_p        = pField;
00975     pacOut->m_vw       = 0;
00976     pacOut->m_vwMax    = vwMax;
00977 }
00978 
00979 void ANSI_String_Skip
00980 (
00981     struct ANSI_In_Context *pacIn,
00982     int   maxVisualWidth,
00983     int  *pnVisualWidth)
00984 {
00985     *pnVisualWidth = 0;
00986     while (pacIn->m_n)
00987     {
00988         int nTokenLength0;
00989         int nTokenLength1;
00990         int iType = ANSI_lex(pacIn->m_n, pacIn->m_p, &nTokenLength0, &nTokenLength1);
00991 
00992         if (iType == TOKEN_TEXT_ANSI)
00993         {
00994             // Process TEXT
00995             //
00996             int nTextToSkip = maxVisualWidth - *pnVisualWidth;
00997             if (nTokenLength0 > nTextToSkip)
00998             {
00999                 // We have reached the limits of the field
01000                 //
01001                 *pnVisualWidth += nTextToSkip;
01002                 pacIn->m_p     += nTextToSkip;
01003                 pacIn->m_n     -= nTextToSkip;
01004                 return;
01005             }
01006 
01007             pacIn->m_p     += nTokenLength0;
01008             pacIn->m_n     -= nTokenLength0;
01009             *pnVisualWidth += nTokenLength0;
01010 
01011             if (nTokenLength1)
01012             {
01013                 // Process ANSI
01014                 //
01015                 ANSI_Parse_m(&(pacIn->m_acs), nTokenLength1, pacIn->m_p, &(pacIn->m_bSawNormal));
01016                 pacIn->m_p     += nTokenLength1;
01017                 pacIn->m_n     -= nTokenLength1;
01018             }
01019         }
01020         else
01021         {
01022             // Process ANSI
01023             //
01024             ANSI_Parse_m(&(pacIn->m_acs), nTokenLength0, pacIn->m_p, &(pacIn->m_bSawNormal));
01025             pacIn->m_n     -= nTokenLength0;
01026             pacIn->m_p     += nTokenLength0;
01027         }
01028     }
01029 }
01030 
01031 // TODO: Rework comment block.
01032 //
01033 // ANSI_String_Copy -- Copy characters into a buffer starting at
01034 // pField0 with maximum size of nField. Truncate the string if it would
01035 // overflow the buffer -or- if it would have a visual with of greater
01036 // than maxVisualWidth. Returns the number of ANSI-encoded characters
01037 // copied to. Also, the visual width produced by this is returned in
01038 // *pnVisualWidth.
01039 //
01040 // There are three ANSI color states that we deal with in this routine:
01041 //
01042 // 1. acsPrevious is the color state at the current end of the field.
01043 //    It has already been encoded into the field.
01044 //
01045 // 2. acsCurrent is the color state that the current TEXT will be shown
01046 //    with. It hasn't been encoded into the field, yet, and if we don't
01047 //    have enough room for at least one character of TEXT, then it may
01048 //    never be encoded into the field.
01049 //
01050 // 3. acsFinal is the required color state at the end. This is usually
01051 //    the normal state or in the case of NOBLEED, it's a specific (and
01052 //    somewhate arbitrary) foreground/background combination.
01053 //
01054 void ANSI_String_Copy
01055 (
01056     struct ANSI_Out_Context *pacOut,
01057     struct ANSI_In_Context  *pacIn,
01058     int maxVisualWidth0
01059 )
01060 {
01061     // Check whether we have previous struck the session limits (given
01062     // by ANSI_String_Out_Init() for field size or visual width.
01063     //
01064     if (pacOut->m_bDone)
01065     {
01066         return;
01067     }
01068 
01069     // What is the working limit for visual width.
01070     //
01071     int vw = 0;
01072     int vwMax = pacOut->m_vwMax;
01073     if (maxVisualWidth0 < vwMax)
01074     {
01075         vwMax = maxVisualWidth0;
01076     }
01077 
01078     // What is the working limit for field size.
01079     //
01080     int nMax = pacOut->m_nMax;
01081 
01082     char *pField = pacOut->m_p;
01083     while (pacIn->m_n)
01084     {
01085         int nTokenLength0;
01086         int nTokenLength1;
01087         int iType = ANSI_lex(pacIn->m_n, pacIn->m_p, &nTokenLength0,
01088             &nTokenLength1);
01089 
01090         if (iType == TOKEN_TEXT_ANSI)
01091         {
01092             // We have a TEXT+[ANSI] phrase. The text length is given
01093             // by nTokenLength0, and the ANSI characters that follow
01094             // (if present) are of length nTokenLength1.
01095             //
01096             // Process TEXT part first.
01097             //
01098             // TODO: If there is a maximum size for the transitions,
01099             // and we have gobs of space, don't bother calculating
01100             // sizes so carefully. It might be faster
01101 
01102             // nFieldEffective is used to allocate and plan space for
01103             // the rest of the physical field (given by the current
01104             // nField length).
01105             //
01106             int nFieldEffective = nMax - 1; // Leave room for '\0'.
01107 
01108             int nTransitionFinal = 0;
01109             if (pacOut->m_iEndGoal <= ANSI_ENDGOAL_NOBLEED)
01110             {
01111                 // If we lay down -any- of the TEXT part, we need to make
01112                 // sure we always leave enough room to get back to the
01113                 // required final ANSI color state.
01114                 //
01115                 if (memcmp( &(pacIn->m_acs),
01116                             &acsRestingStates[pacOut->m_iEndGoal],
01117                             sizeof(ANSI_ColorState)) != 0)
01118                 {
01119                     // The color state of the TEXT isn't the final state,
01120                     // so how much room will the transition back to the
01121                     // final state take?
01122                     //
01123                     ANSI_TransitionColorBinary( &(pacIn->m_acs),
01124                                                 &acsRestingStates[pacOut->m_iEndGoal],
01125                                                 &nTransitionFinal,
01126                                                 pacOut->m_iEndGoal);
01127 
01128                     nFieldEffective -= nTransitionFinal;
01129                 }
01130             }
01131 
01132             // If we lay down -any- of the TEXT part, it needs to be
01133             // the right color.
01134             //
01135             int nTransition = 0;
01136             char *pTransition =
01137                 ANSI_TransitionColorBinary( &(pacOut->m_acs),
01138                                             &(pacIn->m_acs),
01139                                             &nTransition,
01140                                             pacOut->m_iEndGoal);
01141             nFieldEffective -= nTransition;
01142 
01143             // If we find that there is no room for any of the TEXT,
01144             // then we're done.
01145             //
01146             // TODO: The visual width test can be done further up to save time.
01147             //
01148             if (  nFieldEffective <= nTokenLength0
01149                || vw + nTokenLength0 > vwMax)
01150             {
01151                 // We have reached the limits of the field.
01152                 //
01153                 if (nFieldEffective > 0)
01154                 {
01155                     // There was enough physical room in the field, but
01156                     // we would have exceeded the maximum visual width
01157                     // if we used all the text.
01158                     //
01159                     if (nTransition)
01160                     {
01161                         // Encode the TEXT color.
01162                         //
01163                         memcpy(pField, pTransition, nTransition);
01164                         pField += nTransition;
01165                     }
01166 
01167                     // Place just enough of the TEXT in the field.
01168                     //
01169                     int nTextToAdd = vwMax - vw;
01170                     if (nTextToAdd < nFieldEffective)
01171                     {
01172                         nFieldEffective = nTextToAdd;
01173                     }
01174                     memcpy(pField, pacIn->m_p, nFieldEffective);
01175                     pField += nFieldEffective;
01176                     pacIn->m_p += nFieldEffective;
01177                     pacIn->m_n -= nFieldEffective;
01178                     vw += nFieldEffective;
01179                     pacOut->m_acs = pacIn->m_acs;
01180 
01181                     // Was this visual width limit related to the session or
01182                     // the call?
01183                     //
01184                     if (vwMax != maxVisualWidth0)
01185                     {
01186                         pacOut->m_bDone = true;
01187                     }
01188                 }
01189                 else
01190                 {
01191                     // Was size limit related to the session or the call?
01192                     //
01193                     pacOut->m_bDone = true;
01194                 }
01195                 pacOut->m_n += pField - pacOut->m_p;
01196                 pacOut->m_nMax -= pField - pacOut->m_p;
01197                 pacOut->m_p  = pField;
01198                 pacOut->m_vw += vw;
01199                 return;
01200             }
01201 
01202             if (nTransition)
01203             {
01204                 memcpy(pField, pTransition, nTransition);
01205                 pField += nTransition;
01206                 nMax   -= nTransition;
01207             }
01208             memcpy(pField, pacIn->m_p, nTokenLength0);
01209             pField  += nTokenLength0;
01210             nMax    -= nTokenLength0;
01211             pacIn->m_p += nTokenLength0;
01212             pacIn->m_n -= nTokenLength0;
01213             vw += nTokenLength0;
01214             pacOut->m_acs = pacIn->m_acs;
01215 
01216             if (nTokenLength1)
01217             {
01218                 // Process ANSI
01219                 //
01220                 ANSI_Parse_m(&(pacIn->m_acs), nTokenLength1, pacIn->m_p, &(pacIn->m_bSawNormal));
01221                 pacIn->m_p += nTokenLength1;
01222                 pacIn->m_n -= nTokenLength1;
01223             }
01224         }
01225         else
01226         {
01227             // Process ANSI
01228             //
01229             ANSI_Parse_m(&(pacIn->m_acs), nTokenLength0, pacIn->m_p, &(pacIn->m_bSawNormal));
01230             pacIn->m_n -= nTokenLength0;
01231             pacIn->m_p += nTokenLength0;
01232         }
01233     }
01234     pacOut->m_n += pField - pacOut->m_p;
01235     pacOut->m_nMax -= pField - pacOut->m_p;
01236     pacOut->m_p  = pField;
01237     pacOut->m_vw += vw;
01238 }
01239 
01240 int ANSI_String_Finalize
01241 (
01242     struct ANSI_Out_Context *pacOut,
01243     int *pnVisualWidth
01244 )
01245 {
01246     char *pField = pacOut->m_p;
01247     if (pacOut->m_iEndGoal <= ANSI_ENDGOAL_NOBLEED)
01248     {
01249         int nTransition = 0;
01250         char *pTransition =
01251             ANSI_TransitionColorBinary( &(pacOut->m_acs),
01252                                         &acsRestingStates[pacOut->m_iEndGoal],
01253                                         &nTransition, pacOut->m_iEndGoal);
01254         if (nTransition)
01255         {
01256             memcpy(pField, pTransition, nTransition);
01257             pField += nTransition;
01258         }
01259     }
01260     *pField = '\0';
01261     pacOut->m_n += pField - pacOut->m_p;
01262     pacOut->m_p  = pField;
01263     *pnVisualWidth = pacOut->m_vw;
01264     return pacOut->m_n;
01265 }
01266 
01267 // Take an ANSI string and fit as much of the information as possible
01268 // into a field of size nField. Truncate text. Also make sure that no color
01269 // leaks out of the field.
01270 //
01271 int ANSI_TruncateToField
01272 (
01273     const char *szString,
01274     int nField,
01275     char *pField0,
01276     int maxVisualWidth,
01277     int *pnVisualWidth,
01278     int  iEndGoal
01279 )
01280 {
01281     if (!szString)
01282     {
01283         pField0[0] = '\0';
01284         return 0;
01285     }
01286     struct ANSI_In_Context aic;
01287     struct ANSI_Out_Context aoc;
01288     ANSI_String_In_Init(&aic, szString, iEndGoal);
01289     ANSI_String_Out_Init(&aoc, pField0, nField, maxVisualWidth, iEndGoal);
01290     ANSI_String_Copy(&aoc, &aic, maxVisualWidth);
01291     return ANSI_String_Finalize(&aoc, pnVisualWidth);
01292 }
01293 
01294 char *ANSI_TruncateAndPad_sbuf(const char *pString, int nMaxVisualWidth, char fill)
01295 {
01296     char *pStringModified = alloc_sbuf("ANSI_TruncateAndPad_sbuf");
01297     int nAvailable = SBUF_SIZE - nMaxVisualWidth;
01298     int nVisualWidth;
01299     int nLen = ANSI_TruncateToField(pString, nAvailable,
01300         pStringModified, nMaxVisualWidth, &nVisualWidth, ANSI_ENDGOAL_NORMAL);
01301     for (int i = nMaxVisualWidth - nVisualWidth; i > 0; i--)
01302     {
01303         pStringModified[nLen] = fill;
01304         nLen++;
01305     }
01306     pStringModified[nLen] = '\0';
01307     return pStringModified;
01308 }
01309 
01310 char *normal_to_white(const char *szString)
01311 {
01312     static char Buffer[LBUF_SIZE];
01313     int nVisualWidth;
01314     ANSI_TruncateToField( szString,
01315                           sizeof(Buffer),
01316                           Buffer,
01317                           sizeof(Buffer),
01318                           &nVisualWidth,
01319                           ANSI_ENDGOAL_NOBLEED
01320                         );
01321     return Buffer;
01322 }
01323 
01324 typedef struct
01325 {
01326     int len;
01327     char *p;
01328 } LITERAL_STRING_STRUCT;
01329 
01330 static LITERAL_STRING_STRUCT MU_Substitutes[] =
01331 {
01332     { 1, " "  },  // 0
01333     { 1, " "  },  // 1
01334     { 2, "%t" },  // 2
01335     { 2, "%r" },  // 3
01336     { 0, NULL },  // 4
01337     { 2, "%b" },  // 5
01338     { 2, "%%" },  // 6
01339     { 2, "%(" },  // 7
01340     { 2, "%)" },  // 8
01341     { 2, "%[" },  // 9
01342     { 2, "%]" },  // 10
01343     { 2, "%{" },  // 11
01344     { 2, "%}" },  // 12
01345     { 2, "\\\\" } // 13
01346 };
01347 
01348 const unsigned char MU_EscapeConvert[256] =
01349 {
01350 //  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
01351 //
01352     0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 0, 0, 4, 0, 0,  // 0
01353     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 1
01354     1, 0, 0, 0, 0, 6, 0, 0, 7, 8, 0, 0, 0, 0, 0, 0,  // 2
01355     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 3
01356     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 4
01357     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,13,10, 0, 0,  // 5
01358     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 6
01359     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,11, 0,12, 0, 0,  // 7
01360 
01361     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 8
01362     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 9
01363     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // A
01364     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // B
01365     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // C
01366     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // D
01367     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // E
01368     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0   // F
01369 };
01370 
01371 const unsigned char MU_EscapeNoConvert[256] =
01372 {
01373 //  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
01374 //
01375     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 4, 0, 0,  // 0
01376     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 1
01377     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 2
01378     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 3
01379     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 4
01380     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 5
01381     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 6
01382     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 7
01383 
01384     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 8
01385     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 9
01386     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // A
01387     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // B
01388     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // C
01389     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // D
01390     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // E
01391     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0   // F
01392 };
01393 
01394 // Convert raw character sequences into MUX substitutions (type = 1)
01395 // or strips them (type = 0).
01396 //
01397 char *translate_string(const char *szString, bool bConvert)
01398 {
01399     static char szTranslatedString[LBUF_SIZE];
01400     char *pTranslatedString = szTranslatedString;
01401 
01402     const char *pString = szString;
01403     if (!szString)
01404     {
01405         *pTranslatedString = '\0';
01406         return szTranslatedString;
01407     }
01408     size_t nString = strlen(szString);
01409 
01410     ANSI_ColorState acsCurrent;
01411     ANSI_ColorState acsPrevious;
01412     acsCurrent = acsRestingStates[ANSI_ENDGOAL_NOBLEED];
01413     acsPrevious = acsCurrent;
01414     bool bSawNormal = false;
01415     const unsigned char *MU_EscapeChar = (bConvert)? MU_EscapeConvert : MU_EscapeNoConvert;
01416     while (nString)
01417     {
01418         int nTokenLength0;
01419         int nTokenLength1;
01420         int iType = ANSI_lex(nString, pString, &nTokenLength0, &nTokenLength1);
01421 
01422         if (iType == TOKEN_TEXT_ANSI)
01423         {
01424             // Process TEXT
01425             //
01426             int nTransition = 0;
01427             if (bConvert)
01428             {
01429                 char *pTransition = ANSI_TransitionColorEscape(&acsPrevious, &acsCurrent, &nTransition);
01430                 safe_str(pTransition, szTranslatedString, &pTranslatedString);
01431             }
01432             nString -= nTokenLength0;
01433 
01434             while (nTokenLength0--)
01435             {
01436                 unsigned char ch = *pString++;
01437                 unsigned char code = MU_EscapeChar[ch];
01438                 if (code)
01439                 {
01440                     // The following can look one ahead off the end of the
01441                     // current token (and even at the '\0' at the end of the
01442                     // string, but this is acceptable. An extra look will
01443                     // always see either ESC from the next ANSI sequence,
01444                     // or the '\0' on the end of the string. No harm done.
01445                     //
01446                     if (ch == ' ' && pString[0] == ' ')
01447                     {
01448                         code = 5;
01449                     }
01450                     safe_copy_buf(MU_Substitutes[code].p,
01451                         MU_Substitutes[code].len, szTranslatedString,
01452                         &pTranslatedString);
01453                 }
01454                 else
01455                 {
01456                     safe_chr(ch, szTranslatedString, &pTranslatedString);
01457                 }
01458             }
01459             acsPrevious = acsCurrent;
01460 
01461             if (nTokenLength1)
01462             {
01463                 // Process ANSI
01464                 //
01465                 ANSI_Parse_m(&acsCurrent, nTokenLength1, pString, &bSawNormal);
01466                 pString += nTokenLength1;
01467                 nString -= nTokenLength1;
01468             }
01469         }
01470         else
01471         {
01472             // Process ANSI
01473             //
01474             ANSI_Parse_m(&acsCurrent, nTokenLength0, pString, &bSawNormal);
01475             nString -= nTokenLength0;
01476             pString += nTokenLength0;
01477         }
01478     }
01479     *pTranslatedString = '\0';
01480     return szTranslatedString;
01481 }
01482 
01483 /* ---------------------------------------------------------------------------
01484  * munge_space: Compress multiple spaces to one space, also remove leading and
01485  * trailing spaces.
01486  */
01487 char *munge_space(const char *string)
01488 {
01489     char *buffer = alloc_lbuf("munge_space");
01490     const char *p = string;
01491     char *q = buffer;
01492 
01493     if (p)
01494     {
01495         // Remove initial spaces.
01496         //
01497         while (mux_isspace(*p))
01498             p++;
01499 
01500         while (*p)
01501         {
01502             while (*p && !mux_isspace(*p))
01503                 *q++ = *p++;
01504 
01505             while (mux_isspace(*p))
01506             {
01507                 p++;
01508             }
01509 
01510             if (*p)
01511                 *q++ = ' ';
01512         }
01513     }
01514 
01515     // Remove terminal spaces and terminate string.
01516     //
01517     *q = '\0';
01518     return buffer;
01519 }
01520 
01521 /* ---------------------------------------------------------------------------
01522  * trim_spaces: Remove leading and trailing spaces.
01523  */
01524 char *trim_spaces(char *string)
01525 {
01526     char *buffer = alloc_lbuf("trim_spaces");
01527     char *p = string;
01528     char *q = buffer;
01529 
01530     if (p)
01531     {
01532         // Remove initial spaces.
01533         //
01534         while (mux_isspace(*p))
01535         {
01536             p++;
01537         }
01538 
01539         while (*p)
01540         {
01541             // Copy non-space characters.
01542             //
01543             while (*p && !mux_isspace(*p))
01544             {
01545                 *q++ = *p++;
01546             }
01547 
01548             // Compress spaces.
01549             //
01550             while (mux_isspace(*p))
01551             {
01552                 p++;
01553             }
01554 
01555             // Leave one space.
01556             //
01557             if (*p)
01558             {
01559                 *q++ = ' ';
01560             }
01561         }
01562     }
01563 
01564     // Terminate string.
01565     //
01566     *q = '\0';
01567     return buffer;
01568 }
01569 
01570 /*
01571  * ---------------------------------------------------------------------------
01572  * * grabto: Return portion of a string up to the indicated character.  Also
01573  * * returns a modified pointer to the string ready for another call.
01574  */
01575 
01576 char *grabto(char **str, char targ)
01577 {
01578     char *savec, *cp;
01579 
01580     if (!str || !*str || !**str)
01581         return NULL;
01582 
01583     savec = cp = *str;
01584     while (*cp && *cp != targ)
01585         cp++;
01586     if (*cp)
01587         *cp++ = '\0';
01588     *str = cp;
01589     return savec;
01590 }
01591 
01592 int string_compare(const char *s1, const char *s2)
01593 {
01594     if (  mudstate.bStandAlone
01595        || mudconf.space_compress)
01596     {
01597         while (mux_isspace(*s1))
01598         {
01599             s1++;
01600         }
01601         while (mux_isspace(*s2))
01602         {
01603             s2++;
01604         }
01605 
01606         while (  *s1 && *s2
01607               && (  (mux_tolower(*s1) == mux_tolower(*s2))
01608                  || (mux_isspace(*s1) && mux_isspace(*s2))))
01609         {
01610             if (mux_isspace(*s1) && mux_isspace(*s2))
01611             {
01612                 // skip all other spaces.
01613                 //
01614                 do
01615                 {
01616                     s1++;
01617                 } while (mux_isspace(*s1));
01618 
01619                 do
01620                 {
01621                     s2++;
01622                 } while (mux_isspace(*s2));
01623             }
01624             else
01625             {
01626                 s1++;
01627                 s2++;
01628             }
01629         }
01630         if (  *s1
01631            && *s2)
01632         {
01633             return 1;
01634         }
01635 
01636         if (mux_isspace(*s1))
01637         {
01638             while (mux_isspace(*s1))
01639             {
01640                 s1++;
01641             }
01642             return *s1;
01643         }
01644         if (mux_isspace(*s2))
01645         {
01646             while (mux_isspace(*s2))
01647             {
01648                 s2++;
01649             }
01650             return *s2;
01651         }
01652         if (  *s1
01653            || *s2)
01654         {
01655             return 1;
01656         }
01657         return 0;
01658     }
01659     else
01660     {
01661         return mux_stricmp(s1, s2);
01662     }
01663 }
01664 
01665 int string_prefix(const char *string, const char *prefix)
01666 {
01667     int count = 0;
01668 
01669     while (*string && *prefix
01670           && (mux_tolower(*string) == mux_tolower(*prefix)))
01671     {
01672         string++, prefix++, count++;
01673     }
01674     if (*prefix == '\0')
01675     {
01676         // Matched all of prefix.
01677         //
01678         return count;
01679     }
01680     else
01681     {
01682         return 0;
01683     }
01684 }
01685 
01686 /*
01687  * accepts only nonempty matches starting at the beginning of a word
01688  */
01689 
01690 const char *string_match(const char *src, const char *sub)
01691 {
01692     if ((*sub != '\0') && (src))
01693     {
01694         while (*src)
01695         {
01696             if (string_prefix(src, sub))
01697             {
01698                 return src;
01699             }
01700 
01701             // else scan to beginning of next word
01702             //
01703             while (mux_isalnum(*src))
01704             {
01705                 src++;
01706             }
01707             while (*src && !mux_isalnum(*src))
01708             {
01709                 src++;
01710             }
01711         }
01712     }
01713     return 0;
01714 }
01715 
01716 /*
01717  * ---------------------------------------------------------------------------
01718  * * replace_string: Returns an lbuf containing string STRING with all occurances
01719  * * of OLD replaced by NEW. OLD and NEW may be different lengths.
01720  * * (mitch 1 feb 91)
01721  */
01722 
01723 char *replace_string(const char *old, const char *new0, const char *s)
01724 {
01725     if (!s)
01726     {
01727         return NULL;
01728     }
01729     size_t olen = strlen(old);
01730     char *result = alloc_lbuf("replace_string");
01731     char *r = result;
01732     while (*s)
01733     {
01734         // Find next occurrence of the first character of OLD string.
01735         //
01736         const char *p;
01737         if (  olen
01738            && (p = strchr(s, old[0])))
01739         {
01740             // Copy up to the next occurrence of the first char of OLD.
01741             //
01742             size_t n = p - s;
01743             if (n)
01744             {
01745                 safe_copy_buf(s, n, result, &r);
01746                 s += n;
01747             }
01748 
01749             // If we are really at an complete OLD, append NEW to the result
01750             // and bump the input string past the occurrence of OLD.
01751             // Otherwise, copy the character and try matching again.
01752             //
01753             if (!strncmp(old, s, olen))
01754             {
01755                 safe_str(new0, result, &r);
01756                 s += olen;
01757             }
01758             else
01759             {
01760                 safe_chr(*s, result, &r);
01761                 s++;
01762             }
01763         }
01764         else
01765         {
01766             // Finish copying source string. No matches. No further
01767             // work to perform.
01768             //
01769             safe_str(s, result, &r);
01770             break;
01771         }
01772     }
01773     *r = '\0';
01774     return result;
01775 }
01776 
01777 // ---------------------------------------------------------------------------
01778 // replace_tokens: Performs ## and #@ substitution.
01779 //
01780 char *replace_tokens
01781 (
01782     const char *s,
01783     const char *pBound,
01784     const char *pListPlace,
01785     const char *pSwitch
01786 )
01787 {
01788     if (!s)
01789     {
01790         return NULL;
01791     }
01792     char *result = alloc_lbuf("replace_tokens");
01793     char *r = result;
01794 
01795     while (*s)
01796     {
01797         // Find next '#'.
01798         //
01799         const char *p = strchr(s, '#');
01800         if (p)
01801         {
01802             // Copy up to the next occurrence of the first character.
01803             //
01804             size_t n = p - s;
01805             if (n)
01806             {
01807                 safe_copy_buf(s, n, result, &r);
01808                 s += n;
01809             }
01810 
01811             if (  s[1] == '#'
01812                && pBound)
01813             {
01814                 // BOUND_VAR
01815                 //
01816                 safe_str(pBound, result, &r);
01817                 s += 2;
01818             }
01819             else if (  s[1] == '@'
01820                     && pListPlace)
01821             {
01822                 // LISTPLACE_VAR
01823                 //
01824                 safe_str(pListPlace, result, &r);
01825                 s += 2;
01826             }
01827             else if (  s[1] == '$'
01828                     && pSwitch)
01829             {
01830                 // SWITCH_VAR
01831                 //
01832                 safe_str(pSwitch, result, &r);
01833                 s += 2;
01834             }
01835             else
01836             {
01837                 safe_chr(*s, result, &r);
01838                 s++;
01839             }
01840         }
01841         else
01842         {
01843             // Finish copying source string. No matches. No further
01844             // work to perform.
01845             //
01846             safe_str(s, result, &r);
01847             break;
01848         }
01849     }
01850     *r = '\0';
01851     return result;
01852 }
01853 
01854 #if 0
01855 // Returns the number of identical characters in the two strings.
01856 //
01857 int prefix_match(const char *s1, const char *s2)
01858 {
01859     int count = 0;
01860 
01861     while (*s1 && *s2
01862           && (mux_tolower(*s1) == mux_tolower(*s2)))
01863     {
01864         s1++, s2++, count++;
01865     }
01866 
01867     // If the whole string matched, count the null.  (Yes really.)
01868     //
01869     if (!*s1 && !*s2)
01870     {
01871         count++;
01872     }
01873     return count;
01874 }
01875 #endif // 0
01876 
01877 bool minmatch(char *str, char *target, int min)
01878 {
01879     while (*str && *target
01880           && (mux_tolower(*str) == mux_tolower(*target)))
01881     {
01882         str++;
01883         target++;
01884         min--;
01885     }
01886     if (*str)
01887     {
01888         return false;
01889     }
01890     if (!*target)
01891     {
01892         return true;
01893     }
01894     return (min <= 0);
01895 }
01896 
01897 // --------------------------------------------------------------------------
01898 // StringCloneLen: allocate memory and copy string
01899 //
01900 char *StringCloneLen(const char *str, size_t nStr)
01901 {
01902     char *buff = (char *)MEMALLOC(nStr+1);
01903     ISOUTOFMEMORY(buff);
01904     memcpy(buff, str, nStr);
01905     buff[nStr] = '\0';
01906     return buff;
01907 }
01908 
01909 // --------------------------------------------------------------------------
01910 // StringClone: allocate memory and copy string
01911 //
01912 char *StringClone(const char *str)
01913 {
01914     return StringCloneLen(str, strlen(str));
01915 }
01916 
01917 #if 0
01918 // --------------------------------------------------------------------------
01919 // BufferCloneLen: allocate memory and copy buffer
01920 //
01921 char *BufferCloneLen(const char *pBuffer, unsigned int nBuffer)
01922 {
01923     char *buff = (char *)MEMALLOC(nBuffer);
01924     ISOUTOFMEMORY(buff);
01925     memcpy(buff, pBuffer, nBuffer);
01926     return buff;
01927 }
01928 #endif // 0
01929 
01930 /* ---------------------------------------------------------------------------
01931  * safe_copy_str, safe_copy_chr - Copy buffers, watching for overflows.
01932  */
01933 
01934 void safe_copy_str(const char *src, char *buff, char **bufp, int nSizeOfBuffer)
01935 {
01936     if (src == NULL) return;
01937 
01938     char *tp = *bufp;
01939     char *maxtp = buff + nSizeOfBuffer;
01940     while (tp < maxtp && *src)
01941     {
01942         *tp++ = *src++;
01943     }
01944     *bufp = tp;
01945 }
01946 
01947 void safe_copy_str_lbuf(const char *src, char *buff, char **bufp)
01948 {
01949     if (src == NULL)
01950     {
01951         return;
01952     }
01953 
01954     char *tp = *bufp;
01955     char *maxtp = buff + LBUF_SIZE - 1;
01956     while (tp < maxtp && *src)
01957     {
01958         *tp++ = *src++;
01959     }
01960     *bufp = tp;
01961 }
01962 
01963 size_t safe_copy_buf(const char *src, size_t nLen, char *buff, char **bufc)
01964 {
01965     size_t left = LBUF_SIZE - (*bufc - buff) - 1;
01966     if (left < nLen)
01967     {
01968         nLen = left;
01969     }
01970     memcpy(*bufc, src, nLen);
01971     *bufc += nLen;
01972     return nLen;
01973 }
01974 
01975 size_t safe_fill(char *buff, char **bufc, char chFill, size_t nSpaces)
01976 {
01977     // Check for buffer limits.
01978     //
01979     size_t nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1;
01980     if (nSpaces > nBufferAvailable)
01981     {
01982         nSpaces = nBufferAvailable;
01983     }
01984 
01985     // Fill with spaces.
01986     //
01987     memset(*bufc, chFill, nSpaces);
01988     *bufc += nSpaces;
01989     return nSpaces;
01990 }
01991 
01992 bool matches_exit_from_list(char *str, const char *pattern)
01993 {
01994     char *s;
01995 
01996     while (*pattern)
01997     {
01998         for (s = str;   // check out this one
01999              ( *s
02000              && (mux_tolower(*s) == mux_tolower(*pattern))
02001              && *pattern
02002              && (*pattern != EXIT_DELIMITER));
02003              s++, pattern++) ;
02004 
02005         // Did we match it all?
02006         //
02007         if (*s == '\0')
02008         {
02009             // Make sure nothing afterwards
02010             //
02011             while (mux_isspace(*pattern))
02012             {
02013                 pattern++;
02014             }
02015 
02016             // Did we get it?
02017             //
02018             if (  !*pattern
02019                || (*pattern == EXIT_DELIMITER))
02020             {
02021                 return true;
02022             }
02023         }
02024         // We didn't get it, find next string to test
02025         //
02026         while (  *pattern
02027               && *pattern++ != EXIT_DELIMITER)
02028         {
02029             ; // Nothing.
02030         }
02031         while (mux_isspace(*pattern))
02032         {
02033             pattern++;
02034         }
02035     }
02036     return false;
02037 }
02038 
02039 const char Digits100[201] =
02040 "001020304050607080900111213141516171819102122232425262728292\
02041 031323334353637383930414243444546474849405152535455565758595\
02042 061626364656667686960717273747576777879708182838485868788898\
02043 09192939495969798999";
02044 
02045 size_t mux_ltoa(long val, char *buf)
02046 {
02047     char *p = buf;
02048 
02049     if (val < 0)
02050     {
02051         *p++ = '-';
02052         val = -val;
02053     }
02054     unsigned long uval = (unsigned long)val;
02055 
02056     char *q = p;
02057 
02058     const char *z;
02059     while (uval > 99)
02060     {
02061         z = Digits100 + ((uval % 100) << 1);
02062         uval /= 100;
02063         *p++ = *z;
02064         *p++ = *(z+1);
02065     }
02066     z = Digits100 + (uval << 1);
02067     *p++ = *z;
02068     if (uval > 9)
02069     {
02070         *p++ = *(z+1);
02071     }
02072 
02073     size_t nLength = p - buf;
02074     *p-- = '\0';
02075 
02076     // The digits are in reverse order with a possible leading '-'
02077     // if the value was negative. q points to the first digit,
02078     // and p points to the last digit.
02079     //
02080     while (q < p)
02081     {
02082         // Swap characters are *p and *q
02083         //
02084         char temp = *p;
02085         *p = *q;
02086         *q = temp;
02087 
02088         // Move p and first digit towards the middle.
02089         //
02090         --p;
02091         ++q;
02092 
02093         // Stop when we reach or pass the middle.
02094         //
02095     }
02096     return nLength;
02097 }
02098 
02099 char *mux_ltoa_t(long val)
02100 {
02101     static char buff[12];
02102     mux_ltoa(val, buff);
02103     return buff;
02104 }
02105 
02106 void safe_ltoa(long val, char *buff, char **bufc)
02107 {
02108     static char temp[12];
02109     size_t n = mux_ltoa(val, temp);
02110     safe_copy_buf(temp, n, buff, bufc);
02111 }
02112 
02113 size_t mux_i64toa(INT64 val, char *buf)
02114 {
02115     char *p = buf;
02116 
02117     if (val < 0)
02118     {
02119         *p++ = '-';
02120         val = -val;
02121     }
02122     UINT64 uval = (UINT64)val;
02123 
02124     char *q = p;
02125 
02126     const char *z;
02127     while (uval > 99)
02128     {
02129         z = Digits100 + ((uval % 100) << 1);
02130         uval /= 100;
02131         *p++ = *z;
02132         *p++ = *(z+1);
02133     }
02134     z = Digits100 + (uval << 1);
02135     *p++ = *z;
02136     if (uval > 9)
02137     {
02138         *p++ = *(z+1);
02139     }
02140 
02141     size_t nLength = p - buf;
02142     *p-- = '\0';
02143 
02144     // The digits are in reverse order with a possible leading '-'
02145     // if the value was negative. q points to the first digit,
02146     // and p points to the last digit.
02147     //
02148     while (q < p)
02149     {
02150         // Swap characters are *p and *q
02151         //
02152         char temp = *p;
02153         *p = *q;
02154         *q = temp;
02155 
02156         // Move p and first digit towards the middle.
02157         //
02158         --p;
02159         ++q;
02160 
02161         // Stop when we reach or pass the middle.
02162         //
02163     }
02164     return nLength;
02165 }
02166 
02167 #if 0
02168 char *mux_i64toa_t(INT64 val)
02169 {
02170     static char buff[22];
02171     mux_i64toa(val, buff);
02172     return buff;
02173 }
02174 #endif
02175 
02176 void safe_i64toa(INT64 val, char *buff, char **bufc)
02177 {
02178     static char temp[22];
02179     size_t n = mux_i64toa(val, temp);
02180     safe_copy_buf(temp, n, buff, bufc);
02181 }
02182 
02183 const char TableATOI[16][10] =
02184 {
02185     {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9},
02186     { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19},
02187     { 20, 21, 22, 23, 24, 25, 26, 27, 28, 29},
02188     { 30, 31, 32, 33, 34, 35, 36, 37, 38, 39},
02189     { 40, 41, 42, 43, 44, 45, 46, 47, 48, 49},
02190     { 50, 51, 52, 53, 54, 55, 56, 57, 58, 59},
02191     { 60, 61, 62, 63, 64, 65, 66, 67, 68, 69},
02192     { 70, 71, 72, 73, 74, 75, 76, 77, 78, 79},
02193     { 80, 81, 82, 83, 84, 85, 86, 87, 88, 89},
02194     { 90, 91, 92, 93, 94, 95, 96, 97, 98, 99}
02195 };
02196 
02197 long mux_atol(const char *pString)
02198 {
02199     long sum = 0;
02200     int LeadingCharacter = 0;
02201 
02202     // Convert ASCII digits
02203     //
02204     unsigned int c1;
02205     unsigned int c0 = pString[0];
02206     if (!mux_isdigit(c0))
02207     {
02208         while (mux_isspace(pString[0]))
02209         {
02210             pString++;
02211         }
02212         LeadingCharacter = pString[0];
02213         if (  LeadingCharacter == '-'
02214            || LeadingCharacter == '+')
02215         {
02216             pString++;
02217         }
02218         c0 = pString[0];
02219         if (!mux_isdigit(c0))
02220         {
02221             return 0;
02222         }
02223     }
02224 
02225     do
02226     {
02227         c1 = pString[1];
02228         if (mux_isdigit(c1))
02229         {
02230             sum = 100 * sum + TableATOI[c0-'0'][c1-'0'];
02231             pString += 2;
02232         }
02233         else
02234         {
02235             sum = 10 * sum + (c0-'0');
02236             break;
02237         }
02238     } while (mux_isdigit(c0 = pString[0]));
02239 
02240     // Interpret sign
02241     //
02242     if (LeadingCharacter == '-')
02243     {
02244         sum = -sum;
02245     }
02246     return sum;
02247 }
02248 
02249 INT64 mux_atoi64(const char *pString)
02250 {
02251     INT64 sum = 0;
02252     int LeadingCharacter = 0;
02253 
02254     // Convert ASCII digits
02255     //
02256     unsigned int c1;
02257     unsigned int c0 = pString[0];
02258     if (!mux_isdigit(c0))
02259     {
02260         while (mux_isspace(pString[0]))
02261         {
02262             pString++;
02263         }
02264         LeadingCharacter = pString[0];
02265         if (  LeadingCharacter == '-'
02266            || LeadingCharacter == '+')
02267         {
02268             pString++;
02269         }
02270         c0 = pString[0];
02271         if (!mux_isdigit(c0))
02272         {
02273             return 0;
02274         }
02275     }
02276 
02277     do
02278     {
02279         c1 = pString[1];
02280         if (mux_isdigit(c1))
02281         {
02282             sum = 100 * sum + TableATOI[c0-'0'][c1-'0'];
02283             pString += 2;
02284         }
02285         else
02286         {
02287             sum = 10 * sum + (c0-'0');
02288             break;
02289         }
02290     } while (mux_isdigit(c0 = pString[0]));
02291 
02292     // Interpret sign
02293     //
02294     if (LeadingCharacter == '-')
02295     {
02296         sum = -sum;
02297     }
02298     return sum;
02299 }
02300 
02301 // Floating-point strings match one of the following patterns:
02302 //
02303 // [+-]?[0-9]?(.[0-9]+)([eE][+-]?[0-9]{1,3})?
02304 // [+-]?[0-9]+(.[0-9]?)([eE][+-]?[0-9]{1,3})?
02305 // +Inf
02306 // -Inf
02307 // Ind
02308 // NaN
02309 //
02310 bool ParseFloat(PARSE_FLOAT_RESULT *pfr, const char *str, bool bStrict)
02311 {
02312     memset(pfr, 0, sizeof(PARSE_FLOAT_RESULT));
02313 
02314     // Parse Input
02315     //
02316     unsigned char ch;
02317     pfr->pMeat = str;
02318     if (  !mux_isdigit(*str)
02319        && *str != '.')
02320     {
02321         while (mux_isspace(*str))
02322         {
02323             str++;
02324         }
02325 
02326         pfr->pMeat = str;
02327         if (*str == '-')
02328         {
02329             pfr->iLeadingSign = '-';
02330             str++;
02331         }
02332         else if (*str == '+')
02333         {
02334             pfr->iLeadingSign = '+';
02335             str++;
02336         }
02337 
02338         if (  !mux_isdigit(*str)
02339            && *str != '.')
02340         {
02341             // Look for three magic strings.
02342             //
02343             ch = mux_toupper(str[0]);
02344             if (ch == 'I')
02345             {
02346                 // Could be 'Inf' or 'Ind'
02347                 //
02348                 ch = mux_toupper(str[1]);
02349                 if (ch == 'N')
02350                 {
02351                     ch = mux_toupper(str[2]);
02352                     if (ch == 'F')
02353                     {
02354                         // Inf
02355                         //
02356                         if (pfr->iLeadingSign == '-')
02357                         {
02358                             pfr->iString = IEEE_MAKE_NINF;
02359                         }
02360                         else
02361                         {
02362                             pfr->iString = IEEE_MAKE_PINF;
02363                         }
02364                         str += 3;
02365                         goto LastSpaces;
02366                     }
02367                     else if (ch == 'D')
02368                     {
02369                         // Ind
02370                         //
02371                         pfr->iString = IEEE_MAKE_IND;
02372                         str += 3;
02373                         goto LastSpaces;
02374                     }
02375                 }
02376             }
02377             else if (ch == 'N')
02378             {
02379                 // Could be 'Nan'
02380                 //
02381                 ch = mux_toupper(str[1]);
02382                 if (ch == 'A')
02383                 {
02384                     ch = mux_toupper(str[2]);
02385                     if (ch == 'N')
02386                     {
02387                         // Nan
02388                         //
02389                         pfr->iString = IEEE_MAKE_NAN;
02390                         str += 3;
02391                         goto LastSpaces;
02392                     }
02393                 }
02394             }
02395             return false;
02396         }
02397     }
02398 
02399     // At this point, we have processed the leading sign, handled all
02400     // the magic strings, skipped the leading spaces, and best of all
02401     // we either have a digit or a decimal point.
02402     //
02403     pfr->pDigitsA = str;
02404     while (mux_isdigit(*str))
02405     {
02406         pfr->nDigitsA++;
02407         str++;
02408     }
02409 
02410     if (*str == '.')
02411     {
02412         str++;
02413     }
02414 
02415     pfr->pDigitsB = str;
02416     while (mux_isdigit(*str))
02417     {
02418         pfr->nDigitsB++;
02419         str++;
02420     }
02421 
02422     if (  pfr->nDigitsA == 0
02423        && pfr->nDigitsB == 0)
02424     {
02425         return false;
02426     }
02427 
02428     ch = mux_toupper(*str);
02429     if (ch == 'E')
02430     {
02431         // There is an exponent portion.
02432         //
02433         str++;
02434         if (*str == '-')
02435         {
02436             pfr->iExponentSign = '-';
02437             str++;
02438         }
02439         else if (*str == '+')
02440         {
02441             pfr->iExponentSign = '+';
02442             str++;
02443         }
02444         pfr->pDigitsC = str;
02445         while (mux_isdigit(*str))
02446         {
02447             pfr->nDigitsC++;
02448             str++;
02449         }
02450 
02451         if (  pfr->nDigitsC < 1
02452            || 4 < pfr->nDigitsC)
02453         {
02454             return false;
02455         }
02456     }
02457 
02458 LastSpaces:
02459 
02460     pfr->nMeat = str - pfr->pMeat;
02461 
02462     // Trailing spaces.
02463     //
02464     while (mux_isspace(*str))
02465     {
02466         str++;
02467     }
02468 
02469     if (bStrict)
02470     {
02471         return (!*str);
02472     }
02473     else
02474     {
02475         return true;
02476     }
02477 }
02478 
02479 #define ATOF_LIMIT 100
02480 static const double powerstab[10] =
02481 {
02482             1.0,
02483            10.0,
02484           100.0,
02485          1000.0,
02486         10000.0,
02487        100000.0,
02488       1000000.0,
02489      10000000.0,
02490     100000000.0,
02491    1000000000.0
02492 };
02493 
02494 double mux_atof(char *szString, bool bStrict)
02495 {
02496     PARSE_FLOAT_RESULT pfr;
02497     if (!ParseFloat(&pfr, szString, bStrict))
02498     {
02499         return 0.0;
02500     }
02501 
02502     if (pfr.iString)
02503     {
02504         // Return the double value which corresponds to the
02505         // string when HAVE_IEEE_FORMAT.
02506         //
02507 #ifdef HAVE_IEEE_FP_FORMAT
02508         return MakeSpecialFloat(pfr.iString);
02509 #else // HAVE_IEEE_FP_FORMAT
02510         return 0.0;
02511 #endif // HAVE_IEEE_FP_FORMAT
02512     }
02513 
02514     // See if we can shortcut the decoding process.
02515     //
02516     double ret;
02517     if (  pfr.nDigitsA <= 9
02518        && pfr.nDigitsC == 0)
02519     {
02520         if (pfr.nDigitsB <= 9)
02521         {
02522             if (pfr.nDigitsB == 0)
02523             {
02524                 // This 'floating-point' number is just an integer.
02525                 //
02526                 ret = (double)mux_atol(pfr.pDigitsA);
02527             }
02528             else
02529             {
02530                 // This 'floating-point' number is fixed-point.
02531                 //
02532                 double rA = (double)mux_atol(pfr.pDigitsA);
02533                 double rB = (double)mux_atol(pfr.pDigitsB);
02534                 double rScale = powerstab[pfr.nDigitsB];
02535                 ret = rA + rB/rScale;
02536 
02537                 // As it is, ret is within a single bit of what a
02538                 // a call to atof would return. However, we can
02539                 // achieve that last lowest bit of precision by
02540                 // computing a residual.
02541                 //
02542                 double residual = (ret - rA)*rScale;
02543                 ret += (rB - residual)/rScale;
02544             }
02545             if (pfr.iLeadingSign == '-')
02546             {
02547                 ret = -ret;
02548             }
02549             return ret;
02550         }
02551     }
02552 
02553     const char *p = pfr.pMeat;
02554     size_t n = pfr.nMeat;
02555 
02556     // We need to protect certain libraries from going nuts from being
02557     // force fed lots of ASCII.
02558     //
02559     char *pTmp = NULL;
02560     if (n > ATOF_LIMIT)
02561     {
02562         pTmp = alloc_lbuf("mux_atof");
02563         memcpy(pTmp, p, ATOF_LIMIT);
02564         pTmp[ATOF_LIMIT] = '\0';
02565         p = pTmp;
02566     }
02567 
02568     ret = mux_strtod(p, NULL);
02569 
02570     if (pTmp)
02571     {
02572         free_lbuf(pTmp);
02573     }
02574 
02575     return ret;
02576 }
02577 
02578 char *mux_ftoa(double r, bool bRounded, int frac)
02579 {
02580     static char buffer[100];
02581     char *q = buffer;
02582     char *rve = NULL;
02583     int iDecimalPoint = 0;
02584     int bNegative = 0;
02585     int mode = 0;
02586     int nRequest = 50;
02587 
02588     if (bRounded)
02589     {
02590         mode = 3;
02591         nRequest = frac;
02592         if (50 < nRequest)
02593         {
02594             nRequest = 50;
02595         }
02596         else if (nRequest < -20)
02597         {
02598             nRequest = -20;
02599         }
02600     }
02601     char *p = mux_dtoa(r, mode, nRequest, &iDecimalPoint, &bNegative, &rve);
02602     int nSize = rve - p;
02603     if (nSize > 50)
02604     {
02605         nSize = 50;
02606     }
02607 
02608     if (bNegative)
02609     {
02610         *q++ = '-';
02611     }
02612 
02613     if (iDecimalPoint == 9999)
02614     {
02615         // Inf or NaN
02616         //
02617         memcpy(q, p, nSize);
02618         q += nSize;
02619     }
02620     else if (nSize <= 0)
02621     {
02622         // Zero
02623         //
02624         if (bNegative)
02625         {
02626             // If we laid down a minus sign, we should remove it.
02627             //
02628             q--;
02629         }
02630         *q++ = '0';
02631         if (  bRounded
02632            && 0 < nRequest)
02633         {
02634             *q++ = '.';
02635             memset(q, '0', nRequest);
02636             q += nRequest;
02637         }
02638     }
02639     else if (  iDecimalPoint <= -6
02640             || 18 <= iDecimalPoint)
02641     {
02642         *q++ = *p++;
02643         if (1 < nSize)
02644         {
02645             *q++ = '.';
02646             memcpy(q, p, nSize-1);
02647             q += nSize-1;
02648         }
02649         *q++ = 'E';
02650         q += mux_ltoa(iDecimalPoint-1, q);
02651     }
02652     else if (iDecimalPoint <= 0)
02653     {
02654         // iDecimalPoint = -5 to 0
02655         //
02656         *q++ = '0';
02657         *q++ = '.';
02658         memset(q, '0', -iDecimalPoint);
02659         q += -iDecimalPoint;
02660         memcpy(q, p, nSize);
02661         q += nSize;
02662         if (bRounded)
02663         {
02664             int nPad = nRequest - (nSize - iDecimalPoint);
02665             if (0 < nPad)
02666             {
02667                 memset(q, '0', nPad);
02668                 q += nPad;
02669             }
02670         }
02671     }
02672     else
02673     {
02674         // iDecimalPoint = 1 to 17
02675         //
02676         if (nSize <= iDecimalPoint)
02677         {
02678             memcpy(q, p, nSize);
02679             q += nSize;
02680             memset(q, '0', iDecimalPoint - nSize);
02681             q += iDecimalPoint - nSize;
02682             if (  bRounded
02683                && 0 < nRequest)
02684             {
02685                 *q++ = '.';
02686                 memset(q, '0', nRequest);
02687                 q += nRequest;
02688             }
02689         }
02690         else
02691         {
02692             memcpy(q, p, iDecimalPoint);
02693             q += iDecimalPoint;
02694             p += iDecimalPoint;
02695             *q++ = '.';
02696             memcpy(q, p, nSize - iDecimalPoint);
02697             q += nSize - iDecimalPoint;
02698             if (bRounded)
02699             {
02700                 int nPad = nRequest - (nSize - iDecimalPoint);
02701                 if (0 < nPad)
02702                 {
02703                     memset(q, '0', nPad);
02704                     q += nPad;
02705                 }
02706             }
02707         }
02708     }
02709     *q = '\0';
02710     return buffer;
02711 }
02712 
02713 bool is_integer(char *str, int *pDigits)
02714 {
02715     int nDigits = 0;
02716     if (pDigits)
02717     {
02718         *pDigits = 0;
02719     }
02720 
02721     // Leading spaces.
02722     //
02723     while (mux_isspace(*str))
02724     {
02725         str++;
02726     }
02727 
02728     // Leading minus or plus
02729     //
02730     if (*str == '-' || *str == '+')
02731     {
02732         str++;
02733 
02734         // Just a sign by itself isn't an integer.
02735         //
02736         if (!*str)
02737         {
02738             return false;
02739         }
02740     }
02741 
02742     // Need at least 1 integer
02743     //
02744     if (!mux_isdigit(*str))
02745     {
02746         return false;
02747     }
02748 
02749     // The number (int)
02750     //
02751     do
02752     {
02753         str++;
02754         nDigits++;
02755     } while (mux_isdigit(*str));
02756 
02757     if (pDigits)
02758     {
02759         *pDigits = nDigits;
02760     }
02761 
02762     // Trailing Spaces.
02763     //
02764     while (mux_isspace(*str))
02765     {
02766         str++;
02767     }
02768 
02769     return (!*str);
02770 }
02771 
02772 bool is_rational(char *str)
02773 {
02774     // Leading spaces.
02775     //
02776     while (mux_isspace(*str))
02777     {
02778         str++;
02779     }
02780 
02781     // Leading minus or plus sign.
02782     //
02783     if (*str == '-' || *str == '+')
02784     {
02785         str++;
02786 
02787         // But not if just a sign.
02788         //
02789         if (!*str)
02790         {
02791             return false;
02792         }
02793     }
02794 
02795     // Need at least one digit.
02796     //
02797     bool got_one = false;
02798     if (mux_isdigit(*str))
02799     {
02800         got_one = true;
02801     }
02802 
02803     // The number (int)
02804     //
02805     while (mux_isdigit(*str))
02806     {
02807         str++;
02808     }
02809 
02810     // Decimal point.
02811     //
02812     if (*str == '.')
02813     {
02814         str++;
02815     }
02816 
02817     // Need at least one digit
02818     //
02819     if (mux_isdigit(*str))
02820     {
02821         got_one = true;
02822     }
02823 
02824     if (!got_one)
02825     {
02826         return false;
02827     }
02828 
02829     // The number (fract)
02830     //
02831     while (mux_isdigit(*str))
02832     {
02833         str++;
02834     }
02835 
02836     // Trailing spaces.
02837     //
02838     while (mux_isspace(*str))
02839     {
02840         str++;
02841     }
02842 
02843     // There must be nothing else after the trailing spaces.
02844     //
02845     return (!*str);
02846 }
02847 
02848 bool is_real(char *str)
02849 {
02850     PARSE_FLOAT_RESULT pfr;
02851     return ParseFloat(&pfr, str);
02852 }
02853 
02854 // mux_strtok_src, mux_strtok_ctl, mux_strtok_parse.
02855 //
02856 // These three functions work together to replace the functionality of the
02857 // strtok() C runtime library function. Call mux_strtok_src() first with
02858 // the string to parse, then mux_strtok_ctl() with the control
02859 // characters, and finally mux_strtok_parse() to parse out the tokens.
02860 //
02861 // You may call mux_strtok_ctl() to change the set of control characters
02862 // between mux_strtok_parse() calls, however keep in mind that the parsing
02863 // may not occur how you intend it to as mux_strtok_parse() does not
02864 // consume -all- of the controlling delimiters that separate two tokens.
02865 // It consumes only the first one.
02866 //
02867 void mux_strtok_src(MUX_STRTOK_STATE *tts, char *arg_pString)
02868 {
02869     if (!tts || !arg_pString) return;
02870 
02871     // Remember the string to parse.
02872     //
02873     tts->pString = arg_pString;
02874 }
02875 
02876 void mux_strtok_ctl(MUX_STRTOK_STATE *tts, char *pControl)
02877 {
02878     if (!tts || !pControl) return;
02879 
02880     // No character is a control character.
02881     //
02882     memset(tts->aControl, 0, sizeof(tts->aControl));
02883 
02884     // The NULL character is always a control character.
02885     //
02886     tts->aControl[0] = 1;
02887 
02888     // Record the user-specified control characters.
02889     //
02890     while (*pControl)
02891     {
02892         tts->aControl[(unsigned char)*pControl] = 1;
02893         pControl++;
02894     }
02895 }
02896 
02897 char *mux_strtok_parseLEN(MUX_STRTOK_STATE *tts, int *pnLen)
02898 {
02899     *pnLen = 0;
02900     if (!tts)
02901     {
02902         return NULL;
02903     }
02904     char *p = tts->pString;
02905     if (!p)
02906     {
02907         return NULL;
02908     }
02909 
02910     // Skip over leading control characters except for the NUL character.
02911     //
02912     while (tts->aControl[(unsigned char)*p] && *p)
02913     {
02914         p++;
02915     }
02916 
02917     char *pReturn = p;
02918 
02919     // Skip over non-control characters.
02920     //
02921     while (tts->aControl[(unsigned char)*p] == 0)
02922     {
02923         p++;
02924     }
02925 
02926     // What is the length of this token?
02927     //
02928     *pnLen = p - pReturn;
02929 
02930     // Terminate the token with a NUL.
02931     //
02932     if (p[0])
02933     {
02934         // We found a non-NUL delimiter, so the next call will begin parsing
02935         // on the character after this one.
02936         //
02937         tts->pString = p+1;
02938     }
02939     else
02940     {
02941         // We hit the end of the string, so the end of the string is where
02942         // the next call will begin.
02943         //
02944         tts->pString = p;
02945     }
02946 
02947     // Did we find a token?
02948     //
02949     if (*pnLen > 0)
02950     {
02951         return pReturn;
02952     }
02953     else
02954     {
02955         return NULL;
02956     }
02957 }
02958 
02959 char *mux_strtok_parse(MUX_STRTOK_STATE *tts)
02960 {
02961     int nLen;
02962     char *p = mux_strtok_parseLEN(tts, &nLen);
02963     if (p)
02964     {
02965         p[nLen] = '\0';
02966     }
02967     return p;
02968 }
02969 
02970 // This function will filter out any characters in the the set from
02971 // the string.
02972 //
02973 char *RemoveSetOfCharacters(char *pString, char *pSetToRemove)
02974 {
02975     static char Buffer[LBUF_SIZE];
02976     char *pBuffer = Buffer;
02977 
02978     int nLen;
02979     int nLeft = sizeof(Buffer) - 1;
02980     char *p;
02981     MUX_STRTOK_STATE tts;
02982     mux_strtok_src(&tts, pString);
02983     mux_strtok_ctl(&tts, pSetToRemove);
02984     for ( p = mux_strtok_parseLEN(&tts, &nLen);
02985           p && nLeft;
02986           p = mux_strtok_parseLEN(&tts, &nLen))
02987     {
02988         if (nLeft < nLen)
02989         {
02990             nLen = nLeft;
02991         }
02992         memcpy(pBuffer, p, nLen);
02993         pBuffer += nLen;
02994         nLeft -= nLen;
02995     }
02996     *pBuffer = '\0';
02997     return Buffer;
02998 }
02999 
03000 void ItemToList_Init(ITL *p, char *arg_buff, char **arg_bufc,
03001     char arg_chPrefix, char arg_chSep)
03002 {
03003     p->bFirst = true;
03004     p->chPrefix = arg_chPrefix;
03005     p->chSep = arg_chSep;
03006     p->buff = arg_buff;
03007     p->bufc = arg_bufc;
03008     p->nBufferAvailable = LBUF_SIZE - (*arg_bufc - arg_buff) - 1;
03009 }
03010 
03011 bool ItemToList_AddInteger(ITL *pContext, int i)
03012 {
03013     char smbuf[SBUF_SIZE];
03014     char *p = smbuf;
03015     if (  !pContext->bFirst
03016        && pContext->chSep)
03017     {
03018         *p++ = pContext->chSep;
03019     }
03020     if (pContext->chPrefix)
03021     {
03022         *p++ = pContext->chPrefix;
03023     }
03024     p += mux_ltoa(i, p);
03025     size_t nLen = p - smbuf;
03026     if (nLen > pContext->nBufferAvailable)
03027     {
03028         // Out of room.
03029         //
03030         return false;
03031     }
03032     if (pContext->bFirst)
03033     {
03034         pContext->bFirst = false;
03035     }
03036     memcpy(*(pContext->bufc), smbuf, nLen);
03037     *(pContext->bufc) += nLen;
03038     pContext->nBufferAvailable -= nLen;
03039     return true;
03040 }
03041 
03042 bool ItemToList_AddStringLEN(ITL *pContext, size_t nStr, char *pStr)
03043 {
03044     size_t nLen = nStr;
03045     if (  !pContext->bFirst
03046        && pContext->chSep)
03047     {
03048         nLen++;
03049     }
03050     if (pContext->chPrefix)
03051     {
03052         nLen++;
03053     }
03054     if (nLen > pContext->nBufferAvailable)
03055     {
03056         // Out of room.
03057         //
03058         return false;
03059     }
03060     char *p = *(pContext->bufc);
03061     if (pContext->bFirst)
03062     {
03063         pContext->bFirst = false;
03064     }
03065     else if (pContext->chSep)
03066     {
03067         *p++ = pContext->chSep;
03068     }
03069     if (pContext->chPrefix)
03070     {
03071         *p++ = pContext->chPrefix;
03072     }
03073     memcpy(p, pStr, nStr);
03074     *(pContext->bufc) += nLen;
03075     pContext->nBufferAvailable -= nLen;
03076     return true;
03077 }
03078 
03079 bool ItemToList_AddString(ITL *pContext, char *pStr)
03080 {
03081     size_t nStr = strlen(pStr);
03082     return ItemToList_AddStringLEN(pContext, nStr, pStr);
03083 }
03084 
03085 void ItemToList_Final(ITL *pContext)
03086 {
03087     **(pContext->bufc) = '\0';
03088 }
03089 
03090 // mux_stricmp - Compare two strings ignoring case.
03091 //
03092 int mux_stricmp(const char *a, const char *b)
03093 {
03094     while (  *a
03095           && *b
03096           && mux_tolower(*a) == mux_tolower(*b))
03097     {
03098         a++;
03099         b++;
03100     }
03101     int c1 = mux_tolower(*a);
03102     int c2 = mux_tolower(*b);
03103     if (c1 < c2)
03104     {
03105         return -1;
03106     }
03107     else if (c1 > c2)
03108     {
03109         return 1;
03110     }
03111     else
03112     {
03113         return 0;
03114     }
03115 }
03116 
03117 // mux_memicmp - Compare two buffers ignoring case.
03118 //
03119 int mux_memicmp(const void *p1_arg, const void *p2_arg, size_t n)
03120 {
03121     unsigned char *p1 = (unsigned char *)p1_arg;
03122     unsigned char *p2 = (unsigned char *)p2_arg;
03123     while (  n
03124           && mux_tolower(*p1) == mux_tolower(*p2))
03125     {
03126         n--;
03127         p1++;
03128         p2++;
03129     }
03130     if (n)
03131     {
03132         int c1 = mux_tolower(*p1);
03133         int c2 = mux_tolower(*p2);
03134         if (c1 < c2)
03135         {
03136             return -1;
03137         }
03138         else if (c1 > c2)
03139         {
03140             return 1;
03141         }
03142     }
03143     return 0;
03144 }
03145 
03146 // mux_strlwr - Convert string to all lower case.
03147 //
03148 void mux_strlwr(char *a)
03149 {
03150     while (*a)
03151     {
03152         *a = mux_tolower(*a);
03153         a++;
03154     }
03155 }
03156 
03157 // mux_strupr - Convert string to all upper case.
03158 //
03159 void mux_strupr(char *a)
03160 {
03161     while (*a)
03162     {
03163         *a = mux_toupper(*a);
03164         a++;
03165     }
03166 }
03167 
03168 #ifdef WIN32
03169 #define VSNPRINTF _vsnprintf
03170 #else // WIN32
03171 #ifdef NEED_VSPRINTF_DCL
03172 extern char *vsprintf(char *, char *, va_list);
03173 #endif // NEED_VSPRINTF_DCL
03174 #define VSNPRINTF vsnprintf
03175 #endif // WIN32
03176 
03177 // mux_vsnprintf - Is an sprintf-like function that will not overflow
03178 // a buffer of specific size. The size is give by count, and count
03179 // should be chosen to include the '\0' termination.
03180 //
03181 // Returns: A number from 0 to count-1 that is the string length of
03182 // the returned (possibly truncated) buffer.
03183 //
03184 int DCL_CDECL mux_vsnprintf(char *buff, int count, const char *fmt, va_list va)
03185 {
03186     // From the manuals:
03187     //
03188     // vsnprintf returns the number of characters written, not
03189     // including the terminating '\0' character.
03190     //
03191     // It returns a -1 if an output error occurs.
03192     //
03193     // It can return a number larger than the size of the buffer
03194     // on some systems to indicate how much space it -would- have taken
03195     // if not limited by the request.
03196     //
03197     // On Win32, it can fill the buffer completely without a
03198     // null-termination and return -1.
03199 
03200 
03201     // To favor the Unix case, if there is an output error, but
03202     // vsnprint doesn't touch the buffer, we avoid undefined trash by
03203     // null-terminating the buffer to zero-length before the call.
03204     // Not sure that this happens, but it's a cheap precaution.
03205     //
03206     buff[0] = '\0';
03207 
03208     // If Unix version does start touching the buffer, null-terminates,
03209     // and returns -1, we are still safe. However, if Unix version
03210     // touches the buffer writes garbage, and then returns -1, we may
03211     // pass garbage, but this possibility seems very unlikely.
03212     //
03213     int len = VSNPRINTF(buff, count, fmt, va);
03214     if (len < 0 || len > count-1)
03215     {
03216         if (buff[0] == '\0')
03217         {
03218             // vsnprintf did not touch the buffer.
03219             //
03220             len = 0;
03221         }
03222         else
03223         {
03224             len = count-1;
03225         }
03226     }
03227     buff[len] = '\0';
03228     return len;
03229 }
03230 
03231 // This function acts like fgets except that any data on the end of the
03232 // line past the buffer size is truncated instead of being returned on
03233 // the next call.
03234 //
03235 int GetLineTrunc(char *Buffer, size_t nBuffer, FILE *fp)
03236 {
03237     size_t lenBuffer = 0;
03238     if (fgets(Buffer, nBuffer, fp))
03239     {
03240         lenBuffer = strlen(Buffer);
03241     }
03242     if (lenBuffer <= 0)
03243     {
03244         memcpy(Buffer, "\n", 2);
03245         return 1;
03246     }
03247     if (Buffer[lenBuffer-1] != '\n')
03248     {
03249         // The line was too long for the buffer. Continue reading until the
03250         // end of the line.
03251         //
03252         char TruncBuffer[SBUF_SIZE];
03253         size_t lenTruncBuffer;
03254         do
03255         {
03256             if (!fgets(TruncBuffer, sizeof(TruncBuffer), fp))
03257             {
03258                 break;
03259             }
03260             lenTruncBuffer = strlen(TruncBuffer);
03261         }
03262         while (TruncBuffer[lenTruncBuffer-1] != '\n');
03263     }
03264     return lenBuffer;
03265 }
03266 
03267 // Method: Boyer-Moore-Horspool
03268 //
03269 // This method is a simplification of the Boyer-Moore String Searching
03270 // Algorithm, but a useful one. It does not require as much temporary
03271 // storage, and the setup costs are not as high as the full Boyer-Moore.
03272 //
03273 // If we were searching megabytes of data instead of 8KB at most, then
03274 // the full Boyer-Moore would make more sense.
03275 //
03276 #define BMH_LARGE 32767
03277 void BMH_Prepare(BMH_State *bmhs, int nPat, const char *pPat)
03278 {
03279     if (nPat <= 0)
03280     {
03281         return;
03282     }
03283     int k;
03284     for (k = 0; k < 256; k++)
03285     {
03286         bmhs->m_d[k] = nPat;
03287     }
03288 
03289     char chLastPat = pPat[nPat-1];
03290     bmhs->m_skip2 = nPat;
03291     for (k = 0; k < nPat - 1; k++)
03292     {
03293         bmhs->m_d[(unsigned char)pPat[k]] = nPat - k - 1;
03294         if (pPat[k] == chLastPat)
03295         {
03296             bmhs->m_skip2 = nPat - k - 1;
03297         }
03298     }
03299     bmhs->m_d[(unsigned char)chLastPat] = BMH_LARGE;
03300 }
03301 
03302 int BMH_Execute(BMH_State *bmhs, int nPat, const char *pPat, int nSrc, const char *pSrc)
03303 {
03304     if (nPat <= 0)
03305     {
03306         return -1;
03307     }
03308     for (int i = nPat-1; i < nSrc; i += bmhs->m_skip2)
03309     {
03310         while ((i += bmhs->m_d[(unsigned char)(pSrc[i])]) < nSrc)
03311         {
03312             ; // Nothing.
03313         }
03314         if (i < BMH_LARGE)
03315         {
03316             break;
03317         }
03318         i -= BMH_LARGE;
03319         int j = nPat - 1;
03320         const char *s = pSrc + (i - j);
03321         while (--j >= 0 && s[j] == pPat[j])
03322         {
03323             ; // Nothing.
03324         }
03325         if (j < 0)
03326         {
03327             return s-pSrc;
03328         }
03329     }
03330     return -1;
03331 }
03332 
03333 int BMH_StringSearch(int nPat, const char *pPat, int nSrc, const char *pSrc)
03334 {
03335     BMH_State bmhs;
03336     BMH_Prepare(&bmhs, nPat, pPat);
03337     return BMH_Execute(&bmhs, nPat, pPat, nSrc, pSrc);
03338 }
03339 
03340 void BMH_PrepareI(BMH_State *bmhs, int nPat, const char *pPat)
03341 {
03342     if (nPat <= 0)
03343     {
03344         return;
03345     }
03346     int k;
03347     for (k = 0; k < 256; k++)
03348     {
03349         bmhs->m_d[k] = nPat;
03350     }
03351 
03352     char chLastPat = pPat[nPat-1];
03353     bmhs->m_skip2 = nPat;
03354     for (k = 0; k < nPat - 1; k++)
03355     {
03356         bmhs->m_d[mux_toupper(pPat[k])] = nPat - k - 1;
03357         bmhs->m_d[mux_tolower(pPat[k])] = nPat - k - 1;
03358         if (pPat[k] == chLastPat)
03359         {
03360             bmhs->m_skip2 = nPat - k - 1;
03361         }
03362     }
03363     bmhs->m_d[mux_toupper(chLastPat)] = BMH_LARGE;
03364     bmhs->m_d[mux_tolower(chLastPat)] = BMH_LARGE;
03365 }
03366 
03367 int BMH_ExecuteI(BMH_State *bmhs, int nPat, const char *pPat, int nSrc, const char *pSrc)
03368 {
03369     if (nPat <= 0)
03370     {
03371         return -1;
03372     }
03373     for (int i = nPat-1; i < nSrc; i += bmhs->m_skip2)
03374     {
03375         while ((i += bmhs->m_d[(unsigned char)(pSrc[i])]) < nSrc)
03376         {
03377             ; // Nothing.
03378         }
03379         if (i < BMH_LARGE)
03380         {
03381             break;
03382         }
03383         i -= BMH_LARGE;
03384         int j = nPat - 1;
03385         const char *s = pSrc + (i - j);
03386         while (  --j >= 0
03387               && mux_toupper(s[j]) == mux_toupper(pPat[j]))
03388         {
03389             ; // Nothing.
03390         }
03391         if (j < 0)
03392         {
03393             return s-pSrc;
03394         }
03395     }
03396     return -1;
03397 }
03398 
03399 int BMH_StringSearchI(int nPat, const char *pPat, int nSrc, const char *pSrc)
03400 {
03401     BMH_State bmhs;
03402     BMH_PrepareI(&bmhs, nPat, pPat);
03403     return BMH_ExecuteI(&bmhs, nPat, pPat, nSrc, pSrc);
03404 }
03405 
03406 // ---------------------------------------------------------------------------
03407 // cf_art_except:
03408 //
03409 // Add an article rule to the ruleset.
03410 //
03411 
03412 CF_HAND(cf_art_rule)
03413 {
03414     UNUSED_PARAMETER(pExtra);
03415     UNUSED_PARAMETER(nExtra);
03416 
03417     char* pCurrent = str;
03418 
03419     while (mux_isspace(*pCurrent))
03420     {
03421         pCurrent++;
03422     }
03423     char* pArticle = pCurrent;
03424     while (  !mux_isspace(*pCurrent)
03425           && *pCurrent != '\0')
03426     {
03427         pCurrent++;
03428     }
03429     if (*pCurrent == '\0')
03430     {
03431         cf_log_syntax(player, cmd, "No article or regexp specified.");
03432         return -1;
03433     }
03434 
03435     bool bUseAn = false;
03436     bool bOkay = false;
03437 
03438     if (pCurrent - pArticle <= 2)
03439     {
03440         if (mux_tolower(pArticle[0]) == 'a')
03441         {
03442             if (mux_tolower(pArticle[1]) == 'n')
03443             {
03444                 bUseAn = true;
03445                 bOkay = true;
03446             }
03447 
03448             if (mux_isspace(pArticle[1]))
03449             {
03450                 bOkay = true;
03451             }
03452         }
03453     }
03454 
03455     if (!bOkay)
03456     {
03457         *pCurrent = '\0';
03458         cf_log_syntax(player, cmd, "Invalid article '%s'.", pArticle);
03459         return -1;
03460     }
03461 
03462     while (mux_isspace(*pCurrent))
03463     {
03464         pCurrent++;
03465     }
03466 
03467     if (*pCurrent == '\0')
03468     {
03469         cf_log_syntax(player, cmd, "No regexp specified.");
03470         return -1;
03471     }
03472 
03473     const char *errptr;
03474     int erroffset;
03475     pcre* reNewRegexp = pcre_compile(pCurrent, 0, &errptr, &erroffset, NULL);
03476     if (!reNewRegexp)
03477     {
03478         cf_log_syntax(player, cmd, "Error processing regexp '%s':.",
03479               pCurrent, errptr);
03480         return -1;
03481     }
03482 
03483     pcre_extra *study = pcre_study(reNewRegexp, 0, &errptr);
03484 
03485     // Push new rule at head of list.
03486     ArtRuleset** arRules = (ArtRuleset **) vp;
03487     ArtRuleset* arNewRule = (ArtRuleset *) MEMALLOC(sizeof(ArtRuleset));
03488 
03489     arNewRule->m_pNextRule = *arRules;
03490     arNewRule->m_bUseAn = bUseAn;
03491     arNewRule->m_pRegexp = reNewRegexp;
03492     arNewRule->m_pRegexpStudy = study;
03493 
03494     *arRules = arNewRule;
03495     return 0;
03496 }
03497 

Generated on Mon May 28 04:40:11 2007 for MUX by  doxygen 1.4.7