PageRenderTime 53ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/tags/lkcd-7.0.1/lkcdutils/lib/libsial/sial_util.c

#
C | 830 lines | 604 code | 164 blank | 62 comment | 146 complexity | d1ec68ce1cb539634dfb5a2cfac6a20c MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0, LGPL-2.1, LGPL-2.0
  1. /*
  2. * Copyright 2001 Silicon Graphics, Inc. All rights reserved.
  3. */
  4. #include "sial.h"
  5. #include <string.h>
  6. #include <unistd.h>
  7. #include <curses.h>
  8. #include <term.h>
  9. #include <termio.h>
  10. #include <ctype.h>
  11. #include <stdarg.h>
  12. #include <malloc.h>
  13. #include <limits.h>
  14. #include <sys/mman.h>
  15. #include <sys/types.h>
  16. #include <stdlib.h>
  17. #include <regex.h>
  18. #include <ctype.h>
  19. static FILE *ofile=0;
  20. static int cols=25;
  21. static char *bold_on, *bold_off;
  22. static void
  23. sial_getwinsize(void)
  24. {
  25. struct winsize w;
  26. if (ioctl (fileno(ofile), TIOCGWINSZ, &w) == 0)
  27. {
  28. cols=w.ws_col;
  29. }
  30. else /* use ENV */
  31. {
  32. char *ewidth;
  33. if ((ewidth = getenv ("COLUMNS")))
  34. cols = atoi (ewidth);
  35. /* use what's in terminfo */
  36. if (cols <= 0)
  37. cols = tigetnum ("co");
  38. }
  39. if(cols <= 10) cols=10;
  40. if(cols > 80) cols=80;
  41. }
  42. void
  43. sial_setofile(void * f)
  44. {
  45. int out;
  46. int ret;
  47. char *term;
  48. ofile=(FILE *)f;
  49. bold_on="";
  50. bold_off="";
  51. cols=80;
  52. out=fileno(ofile);
  53. if(isatty(out))
  54. {
  55. if(!(term = getenv ("TERM"))) term="dumb";
  56. if(setupterm(term, out, &ret)!=ERR)
  57. {
  58. bold_on=tigetstr("bold");
  59. if(!bold_on) bold_on="";
  60. bold_off=tigetstr("sgr0");
  61. if(!bold_off) bold_off="";
  62. }
  63. sial_getwinsize();
  64. }
  65. }
  66. void *
  67. sial_getofile(void)
  68. {
  69. return ofile;
  70. }
  71. /*
  72. Output a line of text to the screen with line wrap
  73. and escape sequence.
  74. */
  75. #define ESC '<'
  76. #define ESC2 '>'
  77. static int
  78. sial_tabs(int tabs, char *t, int lf)
  79. {
  80. int i;
  81. if(lf) fprintf(ofile, "\n");
  82. for(i=0;i <tabs; i++) fprintf(ofile, t);
  83. return tabs*4;
  84. }
  85. void
  86. sial_format(int tabs, char *str)
  87. {
  88. char *t=" ";
  89. char *p;
  90. int n;
  91. int mode=0;
  92. n=sial_tabs(tabs, t, 0);
  93. sial_getwinsize();
  94. for(p=str; *p; p++) {
  95. /* check for escape */
  96. if(!mode && *p == ESC && *(p+1) && *(p+1) == ESC) {
  97. fprintf(ofile, "%s", bold_on);
  98. p++;
  99. mode=1;
  100. } else if(mode && *p == ESC2 && *(p+1) && *(p+1) == ESC2) {
  101. fprintf(ofile, "%s", bold_off);
  102. p++;
  103. mode=0;
  104. } else if(*p==' ' || *p=='\t' ) {
  105. char *p2;
  106. int wl;
  107. for(p2=p+1; *p2 && *p2 != ' ' && *p2 != '\t'; p2++);
  108. wl=p2-p-1;
  109. if(wl > cols) {
  110. char *p3=p+(cols-n-1);
  111. char c=*p3;
  112. char c2=*(p3+1);
  113. *p3='-';
  114. *(p3+1)='\0';
  115. fprintf(ofile, "%s", p);
  116. *p3=c;
  117. *(p3+1)=c2;
  118. n=sial_tabs(tabs, t, 0);
  119. } else if(n + (p2-p) >= cols) {
  120. n=sial_tabs(tabs, t, 1);
  121. } else {
  122. fprintf(ofile, " ");
  123. n++;
  124. }
  125. } else if(*p=='\n') {
  126. n=sial_tabs(tabs, t, 1);
  127. } else {
  128. fprintf(ofile, "%c", *p);
  129. n++;
  130. }
  131. }
  132. }
  133. void
  134. sial_msg(char *fmt, ...)
  135. {
  136. va_list ap;
  137. va_start(ap, fmt);
  138. vfprintf(ofile, fmt, ap);
  139. va_end(ap);
  140. }
  141. void
  142. sial_freenode(node_t *n)
  143. {
  144. n->free(n->data);
  145. sial_free(n);
  146. }
  147. int lineno=1, lastline=1;
  148. int col=1;
  149. static char *filename=0;
  150. static char *lastfile=0;
  151. void
  152. sial_setlastfile(char *fname, int line)
  153. {
  154. if(!fname) return;
  155. if(lastfile) sial_free(lastfile);
  156. lastfile=sial_strdup(fname);
  157. lastline=line;
  158. }
  159. void
  160. sial_rstpos(void)
  161. {
  162. lineno=1;
  163. col=1;
  164. /* do not free filename */
  165. filename=0;
  166. }
  167. void
  168. sial_setpos(srcpos_t *p)
  169. {
  170. p->line=lineno;
  171. p->col=col;
  172. p->file=filename;
  173. }
  174. /* set the current position */
  175. void
  176. sial_curpos(srcpos_t *p, srcpos_t *s)
  177. {
  178. if(s) {
  179. s->line=lineno;
  180. s->col=col;
  181. s->file=filename;
  182. }
  183. lineno=p->line;
  184. col=p->col;
  185. filename=p->file;
  186. }
  187. int
  188. sial_line(int inc){ return lineno+=inc; }
  189. int
  190. sial_col(int inc) { return col+=inc; }
  191. char *
  192. sial_filename(void) { return filename; }
  193. /*
  194. This function scans a printf() fmt string and transaletes the %p
  195. to %08x or %016x depending on the pointer size of the object image.
  196. We also substiture %> for 8 spaces if the pointer size is 4 bytes, this
  197. permits easy allignment of output on either 32 or 64 bit images.
  198. ex:
  199. Proc %> pid ppid
  200. %p %3d %3d
  201. In this case the %> alligns the pid with it's corresponding value_t
  202. in the next line of output.
  203. We also process the '?' format which will be set to match the
  204. corresponding value_t type.
  205. Also, format versus argument type validation is performed.
  206. */
  207. /*
  208. Printf formats have the form :
  209. %3$-*3$.*4$lld
  210. %20x
  211. %08x
  212. %-08.8f
  213. */
  214. /* these are the buildin blocks for a regex matching formats */
  215. #define F_POSP "([0-9]+\\$)*"
  216. #define F_FLGS "([-'+ #0]*)"
  217. #define F_WARG "(\\*([0-9]+\\$)*){0,1}"
  218. #define F_WIDTH "([0-9]*)"
  219. #define F_PREC "((\\.(\\*([0-9]+\\$)*)*([0-9]*))*)"
  220. #define F_SIZE "([hlL]*)"
  221. #define F_FMT "([diouxXfeEgGcCsSpn?>]{1})"
  222. #define FMTREG F_POSP""F_FLGS""F_WARG""F_WIDTH""F_PREC""F_SIZE""F_FMT
  223. #define M_POSP 1
  224. #define M_FLAGS 2
  225. #define M_WIDTHARG 3
  226. #define M_WIDTDIGITS 4
  227. #define M_WIDTH 5
  228. #define M_PRECARG 8
  229. #define M_PRECDIGITS 9
  230. #define M_PREC 10
  231. #define M_SIZE 11
  232. #define M_FMT 12
  233. #define NMATCH 16
  234. static int addit[]={M_FLAGS,M_WIDTHARG,M_WIDTH,M_PRECARG,M_PREC,M_SIZE};
  235. #define ptrto(idx) (matches[idx].rm_so==matches[idx].rm_eo?0:(pi+matches[idx].rm_so))
  236. #define matchlen(idx) (matches[(idx)].rm_eo-matches[(idx)].rm_so)
  237. void sial_error(char *fmt, ...);
  238. static int
  239. chkforint(char *p, value_t **vals, int *curarg)
  240. {
  241. int pos=-1;
  242. if(!p) return -1;
  243. /* a single star ? */
  244. if(isdigit(p[1])) {
  245. if(sscanf(p+1, "%d", &pos)!=1) {
  246. return pos;
  247. }
  248. pos--;
  249. } else {
  250. pos=*curarg;
  251. *curarg=(*curarg)+1;
  252. }
  253. if(pos < BT_MAXARGS && vals[pos] && vals[pos]->type.type == V_BASE) return pos;
  254. sial_error("Expected 'integer' type for arg%d", pos+1);
  255. return -1;
  256. }
  257. #define pushval(val, s, sig) ( \
  258. sig ? \
  259. ( \
  260. (s==8) ? \
  261. (val)->v.sll \
  262. : ( \
  263. (s==4) ? \
  264. (val)->v.sl \
  265. : ( \
  266. (s==2) ? \
  267. (val)->v.ss \
  268. :( \
  269. (s==1) ? \
  270. (val)->v.sc \
  271. :( \
  272. sial_error("Oops pushval"),1 \
  273. ) \
  274. ) \
  275. ) \
  276. ) \
  277. ) : ( \
  278. (s==8) ? \
  279. (val)->v.ull \
  280. : ( \
  281. (s==4) ? \
  282. (val)->v.ul \
  283. : ( \
  284. (s==2) ? \
  285. (val)->v.us \
  286. :( \
  287. (s==1) ? \
  288. (val)->v.uc \
  289. :( \
  290. sial_error("Oops pushval"),1 \
  291. ) \
  292. ) \
  293. ) \
  294. ) \
  295. ) \
  296. )
  297. static char *
  298. add_fmt(int len, char *s, char *onefmt, int ppos, int wpos, int posarg, value_t **vals)
  299. {
  300. int size=(vals[posarg]->type.type == V_REF ? sial_defbsize(): vals[posarg]->type.size);
  301. int sign=(vals[posarg]->type.type == V_REF ? 0 : sial_issigned(vals[posarg]->type.typattr));
  302. if(vals[posarg]->type.type == V_STRING) {
  303. if(wpos>=0 && ppos<0)
  304. s+=snprintf(s, len, onefmt
  305. , (int)sial_getval(vals[wpos])
  306. , vals[posarg]->v.data);
  307. else if(wpos<0 && ppos>=0)
  308. s+=snprintf(s, len, onefmt
  309. , (int)sial_getval(vals[ppos])
  310. , vals[posarg]->v.data);
  311. else if(wpos>=0 && ppos>=0)
  312. s+=snprintf(s, len, onefmt
  313. , (int)sial_getval(vals[wpos])
  314. , (int)sial_getval(vals[ppos])
  315. , vals[posarg]->v.data);
  316. else s+=snprintf(s, len, onefmt
  317. , vals[posarg]->v.data);
  318. } else {
  319. #if defined(__s390x__) || defined(__s390__)
  320. if(wpos>=0 && ppos<0)
  321. s+=snprintf(s, len, onefmt
  322. , (int)sial_getval(vals[wpos])
  323. , (unsigned long)pushval(vals[posarg], size, sign));
  324. else if(wpos<0 && ppos>=0)
  325. s+=snprintf(s, len, onefmt
  326. , (int)sial_getval(vals[ppos])
  327. , (unsigned long)pushval(vals[posarg], size, sign));
  328. else if(wpos>=0 && ppos>=0)
  329. s+=snprintf(s, len, onefmt
  330. , (int)sial_getval(vals[wpos])
  331. , (int)sial_getval(vals[ppos])
  332. , (unsigned long) pushval(vals[posarg], size, sign));
  333. else s+=snprintf(s, len, onefmt
  334. , (unsigned long) pushval(vals[posarg], size, sign));
  335. #else
  336. if(wpos>=0 && ppos<0)
  337. s+=snprintf(s, len, onefmt
  338. , (int)sial_getval(vals[wpos])
  339. , pushval(vals[posarg], size, sign));
  340. else if(wpos<0 && ppos>=0)
  341. s+=snprintf(s, len, onefmt
  342. , (int)sial_getval(vals[ppos])
  343. , pushval(vals[posarg], size, sign));
  344. else if(wpos>=0 && ppos>=0)
  345. s+=snprintf(s, len, onefmt
  346. , (int)sial_getval(vals[wpos])
  347. , (int)sial_getval(vals[ppos])
  348. , pushval(vals[posarg], size, sign));
  349. else s+=snprintf(s, len, onefmt
  350. , pushval(vals[posarg], size, sign));
  351. #endif
  352. }
  353. return s;
  354. }
  355. static char *
  356. sial_ptr(char *fmt, value_t **vals)
  357. {
  358. /* We need to ensure that we dont overflow our string buffer. Although its unlikely we will overflow it with
  359. just numbers, strings will easliy overflow. So, lets check for strings and see how long they are.
  360. */
  361. int len=0;
  362. char *nfmt=NULL,*ni=NULL;
  363. char *onefmt=NULL, *onei=NULL;
  364. char *p=fmt;
  365. char last=' ';
  366. int curarg=0;
  367. #define NBYTES (len-(nfmt-ni))
  368. int i = 0;
  369. while(vals[i] != NULL) {
  370. if(vals[i]->type.type == V_STRING)
  371. len+=vals[i]->type.size;
  372. i++;
  373. }
  374. /* We add a fudge factor of 100, which should cover all the number arguments */
  375. len+=strlen(fmt) + 100;
  376. nfmt=sial_alloc(len);
  377. ni=nfmt;
  378. onefmt=sial_alloc(len);
  379. onei=onefmt;
  380. while(*p) {
  381. if(*p=='%') {
  382. static regex_t preg;
  383. static int done=0;
  384. regmatch_t matches[NMATCH];
  385. if(!done) {
  386. regcomp(&preg, FMTREG, REG_EXTENDED);
  387. done=1;
  388. }
  389. /* build a new format translation */
  390. onefmt=onei;
  391. *onefmt++=*p++;
  392. /* if the returned pointer is (char*)-1 or NULL then something is wrong */
  393. if(!regexec(&preg, p, NMATCH, matches, 0)) {
  394. int i, n=matches[0].rm_eo-1;
  395. int posarg, wpos, ppos;
  396. char *pi=p; /* save p for ptrto() macro */
  397. /* check that the width and precision field args point
  398. to a int value_t. If they were used */
  399. wpos=chkforint(ptrto(M_WIDTHARG), vals, &curarg);
  400. ppos=chkforint(ptrto(M_PRECARG), vals, &curarg);
  401. /* argument position was specfified ? */
  402. if(ptrto(M_POSP)) {
  403. /* we work from 0-n, printf works from 1-n */
  404. if(sscanf(ptrto(M_POSP), "%d", &posarg)==1) posarg--;
  405. if(posarg >= BT_MAXARGS || !vals[posarg]) {
  406. sial_error("Invalid arg position specified [%d]", posarg+1);
  407. }
  408. } else posarg=curarg++;
  409. /* jump over the format spec in the original */
  410. p+=n;
  411. #if 0
  412. for(i=0;i<NMATCH;i++) {
  413. char buf[40];
  414. if(ptrto(i)) {
  415. int n=matchlen(i);
  416. strncpy(buf, pi+matches[i].rm_so, n);
  417. buf[n]='\0';
  418. printf("match[%d]=[%s]\n", i, buf);
  419. }
  420. }
  421. #endif
  422. /* copy all format specs to destination except fmt */
  423. for(i=0;i<sizeof(addit)/sizeof(addit[0]);i++) {
  424. switch(addit[i]) {
  425. case M_WIDTHARG:
  426. if(wpos >=0 ){
  427. *onefmt++='*';
  428. } else goto def;
  429. break;
  430. case M_PRECARG:
  431. if(ppos >=0 ){
  432. *onefmt++='.';
  433. *onefmt++='*';
  434. } else goto def;
  435. break;
  436. case M_PREC:
  437. if(ptrto(addit[i])) *onefmt++='.';
  438. goto def;
  439. default:
  440. def:
  441. if(ptrto(addit[i])) {
  442. strcpy(onefmt, ptrto(addit[i]));
  443. onefmt+=matchlen(addit[i]);
  444. }
  445. }
  446. }
  447. if(*p=='p') {
  448. ref:
  449. /* if user overrides anything don't do nothing */
  450. if(ptrto(M_FLAGS)||ptrto(M_WIDTH)||ptrto(M_WIDTHARG)||ptrto(M_PREC)||ptrto(M_PRECARG)||ptrto(M_SIZE)) {
  451. *onefmt++='p';
  452. } else {
  453. if(sial_defbsize()==8) {
  454. strcpy(onefmt, "016llx");
  455. onefmt+=6;
  456. } else {
  457. strcpy(onefmt, "08x");
  458. onefmt+=3;
  459. }
  460. }
  461. *onefmt='\0';
  462. p++;
  463. nfmt=add_fmt(NBYTES, nfmt, onei, ppos, wpos, posarg, vals);
  464. } else if(*p=='>') {
  465. nfmt--;
  466. if(sial_defbsize()==8) {
  467. int i;
  468. for(i=0;i<8;i++) *nfmt++=last;
  469. }
  470. p++;
  471. } else if(*p=='?') {
  472. /* put the proper format for the user */
  473. if(!vals[posarg]) {
  474. sial_error("Expected additional argument %d\n", posarg+1);
  475. } else switch(vals[posarg]->type.type) {
  476. case V_BASE: case V_ENUM:
  477. {
  478. if(!ptrto(M_SIZE)) {
  479. if(vals[posarg]->type.size==8) {
  480. *onefmt++='l';
  481. *onefmt++='l';
  482. }
  483. }
  484. if(sial_issigned(vals[posarg]->type.typattr)) {
  485. *onefmt++='d';
  486. }else{
  487. *onefmt++='u';
  488. }
  489. }
  490. break;
  491. case V_REF:
  492. {
  493. *p='p';
  494. goto ref;
  495. }
  496. case V_STRING:
  497. {
  498. *onefmt++='s';
  499. }
  500. break;
  501. }
  502. p++;
  503. *onefmt='\0';
  504. nfmt=add_fmt(NBYTES, nfmt, onei, ppos, wpos, posarg, vals);
  505. } else {
  506. /* check that format and value_t agree */
  507. /* can't do a lot more then check for strings vs anything_else */
  508. if(!vals[posarg]) {
  509. sial_error("Expected additional argument %d\n", posarg+1);
  510. } else if(*p=='s') {
  511. if(vals[posarg]->type.type != V_STRING) {
  512. sial_error("Expected type 'string' as arg%d", posarg+1);
  513. }
  514. } else if(vals[posarg]->type.type == V_STRING) {
  515. sial_error("Incompatible type 'string' in arg%d", posarg+1);
  516. }
  517. *onefmt++=*p++;
  518. *onefmt='\0';
  519. nfmt=add_fmt(NBYTES, nfmt, onei, ppos, wpos, posarg, vals);
  520. }
  521. } else {
  522. sial_warning("Malformed format specifier!");
  523. }
  524. } else {
  525. last=*p;
  526. if(nfmt-ni > len) sial_error("format tranlation overflow!");
  527. *nfmt++=*p++;
  528. }
  529. }
  530. sial_free(onei);
  531. *nfmt='\0';
  532. return ni;
  533. }
  534. value_t* sial_printf(value_t *vfmt, ...)
  535. {
  536. char *fmt = sial_getptr(vfmt, char);
  537. va_list ap;
  538. value_t *vals[BT_MAXARGS];
  539. int i;
  540. va_start(ap, vfmt);
  541. for(i=0;i<BT_MAXARGS-2;i++){
  542. vals[i]=va_arg(ap,value_t*);
  543. }
  544. va_end(ap);
  545. fmt=sial_ptr(fmt, vals);
  546. fprintf(ofile, "%s", fmt);
  547. sial_free(fmt);
  548. return sial_makebtype(1);
  549. }
  550. #define MAX_SPRINTF 2000
  551. value_t* sial_sprintf(value_t *vfmt, ...)
  552. {
  553. char *fmt=sial_getptr(vfmt, char);
  554. int i;
  555. va_list ap;
  556. value_t *vals[BT_MAXARGS];
  557. value_t *v;
  558. va_start(ap, vfmt);
  559. for(i=0;i<BT_MAXARGS-1;i++){
  560. vals[i]=va_arg(ap,value_t*);
  561. }
  562. va_end(ap);
  563. fmt=sial_ptr(fmt, vals);
  564. v=sial_setstrval(sial_newval(), fmt);
  565. sial_free(fmt);
  566. return v;
  567. }
  568. /*
  569. When there is a parse error in a file.
  570. */
  571. void
  572. sial_error(char *fmt, ...)
  573. {
  574. va_list ap;
  575. sial_setlastfile(filename, sial_line(0));
  576. va_start(ap, fmt);
  577. fprintf(ofile, "File %s, line %d, Error: ", filename, sial_line(0));
  578. vfprintf(ofile, fmt, ap);
  579. fprintf(ofile, "\n");
  580. va_end(ap);
  581. sial_exit(1);
  582. }
  583. void
  584. sial_rerror(srcpos_t *p, char *fmt, ...)
  585. {
  586. va_list ap;
  587. sial_setlastfile(p->file, p->line);
  588. va_start(ap, fmt);
  589. fprintf(ofile, "%s : line %d : Error: ", p->file, p->line);
  590. vfprintf(ofile, fmt, ap);
  591. fprintf(ofile, "\n");
  592. va_end(ap);
  593. sial_exit(1);
  594. }
  595. void
  596. sial_warning(char *fmt, ...)
  597. {
  598. va_list ap;
  599. sial_setlastfile(filename, sial_line(0));
  600. va_start(ap, fmt);
  601. fprintf(ofile, "%s : line %d : Warning: ", filename, lineno);
  602. vfprintf(ofile, fmt, ap);
  603. fprintf(ofile, "\n");
  604. va_end(ap);
  605. }
  606. void
  607. sial_rwarning(srcpos_t *p, char *fmt, ...)
  608. {
  609. va_list ap;
  610. sial_setlastfile(p->file, p->line);
  611. va_start(ap, fmt);
  612. fprintf(ofile, "%s : line %d : Warning: ", p->file, p->line);
  613. vfprintf(ofile, fmt, ap);
  614. fprintf(ofile, "\n");
  615. va_end(ap);
  616. }
  617. void
  618. sial_vilast()
  619. {
  620. if(lastfile) {
  621. sial_exevi(lastfile, lastline);
  622. } else {
  623. sial_msg("No last error record available");
  624. }
  625. }
  626. void
  627. sial_getcomment(void)
  628. {
  629. while(1) {
  630. unsigned char c;
  631. while((c=sial_input())!='*' && c!=255)
  632. if(c==255) goto bad;
  633. if((c=sial_input())=='/') return;
  634. else if(c==255) {
  635. bad:
  636. sial_error("Unterminated comment!");
  637. }
  638. }
  639. }
  640. /* on assignment this function is called to set the new value */
  641. void
  642. sial_setfct(value_t *v1, value_t *v2)
  643. {
  644. /* duplicate type and data, safeguarding array info */
  645. sial_dupval(v1, v2);
  646. /* value_t v1 is still setable */
  647. v1->set=1;
  648. v1->setval=v1;
  649. }
  650. node_t *
  651. sial_sibling(node_t *n, node_t *m)
  652. {
  653. node_t *p;
  654. if(m) {
  655. for(p=n;p->next;p=p->next);
  656. p->next=m;
  657. m->next=0;
  658. }
  659. return n;
  660. }