Subversion Repositories wimsdev

Rev

Rev 15588 | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /*    Copyright (C) 1998-2003 XIAO, Gang of Universite de Nice - Sophia Antipolis
  2.  *
  3.  *  This program is free software; you can redistribute it and/or modify
  4.  *  it under the terms of the GNU General Public License as published by
  5.  *  the Free Software Foundation; either version 2 of the License, or
  6.  *  (at your option) any later version.
  7.  *
  8.  *  This program is distributed in the hope that it will be useful,
  9.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.  *  GNU General Public License for more details.
  12.  *
  13.  *  You should have received a copy of the GNU General Public License
  14.  *  along with this program; if not, write to the Free Software
  15.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16.  */
  17. /* line input / output routines */
  18.  
  19. #include <stdarg.h>
  20. #include "libwims.h"
  21.  
  22. /* copy of possibly overlapping strings, to replace strcpy which is not guaranteed in this case
  23.    and indeed produces errors particularly on 64 bits computers */
  24.  
  25. void ovlstrcpy(char *dest, char *src)
  26. {
  27.   memmove(dest, src, strlen(src)+1);
  28. }
  29.  
  30. #define int_buf_size 40
  31.  
  32. /* this is rapid. Output string will be erased at the next call. */
  33. char *int2str(int i)
  34. {
  35.   int neg,t;
  36.   static char int_buf[int_buf_size];
  37.   int_buf[int_buf_size-1]=0;
  38.   neg=0; if(i<0) {neg=1;i=-i;}
  39.   for(t=int_buf_size-2;t>=0;) {
  40.     int_buf[t--]=i%10+'0'; i/=10;
  41.     if(i==0) break;
  42.   }
  43.   if(t<=0) {int_buf[0]=0; return int_buf;} /* should never occur. */
  44.   if(neg) int_buf[t--]='-';
  45.   t++; return int_buf+t;
  46. }
  47.  
  48. void *xmalloc(size_t n)
  49. {
  50.     void *p;
  51.     p=malloc(n);
  52.     if(p==NULL) {
  53.       fprintf(stderr,"Malloc failure."); exit(1);
  54.     }
  55.     return p;
  56. }
  57.  
  58. int msleep(int ms)
  59. {
  60.     struct timespec req, rem;
  61.     if(ms<=0) return 0;
  62.     req.tv_sec=ms/1000; req.tv_nsec=(ms%1000)*1000*1000;
  63.     return nanosleep(&req,&rem);
  64. }
  65.  
  66.   /* dos/mac to unix/linux translation */
  67. void _tolinux(char *p)
  68. {
  69.     char *pp,*p1;
  70.     pp=strchr(p,13); if(pp==NULL) return;
  71.     for(p1=pp; *pp; pp++) {
  72.       if(*pp==13) {
  73.           if(*(pp+1)=='\n' || (pp>p && *(pp-1)=='\n') ||
  74.              (*(pp+1)=='\\' && *(pp+2)=='\n')) continue;
  75.           else *pp='\n';
  76.       }
  77.       *p1++=*pp;
  78.     }
  79.     *p1=0;
  80. }
  81.  
  82.  
  83. /* optimized and secure strcpy */
  84.  
  85. /* copies src to dest, at most lim bytes. Error if more than
  86.    MAX_LINELEN chars would be copied, including final \0. */
  87.  
  88. void mystrncpy(char *dest, const char *src, size_t lim)
  89. {
  90.   if (lim){
  91.     size_t i = strlen(src);
  92.     if (i >= lim) i = lim-1;
  93.     if (i >= MAX_LINELEN) error("cmd_output_too_long");
  94.     memmove(dest,src,i); dest[i]=0;
  95.   }
  96. }
  97.  
  98. /* find matching parenthesis.
  99.  * The entrance point should be after the opening
  100.  * parenthesis.
  101.  * Returns NULL if unmatched.
  102.  */
  103. char *find_matching(char *p, char c)
  104. {
  105.   char *pp;
  106.   int parenth, brak, brace;
  107.   if(c=='|') {
  108.     for(pp=p;*pp!=0;pp++) {
  109.       switch(*pp) {
  110.         case '|': return pp;
  111.         case '(': {
  112.           pp=find_matching(pp+1,')');
  113.           if(pp==NULL) return NULL;
  114.           break;
  115.         }
  116.         case '[': {
  117.           pp=find_matching(pp+1,']');
  118.           if(pp==NULL) return NULL;
  119.           break;
  120.         }
  121.         case '{': {
  122.           pp=find_matching(pp+1,'}');
  123.           if(pp==NULL) return NULL;
  124.           break;
  125.         }
  126.         case ')':
  127.         case ']':
  128.         case '}': return NULL;
  129.  
  130.         default: break;
  131.       }
  132.     }
  133.     return NULL;
  134.   }
  135.   parenth=brak=brace=0;
  136.   for(pp=p; *pp!=0; pp++) {
  137.     switch(*pp) {
  138.       case '[': brak++; break;
  139.       case ']': brak--; break;
  140.       case '(': parenth++; break;
  141.       case ')': parenth--; break;
  142.       case '{': brace++; break;
  143.       case '}': brace--; break;
  144.       default: continue;
  145.     }
  146.     if(parenth<0 || brak<0 || brace<0) {
  147.       if(*pp!=c || parenth>0 || brak>0 || brace>0) return NULL;
  148.       else break;
  149.     }
  150.   }
  151.   if(*pp!=c) return NULL;
  152.   return pp;
  153. }
  154.  
  155. /* Points to the end of the word */
  156. char *find_word_end(char *p)
  157. {
  158.   while(!myisspace(*p) && *p!=0) p++;
  159.   return p;
  160. }
  161.  
  162. /* Strips leading spaces */
  163. char *find_word_start(char *p)
  164. {
  165.   while(myisspace(*p)) p++;
  166.   return p;
  167. }
  168.  
  169. /* find a character in a string, but skipping parentheses. */
  170. char *strparchr(char *p, char c)
  171. {
  172.   char *pp;
  173.  
  174.   for(pp=p;*pp && *pp!=c && pp-p<MAX_LINELEN; pp++) {
  175.     switch(*pp) {
  176.       case '(': pp=find_matching(pp+1,')'); break;
  177.       case '[': pp=find_matching(pp+1,']'); break;
  178.       case '{': pp=find_matching(pp+1,'}'); break;
  179.     }
  180.     if(pp==NULL) return NULL;
  181.   }
  182.   if(*pp==c) return pp; else return NULL;
  183. }
  184.  
  185. /* search for string, skipping parentheses */
  186. char *strparstr(char *p, char *fnd)
  187. {
  188.   char *pp, c=*fnd;
  189.   size_t n = strlen(fnd);
  190.   /*if(*fnd==0) return p+strlen(p);*/
  191.   for(pp=p; *pp; pp++) {
  192.     if(*pp==c && (n==1 || strncmp(pp,fnd,n)==0)) return pp;
  193.     switch(*pp) {
  194.       case '(': pp=find_matching(pp+1,')'); break;
  195.       case '[': pp=find_matching(pp+1,']'); break;
  196.       case '{': pp=find_matching(pp+1,'}'); break;
  197.     }
  198.     if (!pp) { pp = strstr(p,fnd); if (!pp) pp = p+strlen(p); break; }
  199.   }
  200.   return pp;
  201. }
  202.  
  203. /* Points to the end of an item */
  204. char *find_item_end(char *p)
  205. {
  206.   return strparstr(p,",");
  207. }
  208.  
  209. /* Points to the end of an item */
  210. char *find_line_end(char *p)
  211. {
  212.   char *pp=strstr(p,"\n");
  213.   if(pp==NULL) pp=p+strlen(p);
  214.   return pp;
  215. }
  216.  
  217. char *charchr(char *p,char *w)
  218. {
  219.   return strchr(p,w[0]);
  220. }
  221.  
  222. /* Find first occurrence of word */
  223. char *wordchr(char *p, char *w)
  224. {
  225.   char *r; int n;
  226.  
  227.   if(*w==0) return NULL;
  228.   n=strlen(w);
  229.   for(r=strstr(p,w);r!=NULL &&
  230.       ( (r>p && !myisspace(*(r-1))) || (!myisspace(*(r+n)) && *(r+n)!=0) );
  231.     r=strstr(r+1,w)){};
  232.   return r;
  233. }
  234.  
  235. /* Find first occurrence of item */
  236. char *itemchr(char *p, char *w)
  237. {
  238.   char *r, *r1, *r2; int n;
  239.  
  240.   if(*w==0) return NULL;
  241.   n=strlen(w);
  242.   for(r=strstr(p,w);r!=NULL; r=strstr(r+1,w)) {
  243.     r1=r-1;while(r1>=p && myisspace(*r1)) r1--;
  244.     r2=find_word_start(r+n);
  245.     if((r1<p || *r1==',') && (*r2==0 || *r2==',')) return r;
  246.   }
  247.   return r;
  248. }
  249.  
  250. /* Find first occurrence of line */
  251. char *linechr(char *p, char *w)
  252. {
  253.   char *r;
  254.   int n;
  255.  
  256.   if(*w==0) return NULL;
  257.   n=strlen(w);
  258.   for(r=strstr(p,w);r!=NULL; r=strstr(r+1,w)) {
  259.     if((r<=p || *(r-1)=='\n') && (*(r+n)==0 || *(r+n)=='\n'))
  260.       break;
  261.   }
  262.   return r;
  263. }
  264.  
  265. /* find a variable in a string (math expression).
  266.  * Returns the pointer or NULL. */
  267. char *varchr(char *p, char *v)
  268. {
  269.   char *pp; int n;
  270.   if(*v==0) return NULL;
  271.   n=strlen(v);
  272.   for(pp=strstr(p,v); pp!=NULL; pp=strstr(pp+1,v)) {
  273.     if((pp==p || (!myisalnum(*(pp-1)) && *(pp-1)!='_')) &&
  274.        ((!myisalnum(*(pp+n)) && *(pp+n)!='_' && *(pp+n)!='\'')
  275.         || *(pp+n)==0)) break;
  276.   }
  277.   return pp;
  278. }
  279.  
  280. int _cutit_(char *p, char *list[], int max, char *end_finder(char *pt), int tag)
  281. {
  282.   int i;
  283.   char *pp, *pe, *p0;
  284.   if(tag&1) pp=find_word_start(p); else pp=p; /* strip head space */
  285.   for(i=0;i<max && *pp;i++) {
  286.     pe=end_finder(pp);
  287.     if((tag&2) && myisspace(pe[-1])) { /* strip trailing space */
  288.       for(p0=pe; p0>pp && myisspace(p0[-1]); p0--);
  289.       if(p0<pe) *p0=0;
  290.     }
  291.     if(*pe) *pe++=0;
  292.     list[i]=pp;
  293.     if(tag&1) pp=find_word_start(pe); else pp=pe;
  294.   }
  295.   return i;
  296. }
  297.  
  298. int cutitems(char *p, char *list[], int max)
  299. {
  300.   return _cutit_(p,list,max,find_item_end,3);
  301. }
  302.  
  303. int cutwords(char *p, char *list[], int max)
  304. {
  305.   return _cutit_(find_word_start(p),list,max,find_word_end,1);
  306. }
  307.  
  308. int cutlines(char *p, char *list[], int max)
  309. {
  310.   return _cutit_(p,list,max,find_line_end,0);
  311. }
  312.  
  313. int cutchars(char *p, char *list[], int max)
  314. {
  315.   int i; char *pp;
  316.   for(i=0,pp=p;*pp && i<max;list[i++]=pp++);
  317.   return i;
  318. }
  319.  
  320. /* strip trailing spaces; return string end. */
  321. char *strip_trailing_spaces(char *p)
  322. {
  323.   char *pp;
  324.   if(*p==0) return p;
  325.   for(pp=p+strlen(p)-1; pp>=p && myisspace(*pp); pp--);
  326.   if(pp[1]) pp[1]=0;
  327.   return pp;
  328. }
  329.  
  330. /*  strip trailing spaces; return string end. */
  331. char *strip_trailing_spaces2(char *p)
  332. {
  333.   char *pp;
  334.   if(*p==0) return p;
  335.   for(pp=p+strlen(p)-1; pp>=p && isspace(*pp); *(pp--)=0);
  336.   return pp;
  337. }
  338.  
  339. /* Routines for quick search of item in a list. */
  340.  
  341. /* Verify whether a list is well-ordered. For debugging uses.
  342.  * Returns 0 if order is OK, -1 otherwise. */
  343. int verify_order(void *list, int items, size_t item_size){
  344.   int i; char *old, **p;
  345.   p=list; old=*p;
  346.   for(i=item_size;i<items*item_size;i+=item_size) {
  347.     p=list+i;
  348.     if(strcmp(*p,old)<0) {
  349.       fprintf(stderr,"\nTable disorder: %s > %s\n",old,*p);
  350.       exit(1);
  351.     }
  352.     old=*p;
  353.   }
  354.   return 0;
  355. }
  356.  
  357. /* searches a list. Returns index if found, (-1-index of insertion) if nomatch.
  358.  * Uses binary search, list must be sorted. */
  359.  
  360. int search_list(void *list, int items, size_t item_size, const char *str)
  361. {
  362.   int i = 0;
  363.   while (items > 0){
  364.     int m = items / 2, j = i + m;
  365.     int k = strcmp(*(char **)(list + j * item_size), str);
  366.     if (k == 0) return j;
  367.     if (k > 0) items = m; else {i = j + 1; items -= (m + 1);}
  368.   }
  369.   return ~i;
  370. }
  371.  
  372. /* Returns number of lines in string p */
  373. unsigned int linenum(char *p)
  374. {
  375.   int i; char *pp;
  376.  
  377.   /* Ending blank line will be thus removed. */
  378.   i=strlen(p); if(i>1 && *(p+i-1)=='\n') *(p+i-1)=0;
  379.   if(*p=='\n') i=1; else i=0;
  380.   for(pp=p; pp!=NULL && *pp!=0; pp=strchr(pp+1,'\n'), i++);
  381.   return i;
  382. }
  383.  
  384. /* Returns number of items in the list p, comma separated */
  385. unsigned int itemnum(char *p)
  386. {
  387.   int i; char *pp;
  388.  
  389.   if(*p==0) return 0;
  390.   for(i=0,pp=p; pp==p || *(pp-1)!=0; pp=find_item_end(pp)+1, i++);
  391.   return i;
  392. }
  393.  
  394. /* Returns number of words in string p */
  395. unsigned int wordnum(char *p)
  396. {
  397.   int i; char *pp;
  398.  
  399.   for(i=0, pp=find_word_start(p); *pp!=0; i++) {
  400.     while(!myisspace(*pp) && *pp!=0) pp++;
  401.     while(myisspace(*pp)) pp++;
  402.   }
  403.   return i;
  404. }
  405.  
  406. /* This is just to suppress an annoying compiler warning message. */
  407. unsigned int charnum(char *p)
  408. {
  409.   return strlen(p);
  410. }
  411.  
  412. /* find n-th line in string p */
  413. char *fnd_line(char *p, int n, char bf[])
  414. {
  415.   char *pp;
  416.   int i;
  417.  
  418.     /*
  419. for(i=1,pp=p; pp-1!=NULL && *pp!=0 && i<n; pp=strchr(pp,'\n')+1, i++);
  420.     */
  421.   for(i=1,pp=p; i<n; i++) {
  422.     pp=strchr(pp,'\n');
  423.     if (!pp++) {
  424.       fnd_position=NULL; fnd_nextpos=""; *bf=0; return bf;
  425.     }
  426.   }
  427.   fnd_position=pp;
  428.   for(i=0; *(pp+i)!=0 && *(pp+i)!='\n'; i++) *(bf+i)=*(pp+i);
  429.   *(bf+i)=0;
  430.   if(pp[i]=='\n') i++;
  431.   fnd_nextpos=pp+i;
  432.   return bf;
  433. }
  434.  
  435. /* find n-th item in list p, comma separated */
  436. char *fnd_item(char *p, int n, char bf[])
  437. {
  438.   char *pp, *pe;
  439.   int i;
  440.  
  441.   for(i=1,pp=p; i<n && (pp==p || *(pp-1)!=0); pp=find_item_end(pp)+1, i++);
  442.   fnd_position=pp; if(pp>p && *(pp-1)==0) {
  443.     fnd_position=NULL; *bf=0; return bf;
  444.   }
  445.   pp=find_word_start(pp); pe=find_item_end(pp);
  446.   if(*pe) fnd_nextpos=pe+1; else fnd_nextpos=pe;
  447.   while(pe>pp && myisspace(*(pe-1))) pe--;
  448.   memmove(bf,pp,pe-pp); bf[pe-pp]=0;
  449.   return bf;
  450. }
  451.  
  452. /* find n-th word in string p */
  453. char *fnd_word(char *p, int n, char bf[])
  454. {
  455.   char *pp;
  456.   int i;
  457.  
  458.   for(i=1, pp=find_word_start(p); *pp!=0 && i<n ; i++) {
  459.     while(!myisspace(*pp) && *pp!=0) pp++;
  460.     pp=find_word_start(pp);
  461.   }
  462.   if(*pp) fnd_position=pp; else fnd_position=NULL;
  463.   for(i=0; *(pp+i)!=0 && !myisspace(*(pp+i)); i++) *(bf+i)=*(pp+i);
  464.   fnd_nextpos=find_word_start(pp+i);
  465.   *(bf+i)=0;
  466.   return bf;
  467. }
  468.  
  469. /* find n-th char in string p */
  470. char *fnd_char(char *p, int n, char bf[])
  471. {
  472.   int t;
  473.  
  474.   t=strlen(p);
  475.   if(n>t || n<1) {*bf=0;fnd_position=NULL; fnd_nextpos="";}
  476.   else {
  477.     *bf=*(p+n-1); *(bf+1)=0;
  478.     fnd_position=p+n-1;fnd_nextpos=p+n;
  479.   }
  480.   return bf;
  481. }
  482.  
  483. /* Returns number of lines if semicolons changed to new lines */
  484. int rows2lines(char *p)
  485. {
  486.   char *pp, *p2;
  487.   int t;
  488.   if(strchr(p,'\n')!=NULL) return 0;
  489.   for(t=0, pp=p; *pp; pp++) {
  490.     if(*pp=='(') {p2=find_matching(pp+1,')'); if(p2!=NULL) pp=p2; continue;}
  491.     if(*pp=='[') {p2=find_matching(pp+1,']'); if(p2!=NULL) pp=p2; continue;}
  492.     if(*pp=='{') {p2=find_matching(pp+1,'}'); if(p2!=NULL) pp=p2; continue;}
  493.     if(*pp==';') {*pp='\n'; t++; continue;}
  494.     if(*pp=='&' && myisalpha(*(pp+1))) {
  495.       for(p2=pp+1; myisalpha(*p2) && p2-pp<14; p2++);
  496.       pp=p2; continue;
  497.     }
  498.     if(*pp=='&' && *(pp+1)=='#') {
  499.       for(p2=pp+2; myisdigit(*p2) && p2-pp<6; p2++);
  500.       pp=p2; continue;
  501.     }
  502.   }
  503.   return t;
  504. }
  505.  
  506. void lines2rows(char *p)
  507. {
  508.   char *pp;
  509.   strip_trailing_spaces(p);
  510.   for(pp=strchr(find_word_start(p),'\n'); pp!=NULL; pp=strchr(pp+1,'\n'))
  511.     *pp=';';
  512. }
  513.  
  514. unsigned int rownum(char *p)
  515. {
  516.   char buf[MAX_LINELEN+1];
  517.   snprintf(buf,sizeof(buf),"%s",p);
  518.   rows2lines(buf);
  519.   return linenum(buf);
  520. }
  521.  
  522. /* find n-th row in a matrix p */
  523. char *fnd_row(char *p, int n, char bf[])
  524. {
  525.   rows2lines(p); return fnd_line(p,n,bf);
  526. }
  527.  
  528. /* strstr but may have embedded zeros.
  529.  * Returns memory end if not found.
  530.  * Supposes memory ends with 0.
  531.  */
  532. char *memstr(char *s1, char *s2, int len)
  533. {
  534.   char *p, *pp;
  535.   pp=s1;
  536.   for(p=s1; p<s1+len; p=pp) {
  537.     pp=strstr(p,s2); if(pp!=NULL) break;
  538.     pp=p+strlen(p);
  539.     while(pp<s1+len && *pp==0) pp++;
  540.   }
  541.   return pp;
  542. }
  543.  
  544. /* Check whether parentheses are balanced in a given string.
  545.  * Returns 0 if OK.
  546.  */
  547. /* style=0: simple check. style<>0: strong check. */
  548. static int _check_parentheses(char *p, char *q, int style)
  549. {
  550.   int i,j = q-p, k;
  551.   if(style!=0) {
  552.     char *pp, *pe, c;
  553.     for(pp=p;pp<p+j;pp++) {
  554.       switch (*pp) {
  555.         case ')':
  556.         case ']':
  557.         case '}': return -1;
  558.         case '(': c=')'; goto find;
  559.         case '[': c=']'; goto find;
  560.         case '{': c='}';
  561.         find: {
  562.           pe=find_matching(pp+1,c);
  563.           if(pe==NULL||pe>q) return 1;
  564.               if((k=_check_parentheses(pp+1,pe-1,1))!=0) return k;
  565.           else pp=pe;
  566.         }
  567.         default: break;
  568.       }
  569.     }
  570.     return 0;
  571.   }
  572.   for(i=k=0;i<j && k>=0;i++) {
  573.     if(*(p+i)=='(') k++;
  574.     if(*(p+i)==')') k--;
  575.   }
  576.   return k;
  577. }
  578.  
  579. int check_parentheses(char *p, int style)
  580. {
  581.   int j=strlen(p);
  582.   if(j>=MAX_LINELEN) return 65535;
  583.   return _check_parentheses(p, p+j, style);
  584. }
  585.  
  586. /* Strip enclosing pairs of parentheses */
  587. void strip_enclosing_par(char *p)
  588. {
  589.   char *p1;
  590.   partest: strip_trailing_spaces(p);
  591.   if(*p=='(') {
  592.     p1=find_matching(p+1,')');
  593.     if(p1 && *(p1+1)==0) {
  594.       *p1=0; ovlstrcpy(p,find_word_start(p+1));
  595.       goto partest;
  596.     }
  597.   }
  598.   if(*p=='[') {
  599.     p1=find_matching(p+1,']');
  600.     if(p1 && *(p1+1)==0) {
  601.       *p1=0; ovlstrcpy(p,find_word_start(p+1));
  602.       goto partest;
  603.     }
  604.   }
  605.   if(*p=='{') {
  606.     p1=find_matching(p+1,'}');
  607.     if(p1 && *(p1+1)==0) {
  608.       *p1=0; ovlstrcpy(p,find_word_start(p+1));
  609.       goto partest;
  610.     }
  611.   }
  612. }
  613.  
  614. /* change all spaces into ' ', and collapse multiple occurences */
  615. void singlespace(char *p)
  616. {
  617.   char *pp, *pt, *p2;
  618.   for(pp=pt=p;*pp;pp++) {
  619.     if(!myisspace(*pp)) {*pt++=*pp; continue; }
  620.     *pt++=' ';
  621.     for(p2=pp+1;myisspace(*p2);p2++){};
  622.     pp=--p2;
  623.   }
  624.   *pt=0;
  625. }
  626.  
  627. /* collapses all space characters in string. */
  628. void nospace(char *p)
  629. {
  630.   char *pp, *pt;
  631.   for(pp=pt=p;*pp;pp++) if(!myismspace(*pp)) *pt++=*pp;
  632.   *pt=0;
  633. }
  634.  
  635. void _spaces2_(char *p, char c)
  636. {
  637.   char *pp; int n;
  638.   singlespace(p);
  639.   n=strlen(p); if(*p==' ') {memmove(p,p+1,n);n--;}
  640.   if(n==0) return;
  641.   if(p[n-1]==' ') p[n-1]=0;
  642.   for(pp=strchr(p,' '); pp; pp=strchr(pp,' ')) *pp++=c;
  643. }
  644. /* change words to items */
  645. void words2items(char *p)
  646. {
  647.   _spaces2_(p,',');
  648. }
  649.  
  650. /* change words to lines */
  651. void words2lines(char *p)
  652. {
  653.   _spaces2_(p,'\n');
  654. }
  655.  
  656. /* change lines to items */
  657. void lines2items(char *p)
  658. {
  659.   char *pp;
  660.   for(pp=strchr(p,'\n'); pp; pp=strchr(pp,'\n')) *pp++=',';
  661. }
  662.  
  663. /* change lines to words */
  664. void lines2words(char *p)
  665. {
  666.   char *pp;
  667.   for(pp=strchr(p,'\n'); pp; pp=strchr(pp,'\n')) *pp++=' ';
  668. }
  669.  
  670. /* change items to words */
  671. void items2words(char *p)
  672. {
  673.   char *pp;
  674.   for(pp=strparstr(p,",");*pp;pp=strparstr(pp+1,",")) *pp=' ';
  675. }
  676.  
  677. /* change items to lines */
  678. void items2lines(char *p)
  679. {
  680.   char *pp;
  681.   for(pp=strparstr(p,",");*pp;pp=strparstr(pp+1,",")) *pp='\n';
  682. }
  683. #pragma GCC diagnostic push
  684. #pragma GCC diagnostic ignored "-Winvalid-source-encoding"
  685. char *acctab="çéèêëúùûüáàâäãóòôöõíìïîñýÿÇÉÈÊËÚÙÛÜÁÀÂÃÄÓÒÔÖÕÍÌÏÎÑÝ",
  686.      *deatab="ceeeeuuuuaaaaaoooooiiiinyyCEEEEUUUUAAAAAOOOOOIIIINY";
  687.  
  688. /* fold accented letters to unaccented */
  689. void deaccent(char *p)
  690. {
  691.   char *sp;
  692.   char *v;
  693.   for(sp=p;*sp;sp++) {
  694.     if(*sp<0 && (v=strchr(acctab,*sp))!=NULL)
  695.       *sp=*(deatab+(v-acctab));
  696.   }
  697. }
  698.  
  699. static char mytolower (char c) {
  700.   char *v;
  701.   if (c < 0 && (v=strchr(acctab,c))!=NULL)
  702.     c = deatab[v-acctab];
  703.   return tolower(c);
  704. }
  705.  
  706. int mystrcmp (char *p1,char *p2) {
  707.   char *q1=p1, *q2=p2;
  708.   while(*q1 && *q2) {
  709.     int n=mytolower(*q1++)-mytolower(*q2++);
  710.     if(n) return n;
  711.   };
  712.   if (*q2 || *q1) return *q1 ? 1 : -1;
  713.   return strcmp(p1, p2);
  714. }
  715.  
  716. char *reaccents="'`\"^~";
  717. char *reaccentl="aeiouycnAEIOUYCN";
  718. char *reaccentab="\
  719. áàäâãéèëêeíìïîióòöôõúùüûuýyÿyyccccçnnnnñ\
  720. ÁÀÄÂÃÉÈËÊEÍÌÏÎIÓÒÖÔÕÚÙÜÛUÝYYYYCCCCÇNNNNÑ";
  721. #pragma GCC diagnostic pop
  722. /* compose accent using symbol keys */
  723. void reaccent(char *p)
  724. {
  725.   char *sp, *ap, c;
  726.   int i, k;
  727.   if(*p==0) return;
  728.   for(sp=p+1; *sp; sp++) {
  729.     ap=strchr(reaccents,*sp); if(ap==NULL) continue;
  730.     i=ap-reaccents;
  731.     sp--; ap=strchr(reaccentl,*sp); if(ap==NULL) {sp++; continue;}
  732.     k=ap-reaccentl;
  733.     c=reaccentab[k*strlen(reaccents)+i];
  734.     if(c!=*sp) {*sp=c; ovlstrcpy(sp+1,sp+2);}
  735.     else sp++;
  736.   }
  737. }
  738.  
  739. /* modify a string. Bufferlen must be at least MAX_LINELEN */
  740. void string_modify1(char *start, char *bad_beg, char *bad_end, char *good,...)
  741. {
  742.   char buf[MAX_LINELEN+1];
  743.   int ln, le;
  744.   va_list vp;
  745.  
  746.   va_start(vp,good);
  747.   vsnprintf(buf,sizeof(buf),good,vp); va_end(vp);
  748.   ln=strlen(buf); le=strlen(bad_end);
  749.   if(ln+le+(bad_beg-start)>=MAX_LINELEN) {
  750.     error("string_too_long"); return;
  751.   }
  752.   if(ln!=bad_end-bad_beg) memmove(bad_beg+ln,bad_end,le+1);
  753.   memmove(bad_beg,buf,ln);
  754. }
  755.  
  756. /*  modify a string. Bufferlen must be at least MAX_LINELEN */
  757. void string_modify3(char *start, char *bad_beg, char *bad_end, char *good,...)
  758. {
  759.   char buf[MAX_LINELEN+1];
  760.   va_list vp;
  761.  
  762.   va_start(vp,good);
  763.   vsnprintf(buf,sizeof(buf),good,vp); va_end(vp);
  764.   if(strlen(start)-(bad_end-bad_beg)+strlen(buf)>=MAX_LINELEN)
  765.     return; /* this is an error situation. */
  766.   strcat(buf,bad_end);
  767.   ovlstrcpy(bad_beg,buf);
  768. }
  769.  
  770. /* returns number of bytes written */
  771. int catfile(FILE *outf, char *fn,...)
  772. {
  773.   char buf[4096];
  774.   va_list vp;
  775.   int l,tot,fd;
  776.  
  777.   tot=0;
  778.   va_start(vp,fn);
  779.   vsnprintf(buf,sizeof(buf),fn,vp); va_end(vp);
  780.   fd=open(buf,O_RDONLY); if(fd==-1) return 0;
  781.   for(l=read(fd,buf,4096);l>0 && l<=4096; l=read(fd,buf,4096)) {
  782.     fwrite(buf,1,l,outf); tot+=l;
  783.   }
  784.   close(fd);
  785.   return tot;
  786. }
  787.  
  788. /* returns -1 if error */
  789. long int filelength(char *fn,...)
  790. {
  791.   char buf[MAX_FNAME+1];
  792.   va_list vp;
  793.   struct stat st;
  794.   int l;
  795.  
  796.   va_start(vp,fn);
  797.   vsnprintf(buf,sizeof(buf),fn,vp); va_end(vp);
  798.   l=stat(buf,&st); if(l) return -1;
  799.   return st.st_size;
  800. }
  801.  
  802. char *parend(char *p)
  803. {
  804.   char *pp; int t;
  805.   t=0; for(pp=p;*pp;pp++) {
  806.     if(*pp=='(') t++;
  807.     if(*pp==')') {t--; if(t==0) return pp; if(t<0) return NULL;}
  808.   }
  809.   return NULL;
  810. }
  811.  
  812. char *bufprep(char *p)
  813. {
  814. /*  singlespace(p); strip_trailing_spaces(p); return find_word_start(p); */
  815.   nospace(p); return p;
  816. }
  817.  
  818. #pragma GCC diagnostic push
  819. #pragma GCC diagnostic ignored "-Winvalid-source-encoding"
  820. char *htmlsymbs[][2]={
  821.   {"",""},
  822.   {"&agrave;","à"},
  823.   {"&Agrave;","À"},
  824.   {"&aacute;","á"},
  825.   {"&Aacute;","Á"},
  826.   {"&acirc;","â"},
  827.   {"&Acirc;","Â"},
  828.   {"&atilde;","ã"},
  829.   {"&Atilde;","Ã"},
  830.   {"&auml;","ä"},
  831.   {"&Auml;","Ä"},
  832.   {"&aring;","å"},
  833.   {"&Aring;","Å"},
  834.   {"&aelig;","æ"},
  835.   {"&AElig;","Æ"},
  836.   {"&egrave;","è"},
  837.   {"&Egrave;","È"},
  838.   {"&eacute;","é"},
  839.   {"&Eacute;","É"},
  840.   {"&ecirc;","ê"},
  841.   {"&Ecirc;","Ê"},
  842.   {"&euml;","ë"},
  843.   {"&Euml;","Ë"},
  844.   {"&igrave;","ì"},
  845.   {"&Igrave;","Ì"},
  846.   {"&iacute;","í"},
  847.   {"&Iacute;","Í"},
  848.   {"&icirc;","î"},
  849.   {"&Icirc;","Î"},
  850.   {"&iuml;","ï"},
  851.   {"&Iuml;","Ï"},
  852.   {"&ograve;","ò"},
  853.   {"&Ograve;","Ò"},
  854.   {"&oacute;","ó"},
  855.   {"&Oacute;","Ó"},
  856.   {"&ocirc;","ô"},
  857.   {"&Ocirc;","Ô"},
  858.   {"&otilde;","õ"},
  859.   {"&Otilde;","Õ"},
  860.   {"&ouml;","ö"},
  861.   {"&Ouml;","Ö"},
  862.   {"&oslash;","ø"},
  863.   {"&Oslash;","Ø"},
  864.   {"&ugrave;","ù"},
  865.   {"&Ugrave;","Ù"},
  866.   {"&uacute;","ú"},
  867.   {"&Uacute;","Ú"},
  868.   {"&ucirc;","û"},
  869.   {"&Ucirc;","Û"},
  870.   {"&uuml;","ü"},
  871.   {"&Uuml;","Ü"},
  872.   {"&ntilde;","ñ"},
  873.   {"&Ntilde;","Ñ"},
  874.   {"&ccedil;","ç"},
  875.   {"&Ccedil;","Ç"},
  876.   {"&yacute;","ý"},
  877.   {"&Yacute;","Ý"},
  878.   {"&szlig;","ß"},
  879.   {"&laquo;","«"},
  880.   {"&raquo;","»"},
  881.   {"&lsaquo;","\'"},
  882.   {"&rsaquo;","\'"},
  883.   {"&lsquo;","\'"},
  884.   {"&rsquo;","\'"},
  885.   {"&ldquo;","\""},
  886.   {"&rdquo;","\""},
  887.   {"&amp;","&"},
  888.   {"&lt;","<"},
  889.   {"&gt;","<"},
  890.   {"&quot;","\""},
  891.   {"&para;","§"},
  892.   {"&copy;","©"},
  893.   {"&nbsp;"," "},
  894.   {"&euro;","euro(s)"},
  895.   {"&#44;",","},
  896.   {"&#59;",";"},
  897. };
  898. #pragma GCC diagnostic pop
  899.  
  900. #define thesymbs_no (sizeof(htmlsymbs)/sizeof(htmlsymbs[0]) - 1)
  901.  
  902. int htmltrans[6*thesymbs_no][256]; /* 6 is the maximum length of a html symbol stripped of & and ; */
  903.  
  904. void inithtmltrans()
  905. {
  906.   int i, ns, st, nbstates = thesymbs_no;
  907.   for (i = 1; i <= thesymbs_no; i++)
  908.     {
  909.       st = 0;
  910.       unsigned char *p = (unsigned char *)(htmlsymbs[i][0] + 1);
  911.       while (*p != ';')
  912.         {
  913.           ns = htmltrans[st][*p];
  914.           if (ns == 0) ns = (p[1]==';') ? i : -(++nbstates);
  915.           htmltrans[st][*p] = ns;
  916.           st = abs(ns);
  917.           p++;
  918.         }
  919.     }
  920.   /*  printf("%d etats.\n", nbstates); */
  921. }
  922.  
  923.