Subversion Repositories wimsdev

Rev

Rev 12258 | Rev 12884 | Go to most recent revision | 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. {
  345.   int i; char *old, **p;
  346.   p=list; old=*p;
  347.   for(i=item_size;i<items*item_size;i+=item_size) {
  348.     p=list+i;
  349.     if(strcmp(*p,old)<0) {
  350.       fprintf(stderr,"Table disorder: %s > %s",old,*p);
  351.       exit(1);
  352.     }
  353.     old=*p;
  354.   }
  355.   return 0;
  356. }
  357.  
  358. /* searches a list. Returns index if found, (-1-index of insertion) if nomatch.
  359.  * Uses binary search, list must be sorted. */
  360.  
  361. int search_list(void *list, int items, size_t item_size, const char *str)
  362. {
  363.   int i = 0;
  364.   while (items > 0){
  365.     int m = items / 2, j = i + m;
  366.     int k = strcmp(*(char **)(list + j * item_size), str);
  367.     if (k == 0) return j;
  368.     if (k > 0) items = m; else {i = j + 1; items -= (m + 1);}
  369.   }
  370.   return ~i;
  371. }
  372.  
  373. /* Returns number of lines in string p */
  374. unsigned int linenum(char *p)
  375. {
  376.   int i; char *pp;
  377.  
  378.   /* Ending blank line will be thus removed. */
  379.   i=strlen(p); if(i>1 && *(p+i-1)=='\n') *(p+i-1)=0;
  380.   if(*p=='\n') i=1; else i=0;
  381.   for(pp=p; pp!=NULL && *pp!=0; pp=strchr(pp+1,'\n'), i++);
  382.   return i;
  383. }
  384.  
  385. /* Returns number of items in the list p, comma separated */
  386. unsigned int itemnum(char *p)
  387. {
  388.   int i; char *pp;
  389.  
  390.   if(*p==0) return 0;
  391.   for(i=0,pp=p; pp==p || *(pp-1)!=0; pp=find_item_end(pp)+1, i++);
  392.   return i;
  393. }
  394.  
  395. /* Returns number of words in string p */
  396. unsigned int wordnum(char *p)
  397. {
  398.   int i; char *pp;
  399.  
  400.   for(i=0, pp=find_word_start(p); *pp!=0; i++) {
  401.     while(!myisspace(*pp) && *pp!=0) pp++;
  402.     while(myisspace(*pp)) pp++;
  403.   }
  404.   return i;
  405. }
  406.  
  407. /* This is just to suppress an annoying compiler warning message. */
  408. unsigned int charnum(char *p)
  409. {
  410.   return strlen(p);
  411. }
  412.  
  413. /* find n-th line in string p */
  414. char *fnd_line(char *p, int n, char bf[])
  415. {
  416.   char *pp;
  417.   int i;
  418.  
  419.     /*
  420. for(i=1,pp=p; pp-1!=NULL && *pp!=0 && i<n; pp=strchr(pp,'\n')+1, i++);
  421.     */
  422.   for(i=1,pp=p; i<n; i++) {
  423.     pp=strchr(pp,'\n');
  424.     if (!pp++) {
  425.       fnd_position=NULL; fnd_nextpos=""; *bf=0; return bf;
  426.     }
  427.   }
  428.   fnd_position=pp;
  429.   for(i=0; *(pp+i)!=0 && *(pp+i)!='\n'; i++) *(bf+i)=*(pp+i);
  430.   *(bf+i)=0;
  431.   if(pp[i]=='\n') i++;
  432.   fnd_nextpos=pp+i;
  433.   return bf;
  434. }
  435.  
  436. /* find n-th item in list p, comma separated */
  437. char *fnd_item(char *p, int n, char bf[])
  438. {
  439.   char *pp, *pe;
  440.   int i;
  441.  
  442.   for(i=1,pp=p; i<n && (pp==p || *(pp-1)!=0); pp=find_item_end(pp)+1, i++);
  443.   fnd_position=pp; if(pp>p && *(pp-1)==0) {
  444.     fnd_position=NULL; *bf=0; return bf;
  445.   }
  446.   pp=find_word_start(pp); pe=find_item_end(pp);
  447.   if(*pe) fnd_nextpos=pe+1; else fnd_nextpos=pe;
  448.   while(pe>pp && myisspace(*(pe-1))) pe--;
  449.   memmove(bf,pp,pe-pp); bf[pe-pp]=0;
  450.   return bf;
  451. }
  452.  
  453. /* find n-th word in string p */
  454. char *fnd_word(char *p, int n, char bf[])
  455. {
  456.   char *pp;
  457.   int i;
  458.  
  459.   for(i=1, pp=find_word_start(p); *pp!=0 && i<n ; i++) {
  460.     while(!myisspace(*pp) && *pp!=0) pp++;
  461.     pp=find_word_start(pp);
  462.   }
  463.   if(*pp) fnd_position=pp; else fnd_position=NULL;
  464.   for(i=0; *(pp+i)!=0 && !myisspace(*(pp+i)); i++) *(bf+i)=*(pp+i);
  465.   fnd_nextpos=find_word_start(pp+i);
  466.   *(bf+i)=0;
  467.   return bf;
  468. }
  469.  
  470. /* find n-th char in string p */
  471. char *fnd_char(char *p, int n, char bf[])
  472. {
  473.   int t;
  474.  
  475.   t=strlen(p);
  476.   if(n>t || n<1) {*bf=0;fnd_position=NULL; fnd_nextpos="";}
  477.   else {
  478.     *bf=*(p+n-1); *(bf+1)=0;
  479.     fnd_position=p+n-1;fnd_nextpos=p+n;
  480.   }
  481.   return bf;
  482. }
  483.  
  484. /* Returns 1 if semicolons changed to new lines */
  485. int rows2lines(char *p)
  486. {
  487.   char *pp, *p2;
  488.   int t;
  489.   if(strchr(p,'\n')!=NULL) return 0;
  490.   for(t=0, pp=p; *pp; pp++) {
  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=='{') {p2=find_matching(pp+1,'}'); if(p2!=NULL) pp=p2; continue;}
  494.     if(*pp==';') {*pp='\n'; t++; continue;}
  495.     if(*pp=='&' && myisalpha(*(pp+1))) {
  496.       for(p2=pp+1; myisalpha(*p2) && p2-pp<14; p2++);
  497.       pp=p2; continue;
  498.     }
  499.     if(*pp=='&' && *(pp+1)=='#') {
  500.       for(p2=pp+2; myisdigit(*p2) && p2-pp<6; p2++);
  501.       pp=p2; continue;
  502.     }
  503.   }
  504.   return t;
  505. }
  506.  
  507. void lines2rows(char *p)
  508. {
  509.   char *pp;
  510.   strip_trailing_spaces(p);
  511.   for(pp=strchr(find_word_start(p),'\n'); pp!=NULL; pp=strchr(pp+1,'\n'))
  512.     *pp=';';
  513. }
  514.  
  515. unsigned int rownum(char *p)
  516. {
  517.   char buf[MAX_LINELEN+1];
  518.   snprintf(buf,sizeof(buf),"%s",p);
  519.   rows2lines(buf);
  520.   return linenum(buf);
  521. }
  522.  
  523. /* find n-th row in a matrix p */
  524. char *fnd_row(char *p, int n, char bf[])
  525. {
  526.   rows2lines(p); return fnd_line(p,n,bf);
  527. }
  528.  
  529. /* strstr but may have embedded zeros.
  530.  * Returns memory end if not found.
  531.  * Supposes memory ends with 0.
  532.  */
  533. char *memstr(char *s1, char *s2, int len)
  534. {
  535.   char *p, *pp;
  536.   pp=s1;
  537.   for(p=s1; p<s1+len; p=pp) {
  538.     pp=strstr(p,s2); if(pp!=NULL) break;
  539.     pp=p+strlen(p);
  540.     while(pp<s1+len && *pp==0) pp++;
  541.   }
  542.   return pp;
  543. }
  544.  
  545. /* Check whether parentheses are balanced in a given string.
  546.  * Returns 0 if OK.
  547.  */
  548. /* style=0: simple check. style<>0: strong check. */
  549. int check_parentheses(char *p, int style)
  550. {
  551.   int i,j,k;
  552.   j=strlen(p);
  553.   if(j>=MAX_LINELEN) return 65535;
  554.   if(style!=0) {
  555.     char buf[MAX_LINELEN+1];
  556.     char *pp, *pe, c;
  557.     for(pp=p;pp<p+j;pp++) {
  558.       switch (*pp) {
  559.         case ')':
  560.         case ']':
  561.         case '}': return -1;
  562.         case '(': c=')'; goto find;
  563.         case '[': c=']'; goto find;
  564.         case '{': c='}';
  565.         find: {
  566.           pe=find_matching(pp+1,c);
  567.           if(pe==NULL) return 1;
  568.           memcpy(buf,pp+1,pe-pp-1);
  569.           buf[pe-pp-1]=0;
  570.           if((k=check_parentheses(buf,1))!=0) return k;
  571.           else pp=pe;
  572.         }
  573.         default: break;
  574.       }
  575.     }
  576.     return 0;
  577.   }
  578.   for(i=k=0;i<j && k>=0;i++) {
  579.     if(*(p+i)=='(') k++;
  580.     if(*(p+i)==')') k--;
  581.   }
  582.   return k;
  583. }
  584.  
  585. /* Strip enclosing pairs of parentheses */
  586. void strip_enclosing_par(char *p)
  587. {
  588.   char *p1;
  589.   partest: strip_trailing_spaces(p);
  590.   if(*p=='(') {
  591.     p1=find_matching(p+1,')');
  592.     if(p1 && *(p1+1)==0) {
  593.       *p1=0; ovlstrcpy(p,find_word_start(p+1));
  594.       goto partest;
  595.     }
  596.   }
  597.   if(*p=='[') {
  598.     p1=find_matching(p+1,']');
  599.     if(p1 && *(p1+1)==0) {
  600.       *p1=0; ovlstrcpy(p,find_word_start(p+1));
  601.       goto partest;
  602.     }
  603.   }
  604.   if(*p=='{') {
  605.     p1=find_matching(p+1,'}');
  606.     if(p1 && *(p1+1)==0) {
  607.       *p1=0; ovlstrcpy(p,find_word_start(p+1));
  608.       goto partest;
  609.     }
  610.   }
  611. }
  612.  
  613. /* change all spaces into ' ', and collapse multiple occurences */
  614. void singlespace(char *p)
  615. {
  616.   char *pp, *pt, *p2;
  617.   for(pp=pt=p;*pp;pp++) {
  618.     if(!myisspace(*pp)) {*pt++=*pp; continue; }
  619.     *pt++=' ';
  620.     for(p2=pp+1;myisspace(*p2);p2++){};
  621.     pp=--p2;
  622.   }
  623.   *pt=0;
  624. }
  625.  
  626. /* collapses all space characters in string. */
  627. void nospace(char *p)
  628. {
  629.   char *pp, *pt;
  630.   for(pp=pt=p;*pp;pp++) if(!myismspace(*pp)) *pt++=*pp;
  631.   *pt=0;
  632. }
  633.  
  634. void _spaces2_(char *p, char c)
  635. {
  636.   char *pp; int n;
  637.   singlespace(p);
  638.   n=strlen(p); if(*p==' ') {memmove(p,p+1,n);n--;}
  639.   if(n==0) return;
  640.   if(p[n-1]==' ') p[n-1]=0;
  641.   for(pp=strchr(p,' '); pp; pp=strchr(pp,' ')) *pp++=c;
  642. }
  643. /* change words to items */
  644. void words2items(char *p)
  645. {
  646.   _spaces2_(p,',');
  647. }
  648.  
  649. /* change words to lines */
  650. void words2lines(char *p)
  651. {
  652.   _spaces2_(p,'\n');
  653. }
  654.  
  655. /* change lines to items */
  656. void lines2items(char *p)
  657. {
  658.   char *pp;
  659.   for(pp=strchr(p,'\n'); pp; pp=strchr(pp,'\n')) *pp++=',';
  660. }
  661.  
  662. /* change lines to words */
  663. void lines2words(char *p)
  664. {
  665.   char *pp;
  666.   for(pp=strchr(p,'\n'); pp; pp=strchr(pp,'\n')) *pp++=' ';
  667. }
  668.  
  669. /* change items to words */
  670. void items2words(char *p)
  671. {
  672.   char *pp;
  673.   for(pp=strparstr(p,",");*pp;pp=strparstr(pp+1,",")) *pp=' ';
  674. }
  675.  
  676. /* change items to lines */
  677. void items2lines(char *p)
  678. {
  679.   char *pp;
  680.   for(pp=strparstr(p,",");*pp;pp=strparstr(pp+1,",")) *pp='\n';
  681. }
  682. #pragma GCC diagnostic push
  683. #pragma GCC diagnostic ignored "-Winvalid-source-encoding"
  684. char *acctab="çéèêëúùûüáàâäãóòôöõíìïîñýÿÇÉÈÊËÚÙÛÜÁÀÂÃÄÓÒÔÖÕÍÌÏÎÑÝ",
  685.      *deatab="ceeeeuuuuaaaaaoooooiiiinyyCEEEEUUUUAAAAAOOOOOIIIINY";
  686.  
  687. /* fold accented letters to unaccented */
  688. void deaccent(char *p)
  689. {
  690.   char *sp;
  691.   char *v;
  692.   for(sp=p;*sp;sp++) {
  693.     if(*sp<0 && (v=strchr(acctab,*sp))!=NULL)
  694.       *sp=*(deatab+(v-acctab));
  695.   }
  696. }
  697.  
  698. char *reaccents="'`\"^~";
  699. char *reaccentl="aeiouycnAEIOUYCN";
  700. char *reaccentab="\
  701. áàäâãéèëêeíìïîióòöôõúùüûuýyÿyyccccçnnnnñ\
  702. ÁÀÄÂÃÉÈËÊEÍÌÏÎIÓÒÖÔÕÚÙÜÛUÝYYYYCCCCÇNNNNÑ";
  703. #pragma GCC diagnostic pop
  704. /* compose accent using symbol keys */
  705. void reaccent(char *p)
  706. {
  707.   char *sp, *ap, c;
  708.   int i, k;
  709.   if(*p==0) return;
  710.   for(sp=p+1; *sp; sp++) {
  711.     ap=strchr(reaccents,*sp); if(ap==NULL) continue;
  712.     i=ap-reaccents;
  713.     sp--; ap=strchr(reaccentl,*sp); if(ap==NULL) {sp++; continue;}
  714.     k=ap-reaccentl;
  715.     c=reaccentab[k*strlen(reaccents)+i];
  716.     if(c!=*sp) {*sp=c; ovlstrcpy(sp+1,sp+2);}
  717.     else sp++;
  718.   }
  719. }
  720.  
  721. /* modify a string. Bufferlen must be at least MAX_LINELEN */
  722. void string_modify1(char *start, char *bad_beg, char *bad_end, char *good,...)
  723. {
  724.   char buf[MAX_LINELEN+1];
  725.   int ln, le;
  726.   va_list vp;
  727.  
  728.   va_start(vp,good);
  729.   vsnprintf(buf,sizeof(buf),good,vp); va_end(vp);
  730.   ln=strlen(buf); le=strlen(bad_end);
  731.   if(ln+le+(bad_beg-start)>=MAX_LINELEN) {
  732.     error("string_too_long"); return;
  733.   }
  734.   if(ln!=bad_end-bad_beg) memmove(bad_beg+ln,bad_end,le+1);
  735.   memmove(bad_beg,buf,ln);
  736. }
  737.  
  738. /*  modify a string. Bufferlen must be at least MAX_LINELEN */
  739. void string_modify3(char *start, char *bad_beg, char *bad_end, char *good,...)
  740. {
  741.   char buf[MAX_LINELEN+1];
  742.   va_list vp;
  743.  
  744.   va_start(vp,good);
  745.   vsnprintf(buf,sizeof(buf),good,vp); va_end(vp);
  746.   if(strlen(start)-(bad_end-bad_beg)+strlen(buf)>=MAX_LINELEN)
  747.     return; /* this is an error situation. */
  748.   strcat(buf,bad_end);
  749.   ovlstrcpy(bad_beg,buf);
  750. }
  751.  
  752. /* returns number of bytes written */
  753. int catfile(FILE *outf, char *fn,...)
  754. {
  755.   char buf[4096];
  756.   va_list vp;
  757.   int l,tot,fd;
  758.  
  759.   tot=0;
  760.   va_start(vp,fn);
  761.   vsnprintf(buf,sizeof(buf),fn,vp); va_end(vp);
  762.   fd=open(buf,O_RDONLY); if(fd==-1) return 0;
  763.   for(l=read(fd,buf,4096);l>0 && l<=4096; l=read(fd,buf,4096)) {
  764.     fwrite(buf,1,l,outf); tot+=l;
  765.   }
  766.   close(fd);
  767.   return tot;
  768. }
  769.  
  770. /* returns -1 if error */
  771. long int filelength(char *fn,...)
  772. {
  773.   char buf[MAX_FNAME+1];
  774.   va_list vp;
  775.   struct stat st;
  776.   int l;
  777.  
  778.   va_start(vp,fn);
  779.   vsnprintf(buf,sizeof(buf),fn,vp); va_end(vp);
  780.   l=stat(buf,&st); if(l) return -1;
  781.   return st.st_size;
  782. }
  783.  
  784. char *parend(char *p)
  785. {
  786.   char *pp; int t;
  787.   t=0; for(pp=p;*pp;pp++) {
  788.     if(*pp=='(') t++;
  789.     if(*pp==')') {t--; if(t==0) return pp; if(t<0) return NULL;}
  790.   }
  791.   return NULL;
  792. }
  793.  
  794. char *bufprep(char *p)
  795. {
  796. /*  singlespace(p); strip_trailing_spaces(p); return find_word_start(p); */
  797.   nospace(p); return p;
  798. }
  799.