/tags/rel-1-3-26/SWIG/Source/DOH/fio.c

# · C · 555 lines · 421 code · 43 blank · 91 comment · 143 complexity · 19da04ece0a840ff17bd63683f4a714d MD5 · raw file

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