ht.c (5688B)
1 /* 20sep07abu 2 * (c) Software Lab. Alexander Burger 3 */ 4 5 #include "pico.h" 6 7 static char *HtOK[] = { 8 "<b>", "</b>", 9 "<i>", "</i>", 10 "<u>", "</u>", 11 "<p>", "</p>", 12 "<pre>", "</pre>", 13 "<div ", "</div>", 14 "<font ", "</font>", 15 "<img ", "</img>", 16 "<br>", "<hr>", NULL 17 }; 18 19 static bool findHtOK(char *s) { 20 char **p, *q, *t; 21 22 for (p = HtOK; *p; ++p) 23 for (q = *p, t = s;;) { 24 if (*q != *t) 25 break; 26 if (*++q == '\0') 27 return YES; 28 if (*++t == '\0') 29 break; 30 } 31 return NO; 32 } 33 34 // (ht:Prin 'sym ..) -> T 35 any Prin(any x) { 36 any y; 37 38 while (isCell(x = cdr(x))) { 39 if (isNum(y = EVAL(car(x))) || isCell(y) || isExt(y)) 40 prin(y); 41 else { 42 int c; 43 char *p, *q, nm[bufSize(y)]; 44 45 bufString(y, nm); 46 for (p = nm; *p;) { 47 if (findHtOK(p) && (q = strchr(p,'>'))) 48 do 49 Env.put(*p++); 50 while (p <= q); 51 else { 52 switch (*(byte*)p) { 53 case '<': 54 outString("<"); 55 break; 56 case '>': 57 outString(">"); 58 break; 59 case '&': 60 outString("&"); 61 break; 62 case '"': 63 outString("""); 64 break; 65 case 0xFF: 66 Env.put(0xEF); 67 Env.put(0xBF); 68 Env.put(0xBF); 69 break; 70 default: 71 Env.put(c = *p); 72 if ((c & 0x80) != 0) { 73 Env.put(*++p); 74 if ((c & 0x20) != 0) 75 Env.put(*++p); 76 } 77 } 78 ++p; 79 } 80 } 81 } 82 } 83 return T; 84 } 85 86 static void putHex(int c) { 87 int n; 88 89 if ((n = c >> 4 & 0xF) > 9) 90 n += 7; 91 Env.put(n + '0'); 92 if ((n = c & 0xF) > 9) 93 n += 7; 94 Env.put(n + '0'); 95 } 96 97 static int getHex(any *p) { 98 int n, m; 99 100 n = firstByte(car(*p)), *p = cdr(*p); 101 if ((n -= '0') > 9) 102 n -= 7; 103 m = firstByte(car(*p)), *p = cdr(*p); 104 if ((m -= '0') > 9) 105 m -= 7; 106 return n << 4 | m; 107 } 108 109 static void htEncode(char *p) { 110 int c; 111 112 while (c = *p++) { 113 if (strchr(" \"#%&:;<=>?_", c)) 114 Env.put('%'), putHex(c); 115 else { 116 Env.put(c); 117 if ((c & 0x80) != 0) { 118 Env.put(*p++); 119 if ((c & 0x20) != 0) 120 Env.put(*p++); 121 } 122 } 123 } 124 } 125 126 static void htFmt(any x) { 127 any y; 128 129 if (isNum(x)) 130 Env.put('+'), prin(x); 131 else if (isCell(x)) 132 do 133 Env.put('_'), htFmt(car(x)); 134 while (isCell(x = cdr(x))); 135 else if (isNum(y = name(x))) { 136 char nm[bufSize(x)]; 137 138 bufString(x, nm); 139 if (isExt(x)) 140 Env.put('-'), htEncode(nm); 141 else if (hashed(x, hash(y), Intern)) 142 Env.put('$'), htEncode(nm); 143 else if (strchr("$+.", *nm)) { 144 Env.put('%'), putHex(*nm); 145 htEncode(nm+1); 146 } 147 else 148 htEncode(nm); 149 } 150 } 151 152 // (ht:Fmt 'any ..) -> sym 153 any Fmt(any x) { 154 int n, i; 155 cell c[length(x = cdr(x))]; 156 157 for (n = 0; isCell(x); ++n, x = cdr(x)) 158 Push(c[n], EVAL(car(x))); 159 begString(); 160 for (i = 0; i < n;) { 161 htFmt(data(c[i])); 162 if (++i != n) 163 Env.put('&'); 164 } 165 x = endString(); 166 if (n) 167 drop(c[0]); 168 return x; 169 } 170 171 // (ht:Pack 'lst) -> sym 172 any Pack(any x) { 173 int c; 174 cell c1; 175 176 x = EVAL(cadr(x)); 177 begString(); 178 Push(c1,x); 179 while (isCell(x)) { 180 if ((c = symChar(name(car(x)))) == '%') 181 x = cdr(x), Env.put(getHex(&x)); 182 else 183 outName(car(x)), x = cdr(x); 184 } 185 return endString(); 186 } 187 188 /*** Chunked Encoding ***/ 189 #define CHUNK 4000 190 static int Cnt; 191 static void (*Get)(void); 192 static void (*Put)(int); 193 static char Chunk[CHUNK]; 194 195 static int chrHex(void) { 196 if (Chr >= '0' && Chr <= '9') 197 return Chr - 48; 198 else if (Chr >= 'A' && Chr <= 'F') 199 return Chr - 55; 200 else if (Chr >= 'a' && Chr <= 'f') 201 return Chr - 87; 202 else 203 return -1; 204 } 205 206 static void chunkSize(void) { 207 int n; 208 209 if (!Chr) 210 Get(); 211 if ((Cnt = chrHex()) >= 0) { 212 while (Get(), (n = chrHex()) >= 0) 213 Cnt = Cnt << 4 | n; 214 while (Chr != '\n') { 215 if (Chr < 0) 216 return; 217 Get(); 218 } 219 Get(); 220 if (Cnt == 0) { 221 Get(); // Skip '\r' of empty line 222 Chr = 0; // Discard '\n' 223 } 224 } 225 } 226 227 static void getChunked(void) { 228 if (Cnt <= 0) 229 Chr = -1; 230 else { 231 Get(); 232 if (--Cnt == 0) { 233 Get(), Get(); // Skip '\n', '\r' 234 chunkSize(); 235 } 236 } 237 } 238 239 // (ht:In 'flg . prg) -> any 240 any In(any x) { 241 x = cdr(x); 242 if (isNil(EVAL(car(x)))) 243 return prog(cdr(x)); 244 Get = Env.get, Env.get = getChunked; 245 chunkSize(); 246 x = prog(cdr(x)); 247 Env.get = Get; 248 Chr = 0; 249 return x; 250 } 251 252 static void wrChunk(void) { 253 int i; 254 char buf[16]; 255 256 sprintf(buf, "%x\r\n", Cnt); 257 i = 0; 258 do 259 Put(buf[i]); 260 while (buf[++i]); 261 for (i = 0; i < Cnt; ++i) 262 Put(Chunk[i]); 263 Put('\r'), Put('\n'); 264 } 265 266 static void putChunked(int c) { 267 Chunk[Cnt++] = c; 268 if (Cnt == CHUNK) 269 wrChunk(), Cnt = 0; 270 } 271 272 // (ht:Out 'flg . prg) -> any 273 any Out(any x) { 274 x = cdr(x); 275 if (isNil(EVAL(car(x)))) 276 x = prog(cdr(x)); 277 else { 278 Cnt = 0; 279 Put = Env.put, Env.put = putChunked; 280 x = prog(cdr(x)); 281 if (Cnt) 282 wrChunk(); 283 Env.put = Put; 284 outString("0\r\n\r\n"); 285 } 286 flush(OutFile); 287 return x; 288 }