1 
2 /* xorriso - creates, loads, manipulates and burns ISO 9660 filesystem images.
3 
4    Copyright 2007-2014 Thomas Schmitt, <scdbackup@gmx.net>
5 
6    Provided under GPL version 2 or later.
7 
8    This file contains the implementation of functions around files and strings.
9 */
10 
11 #ifdef HAVE_CONFIG_H
12 #include "../config.h"
13 #endif
14 
15 #include <ctype.h>
16 #include <sys/types.h>
17 #include <unistd.h>
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <sys/stat.h>
22 #include <sys/time.h>
23 #include <time.h>
24 #include <pwd.h>
25 #include <grp.h>
26 
27 
28 #include "sfile.h"
29 
30 
31 /* @param flag bit0= do not clip off carriage return at line end
32 */
Sfile_fgets_n(char * line,int maxl,FILE * fp,int flag)33 char *Sfile_fgets_n(char *line, int maxl, FILE *fp, int flag)
34 {
35  int l;
36  char *ret;
37 
38  ret= fgets(line,maxl,fp);
39  if(ret==NULL)
40    return(NULL);
41  l= strlen(line);
42  if(l > 0 && !(flag & 1)) if(line[l-1] == '\r') line[--l]= 0;
43  if(l > 0) if(line[l-1] == '\n') line[--l]= 0;
44  if(l > 0 && !(flag & 1)) if(line[l-1] == '\r') line[--l]= 0;
45  return(ret);
46 }
47 
48 
Sfile_count_char(char * text,char to_count)49 int Sfile_count_char(char *text, char to_count)
50 {
51  int count= 0;
52  char *cpt;
53 
54  for(cpt= text; *cpt != 0; cpt++)
55    if(*cpt == to_count)
56      count++;
57  return count;
58 }
59 
60 
Sfile_count_components(char * path,int flag)61 int Sfile_count_components(char *path, int flag)
62 /*
63  bit0= do not ignore trailing slash
64  bit1= do not ignore empty components (other than the empty root name)
65 */
66 {
67  int l,count= 0;
68  char *cpt;
69 
70  l= strlen(path);
71  if(l==0)
72    return(0);
73  count= 1;
74  for(cpt= path+l-1;cpt>=path;cpt--) {
75    if(*cpt=='/') {
76      if(*(cpt+1)==0   && !(flag&1))
77  continue;
78      if(*(cpt+1)=='/' && !(flag&2))
79  continue;
80      count++;
81    }
82  }
83  return(count);
84 }
85 
86 
Sfile_component_pointer(char * path,char ** sourcept,int idx,int flag)87 int Sfile_component_pointer(char *path, char **sourcept, int idx, int flag)
88 /*
89  bit0= do not ignore trailing slash
90  bit1= do not ignore empty components (other than the empty root name)
91  bit2= accept 0 as '/'
92 */
93 {
94  int count= 0;
95  char *spt;
96 
97  for(spt= path;*spt!=0 || (flag&4);spt++) {
98    if(count>=idx) {
99      *sourcept= spt;
100      return(1);
101    }
102    if(*spt=='/' || *spt==0) {
103      if(*(spt+1)=='/' && !(flag&2))
104  continue;
105      if(*(spt+1)==0 && !(flag&1))
106  continue;
107      count++;
108    }
109  }
110  if((flag&1) && count>=idx)
111    return(1);
112  return(0);
113 }
114 
115 
Sfile_leafname(char * path,char leafname[SfileadrL],int flag)116 int Sfile_leafname(char *path, char leafname[SfileadrL], int flag)
117 {
118  int count, ret;
119  char *lpt;
120 
121  leafname[0]= 0;
122  count= Sfile_count_components(path, 0);
123  if(count==0)
124    return(0);
125  ret= Sfile_component_pointer(path, &lpt, count-1, 0);
126  if(ret<=0)
127    return(ret);
128  if(Sfile_str(leafname, lpt, 0)<=0)
129    return(0);
130  lpt= strchr(leafname, '/');
131  if(lpt!=NULL)
132    *lpt= 0;
133  return(1);
134 }
135 
136 
Sfile_add_to_path(char path[SfileadrL],char * addon,int flag)137 int Sfile_add_to_path(char path[SfileadrL], char *addon, int flag)
138 {
139  int l;
140 
141  l= strlen(path);
142  if(l+1>=SfileadrL)
143    return(0);
144  if(l==0) {
145    strcpy(path,"/");
146    l= 1;
147  } else if(path[l-1]!='/') {
148    path[l++]= '/';
149    path[l]= 0;
150  }
151  if(l+strlen(addon)>=SfileadrL)
152    return(0);
153  if(addon[0]=='/')
154    strcpy(path+l,addon+1);
155  else
156    strcpy(path+l,addon);
157  return(1);
158 }
159 
160 
Sfile_prepend_path(char * prefix,char path[SfileadrL],int flag)161 int Sfile_prepend_path(char *prefix, char path[SfileadrL], int flag)
162 {
163  int l, i, slashes, prefix_len, path_len;
164 
165  l= strlen(prefix);
166  if(l == 0)
167    return(1);
168 
169  /* Do not copy slashes between both parts */
170  for(prefix_len= l; prefix_len > 0; prefix_len--)
171    if(prefix[prefix_len - 1] != '/')
172  break;
173  if(prefix_len == 0)
174    prefix_len= strlen(prefix) - 1;
175  path_len= strlen(path);
176  for(slashes= 0; slashes < path_len; slashes++)
177    if(path[slashes] != '/')
178  break;
179 
180  l= (strlen(path) - slashes) + prefix_len + 1;
181  if(l>=SfileadrL) {
182 
183 #ifdef Not_yeT
184    /* >>> ??? how to transport messages to xorriso ? */
185    sprintf(xorriso->info_text,
186            "Combination of wd and relative address too long (%d > %d)",
187            l,SfileadrL-1);
188    Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
189 #endif
190 
191    return(-1);
192  }
193  l-= strlen(path);
194  if(l < 0) {
195    for(i= slashes; i <= path_len + 1; i++)
196      path[i+l]= path[i];
197  } else if(l > 0) {
198    for(i= path_len + 1; i >= slashes; i--)
199      path[i+l]= path[i];
200  }
201  if(prefix_len > 0)
202    memcpy(path, prefix, prefix_len);
203  path[l - 1 + slashes]= '/';
204  return(1);
205 }
206 
207 
Sfile_get_dev_fd_no(char * filename,int flag)208 int Sfile_get_dev_fd_no(char *filename, int flag)
209 {
210  int i, fd= -1;
211 
212  if(strncmp(filename, "/dev/fd/", 8) != 0)
213    return(-1);
214  for(i = 8; filename[i]; i++)
215    if(filename[i] < '0' || filename[i] > '9')
216  break;
217  if(i > 8 && filename[i] == 0)
218    sscanf(filename + 8, "%d", &fd);
219  if(fd < 0)
220    fd = -1;
221  return(fd);
222 }
223 
224 
Sfile_type(char * filename,int flag)225 int Sfile_type(char *filename, int flag)
226 /*
227  bit0= return -1 if file is missing
228  bit1= return a hardlink with siblings as type 5
229  bit2= evaluate eventual link target rather than the link object itself
230  bit3= return a socket or a char device as types 7 or 8 rather than 0
231  bit4= interpret /dev/fd/#fd# as open file descriptor fd
232 */
233 /*
234  return:
235   0=unknown
236   1=regular
237   2=directory
238   3=symbolic link
239   4=named pipe
240   5=multiple hardlink (with bit1)
241   6=block device
242   7=socket (with bit3)
243   8=character device (with bit3)
244  | 1024 if interpreted as /dev/fd/#fd#
245  | 2048 if interpreted as /dev/fd/#fd# and not fstatable
246 */
247 {
248  struct stat stbuf;
249  int fd= -1, was_dev_fd= 0, ret;
250 
251  if(flag & 16)
252     fd= Sfile_get_dev_fd_no(filename, 0);
253  if(fd != -1) {
254    was_dev_fd= 1;
255    if(fstat(fd, &stbuf) == -1)
256      return(1024 | 2048);
257  } else if(flag&4) {
258    if(stat(filename,&stbuf)==-1) {
259      if(flag&1) return(-1);
260      else       return(0);
261    }
262  } else {
263    if(lstat(filename,&stbuf)==-1) {
264      if(flag&1) return(-1);
265      else       return(0);
266    }
267  }
268  if(S_ISREG(stbuf.st_mode)) {
269    if(flag&2)
270      if(stbuf.st_nlink>1)
271        {ret= 5; goto ex;}
272    {ret= 1; goto ex;}
273  }
274  if(S_ISDIR(stbuf.st_mode))
275    {ret= 2; goto ex;}
276  if((stbuf.st_mode&S_IFMT)==S_IFLNK)
277    {ret= 3; goto ex;}
278  if(S_ISFIFO(stbuf.st_mode))
279    {ret= 4; goto ex;}
280  if(S_ISBLK(stbuf.st_mode))
281    {ret= 6; goto ex;}
282  if(flag&8)
283    if((stbuf.st_mode&S_IFMT)==S_IFSOCK)
284      {ret= 7; goto ex;}
285  if(flag&8)
286    if(S_ISCHR(stbuf.st_mode))
287      {ret= 8; goto ex;}
288  ret = 0;
289 ex:;
290  return(ret | (was_dev_fd << 10));
291 }
292 
293 
Sfile_datestr(time_t tim,short int flag)294 char *Sfile_datestr(time_t tim, short int flag)
295 /*
296  bit0=with hours+minutes
297  bit1=with seconds
298 
299  bit8= local time rather than UTC
300 */
301 {
302  static char zeitcode[80]={"000000"};
303  char puff[80];
304  struct tm *azt;
305 
306  if(flag&256)
307    azt = localtime(&tim);
308  else
309    azt = gmtime(&tim);
310 
311  if(azt->tm_year>99)
312    sprintf(zeitcode,"%c%1.1d%2.2d%2.2d",
313            'A'+(azt->tm_year-100)/10,azt->tm_year%10,
314            azt->tm_mon+1,azt->tm_mday);
315  else
316    sprintf(zeitcode,"%2.2d%2.2d%2.2d",
317            azt->tm_year,azt->tm_mon+1,azt->tm_mday);
318  if(flag&1){
319    sprintf(puff,".%2.2d%2.2d",azt->tm_hour,azt->tm_min);
320    strcat(zeitcode,puff);
321  }
322  if(flag&2){
323    sprintf(puff,"%2.2d",azt->tm_sec);
324    strcat(zeitcode,puff);
325  }
326 
327  return(zeitcode);
328 }
329 
330 
Sfile_scale(double value,char * result,int siz,double thresh,int flag)331 int Sfile_scale(double value, char *result, int siz, double thresh, int flag)
332 /*
333  bit0= eventually ommit 'b'
334  bit1= make text as short as possible
335  bit2= no fraction (if it would fit at all)
336 */
337 {
338  char scale_c,scales[7],form[80], *negpt= NULL, *cpt;
339  int i,dec_siz= 0,avail_siz= 1;
340 
341  if(value<0) {
342    value= -value;
343    siz--;
344    result[0]= '-';
345    negpt= result;
346    result++;
347  }
348  strcpy(scales,"bkmgtp");
349  scale_c= scales[0];
350  for(i=1;scales[i]!=0;i++) {
351    if(value<thresh-0.5)
352  break;
353    value/= 1024.0;
354    scale_c= scales[i];
355  }
356  if(scale_c!='b' && !(flag&4)) { /* is there room for fractional part ? */
357    avail_siz= siz-1;
358    sprintf(form,"%%.f");
359    sprintf(result,"%.f",value);
360    if(((int) strlen(result)) <= avail_siz - 2)
361      dec_siz= 1;                                  /* we are very modest */
362  }
363  if(scale_c=='b' && (flag&1)) {
364    if(flag&2)
365      sprintf(form,"%%.f");
366    else
367      sprintf(form,"%%%d.f",siz);
368    sprintf(result,form,value);
369  } else {
370    if(flag&2)
371      sprintf(form,"%%.f%%c");
372    else if(dec_siz>0)
373      sprintf(form,"%%%d.%df%%c",avail_siz,dec_siz);
374    else
375      sprintf(form,"%%%d.f%%c",siz-1);
376    sprintf(result,form,value,scale_c);
377  }
378  if(negpt != NULL) {
379    for(cpt= result; *cpt==' '; cpt++);
380    if(cpt > result) {
381      *negpt= ' ';
382      *(cpt - 1)= '-';
383    }
384  }
385  return(1);
386 }
387 
388 
Sfile_off_t_text(char text[80],off_t num,int flag)389 int Sfile_off_t_text(char text[80], off_t num, int flag)
390 {
391  char *tpt;
392  off_t hnum, scale= 1;
393  int digits= 0, d, i;
394 
395  tpt= text;
396  hnum= num;
397  if(hnum<0) {
398    *(tpt++)= '-';
399    hnum= -num;
400  }
401  if(hnum<0) { /* it can stay nastily persistent */
402    strcpy(text, "_overflow_");
403    return(0);
404  }
405  for(i= 0; i<23; i++) { /* good for up to 70 bit = 10 exp 21.07... */
406    if(hnum==0)
407  break;
408    hnum/= 10;
409    if(hnum)
410      scale*= 10;
411  }
412  if(i==0) {
413    strcpy(text, "0");
414    return(1);
415  }
416  if(i==23) {
417    strcpy(text, "_overflow_");
418    return(0);
419  }
420  digits= i;
421  hnum= num;
422  for(; i>0; i--) {
423    d= hnum/scale;
424    tpt[digits-i]= '0'+d;
425    hnum= hnum%scale;
426    scale/= 10;
427  }
428  tpt[digits]= 0;
429  return(1);
430 }
431 
432 
433 /* Converts backslash codes into single characters:
434     \a BEL 7 , \b BS 8 , \e ESC 27 , \f FF 12 , \n LF 10 , \r CR 13 ,
435     \t  HT 9 , \v VT 11 , \\ \ 92
436     \[0-9][0-9][0-9] octal code , \x[0-9a-f][0-9a-f] hex code ,
437     \cX control-x (ascii(X)-64)
438    @param upto  maximum number of characters to examine for backslash.
439                 The scope of a backslash (0 to 3 characters) is not affected.
440    @param eaten returns the difference in length between input and output
441    @param flag bit0= only determine *eaten, do not convert
442                bit1= convert \000 to binary 0
443 */
Sfile_bsl_interpreter(char * text,int upto,int * eaten,int flag)444 int Sfile_bsl_interpreter(char *text, int upto, int *eaten, int flag)
445 {
446  char *rpt, *wpt, num_text[8], wdummy[8];
447  unsigned int num= 0;
448 
449  *eaten= 0;
450  wpt= text;
451  for(rpt= text; *rpt != 0 && rpt - text < upto; rpt++) {
452    if(flag & 1)
453      wpt= wdummy;
454    if(*rpt == '\\') {
455      rpt++;
456      (*eaten)++;
457      if(*rpt == 'a') {
458        *(wpt++)= 7;
459      } else if(*rpt == 'b') {
460        *(wpt++)= 8;
461      } else if(*rpt == 'e') {
462        *(wpt++)= 27;
463      } else if(*rpt == 'f') {
464        *(wpt++)= 12;
465      } else if(*rpt == 'n') {
466        *(wpt++)= 10;
467      } else if(*rpt == 'r') {
468        *(wpt++)= 13;
469      } else if(*rpt == 't') {
470        *(wpt++)= 9;
471      } else if(*rpt == 'v') {
472        *(wpt++)= 11;
473      } else if(*rpt == '\\') {
474        *(wpt++)= '\\';
475      } else if(rpt[0] >= '0' && rpt[0] <= '7' &&
476                rpt[1] >= '0' && rpt[1] <= '7' &&
477                rpt[2] >= '0' && rpt[2] <= '7') {
478        num_text[0]= '0';
479        num_text[1]= *(rpt + 0);
480        num_text[2]= *(rpt + 1);
481        num_text[3]= *(rpt + 2);
482        num_text[4]= 0;
483        sscanf(num_text, "%o", &num);
484        if((num > 0 || (flag & 2)) && num <= 255) {
485          rpt+= 2;
486          (*eaten)+= 2;
487          *(wpt++)= num;
488        } else
489          goto not_a_code;
490      } else if(rpt[0] == 'x' &&
491                ((rpt[1] >= '0' && rpt[1] <= '9') ||
492                 (rpt[1] >= 'A' && rpt[1] <= 'F') ||
493                 (rpt[1] >= 'a' && rpt[1] <= 'f'))
494                &&
495                ((rpt[2] >= '0' && rpt[2] <= '9') ||
496                 (rpt[2] >= 'A' && rpt[2] <= 'F') ||
497                 (rpt[2] >= 'a' && rpt[2] <= 'f'))
498                ) {
499        num_text[0]= *(rpt + 1);
500        num_text[1]= *(rpt + 2);
501        num_text[2]= 0;
502        sscanf(num_text, "%x", &num);
503        if(num > 0 && num <= 255) {
504          rpt+= 2;
505          (*eaten)+= 2;
506          *(wpt++)= num;
507        } else
508          goto not_a_code;
509      } else if(*rpt == 'c') {
510        if(rpt[1] > 64 && rpt[1] < 96) {
511          *(wpt++)= rpt[1] - 64;
512          rpt++;
513          (*eaten)++;
514        } else
515          goto not_a_code;
516      } else {
517 not_a_code:;
518        *(wpt++)= '\\';
519        rpt--;
520        (*eaten)--;
521      }
522    } else
523      *(wpt++)= *rpt;
524  }
525  *wpt= *rpt;
526  return(1);
527 }
528 
529 
530 /* @param flag bit0= only encode inside quotes
531                bit1= encode < 32 outside quotes except 7, 8, 9, 10, 12, 13
532                bit2= encode in any case above 126
533                bit3= encode in any case shellsafe and name-value-safe:
534                      <=42 , 59, 60, 61, 62, 63, 92, 94, 96, >=123
535 */
Sfile_bsl_encoder(char ** result,char * text,size_t text_len,int flag)536 int Sfile_bsl_encoder(char **result, char *text, size_t text_len, int flag)
537 {
538  signed char *rpt;
539  char *wpt;
540  int count, sq_open= 0, dq_open= 0;
541 
542  count= 0;
543  for(rpt= (signed char *) text; (size_t) (((char *) rpt) - text) < text_len;
544      rpt++) {
545    count++;
546    if(flag & 8) {
547       if(!(*rpt <= 42 || (*rpt >= 59 && *rpt <= 63) ||
548            *rpt == 92 || *rpt == 94 || *rpt == 96 || *rpt >= 123))
549  continue;
550    } else if(*rpt >= 32 && *rpt <= 126 && *rpt != '\\')
551  continue;
552    if(((*rpt >= 7 && *rpt <= 13) || *rpt == 27 || *rpt == '\\') && !(flag & 8))
553      count++;
554    else
555      count+= 3;
556  }
557  (*result)= wpt= calloc(count + 1, 1);
558  if(wpt == NULL)
559    return(-1);
560  for(rpt= (signed char *) text; (size_t) (((char *) rpt) - text) < text_len;
561      rpt++) {
562    if(*rpt == '\'')
563      sq_open= !(sq_open || dq_open);
564    if(*rpt == '"')
565      dq_open= !(sq_open || dq_open);
566 
567    if(flag & 8) {
568      if(!(*rpt <= 42 || (*rpt >= 59 && *rpt <= 63) ||
569           *rpt == 92 || *rpt == 94 || *rpt == 96 || *rpt >= 123)) {
570        *(wpt++)= *rpt;
571  continue;
572      }
573    } else if(*rpt >= 32 && *rpt <= 126 && *rpt != '\\') {
574      *(wpt++)= *rpt;
575  continue;
576    } else if( ((flag & 1) && !(sq_open || dq_open)) &&
577              !((flag & 2) && (*rpt >= 1 && * rpt <= 31 &&
578                !(*rpt == 7 || *rpt == 8 || *rpt == 9 || *rpt == 10 ||
579                  *rpt == 12 || *rpt == 13))) &&
580              !((flag & 4) && (*rpt > 126 || *rpt < 0)) &&
581              !((flag & 6) && *rpt == '\\')) {
582      *(wpt++)= *rpt;
583  continue;
584    }
585    *(wpt++)= '\\';
586    if(((*rpt >= 7 && *rpt <= 13) || *rpt == 27 || *rpt == '\\') && !(flag&8)) {
587      if(*rpt == 7)
588        *(wpt++)= 'a';
589      else if(*rpt == 8)
590        *(wpt++)= 'b';
591      else if(*rpt == 9)
592        *(wpt++)= 't';
593      else if(*rpt == 10) {
594        *(wpt++)= 'n';
595      } else if(*rpt == 11)
596        *(wpt++)= 'v';
597      else if(*rpt == 12)
598        *(wpt++)= 'f';
599      else if(*rpt == 13)
600        *(wpt++)= 'r';
601      else if(*rpt == 27)
602        *(wpt++)= 'e';
603      else if(*rpt == '\\')
604        *(wpt++)= '\\';
605    } else {
606      sprintf(wpt, "%-3.3o", (unsigned int) *((unsigned char *) rpt));
607      wpt+= 3;
608    }
609  }
610  *wpt= 0;
611  return(1);
612 }
613 
614 
Sfile_destroy_argv(int * argc,char *** argv,int flag)615 int Sfile_destroy_argv(int *argc, char ***argv, int flag)
616 {
617  int i;
618 
619  if(*argc>0 && *argv!=NULL){
620    for(i=0;i<*argc;i++){
621      if((*argv)[i]!=NULL)
622        Smem_freE((*argv)[i]);
623    }
624    Smem_freE((char *) *argv);
625  }
626  *argc= 0;
627  *argv= NULL;
628  return(1);
629 }
630 
631 
Sfile_sep_make_argv(char * progname,char * line,char * separators,int max_words,int * argc,char *** argv,int flag)632 int Sfile_sep_make_argv(char *progname, char *line, char *separators,
633                         int max_words, int *argc, char ***argv, int flag)
634 /*
635  bit0= read progname as first argument from line
636  bit1= just release argument list argv and return
637  bit2= abort with return(0) if incomplete quotes are found
638  bit3= eventually prepend missing '-' to first argument read from line
639  bit4= like bit2 but only check quote completeness, do not allocate memory
640  bit5+6= interpretation of backslashes:
641        0= no interpretation, leave unchanged
642        1= only inside double quotes
643        2= outside single quotes
644        3= everywhere
645  bit7= append a NULL element to argv
646 */
647 {
648  int i,pass,maxl=0,l,argzaehl=0,bufl,line_start_argc, bsl_mode, ret= 0, eaten;
649  char *cpt,*start;
650  char *buf= NULL;
651 
652  Sfile_destroy_argv(argc,argv,0);
653  if(flag&2)
654    {ret= 1; goto ex;}
655 
656  if(flag & 16)
657    flag|= 4;
658  bsl_mode= (flag >> 5) & 3;
659 
660  buf= calloc(strlen(line) + SfileadrL, 1);
661  if(buf == NULL)
662    {ret= -1; goto ex;}
663  for(pass=0;pass<2;pass++) {
664    cpt= line-1;
665    if(!(flag&1)){
666      argzaehl= line_start_argc= 1;
667      if(pass==0)
668        maxl= strlen(progname);
669      else
670        strcpy((*argv)[0],progname);
671    } else {
672      argzaehl= line_start_argc= 0;
673      if(pass==0) maxl= 0;
674    }
675    while(*(++cpt)!=0){
676      if(*separators) {
677        if(strchr(separators, *cpt) != NULL)
678    continue;
679      } else if(isspace(*cpt))
680    continue;
681      start= cpt;
682      buf[0]= 0;
683      cpt--;
684 
685      if(max_words > 0 && argzaehl >= max_words && *cpt != 0) {
686        /* take uninterpreted up to the end */
687        cpt+= strlen(cpt) - 1;
688      }
689 
690      while(*(++cpt)!=0) {
691        if(*separators) {
692          if(strchr(separators, *cpt) != NULL)
693      break;
694        } else if(isspace(*cpt))
695      break;
696        if(*cpt=='"'){
697          l= cpt-start; bufl= strlen(buf);
698          if(l>0) {
699            strncpy(buf + bufl, start, l); buf[bufl + l]= 0;
700            if(bsl_mode >= 3) {
701              ret= Sfile_bsl_interpreter(buf + bufl, l, &eaten, 0);
702              if(ret <= 0)
703                goto ex;
704            }
705          }
706          l= strlen(buf);
707          start= cpt+1;
708          while(*(++cpt)!=0) if(*cpt=='"') break;
709          if((flag&4) && *cpt==0)
710            {ret= 0; goto ex;}
711          l= cpt-start; bufl= strlen(buf);
712          if(l>0) {
713            strncpy(buf + bufl, start, l);
714            buf[bufl + l]= 0;
715            if(bsl_mode >= 1) {
716              ret= Sfile_bsl_interpreter(buf + bufl, l, &eaten, 0);
717              if(ret <= 0)
718                goto ex;
719            }
720          }
721          start= cpt+1;
722        }else if(*cpt=='\''){
723          l= cpt-start; bufl= strlen(buf);
724          if(l>0) {
725            strncpy(buf + bufl, start, l); buf[bufl + l]= 0;
726            if(bsl_mode >= 3) {
727              ret= Sfile_bsl_interpreter(buf + bufl, l, &eaten, 0);
728              if(ret <= 0)
729                goto ex;
730            }
731          }
732          l= strlen(buf);
733          start= cpt+1;
734          while(*(++cpt)!=0) if(*cpt=='\'') break;
735          if((flag&4) && *cpt==0)
736            {ret= 0; goto ex;}
737          l= cpt-start; bufl= strlen(buf);
738          if(l>0) {
739            strncat(buf,start,l);buf[bufl+l]= 0;
740            if(bsl_mode >= 2) {
741              ret= Sfile_bsl_interpreter(buf + bufl, l, &eaten, 0);
742              if(ret <= 0)
743                goto ex;
744            }
745          }
746          start= cpt+1;
747        }
748      if(*cpt==0) break;
749      }
750      l= cpt-start;
751      bufl= strlen(buf);
752      if(l>0) {
753        strncpy(buf + bufl, start, l); buf[bufl + l]= 0;
754        if(bsl_mode >= 3) {
755          ret= Sfile_bsl_interpreter(buf + bufl, l, &eaten, 0);
756          if(ret <= 0)
757            goto ex;
758        }
759      }
760      l= strlen(buf);
761      if(pass==0){
762        if(argzaehl==line_start_argc && (flag&8))
763          if(buf[0]!='-' && buf[0]!=0 && buf[0]!='#')
764            l++;
765        if(l>maxl) maxl= l;
766      }else{
767        strcpy((*argv)[argzaehl],buf);
768        if(argzaehl==line_start_argc && (flag&8))
769          if(buf[0]!='-' && buf[0]!=0 && buf[0]!='#')
770            sprintf((*argv)[argzaehl],"-%s", buf);
771      }
772      argzaehl++;
773    if(*cpt==0) break;
774    }
775    if(pass==0){
776      if(flag & 16)
777        {ret= 1; goto ex;}
778      *argc= argzaehl;
779      if(argzaehl>0 || (flag & 128)) {
780        *argv= (char **) Smem_malloC((argzaehl + !!(flag & 128))
781                                     * sizeof(char *));
782        if(*argv==NULL)
783          {ret= -1; goto ex;}
784      }
785      for(i=0;i<*argc;i++) {
786        (*argv)[i]= (char *) Smem_malloC((maxl+1));
787        if((*argv)[i]==NULL)
788          {ret= -1; goto ex;}
789      }
790      if(flag & 128)
791        (*argv)[*argc]= NULL;
792    }
793  }
794  ret= 1;
795 ex:
796  if(buf != NULL)
797    free(buf);
798  return(ret);
799 }
800 
801 
Sfile_make_argv(char * progname,char * line,int * argc,char *** argv,int flag)802 int Sfile_make_argv(char *progname, char *line, int *argc, char ***argv,
803                     int flag)
804 {
805  return Sfile_sep_make_argv(progname, line, "", 0, argc, argv, flag);
806 }
807 
808 
809 /* @param flag bit0= append */
Sfile_str(char target[SfileadrL],char * source,int flag)810 int Sfile_str(char target[SfileadrL], char *source, int flag)
811 {
812  int l;
813 
814  l= strlen(source);
815  if(flag&1)
816    l+= strlen(target);
817  if(l>=SfileadrL) {
818    fprintf(stderr, "--- Path string overflow (%d > %d). Malicious input ?\n",
819            l,SfileadrL-1);
820    return(0);
821  }
822  if(flag&1)
823    strcat(target, source);
824  else
825    strcpy(target, source);
826  return(1);
827 }
828 
829 
830 /** Combine environment variable HOME with given filename
831     @param filename Address relative to $HOME
832     @param fileadr Resulting combined address
833     @param fa_size Size of array fileadr
834     @param flag Unused yet
835     @return 1=ok , 0=no HOME variable , -1=result address too long
836 */
Sfile_home_adr_s(char * filename,char * fileadr,int fa_size,int flag)837 int Sfile_home_adr_s(char *filename, char *fileadr, int fa_size, int flag)
838 {
839  char *home;
840 
841  strcpy(fileadr,filename);
842  home= getenv("HOME");
843  if(home==NULL)
844    return(0);
845  if((int) (strlen(home) + strlen(filename) + 1) >= fa_size)
846    return(-1);
847  strcpy(fileadr,home);
848  if(filename[0]!=0){
849    strcat(fileadr,"/");
850    strcat(fileadr,filename);
851  }
852  return(1);
853 }
854 
855 
856 /** Return a double representing seconds and microseconds since 1 Jan 1970 */
Sfile_microtime(int flag)857 double Sfile_microtime(int flag)
858 {
859  struct timeval tv;
860 
861  gettimeofday(&tv, NULL);
862  return((double) (tv.tv_sec+1.0e-6*tv.tv_usec));
863 }
864 
865 
Sfile_decode_datestr(struct tm * reply,char * text,int flag)866 int Sfile_decode_datestr(struct tm *reply, char *text, int flag)
867 /* YYMMDD[.hhmm[ss]] */
868 {
869  int i,l;
870  time_t current_time;
871  struct tm *now;
872 
873  current_time= time(0);
874  now= localtime(&current_time);
875  for(i=0; i < (int) sizeof(struct tm); i++)
876    ((char *) reply)[i]= ((char *) now)[i];
877 
878  if(text[0]<'0'|| (text[0]>'9' && text[0]<'A') || text[0]>'Z')
879    return(0);
880  l= strlen(text);
881  for(i=1;i<l;i++)
882    if(text[i]<'0'||text[i]>'9')
883      break;
884  if(i!=6)
885    return(0);
886  if(text[i]==0)
887    goto decode;
888  if(text[i]!='.' || (l!=11 && l!=13))
889    return(0);
890  for(i++;i<l;i++)
891    if(text[i]<'0'||text[i]>'9')
892      break;
893  if(i!=l)
894    return(0);
895 
896 decode:;
897  reply->tm_hour= 0;
898  reply->tm_min= 0;
899  reply->tm_sec= 0;
900  i= 0;
901  if(text[0]>='A')
902    reply->tm_year= 100+(text[i]-'A')*10+text[1]-'0';
903  else
904    reply->tm_year= 10*(text[0]-'0')+text[1]-'0';
905  reply->tm_mon=  10*(text[2]-'0')+text[3]-'0'-1;
906  reply->tm_mday= 10*(text[4]-'0')+text[5]-'0';
907  if(l==6)
908    return(1);
909  reply->tm_hour= 10*(text[7]-'0')+text[8]-'0';
910  reply->tm_min=  10*(text[9]-'0')+text[10]-'0';
911  if(l==11)
912    return(1);
913  reply->tm_sec=  10*(text[11]-'0')+text[12]-'0';
914  return(1);
915 }
916 
917 
918 /* From libisofs:
919    Find backward from idx the start byte of a possible UTF-8 character.
920      https://en.wikipedia.org/wiki/UTF-8#Description
921 */
922 static
find_utf8_start(char * name,int idx,int flag)923 int find_utf8_start(char *name, int idx, int flag)
924 {
925     unsigned char *uname, uch;
926     int i;
927 
928     uname= (unsigned char *) name;
929     if ((uname[idx] & 0xc0) != 0x80)
930         return idx;                                /* not an UTF-8 tail byte */
931     for (i = 0; i < 5 && idx - 1 - i >= 0; i++) {
932                                             /* up to deprecated 6-byte codes */
933         uch = uname[idx - 1 - i];
934         if ((uch & 0xe0) == 0xc0 || (uch & 0xf0) == 0xe0 ||
935             (uch & 0xf8) == 0xf0 || (uch & 0xfc) == 0xf8 ||
936             (uch & 0xfe) == 0xfc)
937             return (idx - 1 - i);                  /* UTF-8 start byte found */
938         if ((uch & 0xc0) != 0x80)
939           return idx;                 /* not an UTF-8 tail byte, so no UTF-8 */
940     }
941     return idx;                                      /* no UTF-8 start found */
942 }
943 
944 
Sfile_flatten_utf8_heads(char * name,int idx,int flag)945 int Sfile_flatten_utf8_heads(char *name, int idx, int flag)
946 {
947  int neck;
948 
949  neck = find_utf8_start(name, idx, 0);
950  if(neck >= idx)
951    return(2);
952  for(; neck < idx; neck++)
953     name[neck] = '_';
954  return(1);
955 }
956 
957 
958