/tags/rel-1-3-26/SWIG/Source/DOH/fio.c
C | 555 lines | 421 code | 43 blank | 91 comment | 140 complexity | 19da04ece0a840ff17bd63683f4a714d MD5 | raw file
Possible License(s): LGPL-2.1, Cube, GPL-3.0, 0BSD, GPL-2.0
1/* ----------------------------------------------------------------------------- 2 * fio.c 3 * 4 * This file implements a number of standard I/O operations included 5 * formatted output, readline, and splitting. 6 * 7 * Author(s) : David Beazley (beazley@cs.uchicago.edu) 8 * 9 * Copyright (C) 1999-2000. The University of Chicago 10 * See the file LICENSE for information on usage and redistribution. 11 * ----------------------------------------------------------------------------- */ 12 13char cvsroot_fio_c[] = "$Header$"; 14 15#include "dohint.h" 16 17#define OBUFLEN 512 18 19static DOH *encodings = 0; /* Encoding hash */ 20 21/* ----------------------------------------------------------------------------- 22 * Writen() 23 * 24 * Write's N characters of output and retries until all characters are 25 * written. This is useful should a write operation encounter a spurious signal. 26 * ----------------------------------------------------------------------------- */ 27 28static int Writen(DOH *out, void *buffer, int len) { 29 int nw = len, ret; 30 char *cb = (char *) buffer; 31 while (nw) { 32 ret = Write(out,cb,nw); 33 if (ret < 0) return -1; 34 nw = nw - ret; 35 cb += ret; 36 } 37 return len; 38} 39 40/* ----------------------------------------------------------------------------- 41 * DohEncoding() 42 * 43 * Registers a new printf encoding method. An encoder function should accept 44 * two file-like objects and operate as a filter. 45 * ----------------------------------------------------------------------------- */ 46 47void 48DohEncoding(char *name, DOH *(*fn)(DOH *s)) { 49 if (!encodings) encodings = NewHash(); 50 Setattr(encodings,(void *) name, NewVoid((void *)fn,0)); 51} 52 53/* internal function for processing an encoding */ 54static DOH *encode(char *name, DOH *s) { 55 DOH *handle, *ns; 56 DOH *(*fn)(DOH *); 57 long pos; 58 if (!encodings || !(handle = Getattr(encodings,name))) { 59 return Copy(s); 60 } 61 pos = Tell(s); 62 Seek(s,0,SEEK_SET); 63 fn = (DOH *(*)(DOH *)) Data(handle); 64 ns = (*fn)(s); 65 Seek(s,pos,SEEK_SET); 66 return ns; 67} 68 69/* ----------------------------------------------------------------------------- 70 * DohvPrintf() 71 * 72 * DOH implementation of printf. Output can be directed to any file-like object 73 * including bare FILE * objects. The same formatting codes as printf are 74 * recognized with two extensions: 75 * 76 * %s - Prints a "char *" or the string representation of any 77 * DOH object. This will implicitly result in a call to 78 * Str(obj). 79 * 80 * %(encoder)* - Filters the output through an encoding function registered 81 * with DohEncoder(). 82 * 83 * Note: This function is not particularly memory efficient with large strings. 84 * It's better to use Dump() or some other method instead. 85 * ----------------------------------------------------------------------------- */ 86 87int 88DohvPrintf(DOH *so, const char *format, va_list ap) 89{ 90 static char *fmt_codes = "dioxXucsSfeEgGpn"; 91 int state = 0; 92 const char *p = format; 93 char newformat[256]; 94 char obuffer[OBUFLEN]; 95 char *fmt = 0; 96 char temp[64]; 97 int widthval = 0; 98 int precval = 0; 99 int maxwidth; 100 char *w = 0; 101 int ivalue; 102 double dvalue; 103 void *pvalue; 104 char *stemp; 105 int nbytes = 0; 106 char encoder[128], *ec = 0; 107 108 memset (newformat, 0, sizeof (newformat)); 109 110 while (*p) { 111 switch(state) { 112 case 0: /* Ordinary text */ 113 if (*p != '%') { 114 Putc(*p,so); 115 nbytes++; 116 } else{ 117 fmt = newformat; 118 widthval = 0; 119 precval = 0; 120 *(fmt++) = *p; 121 encoder[0] = 0; 122 state = 10; 123 } 124 break; 125 case 10: /* Look for a width and precision */ 126 if (isdigit((int)*p) && (*p != '0')) { 127 w = temp; 128 *(w++) = *p; 129 *(fmt++) = *p; 130 state = 20; 131 } else if (strchr(fmt_codes,*p)) { 132 /* Got one of the formatting codes */ 133 p--; 134 state = 100; 135 } else if (*p == '*') { 136 /* Width field is specified in the format list */ 137 widthval = va_arg(ap,int); 138 sprintf(temp,"%d",widthval); 139 for (w = temp; *w; w++) { 140 *(fmt++) = *w; 141 } 142 state = 30; 143 } else if (*p == '%') { 144 Putc(*p,so); 145 fmt = newformat; 146 nbytes++; 147 state = 0; 148 } else if (*p == '(') { 149 ec = encoder; 150 state = 60; 151 } else { 152 *(fmt++) = *p; 153 } 154 break; 155 156 case 20: /* Hmmm. At the start of a width field */ 157 if (isdigit((int)*p)) { 158 *(w++) = *p; 159 *(fmt++) = *p; 160 } else if (strchr(fmt_codes,*p)) { 161 /* Got one of the formatting codes */ 162 /* Figure out width */ 163 *w = 0; 164 widthval = atoi(temp); 165 p--; 166 state = 100; 167 } else if (*p == '.') { 168 *w = 0; 169 widthval = atoi(temp); 170 w = temp; 171 *(fmt++) = *p; 172 state = 40; 173 } else { 174 /* ??? */ 175 *w = 0; 176 widthval = atoi(temp); 177 state = 50; 178 } 179 break; 180 181 case 30: /* Parsed a width from an argument. Look for a . */ 182 if (*p == '.') { 183 w = temp; 184 *(fmt++) = *p; 185 state = 40; 186 } else if (strchr(fmt_codes,*p)) { 187 /* Got one of the formatting codes */ 188 /* Figure out width */ 189 p--; 190 state = 100; 191 } else { 192 /* hmmm. Something else. */ 193 state = 50; 194 } 195 break; 196 197 case 40: 198 /* Start of precision expected */ 199 if (isdigit((int)*p) && (*p != '0')) { 200 *(fmt++) = *p; 201 *(w++) = *p; 202 state = 41; 203 } else if (*p == '*') { 204 /* Precision field is specified in the format list */ 205 precval = va_arg(ap,int); 206 sprintf(temp,"%d",precval); 207 for (w = temp; *w; w++) { 208 *(fmt++) = *w; 209 } 210 state = 50; 211 } else if (strchr(fmt_codes,*p)) { 212 p--; 213 state = 100; 214 } else { 215 *(fmt++) = *p; 216 state = 50; 217 } 218 break; 219 case 41: 220 if (isdigit((int)*p)) { 221 *(fmt++) = *p; 222 *(w++) = *p; 223 } else if (strchr(fmt_codes,*p)) { 224 /* Got one of the formatting codes */ 225 /* Figure out width */ 226 *w = 0; 227 precval = atoi(temp); 228 p--; 229 state = 100; 230 } else { 231 *w = 0; 232 precval = atoi(temp); 233 *(fmt++) = *p; 234 state = 50; 235 } 236 break; 237 /* Hang out, wait for format specifier */ 238 case 50: 239 if (strchr(fmt_codes,*p)) { 240 p--; 241 state = 100; 242 } else { 243 *(fmt++) = *p; 244 } 245 break; 246 247 /* Got an encoding header */ 248 case 60: 249 if (*p == ')') { 250 *ec = 0; 251 state = 10; 252 } else { 253 *ec = *p; 254 ec++; 255 } 256 break; 257 case 100: 258 /* Got a formatting code */ 259 if (widthval < precval) maxwidth = precval; 260 else maxwidth = widthval; 261 if ((*p == 's') || (*p == 'S')) { /* Null-Terminated string */ 262 DOH *doh; 263 DOH *Sval; 264 DOH *enc = 0; 265 doh = va_arg(ap, DOH *); 266 if (DohCheck(doh)) { 267 /* Is a DOH object. */ 268 if (DohIsString(doh)) { 269 Sval = doh; 270 } else { 271 Sval = Str(doh); 272 } 273 if (strlen(encoder)) { 274 enc = encode(encoder,Sval); 275 maxwidth = maxwidth+strlen(newformat)+Len(enc); 276 } else { 277 maxwidth = maxwidth+strlen(newformat)+Len(Sval); 278 } 279 *(fmt++) = 's'; 280 *fmt = 0; 281 if ((maxwidth + 1) < OBUFLEN) { 282 stemp = obuffer; 283 } else { 284 stemp = (char *) DohMalloc(maxwidth+1); 285 } 286 if (enc) { 287 nbytes+=sprintf(stemp,newformat,Data(enc)); 288 } else { 289 nbytes+=sprintf(stemp,newformat,Data(Sval)); 290 } 291 if (Writen(so,stemp,strlen(stemp)) < 0) return -1; 292 if ((DOH *) Sval != doh) { 293 Delete(Sval); 294 } 295 if (enc) Delete(enc); 296 if (*p == 'S') { 297 Delete(doh); 298 } 299 if (stemp != obuffer) { 300 DohFree(stemp); 301 } 302 } else { 303 if (!doh) doh = (char *)""; 304 305 if (strlen(encoder)) { 306 DOH *s = NewString(doh); 307 Seek(s,0, SEEK_SET); 308 enc = encode(encoder,s); 309 Delete(s); 310 doh = Char(enc); 311 } else { 312 enc = 0; 313 } 314 maxwidth = maxwidth+strlen(newformat)+strlen((char *) doh); 315 *(fmt++) = 's'; 316 *fmt = 0; 317 if ((maxwidth+1) < OBUFLEN) { 318 stemp = obuffer; 319 } else { 320 stemp = (char *) DohMalloc(maxwidth + 1); 321 } 322 nbytes+=sprintf(stemp,newformat,doh); 323 if (Writen(so,stemp,strlen(stemp)) < 0) return -1; 324 if (stemp != obuffer) { 325 DohFree(stemp); 326 } 327 if (enc) Delete(enc); 328 } 329 } else { 330 *(fmt++) = *p; 331 *fmt = 0; 332 maxwidth = maxwidth+strlen(newformat)+64; 333 334 /* Only allocate a buffer if it is too big to fit. Shouldn't have to do 335 this very often */ 336 337 if (maxwidth < OBUFLEN) 338 stemp = obuffer; 339 else 340 stemp = (char *) DohMalloc(maxwidth+1); 341 switch(*p) { 342 case 'd': 343 case 'i': 344 case 'o': 345 case 'u': 346 case 'x': 347 case 'X': 348 case 'c': 349 ivalue = va_arg(ap,int); 350 nbytes+=sprintf(stemp,newformat,ivalue); 351 break; 352 case 'f': 353 case 'g': 354 case 'e': 355 case 'E': 356 case 'G': 357 dvalue = va_arg(ap,double); 358 nbytes+=sprintf(stemp,newformat,dvalue); 359 break; 360 case 'p': 361 pvalue = va_arg(ap,void *); 362 nbytes+=sprintf(stemp,newformat,pvalue); 363 break; 364 default: 365 break; 366 } 367 if (Writen(so,stemp,strlen(stemp)) < 0) return -1; 368 if (stemp != obuffer) DohFree(stemp); 369 } 370 state = 0; 371 break; 372 } 373 p++; 374 } 375 if (state) { 376 int r; 377 *fmt = 0; 378 r = Writen(so,fmt,strlen(fmt)); 379 if (r < 0) return -1; 380 nbytes += r; 381 } 382 return nbytes; 383} 384 385/* ----------------------------------------------------------------------------- 386 * DohPrintf() 387 * 388 * Variable length argument entry point to Printf 389 * ----------------------------------------------------------------------------- */ 390 391int 392DohPrintf(DOH *obj, const char *format, ...) { 393 va_list ap; 394 int ret; 395 va_start(ap,format); 396 ret = DohvPrintf(obj,format,ap); 397 va_end(ap); 398 return ret; 399} 400 401/* ----------------------------------------------------------------------------- 402 * DohPrintv() 403 * 404 * Print a null-terminated variable length list of DOH objects 405 * ----------------------------------------------------------------------------- */ 406 407int DohPrintv(DOHFile *f, ...) { 408 va_list ap; 409 int ret = 0; 410 DOH *obj; 411 va_start(ap,f); 412 while(1) { 413 obj = va_arg(ap,void *); 414 if ((!obj) || (obj == DohNone)) break; 415 if (DohCheck(obj)) { 416 ret += DohDump(obj,f); 417 } else { 418 ret += DohWrite(f,obj,strlen((char *) obj)); 419 } 420 } 421 va_end(ap); 422 return ret; 423} 424 425/* ----------------------------------------------------------------------------- 426 * DohCopyto() 427 * 428 * Copies all of the input from an input stream to an output stream. Returns the 429 * number of bytes copied. 430 * ----------------------------------------------------------------------------- */ 431 432int 433DohCopyto(DOH *in, DOH *out) { 434 int nbytes = 0, ret; 435 int nwrite = 0, wret; 436 char *cw; 437 char buffer[16384]; 438 439 if ((!in) || (!out)) return 0; 440 while (1) { 441 ret = Read(in,buffer,16384); 442 if (ret > 0) { 443 nwrite = ret; 444 cw = buffer; 445 while (nwrite) { 446 wret = Write(out,cw,nwrite); 447 if (wret < 0) return -1; 448 nwrite = nwrite - wret; 449 cw += wret; 450 } 451 nbytes += ret; 452 } else { 453 return nbytes; 454 } 455 } 456} 457 458 459/* ----------------------------------------------------------------------------- 460 * DohSplit() 461 * 462 * Split an input stream into a list of strings delimited by the specified 463 * character. Optionally accepts a maximum number of splits to perform. 464 * ----------------------------------------------------------------------------- */ 465 466DOH * 467DohSplit(DOH *in, char ch, int nsplits) { 468 DOH *list; 469 DOH *str; 470 int c; 471 472 list = NewList(); 473 474 if (DohIsString(in)) { 475 Seek(in,0,SEEK_SET); 476 } 477 478 while (1) { 479 str = NewString(""); 480 do { 481 c = Getc(in); 482 } while ((c != EOF) && (c == ch)); 483 if (c != EOF) { 484 Putc(c,str); 485 while (1) { 486 c = Getc(in); 487 if ((c == EOF) || ((c == ch) && (nsplits != 0))) break; 488 Putc(c,str); 489 } 490 nsplits--; 491 } 492 Append(list,str); 493 Delete(str); 494 if (c == EOF) break; 495 } 496 return list; 497} 498 499/* ----------------------------------------------------------------------------- 500 * DohSplitLines() 501 * 502 * Split an input stream into a list of strings delimited by newline characters. 503 * ----------------------------------------------------------------------------- */ 504 505DOH * 506DohSplitLines(DOH *in) { 507 DOH *list; 508 DOH *str; 509 int c = 0; 510 511 list = NewList(); 512 513 if (DohIsString(in)) { 514 Seek(in,0,SEEK_SET); 515 } 516 517 while (c != EOF) { 518 str = NewString(""); 519 while ((c = Getc(in)) != '\n' && c != EOF) { 520 Putc(c, str); 521 } 522 Append(list,str); 523 Delete(str); 524 } 525 return list; 526} 527 528 529/* ----------------------------------------------------------------------------- 530 * DohReadline() 531 * 532 * Read a single input line and return it as a string. 533 * ----------------------------------------------------------------------------- */ 534 535DOH * 536DohReadline(DOH *in) { 537 char c; 538 int n = 0; 539 DOH *s = NewString(""); 540 while (1) { 541 if (Read(in,&c,1) < 0) { 542 if (n == 0) { 543 Delete(s); 544 return 0; 545 } 546 return s; 547 } 548 if (c == '\n') return s; 549 if (c == '\r') continue; 550 Putc(c,s); 551 n++; 552 } 553} 554 555