


/*

    ( cd .. ; libisoburn-develop/test/compile_xorriso.sh -g )

or

    cc -g -DXorriso_with_maiN -DXorriso_with_regeX -DXorriso_with_readlinE \
          -Wall -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE \
          -o test/xorriso \
          test/xorriso.c test/xorrisoburn.c \
          -lpthread -lreadline -lburn -lisofs -lisoburn 

or

    cc -g -DXorriso_with_regeX -DXorriso_with_readlinE \
          -Wall -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE \
          -c \
          test/xorriso.c test/xorrisoburn.c

*/

/* Command line oriented batch and dialog tool which creates, loads,
   manipulates and burns ISO 9660 filesystem images.

   Copyright 2007 Thomas Schmitt, <scdbackup@gmx.net>

   Initial code of this program was derived from program src/askme.c out
   of scdbackup-0.8.8, Copyright 2007 Thomas Schmitt, BSD-License.

   Provided under GPL version 2, with the announcement that this might
   get changed in future. I would prefer BSD or a modifyied LGPL with no
   option to choose any kind of future GPL version.
   (This announcement affects only future releases of xorriso.
    If you obtain a copy licensed as "GPL version 2" then this license is
    not revocable for that particular copy, of course.)
*/

#define PROG_VERSION "0.0.0"

/** The source code release timestamp */
#include "xorriso_timestamp.h"
#ifndef Xorriso_timestamP
#define Xorriso_timestamP "-none-given-"
#endif

/** The binary build timestamp is to be set externally by the compiler */
#ifndef Xorriso_build_timestamP
#define Xorriso_build_timestamP "-none-given-"
#endif

#include <ctype.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <dirent.h>
#include <time.h>
#include <utime.h>
#include <pwd.h>
#include <grp.h>

/* eventually, this is done in xorriso_private.h : #include <regex.h> */

#ifdef Xorriso_with_readlinE
#ifdef Xorriso_with_old_readlinE
#include <readline.h>
#include <history.h>
#else /* Xorriso_with_old_readlinE */
#include <readline/readline.h>
#include <readline/history.h>
#endif /* ! Xorriso_with_old_readlinE */
#endif /* Xorriso_with_readlinE */

#define TSOB_FELD(typ,anz) (typ *) malloc((anz)*sizeof(typ));


/* Diet facility: exclude help texts from binaries */
/* This will eventually be redefined to eat up its content */
#define AlN(x) x


/* There is only one stage of diet: Xorriso_no_helP */
#ifdef Xorriso_no_helP
#undef AlN
#define AlN(x) 
#endif


/* ------------------------------------------------------------------------ */


/* The official xorriso options API. "No shortcuts" */
#include "xorriso.h"

/* The inner isofs- and burn-library interface */
#include "xorrisoburn.h"

/* The inner description of XorrisO */
#define Xorriso_is_xorriso_selF 1
#include "xorriso_private.h"


/* ------------------------------------------------------------------------ */


#ifndef Xorriso_sfile_externaL


char *Sfile_fgets(char *line, int maxl, FILE *fp)
{
 int l;
 char *ret;

 ret= fgets(line,maxl,fp);
 if(ret==NULL)
   return(NULL);
 l= strlen(line);
 if(l>0) if(line[l-1]=='\r') line[--l]= 0;
 if(l>0) if(line[l-1]=='\n') line[--l]= 0;
 if(l>0) if(line[l-1]=='\r') line[--l]= 0;
 return(ret);
}


int Sfile_fclose(FILE *fp)
{
 if(fp!=stdout && fp!=stdin && fp!=NULL)
   fclose(fp);
 return(1);
}


int Sfile_count_components(char *path, int flag)
/*
 bit0= do not ignore trailing slash
 bit1= do not ignore empty components (other than the empty root name)
*/
{
 int l,count= 0;
 char *cpt;

 l= strlen(path);
 if(l==0)
   return(0);
 count= 1;
 for(cpt= path+l-1;cpt>=path;cpt--) { 
   if(*cpt=='/') {
     if(*(cpt+1)==0   && !(flag&1))
 continue;
     if(*(cpt+1)=='/' && !(flag&2))
 continue;
     count++;
   }
 }
 return(count);
}


int Sfile_component_pointer(char *path, char **sourcept, int idx, int flag)
/*
 bit0= do not ignore trailing slash
 bit1= do not ignore empty components (other than the empty root name)
 bit2= accept 0 as '/'
*/
{
 int count= 0;
 char *spt;

 for(spt= path;*spt!=0 || (flag&4);spt++) {
   if(count>=idx) {
     *sourcept= spt;
     return(1);
   }
   if(*spt=='/' || *spt==0) {
     if(*(spt+1)=='/' && !(flag&2))
 continue;
     if(*(spt+1)==0 && !(flag&1))
 continue;
     count++;
   }
 }
 if((flag&1) && count>=idx)
   return(1);
 return(0);
}


int Sfile_add_to_path(char path[SfileadrL], char *addon, int flag)
{
 int l;

 l= strlen(path);
 if(l==0) {
   strcpy(path,"/");
   l= 1;
 } else if(path[l-1]!='/') {
   path[l++]= '/';
   path[l]= 0;
 }
 if(l+strlen(addon)>=SfileadrL)
   return(0);
 if(addon[0]=='/')
   strcpy(path+l,addon+1);
 else
   strcpy(path+l,addon);
 return(1);
}


int Sfile_prepend_path(char *prefix, char path[SfileadrL], int flag)
{
 int l, i;

 l= strlen(path)+strlen(prefix)+1;
 if(l>=SfileadrL) {

#ifdef Not_yeT
   /* >>> ??? how to transport messages to xorriso ? */
   sprintf(xorriso->info_text,
           "Combination of wd and relative address too long (%d > %d)",
           l,SfileadrL-1);
   Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
#endif

   return(-1);
 }
 l-= strlen(path);
 for(i= strlen(path)+1; i>=0; i--)
   path[i+l]= path[i];
 strcpy(path,prefix);
 path[l-1]= '/';
 return(1);
}

int Sfile_being_group_member(struct stat *stbuf, int flag)
{
 int i, suppl_groups;
 gid_t *suppl_glist;

 if (getegid()==stbuf->st_gid)
   return(1);
 suppl_groups= getgroups(0, NULL);
 suppl_glist= (gid_t *) malloc((suppl_groups + 1) * sizeof(gid_t));
 if (suppl_glist==NULL)
   return(-1);
 suppl_groups= getgroups(suppl_groups+1,suppl_glist);
 for (i= 0; i<suppl_groups; i++) {
   if (suppl_glist[i]==stbuf->st_gid) {
     free((char *) suppl_glist);
     return(1);
   }
 }
 free((char *) suppl_glist);
 return(0);
}


int Sfile_type(char *filename, int flag)
/*
 bit0= return -1 if file is missing 
 bit1= return a hardlink with siblings as type 5
 bit2= evaluate eventual link target rather than the link object itself
 bit3= return a socket or a char device as types 7 or 8 rather than 0
*/
/*
 return:
  0=unknown
  1=regular
  2=directory
  3=symbolic link
  4=named pipe
  5=multiple hardlink (with bit1)
  6=block device
  7=socket (with bit3)
  8=character device (with bit3)
*/
{
 struct stat stbuf;
 if(flag&4) {
   if(stat(filename,&stbuf)==-1) {
     if(flag&1) return(-1);
     else       return(0);
   }
 } else {
   if(lstat(filename,&stbuf)==-1) {
     if(flag&1) return(-1);
     else       return(0);
   }
 }
 if(S_ISREG(stbuf.st_mode)) {
   if(flag&2)
     if(stbuf.st_nlink>1)
       return(5);
   return(1);
 }
 if(S_ISDIR(stbuf.st_mode))
   return(2);
 if((stbuf.st_mode&S_IFMT)==S_IFLNK)
   return(3);
 if(S_ISFIFO(stbuf.st_mode))
   return(4);
 if(S_ISBLK(stbuf.st_mode))
   return(6);
 if(flag&8)
   if((stbuf.st_mode&S_IFMT)==S_IFSOCK)
     return(7);
 if(flag&8)
   if(S_ISCHR(stbuf.st_mode))
     return(8);
 return(0);
}


int Sfile_lookup_permissions(char *fname, int *perms, mode_t *st_mode,int flag)
/* perms: bit0= r , bit1= w , bit2= x */
/* return: <0 fatal error, 0= file nonexistent, 1=owner, 2=group, 3=other */
{
 struct stat stbuf;

 *perms= 0;
 if(stat(fname,&stbuf)==-1)
   return(0);
 *st_mode= stbuf.st_mode;
 if(geteuid()==stbuf.st_uid || geteuid()==0) {
   if(stbuf.st_mode & S_IRUSR)
     (*perms)|= 1; 
   if(stbuf.st_mode & S_IWUSR)
     (*perms)|= 2; 
   if(stbuf.st_mode & S_IXUSR)
     (*perms)|= 4; 
   return(1);
 }
 /* group membership is a complicated thing */
 if(Sfile_being_group_member(&stbuf,0)>0) {
   if(stbuf.st_mode & S_IRGRP)
     (*perms)|= 1; 
   if(stbuf.st_mode & S_IWGRP)
     (*perms)|= 2; 
   if(stbuf.st_mode & S_IXGRP)
     (*perms)|= 4; 
   return(2);
 }
 if(stbuf.st_mode & S_IROTH)
   (*perms)|= 1; 
 if(stbuf.st_mode & S_IWOTH)
   (*perms)|= 2; 
 if(stbuf.st_mode & S_IXOTH)
   (*perms)|= 4; 
 return(3);
}


int Sfile_select(int *fds, int fdcount, int fdidx[3], unsigned int microsec,
                 int flag)
/*
 bit0= check for reading (and choose one into fdidx[0])
 bit1= check for writing (and choose one into fdidx[1])
 bit2= check for exception (and choose one into fdidx[2])
 bit3= initialize fdidx
return-bits are set according to matching flag-bits
*/
{
 struct timeval wt;
 fd_set rds,wts,exs,*s;
 int ready,ret,i,j,max_fd= -1;

 if(flag&8)
   for(j=0;j<3;j++)
     fdidx[j]= 0;
 wt.tv_sec=  microsec/1000000;
 wt.tv_usec= microsec%1000000;
 FD_ZERO(&rds);
 FD_ZERO(&wts);
 FD_ZERO(&exs);
 for(i= 0;i<fdcount;i++) {
   if(fds[i]<0)
 continue;
   if(flag&1)
     FD_SET(fds[i],&rds);
   if(flag&2)
     FD_SET(fds[i],&wts);
   if(flag&4)
     FD_SET(fds[i],&exs);
   if(fds[i]>max_fd)
     max_fd= fds[i];
 }
 ready= select(max_fd+1,&rds,&wts,&exs,&wt);
 if(ready<=0)
   return(0);
 ret= 0;
 if(fdcount>0)
   for(j=0;j<2;j++)
     fdidx[j]= (fdidx[j]+1)%fdcount;
 for(i= 0;i<fdcount;i++) {
   for(j=0;j<3;j++) {
     if(j==0)
       s= &rds;
     else if(j==1)
       s= &wts;
     else
       s= &exs;
     if((flag&(1<<j)) && !(ret&(1<<j))) {
       if(fds[fdidx[j]]<0) 
         fdidx[j]= (fdidx[j]+1)%fdcount;
       else if(FD_ISSET(fds[fdidx[j]],s))
         ret|= (1<<j);
       else
         fdidx[j]= (fdidx[j]+1)%fdcount;
     }
   }
 }
 return(ret);
}


int Sfile_identical(char *file1, char *file2, int flag)
/*
 bit0= check whether it is the same  i-node 
*/
{
 FILE *fp1,*fp2;
 struct stat stbuf;
 int ret,c1,c2;
 ino_t ino1,ino2;
 dev_t dev1,dev2;

 ret= 0;

 if(flag&1){
   if(stat(file1,&stbuf)==-1) return(0);
   ino1= stbuf.st_ino;
   dev1= stbuf.st_dev;
   if(stat(file2,&stbuf)==-1) return(0);
   ino2= stbuf.st_ino;
   dev2= stbuf.st_dev;
   return((ino1==ino2) && (dev1==dev2));
 }

 fp1= fopen(file1,"rb");
 fp2= fopen(file2,"rb");
 if(fp1==NULL||fp2==NULL) goto fertig;
 while(1){
   c1= fgetc(fp1);
   c2= fgetc(fp2);
   if(c1==EOF && c2==EOF){
     ret= 1;
 break;
   }
   if(c1!=c2)
 break;
 }
fertig:;
 if(fp1!=NULL) fclose(fp1);
 if(fp2!=NULL) fclose(fp2);
 return(ret);
}


char *Sfile_datestr(time_t tim, short int flag)
/*
 bit0=with hours+minutes  
 bit1=with seconds

 bit8= local time rather than UTC
*/
{
 static char zeitcode[80]={"000000"};
 char puff[80];
 struct tm *azt;

 if(flag&256) 
   azt = localtime(&tim);
 else
   azt = gmtime(&tim);
 
 if(azt->tm_year>99)
   sprintf(zeitcode,"%c%1.1d%2.2d%2.2d",
           'A'+(azt->tm_year-100)/10,azt->tm_year%10,
           azt->tm_mon+1,azt->tm_mday);
 else
   sprintf(zeitcode,"%2.2d%2.2d%2.2d",
           azt->tm_year,azt->tm_mon+1,azt->tm_mday);
 if(flag&1){
   sprintf(puff,".%2.2d%2.2d",azt->tm_hour,azt->tm_min);
   strcat(zeitcode,puff);
 }
 if(flag&2){
   sprintf(puff,"%2.2d",azt->tm_sec);
   strcat(zeitcode,puff);
 }

 return(zeitcode);
}


int Sfile_scale(double value, char *result, int siz, double thresh, int flag)
/*
 bit0= eventually ommit 'b'
 bit1= make text as short as possible
 bit2= no fraction (if it would fit at all)
*/
{
 char scale_c,scales[6],form[80];
 int i,dec_siz= 0,avail_siz= 1;

 strcpy(scales,"bkmgtp");
 scale_c= scales[0];
 for(i=1;scales[i]!=0;i++) {
   if(value<thresh-0.5) 
 break;
   value/= 1024.0;
   scale_c= scales[i];
 } 
 if(scale_c!='b' && !(flag&4)) { /* is there room for fractional part ? */
   avail_siz= siz-1;
   sprintf(form,"%%.lf");
   sprintf(result,"%.lf",value);
   if(strlen(result)<=avail_siz-2) 
     dec_siz= 1;                                  /* we are very modest */
 }
 if(scale_c=='b' && (flag&1)) {
   if(flag&2)
     sprintf(form,"%%.lf");
   else
     sprintf(form,"%%%d.lf",siz);
   sprintf(result,form,value);
 } else {
   if(flag&2)
     sprintf(form,"%%.lf%%c");
   else if(dec_siz>0) 
     sprintf(form,"%%%d.%dlf%%c",avail_siz,dec_siz);
   else
     sprintf(form,"%%%d.lf%%c",siz-1);
   sprintf(result,form,value,scale_c);
 }
 return(1);
}


int Sfile_destroy_argv(int *argc, char ***argv, int flag)
{
 int i;

 if(*argc>0 && *argv!=NULL){
   for(i=0;i<*argc;i++){
     if((*argv)[i]!=NULL)
       Smem_freE((*argv)[i]);
   }
   Smem_freE((char *) *argv);
 }
 *argc= 0;
 *argv= NULL;
 return(1);
}


int Sfile_make_argv(char *progname, char *line, int *argc, char ***argv,
                    int flag)
/*
 bit0= read progname as first argument from line
 bit1= just release argument list argv and return
 bit2= abort with return(0) if incomplete quotes are found
 bit3= eventually prepend missing '-' to first argument read from line
*/
{
 int i,pass,maxl=0,l,argzaehl=0,bufl,line_start_argc;
 char *cpt,*start;
 char buf[SfileadrL];

 Sfile_destroy_argv(argc,argv,0);
 if(flag&2) return(1);

 for(pass=0;pass<2;pass++) {
   cpt= line-1;
   if(!(flag&1)){
     argzaehl= line_start_argc= 1;
     if(pass==0)
       maxl= strlen(progname);
     else
       strcpy((*argv)[0],progname);
   } else {
     argzaehl= line_start_argc= 0;
     if(pass==0) maxl= 0;
   }
   while(*(++cpt)!=0){
   if(isspace(*cpt)) continue;
     start= cpt;
     buf[0]= 0;
     cpt--;
     while(*(++cpt)!=0) {
     if(isspace(*cpt)) break;
       if(*cpt=='"'){
         l= cpt-start; bufl= strlen(buf);
         if(l>0) {strncat(buf,start,l);buf[bufl+l]= 0;}
         l= strlen(buf);
         start= cpt+1;
         while(*(++cpt)!=0) if(*cpt=='"') break;
         if((flag&4) && *cpt==0)
           return(0);
         l= cpt-start; bufl= strlen(buf);
         if(l>0) {strncat(buf,start,l);buf[bufl+l]= 0;}
         start= cpt+1;
       }else if(*cpt=='\''){
         l= cpt-start; bufl= strlen(buf);
         if(l>0) {strncat(buf,start,l);buf[bufl+l]= 0;}
         l= strlen(buf);
         start= cpt+1;
         while(*(++cpt)!=0) if(*cpt=='\'') break;
         if((flag&4) && *cpt==0)
           return(0);
         l= cpt-start; bufl= strlen(buf);
         if(l>0) {strncat(buf,start,l);buf[bufl+l]= 0;}
         start= cpt+1;
       }
     if(*cpt==0) break;
     }
     l= cpt-start;
     bufl= strlen(buf);
     if(l>0) {strncat(buf,start,l);buf[bufl+l]= 0;}
     l= strlen(buf);
     if(pass==0){
       if(argzaehl==line_start_argc && (flag&8))
         if(buf[0]!='-' && buf[0]!=0 && buf[0]!='#')
           l++;
       if(l>maxl) maxl= l;
     }else{
       strcpy((*argv)[argzaehl],buf);
       if(argzaehl==line_start_argc && (flag&8))
         if(buf[0]!='-' && buf[0]!=0 && buf[0]!='#')
           sprintf((*argv)[argzaehl],"-%s", buf);
     }
     argzaehl++;
   if(*cpt==0) break;
   }
   if(pass==0){
     *argc= argzaehl;
     if(argzaehl>0) {
         *argv= (char **) Smem_malloC(argzaehl*sizeof(char *));
       if(*argv==NULL)
         return(-1);
     }
     for(i=0;i<*argc;i++) {
       (*argv)[i]= (char *) Smem_malloC((maxl+1));
       if((*argv)[i]==NULL)
         return(-1);
     }
   }
 }
 return(1);
}


/* @param flag bit0= append */
int Sfile_str(char target[SfileadrL], char *source, int flag)
{
 int l;

 l= strlen(source);
 if(flag&1)
   l+= strlen(target);
 if(l>=SfileadrL) {
   fprintf(stderr, "--- Path string overflow (%d > %d). Malicious input ?\n",
           l,SfileadrL-1);
   return(0);
 }
 if(flag&1)
   strcat(target, source);
 else
   strcpy(target, source);
 return(1);
}


/** Combine environment variable HOME with given filename
    @param filename Address relative to $HOME
    @param fileadr Resulting combined address
    @param fa_size Size of array fileadr
    @param flag Unused yet
    @return 1=ok , 0=no HOME variable , -1=result address too long
*/
int Sfile_home_adr_s(char *filename, char *fileadr, int fa_size, int flag)
{
 char *home;

 strcpy(fileadr,filename);
 home= getenv("HOME");
 if(home==NULL)
   return(0);
 if(strlen(home)+strlen(filename)+1>=fa_size)
   return(-1);
 strcpy(fileadr,home);
 if(filename[0]!=0){
   strcat(fileadr,"/");
   strcat(fileadr,filename);
 }
 return(1);
}


#endif /*  Xorriso_sfile_externaL */


/* --------------------------------- misc --------------------------------- */


int Write_to_channel(char *text, int channel_no, int flag)
/*
 bit0= packet write disabled, write to stdin resp. stderr
 bit1= text is the name of the log file for the given channel 
 bit2= text is the name of the consolidated packet log file for all channels 
bit15= with bit1 or bit2: close depicted log file
*/
{
 char *rpt,*npt,ret= 1;
 char prefix[16];
 static int num_channels= 4;
 static char channel_prefixes[4][4]= {".","R","I","M"};
 static FILE *logfile_fp[4]= {NULL,NULL,NULL,NULL};
 static FILE *pktlog_fp= NULL;

 if(channel_no<0 || channel_no>=num_channels)
   return(-1);

 /* Logfiles */
 if((flag&2) && logfile_fp[channel_no]!=NULL) {
   fprintf(logfile_fp[channel_no],
     "! end ! end ! end ! end ! end ! end ! end ! end xorriso log : %s : %s\n",
           channel_prefixes[channel_no],Sfile_datestr(time(0),1|2|256));
   fclose(logfile_fp[channel_no]);
   logfile_fp[channel_no]= NULL;
 }
 if((flag&4) && pktlog_fp!=NULL) {
   fprintf(pktlog_fp,
 "I:1:! end ! end ! end ! end ! end ! end ! end ! end xorriso log : %s : %s\n",
           channel_prefixes[channel_no],Sfile_datestr(time(0),1|2|256));
   fclose(pktlog_fp);
   pktlog_fp= NULL;
 }
 if(flag&(1<<15))
   return(1);
 if((flag&2)) {
   logfile_fp[channel_no]= fopen(text,"a");
   if(logfile_fp[channel_no]==NULL)
     return(0);
   fprintf(logfile_fp[channel_no],
  "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! xorriso log : %s : %s\n",
           channel_prefixes[channel_no],Sfile_datestr(time(0),1|2|256));
   fflush(logfile_fp[channel_no]);
 }
 if((flag&4)) {
   pktlog_fp= fopen(text,"a");
   if(pktlog_fp==NULL)
     return(0);
   fprintf(pktlog_fp,
  "I:1:!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! xorriso log : . : %s\n",
           Sfile_datestr(time(0),1|2|256));
   fflush(pktlog_fp);
 }
 if(flag&(2|4))
   return(1);
 if(flag&1) {
   if(channel_no==1 || channel_no==3)
     printf("%s",text);
   if(channel_no==2 || channel_no==3)
     fprintf(stderr,"%s",text);
   if(logfile_fp[channel_no]!=NULL) {
     fprintf(logfile_fp[channel_no],"%s",text);
     fflush(logfile_fp[channel_no]);
   }
   if(pktlog_fp!=NULL)
     return(1);
 }
 rpt= text;
 sprintf(prefix,"%s:x: ",channel_prefixes[channel_no]);
 while(*rpt!=0) {
   npt= strchr(rpt,'\n');
   if(npt==NULL)
     prefix[2]= '0';
   else
     prefix[2]= '1';
   if(!(flag&1)) {
     ret= fwrite(prefix,5,1,stdout);
     if(ret<=0)
       return(0);
   }
   if(pktlog_fp!=NULL) {
     ret= fwrite(prefix,5,1,pktlog_fp);
     if(ret<=0)
       return(0);
   }
   if(npt==NULL) {
     if(!(flag&1)) {
       ret= fwrite(rpt,strlen(rpt),1,stdout);
       if(ret<=0)
         return(0);
       ret= fwrite("\n",1,1,stdout);
       if(ret<=0)
         return(0);
     }
     if(pktlog_fp!=NULL) {
       ret= fwrite(rpt,strlen(rpt),1,pktlog_fp);
       if(ret<=0)
         return(0);
       ret= fwrite("\n",1,1,pktlog_fp);
       if(ret<=0)
         return(0);
     }
 break;
   } else {
     if(!(flag&1)) {
       ret= fwrite(rpt,npt+1-rpt,1,stdout);
       if(ret<=0)
         return(0);
     }
     if(pktlog_fp!=NULL) {
       ret= fwrite(rpt,npt+1-rpt,1,pktlog_fp);
       if(ret<=0)
         return(0);
     }
   }
   rpt= npt+1;
 }
 if(!(flag&1))
   fflush(stdout);
 if(pktlog_fp!=NULL)
   fflush(pktlog_fp);
 return(1);
}


int Exec_cmd(char *prog, char *cmd, char *simple_arg, char **argv,
             char errmsg[SfileadrL], int flag)
/*
 bit0= package mode (!bit0 of Write_to_channel())
*/
{
 int wait_status,is_dead= 0,pipes_open= 0,ret,channel_no;
 int stdout_pipe[2],stderr_pipe[2],fds[2],fdidx[3];
 char **exec_argv,*simple_argv[3],buffer[256];
 pid_t pid,dead_pid;
 static int debug= 0;

 errmsg[0]= 0;
 if(debug)
   fprintf(stderr,"Exec_cmd():fork\n");

 /* create pipes */
 if(pipe(stdout_pipe)==-1) {
cannot_make_pipe:;
   sprintf(errmsg,"%s : cannot create two pipes\n   reason given:   %s\n",
                  prog,strerror(errno));
   return(-1);
 }
 if(pipe(stderr_pipe)==-1) {
   close(stdout_pipe[0]);
   close(stdout_pipe[1]);
   goto cannot_make_pipe;
 }
 pipes_open= 1;

 pid= fork();
 if(pid==-1) {
   sprintf(errmsg,"%s : cannot fork a new process\n   reason given:   %s\n",
                  prog,strerror(errno));
   {ret= -1; goto father_ex;}
 } else if(pid>0) { /* original process */
   if(debug)
     fprintf(stderr,"Exec_cmd():father\n");
   /* close unused pipe ends so we register EOF by the child process */
   close(stdout_pipe[1]);
   close(stderr_pipe[1]);
   fds[0]= stdout_pipe[0];
   fds[1]= stderr_pipe[0];
   is_dead= 0;
   while(1) {
     if((fds[0]==-1 && fds[1]==-1)) { /* not before both pipes have closed */
       dead_pid= wait3(&wait_status,WNOHANG,NULL);
       if(dead_pid==pid) {
         is_dead= 1;
   break;
       } else if(dead_pid<0) {
         sprintf(errmsg,
                 "%s : error while waiting for end of sub process\n   %s\n",
                 prog,strerror(errno));
         {ret= -1; goto father_ex;}
       }
     }

     /* check for input at both pipes */;
     ret= Sfile_select(fds,2,fdidx,100000,1|8);
     if(ret<=0 || fdidx[0]<0 || fdidx[0]>1)
   continue;
     ret= read(fds[fdidx[0]],buffer,sizeof(buffer)-3);
     if(ret<0) {
       sprintf(errmsg,"--- error %d on read from %s pipe : %s\n",
                      errno,(fdidx[0]?"stdout":"stderr"),
                      (errno>0?strerror(errno):"-unknown error-"));
       {ret= -1; goto father_ex;}
     }
     if(ret==0) {
       fds[fdidx[0]]= -1;
   continue;
     }  
     buffer[ret]= 0;
     channel_no= fdidx[0]+1;
     ret= Write_to_channel(buffer,channel_no,!(flag&1));
     if(ret<=0) {
       sprintf(errmsg,"--- error %d on write to %s : %s\n",
                      errno,(fdidx[0]?"stdout":"stderr"),
                      (errno>0?strerror(errno):"-unknown error-"));
       {ret= -1; goto father_ex;}
     }
   }
   ret= 127;
   if(WIFEXITED(wait_status))
     ret= WEXITSTATUS(wait_status);
father_ex:;
   if(pipes_open) {
     close(stdout_pipe[0]);
     close(stderr_pipe[0]);
   }
   return(ret);
 }

 if(debug)
   fprintf(stderr,"Exec_cmd():child\n");

 /* Connect stdout and stderr to the appropriate ends of the pipes. */
 close(1);
 ret= dup(stdout_pipe[1]);
 if(ret==-1) {
cannot_dup_pipe:;
   sprintf(errmsg,
         "%s : cannot redirect standard i/o to pipes\n   reason given:   %s\n",
           prog,strerror(errno));
   Write_to_channel(errmsg,2,!(flag&1));
   exit(1);
 }
 close(2);
 ret= dup(stderr_pipe[1]);
 if(ret==-1)
   goto cannot_dup_pipe;
 /* close pipes so we register EOF by the father process */
 close(stdout_pipe[0]);
 close(stdout_pipe[1]);
 close(stderr_pipe[0]);
 close(stderr_pipe[1]);

 /* switch process to desired program */
 if(simple_arg!=NULL) {
   simple_argv[0]= cmd;
   simple_argv[1]= simple_arg;
   simple_argv[2]= NULL;
   exec_argv= simple_argv;
 } else {
   exec_argv= argv;
 }
 if(debug) { int i;
   fprintf(stderr,"debug: cmd='%s'\n",cmd);
   for(i=0;exec_argv[i]!=NULL;i++)
     fprintf(stderr,"debug: argv[%d]='%s'\n",i,exec_argv[i]);
 }
 if(strchr(cmd,'/')!=NULL)
   execv(cmd,exec_argv);
 else
   execvp(cmd,exec_argv);
 sprintf(errmsg,"%s : cannot start program %s\n   reason given:   %s\n",
                prog,cmd,strerror(errno));
 Write_to_channel(errmsg,2,!(flag&1));
 exit(127); 
}


int Exec_cmd_line(char *prog, char *cmd_line,
                  int extra_argc, char **extra_argv, char *errmsg, int flag)
/*
 bit0= packade mode (!bit0 of Write_to_channel())
*/
{
 int ret,cmd_argc= 0,i,w;
 char **cmd_argv= NULL,**argv= NULL;

 ret= Sfile_make_argv("",cmd_line,&cmd_argc,&cmd_argv,1);
 if(ret<=0)
   {ret= -1; goto ex;}
 argv= TSOB_FELD(char *,cmd_argc+extra_argc+1);
 if(argv==NULL)
   {ret= -1; goto ex;}
 w= 0;
 for(i=0;i<cmd_argc;i++)
   argv[w++]= cmd_argv[i];
 for(i=0;i<extra_argc;i++)
   argv[w++]= extra_argv[i];
 argv[w]= NULL;
 ret= Exec_cmd(prog,argv[0],NULL,argv,errmsg,flag&1);
ex:;
 if(argv!=NULL)
   free((char *) argv);
 Sfile_make_argv("",cmd_line,&cmd_argc,&cmd_argv,2);
 return(ret);
}


int Strcmp(const void *pt1, const void *pt2)
{
 return(strcmp(*((char **) pt1), *((char **) pt2)));
}


int Sort_argv(int argc, char **argv, int flag)
{
 if(argc<=0)
   return(2);
 qsort(argv,(size_t) argc,sizeof(char *),Strcmp);
 return(1);
}


int Set_bit(int *data, int idx, int flag)
/*
 bit0= clear bit
*/
{
 if(idx<0 || idx>31)
   return(0);
 if(flag&1)
   (*data)&= ~(1<<idx);
 else
   (*data)|= (1<<idx);
 return(1);
}


FILE *Afile_fopen(char *filename, char *mode, int flag)
/*
 bit0= do not print error message on failure
 bit6= write packeted error messages (see Write_to_channel())
*/
{
 FILE *fp= NULL;
 char errmsg[2*SfileadrL];

 if(strcmp(filename,"-")==0) {
   if(mode[0]=='a' || mode[0]=='w' ||
      (mode[0]=='r' && mode[1]=='+') ||
      (mode[0]=='r' && mode[1]=='b' && mode[2]=='+')) 
     fp= stdout;
   else
     fp= stdin;
 } else if(strncmp(filename,"tcp:",4)==0){
   sprintf(errmsg,"sorry - TCP/IP service isn't implemented yet.\n");
   Write_to_channel(errmsg,2,!(flag&64));
 } else if(strncmp(filename,"file:",5)==0){
   fp= fopen(filename+5,mode);
 } else {
   fp= fopen(filename,mode);
 }
 if(fp==NULL){
   if(!(flag&1)) {
     sprintf(errmsg,"failed to open file '%s' in %s mode\n",filename,mode);
     if(errno>0)
       sprintf(errmsg+strlen(errmsg),"   %s\n",strerror(errno));
     Write_to_channel(errmsg,2,!(flag&64));
   }
   return(NULL);
 }
 return(fp);
}


/** Convert a text into a number of type double and multiply it by unit code
    [kmgtpe] (2^10 to 2^60) or [s] (2048). (Also accepts capital letters.)
    @param text Input like "42", "2k", "3.14m" or "-1g"
    @param flag Bitfield for control purposes:
                bit0= return -1 rathern than 0 on failure
    @return The derived double value
*/
double Scanf_io_size(char *text, int flag)
/*
 bit0= default value -1 rather than 0
*/
{
 int c;
 double ret= 0.0;

 if(flag&1)
   ret= -1.0;
 if(text[0]==0)
   return(ret);
 sscanf(text,"%lf",&ret);
 c= text[strlen(text)-1];
 if(c=='k' || c=='K') ret*= 1024.0;
 if(c=='m' || c=='M') ret*= 1024.0*1024.0;
 if(c=='g' || c=='G') ret*= 1024.0*1024.0*1024.0;
 if(c=='t' || c=='T') ret*= 1024.0*1024.0*1024.0*1024.0;
 if(c=='p' || c=='P') ret*= 1024.0*1024.0*1024.0*1024.0*1024.0;
 if(c=='e' || c=='E') ret*= 1024.0*1024.0*1024.0*1024.0*1024.0*1024.0;
 if(c=='s' || c=='S') ret*= 2048.0;
 return(ret);
}


/* ------------------------------------------------------------------------ */


#ifndef Xorriso_sregex_externaL

#ifndef Smem_malloC
#define Smem_malloC malloc
#endif
#ifndef Smem_freE
#define Smem_freE free
#endif


int Sregex_string_cut(char **handle, char *text, int len, int flag)
/*
 bit0= append (text!=NULL)
*/
{
 int l=0;
 char *old_handle;

 if((flag&1)&&*handle!=NULL)
   l+= strlen(*handle);
 old_handle= *handle;
 if(text!=NULL) {
   l+= len;
   *handle= TSOB_FELD(char,l+1);
   if(*handle==NULL) {
     *handle= old_handle;
     return(0);
   }
   if((flag&1) && old_handle!=NULL)
     strcpy(*handle,old_handle);
   else
     (*handle)[0]= 0;
   if(len>0)
     strncat(*handle,text,len);
 } else {
   *handle= NULL;
 }
 if(old_handle!=NULL)
   Smem_freE(old_handle);
 return(1);
}


int Sregex_string(char **handle, char *text, int flag)
/*
 bit0= append (text!=NULL)
*/
{
 int ret,l=0;

 if(text!=NULL)
   l= strlen(text);
 
/* #define Sregex_looking_for_contenT 1 */
#ifdef Sregex_looking_for_contenT
 /* a debugging point if a certain text content has to be caught */
 if(text!=NULL)
   if(strcmp(text,"clear")==0)
     ret= 0;
#endif

 ret= Sregex_string_cut(handle,text,l,flag&1);
 return(ret);
}


/*
  from Juergen Helbing's  yencode-c.txt 
  found at  www.yenc.org  , Feb 4,  2002
  license : "It is public domain - as well as the yEnc specification"
  some alterations made to adapt it to Sregex_crc32() 

  seems to be compatible with SFV/CSV files
*/                       

int Sregex_crc32_yenc(char *data, int len, unsigned long *crc, int flag)
/*
 bit0= start of data polynom
*/
{
 /* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
 static unsigned long crc_tab[256] = {
   0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 
   0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
   0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
   0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
   0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
   0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
   0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
   0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
   0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
   0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
   0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
   0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
   0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
   0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
   0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
   0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
   0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
   0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
   0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
   0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
   0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
   0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
   0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
   0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
   0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
   0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
   0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
   0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
   0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
   0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
   0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
   0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
   0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
   0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
   0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
   0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
   0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
   0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
   0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
   0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
   0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
   0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
   0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
   0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
   0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
   0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
   0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
   0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
   0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
   0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
   0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
   0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
   0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
   0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
   0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
   0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
   0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
   0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
   0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
   0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
   0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
   0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
   0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
   0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};

 int k;
 unsigned long crc_val,ch1,ch2,cc;

 if(flag&1)
   crc_val = ~0;
 else
   crc_val = ~*crc;

 for(k=0;k<len;k++) {
   cc= data[k] & 0xffL;
   ch1= (crc_val ^ cc) & 0xffL;
   ch1= crc_tab[ch1];
   ch2= (crc_val>>8L) & 0xffffffL;
   crc_val= ch1 ^ ch2;
 }
 *crc= ~crc_val;
 return(1);
}

#endif /*  Xorriso_sregex_externaL */


#ifndef Xorriso_text_shellsafe_externaL 

char *Text_shellsafe(char *in_text, char *out_text, int flag)
{
 int l,i,w=0;

 /* enclose everything by hard quotes */
 l= strlen(in_text);
 out_text[w++]= '\'';
 for(i=0;i<l;i++){
   if(in_text[i]=='\''){
     /* escape hard quote within the text */
     out_text[w++]= '\'';
     out_text[w++]= '"';
     out_text[w++]= '\'';
     out_text[w++]= '"';
     out_text[w++]= '\'';
   } else {
     out_text[w++]= in_text[i];
   }
 }
 out_text[w++]= '\'';
 out_text[w++]= 0;
 return(out_text);
}


#endif /* ! Xorriso_text_shellsafe_externaL */



 
#ifndef Xorriso_fileliste_externaL 

/* ??? ts A71006 : Is this compatible with mkisofs pathspecs ?
                   I dimly remember so */

int Fileliste__target_source_limit(char *line, char sep, char **limit_pt,
                                    int flag)
{
 char *npt;

 for(npt= line;*npt!=0;npt++) {
   if(*npt=='\\') {
     if(*(npt+1)!=0)
       npt++;
 continue;
   }
   if(*npt=='=')
 break;
 }
 if(*npt==0)
   npt= NULL;
 (*limit_pt)= npt;
 return(npt!=NULL);
}


int Fileliste__unescape_target(char *line, char *endpt, char sep, int flag)
{
 char *wpt,*rpt;

 if(endpt==NULL)
   endpt= line+strlen(line);

 /* unescape sep and '\\' */
 wpt= line;
 for(rpt= line; rpt<endpt; rpt++) {
   if(*rpt=='\\') {
     if(*(rpt+1)==sep || *(rpt+1)=='\\')
       rpt++;
   }
   *(wpt++)= *rpt;
 }
 *wpt= 0;
 return(1);
} 


int Fileliste__escape_target(char *target, int flag)
{
 int i,offset= 0;
 /* escape '=' and '\\' in target address */
 for(i= strlen(target)-1;i>=0;i--)
   if(target[i]=='=' || target[i]=='\\')
     offset++;
 target[strlen(target)+offset]= 0;
 for(i= strlen(target)-1;i>=0;i--) {
   if(target[i]=='=' || target[i]=='\\') {
     target[i+offset]= target[i];
     offset--;
     target[i+offset]= '\\';
   } else {
     target[i+offset]= target[i];
   }
 }
 return(1);
}

#endif /* ! Xorriso_fileliste_externaL */


#ifndef Xorriso_cleanup_externaL

/* <<< ??? ts A71006 : will this be replaced by the libburn signal handler ? */

#include <signal.h>
typedef void (*sighandler_t)(int);


/* Signals to be caught */
static int signal_list[]= {
 SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT,
 SIGFPE, SIGSEGV, SIGPIPE, SIGALRM, SIGTERM,
 SIGUSR1, SIGUSR2, SIGXCPU, SIGTSTP, SIGTTIN,
 SIGTTOU,
 SIGBUS, SIGPOLL, SIGPROF, SIGSYS, SIGTRAP,
 SIGVTALRM, SIGXCPU, SIGXFSZ, -1
};
static char *signal_name_list[]= {
 "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGABRT",
 "SIGFPE", "SIGSEGV", "SIGPIPE", "SIGALRM", "SIGTERM",
 "SIGUSR1", "SIGUSR2", "SIGXCPU", "SIGTSTP", "SIGTTIN",
 "SIGTTOU",
 "SIGBUS", "SIGPOLL", "SIGPROF", "SIGSYS", "SIGTRAP",
 "SIGVTALRM", "SIGXCPU", "SIGXFSZ", "@"
};
static int signal_list_count= 24;


/* Signals not to be caught */
static int non_signal_list[]= {
  SIGKILL, SIGCHLD, SIGSTOP, SIGURG, -1
};
static int non_signal_list_count= 4;


/* run time dynamic part */
static char cleanup_msg[SfileadrL]= {""};
static int cleanup_exiting= 0;

static void *cleanup_app_handle= NULL;
static Cleanup_app_handler_T cleanup_app_handler= NULL;
static int cleanup_perform_app_handler_first= 0;


static int Cleanup_handler_exit(int exit_value, int signum, int flag)
{
 int ret;

 if(cleanup_perform_app_handler_first)
   if(cleanup_app_handler!=NULL) {
     ret= (*cleanup_app_handler)(cleanup_app_handle,signum,0);
     if(ret==2)
       return(2);
   }
 if(cleanup_exiting) {
   if(cleanup_msg[0]!=0)
     fprintf(stderr,"%s\n",cleanup_msg);
   fprintf(stderr,"cleanup: ABORT : repeat by pid=%d, signum=%d\n",
           getpid(),signum);
   return(0);
 }
 cleanup_exiting= 1;
 if(cleanup_msg[0]!=0)
   fprintf(stderr,"%s\n",cleanup_msg);
 alarm(0);
 if(!cleanup_perform_app_handler_first)
   if(cleanup_app_handler!=NULL)
     (*cleanup_app_handler)(cleanup_app_handle,signum,0);
 exit(exit_value);
}


static void Cleanup_handler_generic(int signum)
{
 int i;

 sprintf(cleanup_msg,"UNIX-SIGNAL caught:  %d  errno= %d",signum,errno);
 for(i= 0; i<signal_list_count; i++)
   if(signum==signal_list[i]) {
     sprintf(cleanup_msg,"UNIX-SIGNAL:  %s  errno= %d",
             signal_name_list[i],errno);
 break;
   }
 Cleanup_handler_exit(1,signum,0);
}


int Cleanup_set_handlers(void *handle, Cleanup_app_handler_T handler, int flag)
/*
 bit0= set to default handlers
 bit1= set to ignore
 bit2= set cleanup_perform_app_handler_first
 bit3= set SIGABRT to handler (makes sense with bits 0 or 1)
*/
{
 int i,j,max_sig= -1,min_sig= 0x7fffffff;
 sighandler_t sig_handler;

 cleanup_msg[0]= 0;
 cleanup_app_handle= handle;
 cleanup_app_handler= handler;
 if(flag&4)
   cleanup_perform_app_handler_first= 1;
 if(flag&1)
   sig_handler= SIG_DFL;
 else if(flag&2)
   sig_handler= SIG_IGN;
 else
   sig_handler= Cleanup_handler_generic;
 /* set all signal numbers between the lowest and highest in the list
    except those in the non-signal list */
 for(i= 0; i<signal_list_count; i++) {
   if(signal_list[i]>max_sig)
     max_sig= signal_list[i];
   if(signal_list[i]<min_sig)
     min_sig= signal_list[i];
 }
 for(i= min_sig; i<=max_sig; i++) {
   for(j= 0; j<non_signal_list_count; j++)
     if(i==non_signal_list[j])
   break;
   if(j>=non_signal_list_count) {
     if(i==SIGABRT && (flag&8))
       signal(i,Cleanup_handler_generic);
     else
       signal(i,sig_handler);
   }
 }
 return(1);
}


#endif /* ! Xorriso_cleanup_externaL */


#ifndef Xorriso_dirseq_externaL

/* ------------------------------------------------------------------------ */
/* DirseQ : crawl along a directory's content list */

static int Dirseq_buffer_sizE= 1000;

struct DirseQ {
  DIR *dirpt;
  int count;  
  char **buffer;
  int buffer_size;
  int buffer_fill;
  int buffer_rpt;
};

int Dirseq_destroy(struct DirseQ **o, int flag);
int Dirseq_next_adrblock(struct DirseQ *o, char *replies[], int *reply_count,
                         int max_replies, int flag);


int Dirseq_new(struct DirseQ **o, char *dir, int flag)
/*
 bit0= do not complain about failed opendir()
*/
{
 int ret,i;
 struct DirseQ *m;

 m= *o= TSOB_FELD(struct DirseQ,1);
 if(m==NULL)
   return(-1);
 m->dirpt= NULL;
 m->count= 0;
 m->buffer= NULL;
 m->buffer_size= 0;
 m->buffer_fill= 0;
 m->buffer_rpt= 0;
 m->buffer= TSOB_FELD(char *,Dirseq_buffer_sizE);
 if(m->buffer==NULL)
   {ret= -1; goto failed;}
 m->buffer_size= Dirseq_buffer_sizE;
 for(i= 0;i<m->buffer_size;i++)
   m->buffer[i]= NULL;
 if(dir[0]==0)
   m->dirpt= opendir(".");
 else
   m->dirpt= opendir(dir);
 if(m->dirpt==NULL) {
   if(!(flag&1))
     fprintf(stderr,"opendir(%s) failed : %s\n",dir,strerror(errno));
   ret= 0; goto failed;
 }
 return(1);
failed:;
 Dirseq_destroy(o,0);
 return(ret);
}


int Dirseq_destroy(struct DirseQ **o, int flag)
{
 int i;

 if(*o==NULL)
   return(0);
 if((*o)->dirpt!=NULL)
   closedir((*o)->dirpt);
 if((*o)->buffer!=NULL) {
   for(i=0;i<(*o)->buffer_size;i++)
     if((*o)->buffer[i]!=NULL)
       free((*o)->buffer[i]);
   free((char *) (*o)->buffer);
 }
 free((char *) *o);
 (*o)= NULL;
 return(1);
}


int Dirseq_rewind(struct DirseQ *o, int flag)
{
 rewinddir(o->dirpt);
 return(1);
}


int Dirseq_next_adr(struct DirseQ *o, char reply[SfileadrL], int flag)
/*
flag:
 bit0= permission to use buffer
 bit1= do not increment counter
 bit2= ignore buffer in any case
 bit3= do not exclude '.' and '..'
 bit4= sort buffer
 bit5= sort only incomplete last buffer
return:
 <0 error
 0= no more entries available
 1= ok, reply is valid
*/
{
 int ret;
 struct dirent *entry;
 char *name;

 static int override_flag_0= 0,override_flag_1= 32;
 flag= (flag&~override_flag_0)|override_flag_1;

 if((flag&1) && o->buffer_rpt>=o->buffer_fill) {
   /* permission to buffer and buffer empty : load a buffer */
   ret= Dirseq_next_adrblock(o,o->buffer,&(o->buffer_fill),
                             o->buffer_size,2|4|(flag&16));
   if(ret<=0)
     return(ret);
   o->buffer_rpt= 0;
   if((flag&32) && o->buffer_fill<o->buffer_size && o->buffer_fill>0) 
     Sort_argv(o->buffer_fill,o->buffer,0);
 }
 if(o->buffer_rpt<o->buffer_fill && !(flag&4)) {
   ret= Sfile_str(reply,o->buffer[o->buffer_rpt],0);
   Sregex_string(&(o->buffer[o->buffer_rpt]),NULL,0);
   if(ret<=0)
     return(-1);
   (o->buffer_rpt)++;
   if(!(flag&2))
     o->count++;
   return(1);
 }
 do {
   entry= readdir(o->dirpt);
   if(entry==NULL) {
     /* >>> how to distinguish error from EOF , do i need a (FILE *) ? */
     return(0);
   }
   if(strlen(entry->d_name)>4095) {
     fprintf(stderr,"--- oversized directory entry (number %d) :\n    %s",
                    o->count+1,entry->d_name);
     return(-1);
   }
   name= entry->d_name;
   if(flag&8)
 break;
   /* skip "." and ".." */
 } while(name[0]=='.' && ((name[1]=='.' && name[2]==0) || name[1]==0));
 if(Sfile_str(reply,name,0)<=0)
   return(-1);
 if(!(flag&2))
   o->count++;
 return(1);
}


int Dirseq_next_adrblock(struct DirseQ *o, char *replies[], int *reply_count,
                         int max_replies, int flag)
/* @param replies A vector of Sregex_string pointers */
/*
flag:
 bit0= permission to use buffer
 bit1= do not increment counter
 bit2= ignore buffer in any case
 bit4= sort replies
return:
 <0 error
 0= no more entries available
 1= ok, reply is valid
*/
{
 int i,ret;
 char reply[SfileadrL];

 *reply_count= 0;
 for(i=0;i<max_replies;i++) {
   ret= Dirseq_next_adr(o,reply,flag&(1|2|4));
   if(ret<0)
     return(ret);
   if(ret==0)
 break;
   if(Sregex_string(&(replies[i]),reply,0)<=0)
     return(-1);
   (*reply_count)++;
 }
 if((*reply_count)==0)
   return(0);
 if(flag&16) 
   Sort_argv(*reply_count,replies,0);
 return(1);
}


#endif /* ! Xorriso_dirseq_externaL */


/* ------------------------------- Xorriso -------------------------------- */

/** The list of startup file names */
#define Xorriso_rc_nuM 4

static char Xorriso_sys_rc_nameS[Xorriso_rc_nuM][80]= {
 "/etc/default/xorriso",
 "/etc/opt/xorriso/rc",
 "/etc/xorriso/xorriso.conf",
 "placeholder for $HOME/.xorrisorc"
};


int Xorriso_new(struct XorrisO ** xorriso,char *progname, int flag)
{
 int i;
 struct XorrisO *m;
 
 *xorriso= m= TSOB_FELD(struct XorrisO,1);
 if(m==NULL)
   return(-1);
 m->libs_are_started= 0;
 strncpy(m->progname,progname,sizeof(m->progname)-1);
 m->progname[sizeof(m->progname)-1]= 0;
 if(getcwd(m->initial_wdx,sizeof(m->initial_wdx)-1)==NULL)
   m->initial_wdx[0]= 0;
 m->no_rc= 0;

 m->rc_filename_count= Xorriso_rc_nuM;
 for(i=0;i<m->rc_filename_count-1;i++)
   strcpy(m->rc_filenames[i],Xorriso_sys_rc_nameS[i]);
 m->rc_filenames[m->rc_filename_count-1][0]= 0;

 m->wdi[0]= 0;
 strcpy(m->wdx, m->initial_wdx);
 m->did_something_useful= 0;
 m->do_joliet= 0;
 m->do_follow_links= 0;
 m->do_global_uid= 0;
 m->global_uid= 0;
 m->volid[0]= 0;
 m->do_global_gid= 0;
 m->do_overwrite= 1;
 m->do_reassure= 0;
 m->global_gid= 0;
 m->indev[0]= 0;
 m->in_drive_handle= NULL;
 m->in_volset_handle= NULL;
 m->volset_change_pending= 0;
 m->outdev[0]= 0;
 m->out_drive_handle= NULL;
 m->ban_stdio_write= 0;
 m->do_dummy= 0;
 m->do_close= 0;
 m->speed= 0;
 m->fs= 4*512; /* 4 MiB */
 m->allow_graft_points= 0;
 m->dialog= 0;
 m->search_mode= 0;
 m->structured_search= 1;
 m->use_stdin= 0;
 m->result_page_length= 0;
 m->result_page_width= 80;
 m->mark_text[0]= 0;
 m->packet_output= 0;
 for(i=0; i<4; i++)
   m->logfile[i][0]= 0;
 m->status_history_max= Xorriso_status_history_maX;
 strcpy(m->report_about_text, "ALL");
 Xorriso__text_to_sev(m->report_about_text, &m->report_about_severity, 0);
 m->library_msg_direct_print= 0;
 strcpy(m->abort_on_text,"FATAL");
 Xorriso__text_to_sev(m->abort_on_text, &m->abort_on_severity, 0);
 m->problem_status= 0;
 m->problem_status_text[0]= 0;
#ifdef Xorriso_with_regeX
 m->re= NULL;
 /* >>> ??? how to initialize m->match[0] ? */
#endif /* Xorriso_with_regeX */
 m->re_constants= NULL;
 m->re_count= 0;
 m->re_fill= 0;
 m->reg_expr[0]= 0;
 m->is_dialog= 0;
 m->bar_is_fresh= 0;
 m->pending_option[0]= 0;
 m->request_to_abort= 0;
 m->idle_time= 0.0;
 m->re_failed_at= -1;
 m->prepended_wd= 0;
 m->insert_count= 0;
 m->insert_bytes= 0;
 m->error_count= 0;
 m->result_line[0]= 0;
 m->result_line_counter= 0;
 m->result_page_counter= 0;
 m->result_open_line_len= 0;
 m->info_text[0]= 0;

 return(1);
}


int Xorriso_destroy_re(struct XorrisO *m, int flag)
{
 int i;

#ifdef Xorriso_with_regeX
 if(m->re!=NULL) {
   for(i=0;i<m->re_fill;i++) {
     if(m->re_constants!=NULL)
       if(m->re_constants[i]!=NULL)
   continue; /* ,->re[i] was never subject to regcomp() */
     regfree(&(m->re[i]));
   }
   free((char *) m->re);
   m->re= NULL;
 }
#endif /* Xorriso_with_regeX */

 if(m->re_constants!=NULL) {
   for(i=0;i<m->re_fill;i++)
     if(m->re_constants[i]!=NULL)
       free(m->re_constants[i]);
   free((char *) m->re_constants);
   m->re_constants= NULL;
 }
 m->re_count= 0;
 m->re_fill= 0;
 return(1);
}


int Xorriso_destroy(struct XorrisO **xorriso, int flag)
{
 struct XorrisO *m;

 m= *xorriso;
 if(m==NULL)
   return(0);
 Xorriso_destroy_re(m,0);

 free((char *) m);
 *xorriso= NULL;
 return(1);
}


int Xorriso_dialog_input(struct XorrisO *xorriso, char line[], int linesize,
                         int flag)
/*
 bit0= do not write to history
 bit1= do not read input (but eventually write to history)
 bit2= do not write to history line which begin with "-history:" or "-history "
*/
{
 char *cpt= NULL;
 int ret;
#ifdef Xorriso_with_readlinE
 int l;
 static char last_input[SfileadrL]= {""};
#endif /* ! Xorriso_with_readlinE */
 double tdiff;
 struct timeval tv;
 struct timezone tz;

 gettimeofday(&tv,&tz);
 tdiff= tv.tv_sec+(1.e-6*(double) tv.tv_usec);

 fflush(stdout);

#ifdef Xorriso_with_readlinE

 if(xorriso->use_stdin) {
   if(flag&2)
     {ret= 1; goto ex;}
   if(Sfile_fgets(line,linesize-1,stdin)==NULL) {
     /* need a very dramatic end */
     kill(getpid(),SIGHUP);
     {ret= -1; goto ex;}
   }
   {ret= 1; goto ex;}
 }
 if(flag&2) {
   cpt= NULL;
 } else {
   cpt= readline("");
   if(cpt==NULL) {
     /* need a very dramatic end */
     kill(getpid(),SIGHUP);
     {ret= -1; goto ex;}
   }
   l= strlen(cpt);
   if(l>=linesize) {
     strncpy(line,cpt,linesize-1);
     line[sizeof(line)-1]= 0;
   } else 
     strcpy(line,cpt);
 }
 if(line[0]!=0 && strcmp(last_input,line)!=0 && !(flag&1))
   if(!((flag&4) && 
      (strncmp(line,"-history:",9)==0 || strncmp(line,"-history ",9)==0))) {
     add_history(line);
     strncpy(last_input,line,sizeof(last_input)-1);
     last_input[sizeof(last_input)-1]= 0;
   }

#else /*  Xorriso_with_readlinE */

 if(flag&2)
   {ret= 1; goto ex;}
 if(Sfile_fgets(line,linesize-1,stdin)==NULL) {
   /* need a very dramatic end */
   kill(getpid(),SIGHUP);
   {ret= -1; goto ex;}
 }

#endif /* ! Xorriso_with_readlinE */

 ret= 1;
ex:;
 if(cpt!=NULL)
   free(cpt);
 gettimeofday(&tv,&tz);
 xorriso->idle_time+= tv.tv_sec+(1.e-6*(double) tv.tv_usec)-tdiff;
 return(ret);
}


int Xorriso_request_confirmation(struct XorrisO *xorriso, int flag)
/*
 bit0= important operation going on: 
       demand confirmation of abort, only abort on @@@
 bit1= mark '@' and '@@' by return 4
 bit2= accept: i=ignore , r=retry , x=abort
 bit3= @@@ = 'done reading' rather than 'abort'
*/
/* return: <=0 error , 1=go on , 2=abort , 3=redo request, 4=see flag bit1
                       (5=skip volume) , 6=retry failed operation
 */
{
 int ret;
 char line[SfileadrL],*cpt,previous_line[SfileadrL];
 char *abort_req_text,*abort_really_text;

 if(flag&8) {
   abort_req_text= "request to end";
   abort_really_text= "done reading";
 } else {
   abort_req_text= "request to abort";
   abort_really_text= "abort";
 }
 ret= Xorriso_dialog_input(xorriso,line,sizeof(line),1);
 xorriso->result_line_counter= 0;
 xorriso->result_page_counter++;
 if(ret<=0)
   if(xorriso->result_page_length>0)
     xorriso->result_page_length= -xorriso->result_page_length;

 cpt= line;
 if(*cpt=='@') {
   if(strcmp(cpt,"@@@")==0) {
request_to_abort:;
     if(flag&1) {
       strcpy(previous_line,cpt);
       sprintf(xorriso->info_text,
               "....... [%s = %s registered. Really %s ? (y/n) ] .......\n",
               cpt,abort_req_text,abort_really_text);
       Xorriso_info(xorriso,0);
       ret= Xorriso_dialog_input(xorriso,line,sizeof(line),1);
       if(ret<=0)
         return(ret);
       cpt= line;
       if(strcmp(cpt,previous_line)==0 || 
          ((*cpt=='Y' || *cpt=='y' || *cpt=='j' || *cpt=='J' || *cpt=='1') &&
             *(cpt+1)==0)) {
         xorriso->request_to_abort= 1;
         sprintf(xorriso->info_text,
                 "------- ( %s confirmed )\n",abort_req_text);
         Xorriso_info(xorriso,0);
         return(2);
       }
       sprintf(xorriso->info_text,
               "....... ( %s revoked )\n",abort_req_text);
       Xorriso_info(xorriso,0);
       return(3);
     }
     xorriso->request_to_abort= 1;
     sprintf(xorriso->info_text,
"----------- [%s = request to abort registered. Operation ends ] ------------\n",
               cpt);
     Xorriso_info(xorriso,0);
     return(2);
   } else if(strcmp(cpt,"@@")==0) {
     goto klammer_affe;
     
   } else if(strcmp(cpt,"@")==0) {
klammer_affe:;
     if(xorriso->result_page_length>0)
       xorriso->result_page_length= -xorriso->result_page_length;
     if(flag&1) {
       sprintf(xorriso->info_text,
"... [@ = page prompt suppression registered. -page disabled temporarily ] ...\n");
       Xorriso_info(xorriso,0);
     }

   } else {
     Xorriso_dialog_input(xorriso,cpt,strlen(line)+1,2); /* write to history */
     sprintf(xorriso->info_text,
 "--- Unrecognized input beginning with @. Please enter someting else.\n");
     Xorriso_info(xorriso,0);
     return(3);
   }
   if(flag&2)
     return(4);
   if(flag&1)
     return(3);
   return(1);
 } else if(flag&4) {

   if(strcmp(cpt,"i")==0 || strcmp(cpt,"I")==0 || *cpt==0) { 
     return(1);
   } else if(strcmp(cpt,"r")==0 || strcmp(cpt,"R")==0) {
     return(6);
   } else if(strcmp(cpt,"x")==0 || strcmp(cpt,"X")==0) {
     goto request_to_abort;
   } else {
     /* >>> unknown input */
     sprintf(xorriso->info_text,
             "--- Please enter one of : empty line, i, r, x, @, @@, @@@\n");
     Xorriso_info(xorriso,0);
     return(3);
   }

 } else if(*cpt=='-' && !(flag&1)) {
   Xorriso_dialog_input(xorriso,cpt,strlen(line)+1,2); /* write to history */
   strcpy(xorriso->pending_option,cpt);
   xorriso->request_to_abort= 1;
   sprintf(xorriso->info_text,
"------------ [-* = input of option registered. Operation ends ] -------------\n");
   Xorriso_info(xorriso,0);
   return(2);

 } else if(*cpt!=0 && !(flag&1)) {
   Xorriso_dialog_input(xorriso,cpt,strlen(line)+1,2); /* write to history */
   strcpy(xorriso->pending_option,cpt);
   xorriso->request_to_abort= 1;
   sprintf(xorriso->info_text,
"------------ [ input of searchtext registered. Operation ends ] -------------\n");
   Xorriso_info(xorriso,0);
   return(2);
 } else if(*cpt!=0) {
   Xorriso_dialog_input(xorriso,cpt,strlen(line)+1,2); /* write to history */
   sprintf(xorriso->info_text,
           "--- Please enter one of : empty line, @, @@, @@@\n");
   Xorriso_info(xorriso,0);
   return(3);
 }
 return(1);
}


int Xorriso_predict_linecount(struct XorrisO *xorriso, char *line,
                              int *linecount, int flag)
{
 int width,l;
 char *spt,*ept;

 *linecount= 0;
 spt= line;
 width= xorriso->result_page_width;
 while(1) {
   ept= strchr(spt,'\n');
   if(ept==NULL)
     l= strlen(spt);
   else
     l= ept-spt;
   l+= xorriso->result_open_line_len;
   if(ept!=NULL && l==0)
     (*linecount)++;
   else {
     (*linecount)+= l/width;
     if(ept==NULL) {
       xorriso->result_open_line_len= l%width;
 break;
     }
     (*linecount)+= !!(l%width);
   }
   xorriso->result_open_line_len= 0;
   spt= ept+1;
 }
 return(1);
}


int Xorriso_pager(struct XorrisO *xorriso, char *line, int flag)
/*
 bit1= mark '@' by return 4
*/
/* return: <=0 error , 1=go on , 2=abort , 4=see flag bit1*/
{
 int ret,linecount;
 char info_text[10*SfileadrL];

 if(xorriso->result_page_length<=0)
   return(1);
 Xorriso_predict_linecount(xorriso,line,&linecount,0);
 if(xorriso->result_line_counter+linecount>xorriso->result_page_length) {
ask_for_page:;
   strcpy(info_text,xorriso->info_text);
   sprintf(xorriso->info_text,"\n");
   Xorriso_info(xorriso,0);
   sprintf(xorriso->info_text,
".... [Press Enter to continue. @,Enter avoids further stops. @@@ aborts] ....\n");
   Xorriso_info(xorriso,0);
   ret= Xorriso_request_confirmation(xorriso,flag&2);
   strcpy(xorriso->info_text,info_text);
   if(ret<=0)
     return(ret);
   if(ret==2)
     return(2);
   if(ret==3)
     goto ask_for_page;
 }
 xorriso->result_line_counter+= linecount;
 return(1);
}


int Xorriso_result(struct XorrisO *xorriso, int flag)
/*
 bit0= no considerations or computations or dialog. Just put out.
*/
{
 int ret;

 if(flag&1)
   goto put_it_out;
 if(xorriso->request_to_abort)
   return(1);
 if(xorriso->result_page_length>0) {
   ret= Xorriso_pager(xorriso,xorriso->result_line,2);
   if(ret<=0)
     return(ret);
   if(ret==2)
     return(1);
   if(xorriso->request_to_abort)
     return(1);
 }
put_it_out:;
 xorriso->bar_is_fresh= 0;
 ret= Write_to_channel(xorriso->result_line,1,!xorriso->packet_output);
 return(ret);
}


int Xorriso_info(struct XorrisO *xorriso, int flag)
/*
 bit0= use pager (as with result)
 bit1= permission to suppress output
*/
{
 int ret;

 if(flag&2)
   if(xorriso->request_to_abort)
     return(1);
 if(flag&1) {
   ret= Xorriso_pager(xorriso,xorriso->info_text,2);
   if(ret<=0)
     return(ret);
   if(ret==2)
     return(1);
   if(flag&2)
     if(xorriso->request_to_abort)
       return(1);
 }
 xorriso->bar_is_fresh= 0;
 ret= Write_to_channel(xorriso->info_text,2,!xorriso->packet_output);
 return(ret);
}


int Xorriso_mark(struct XorrisO *xorriso, int flag)
{
 int ret= 1,r_ret,i_ret;

 if(xorriso->mark_text[0]==0)
   return(1);
 if(xorriso->packet_output) 
   ret= Write_to_channel(xorriso->mark_text,3,0);
 else {
   sprintf(xorriso->result_line,"%s\n",xorriso->mark_text);
   r_ret= Xorriso_result(xorriso,1);
   strcpy(xorriso->info_text,xorriso->result_line);
   i_ret= Xorriso_info(xorriso,0);
   if(r_ret==0 || i_ret==0)
     ret= 0;
 }
 return(ret);
}


int Xorriso_restxt(struct XorrisO *xorriso, char *text)
{
 int ret;

 strncpy(xorriso->result_line,text,sizeof(xorriso->result_line)-1);
 xorriso->result_line[sizeof(xorriso->result_line)-1]= 0;
 ret= Xorriso_result(xorriso,0);
 return(ret);
}


int Xorriso_reset_counters(struct XorrisO *xorriso, int flag)
/*
 bit0= reset xorriso->found to -1
*/
{
 xorriso->error_count= 0;
 xorriso->insert_count= 0;
 xorriso->insert_bytes= 0;
 return(1);
}


int Xorriso__bourne_to_reg(char bourne_expr[], char reg_expr[], int flag)
/* reg_expr should be twice as large as bourne_expr ( + 2 to be exact) */
/* return: 2= bourne_expr is surely a constant */
{
 char *wpt,*lpt;
 int backslash= 0,is_constant= 1,in_square_brackets= 0;
 int first_in_square_brackets=0;

 wpt= reg_expr;
 lpt= bourne_expr;

 *(wpt++)= '^';

 while(*lpt!=0){
  if(first_in_square_brackets>0)
    first_in_square_brackets--;
  if(!backslash){
    switch(*lpt){
    case '?':
      *(wpt++)= '.';
      is_constant= 0;
    break;case '*':
      *(wpt++)= '.';
      *(wpt++)= '*';
      is_constant= 0;
    break;case '.':
      *(wpt++)= '\\';
      *(wpt++)= '.';
    break;case '+':
      *(wpt++)= '\\';
      *(wpt++)= '+';
    break;case '[':
      *(wpt++)= *lpt;
      first_in_square_brackets= 2;
      in_square_brackets= 1;
      is_constant= 0;
    break;case ']':
      *(wpt++)= *lpt;
      in_square_brackets= 0;
    break;case '!':
      if(first_in_square_brackets)
        *(wpt++)= '^';
      else if(in_square_brackets)
        *(wpt++)= '!';
      else {
        *(wpt++)= '\\';
        *(wpt++)= '!';
      }
    break;case '^':
      if(in_square_brackets)
        *(wpt++)= '^';
      else
        *(wpt++)= '\\';
        *(wpt++)= '^';
    break;case '$':
      *(wpt++)= '\\';
      *(wpt++)= '$';
    break;case '\\':
      backslash= 1;
      *(wpt++)= '\\';
      is_constant= 0;
    break;default:
      *(wpt++)= *lpt;
    }
  } else {
    backslash= 0;
    *(wpt++)= *lpt;
  }
  lpt++;
 }
 *(wpt++)= '$';
 *wpt= 0;
 return(1+(is_constant>0));
}


int Xorriso_prepare_regex(struct XorrisO *xorriso, char *adr, int flag)
/*
 bit0= do not augment relative structured search by xorriso->wd
*/
{
 int l,ret,i,count,bonked= 0,is_constant;
 char *cpt,*npt,adr_part[2*SfileadrL],absolute_adr[2*SfileadrL],*adr_start;

#ifndef Xorriso_with_regeX

 if(xorriso->search_mode==2 || 
    (xorriso->search_mode==3 && xorriso->structured_search==0)) {
no_regex_available:;
   sprintf(xorriso->info_text,"%s : regular expressions not implemented",
           xorriso->progname);
   Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
   return(0);
 }
   
#endif /* ! Xorriso_with_regeX */

 if(xorriso->search_mode>=2 && xorriso->search_mode<=4) {
   if(xorriso->search_mode==3 || xorriso->search_mode==4) {
     l= strlen(adr)+strlen(xorriso->wdi)+1;
     if(l*2+2>sizeof(xorriso->reg_expr) || l*2+2>sizeof(adr_part)) {
       sprintf(xorriso->info_text,"Search pattern too long");
       Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
       return(0);
     }
   }
   Xorriso_destroy_re(xorriso,0);
   if(xorriso->structured_search && xorriso->search_mode==3) {
     if(adr[0]!='/' && !(flag&1)) {
       /* relative expression : prepend working directory */
       sprintf(absolute_adr,"%s/%s",xorriso->wdi,adr);
       adr_start= absolute_adr;
       xorriso->prepended_wd= 1;
     } else
       adr_start= adr;
     /* count slashes */;
     cpt= adr_start;
     while(*cpt=='/')
       cpt++;
     for(i= 0;1;i++) {
       cpt= strchr(cpt,'/');
       if(cpt==NULL)
     break;
       while(*cpt=='/')
         cpt++;
     }
     count= i+1;

#ifdef Xorriso_with_regeX
     xorriso->re= TSOB_FELD(regex_t,count);
     if(xorriso->re==NULL)
       return(-1);
#endif /* Xorriso_with_regeX */

     xorriso->re_constants= TSOB_FELD(char *,count);
     if(xorriso->re_constants==NULL)
       return(-1);
     for(i= 0;i<count;i++)
       xorriso->re_constants[i]= NULL;
     xorriso->re_count= count;
     xorriso->re_fill= 0;
       
     /* loop over slash chunks*/;
     cpt= adr_start;
     xorriso->re_fill= 0;
     while(*cpt=='/')
       cpt++;
     for(i= 0;i<count;i++) {
       npt= strchr(cpt,'/');
       if(npt==NULL) {
         if(strlen(cpt)>=sizeof(adr_part))
           return(-1);
         strcpy(adr_part,cpt);
       } else {
         if(npt-cpt>=sizeof(adr_part))
           return(-1);
         strncpy(adr_part,cpt,npt-cpt);
         adr_part[npt-cpt]= 0;
       }

       if(adr_part[0]==0)
         goto next_adr_part;
       if(adr_part[0]=='.' && adr_part[1]==0)
         goto next_adr_part;
       if(adr_part[0]=='.' && adr_part[1]=='.' && adr_part[2]==0) {
         /* delete previous part */
         if(xorriso->re_fill<=0) {
           bonked= 1;
           goto next_adr_part;
         } 
         if(xorriso->re_constants[xorriso->re_fill-1]!=NULL) {
           free(xorriso->re_constants[xorriso->re_fill-1]);
           xorriso->re_constants[xorriso->re_fill-1]= NULL;
         } else
#ifdef Xorriso_with_regeX
           regfree(&(xorriso->re[xorriso->re_fill-1]));
#else /* Xorriso_with_regeX */
           ;
#endif /* ! Xorriso_with_regeX */
         (xorriso->re_fill)--;
         goto next_adr_part;
       }
       if(strcmp(adr_part,"*")==0) {
         adr_part[0]= 0;
         ret= 2;
       } else
         ret= Xorriso__bourne_to_reg(adr_part,xorriso->reg_expr,0);
       if(ret==2) {
         if(Sregex_string(&(xorriso->re_constants[xorriso->re_fill]),adr_part,0)
            <=0)
           return(-1);
       } else {

#ifdef Xorriso_with_regeX
         if(regcomp(&(xorriso->re[xorriso->re_fill]),xorriso->reg_expr,0)!=0)
           goto cannot_compile;
#else /* Xorriso_with_regeX */
         if(!warned_of_regex) {
           sprintf(xorriso->info_text,
                   "No wildcards get recognized besides single '*'");
           Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "WARNING",0);
           warned_of_regex= 1;
         }
         if(Sregex_string(&(xorriso->re_constants[xorriso->re_fill]),adr_part,0)
            <=0)
           return(-1);
#endif /* ! Xorriso_with_regeX */

       }
       xorriso->re_fill++;
next_adr_part:;
       if(i==count-1)
     break;
       cpt= npt+1;
       while(*cpt=='/')
         cpt++;
     }
     if(bonked) {
       sprintf(xorriso->info_text, "Your '..' bonked at the root directory.");
       Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "WARNING",0);
     }

     Xorriso__bourne_to_reg(adr_start,xorriso->reg_expr,0); /* just for show */

   } else { 
     is_constant= 0;
     if(strcmp(adr,"*")==0) {
       is_constant= 1;
     } else if(xorriso->search_mode==3 || xorriso->search_mode==4) {
       ret= Xorriso__bourne_to_reg(adr,xorriso->reg_expr,0);
       is_constant= (ret==2);
     } else {
       if(strlen(adr)>=sizeof(xorriso->reg_expr))
         return(-1);
       strcpy(xorriso->reg_expr,adr);
     }
     xorriso->re_count= 0; /* tells matcher that this is not structured */
     xorriso->re_constants= TSOB_FELD(char *,1);
     if(xorriso->re_constants==NULL)
       return(-1);
     xorriso->re_constants[0]= NULL;
     if(is_constant) {
       if(strcmp(adr,"*")==0) {
         if(Sregex_string(&(xorriso->re_constants[0]),"",0)<=0)
           return(-1);
       } else {
         if(Sregex_string(&(xorriso->re_constants[0]),adr,0)<=0)
           return(-1);
       }
       xorriso->re_fill= 1;
     } else { 
#ifdef Xorriso_with_regeX
       xorriso->re= TSOB_FELD(regex_t,1);
       if(xorriso->re==NULL)
         return(-1);
       if(regcomp(&(xorriso->re[0]),xorriso->reg_expr,0)!=0) {
cannot_compile:;
         sprintf(xorriso->info_text, "Cannot compile regular expression : %s",
                 xorriso->reg_expr);
         Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY",0);
         return(0);
       }
#else /* Xorriso_with_regeX */
       sprintf(xorriso->info_text,
              "No wildcards get recognized besides single '*'");
       Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "WARNING",0);
       Xorriso_info(xorriso,0);
       if(Sregex_string(&(xorriso->re_constants[0]),adr,0)<=0)
         return(-1);
       xorriso->re_fill= 1;
#endif /* ! Xorriso_with_regeX */
     }

   }
 }
 return(1);
}


int Xorriso_regexec(struct XorrisO *xorriso, char *to_match, int *failed_at,
                    int flag)
/*
 bit0= do not shortcut last component of to_match
 bit2= retry beginning at failed last component 
*/
{
 int ret,i,re_start= 0,reg_nomatch= -1;
 char *cpt,*npt,adr_part[SfileadrL],*mpt;

#ifdef Xorriso_with_regeX
 reg_nomatch= REG_NOMATCH;
#endif /* Xorriso_with_regeX */

 *failed_at= 0;
 if(!(xorriso->structured_search && xorriso->re_count>0)) {
   if(xorriso->re_constants!=NULL)
     if(xorriso->re_constants[0]!=NULL) {
       if(xorriso->re_constants[0][0]==0)
         return(0);
       if(strcmp(xorriso->re_constants[0],to_match)!=0)
         return(reg_nomatch);
       return(0);
     }  
#ifdef Xorriso_with_regeX
   ret= regexec(&(xorriso->re[0]),to_match,1,xorriso->match,0);
#else
   ret= reg_nomatch;
#endif /* ! Xorriso_with_regeX */

   return(ret);
 }

 cpt= to_match;
 while(*cpt=='/')
  cpt++;
 if(flag&4)
   re_start= xorriso->re_failed_at;
 if(re_start<0)
   re_start= 0;
 for(i= re_start;i<xorriso->re_fill;i++) {
   *failed_at= i;
   npt= strchr(cpt,'/');
   if(npt==NULL) {
     if(i<xorriso->re_fill-1 && !(flag&1)) 
       return(reg_nomatch); /* this must be the last expression part */
     mpt= cpt;
   } else {
     strncpy(adr_part,cpt,npt-cpt);
     adr_part[npt-cpt]= 0;
     mpt= adr_part;
   }
   if(xorriso->re_constants[i]!=NULL) {
     if(xorriso->re_constants[i][0]!=0) /* empty constant matches anything */
       if(strcmp(xorriso->re_constants[i],mpt)!=0)
         return(reg_nomatch);
   } else {

#ifdef Xorriso_with_regeX
     ret= regexec(&(xorriso->re[i]),mpt,1,xorriso->match,0);
     if(ret!=0)
       return(ret);
#else
     return(reg_nomatch);
#endif /* ! Xorriso_with_regeX */

   }
   if(npt==NULL) {
     if(i>=xorriso->re_fill-1)
       return(0); /* MATCH */
     *failed_at= i+1;
     return(reg_nomatch);
   }
   cpt= npt+1;
   while(*cpt=='/')
     cpt++; 
 }
 *failed_at= xorriso->re_fill;
 return(reg_nomatch);
}


int Xorriso_match_file(struct XorrisO *xorriso, char *to_match, char *adr,
                       int flag)
/*
 bit0= match under fsm rules: with search_mode 0 : do not accept partial match
 bit1= with xorriso->search_mode==4 : do not check for '/'
 bit2= single level bit for Xorriso_regexec()
*/
/* return:
  <0 error
   0 no match
   1 match
   2 match with request to break volume loop
*/
{
 int ret,l,failed_at;
 char *cpt;

 l= strlen(to_match);
 if(xorriso->search_mode==0) {
   if(flag&1) {
     if(strcmp(adr,to_match)==0)
       return(2);
   } else {
     if(strncmp(adr,to_match,l)==0)
       if(adr[l]=='/'||adr[l]==0)
         return(2);
   }
   l= strlen(adr);
   if(strncmp(to_match,adr,l)==0)
     if(to_match[l]=='/'||to_match[l]==0) {
       return(1);
     }
 } else if(xorriso->search_mode==1) {
   if(strstr(to_match,adr)!=NULL)
     return(1);
 } else if(xorriso->search_mode>=2 && xorriso->search_mode<=4) {
   if(xorriso->search_mode==4 && !(flag&2)) {
     cpt= strrchr(to_match,'/');
     if(cpt==NULL)
       cpt= to_match;
     else
       cpt++;
   } else
     cpt= to_match;
   ret= Xorriso_regexec(xorriso,cpt,&failed_at,1|(flag&4));
   if(ret==0)
     return(1);
   xorriso->re_failed_at= failed_at;
 }
 return(0);
}


int Xorriso_status_result(struct XorrisO *xorriso, char *filter, FILE *fp,
                          int flag)
/* 
bit1= do only report to fp
*/
{
 int ret,l;

 if(filter!=NULL)
   if(filter[0]=='-') {
     l= strlen(filter);
     if(strncmp(filter,xorriso->result_line,l)!=0)
       return(2);
   }
 if(!(flag&2))
   Xorriso_result(xorriso,0);
 if(fp!=NULL) {
   ret= fwrite(xorriso->result_line,strlen(xorriso->result_line),1,fp);
   if(ret<=0)
     return(ret);
 }   
 return(1);
}


int Xorriso_status(struct XorrisO *xorriso, char *filter, FILE *fp, int flag)
/*
 bit0= do only report non-default settings
 bit1= do only report to fp
 bit2= report current -resume status even if bit0 is set, but only if valid
 bit3= report readline history
 bit4= report -resume options indirectly as 
              -options_from_file:${resume_state_file}_pos
*/
{
 int is_default,no_defaults,i;
 char *line, sfe[4*SfileadrL];
 static char channel_prefixes[4][4]= {".","R","I","M"};

 no_defaults= flag&1;
 line= xorriso->result_line;

 if(xorriso->no_rc) {
   sprintf(line,"-no_rc\n");
   Xorriso_status_result(xorriso,filter,fp,flag&2);
 }
 is_default= 0;
 if(xorriso->dialog)
   sprintf(line,"-dialog\n");
 else {
   sprintf(line,"-dialog_reset\n");
   is_default= 1;
 }
 if(!(is_default && no_defaults))
   Xorriso_status_result(xorriso,filter,fp,flag&2);

 is_default= (xorriso->result_page_length==0 && xorriso->result_page_width==80);
 sprintf(line,"-page %d %d\n",
              (xorriso->result_page_length>=0?xorriso->result_page_length
                                           :-xorriso->result_page_length),
              xorriso->result_page_width);
 if(!(is_default && no_defaults))
   Xorriso_status_result(xorriso,filter,fp,flag&2);

 is_default= 0;
 if(xorriso->use_stdin)
   sprintf(line,"-use_stdin\n");
 else {
   sprintf(line,"-use_readline\n");
   is_default= 1;
 }
 if(!(is_default && no_defaults))
   Xorriso_status_result(xorriso,filter,fp,flag&2);

 is_default= !xorriso->packet_output;
 sprintf(line,"-pkt_output %s\n",(xorriso->packet_output?"on":"off"));
 if(!(is_default && no_defaults))
   Xorriso_status_result(xorriso,filter,fp,flag&2);

 for(i=0;i<4;i++) {
   is_default= (xorriso->logfile[i]!=0);
   sprintf(line,"-logfile %s %s\n",
           channel_prefixes[i],Text_shellsafe(xorriso->logfile[i],sfe,0));
   if(!(is_default && no_defaults))
     Xorriso_status_result(xorriso,filter,fp,flag&2);
 }

 is_default= (xorriso->mark_text[0]==0);
 sprintf(line,"-mark %s\n",Text_shellsafe(xorriso->mark_text,sfe,0));
 if(!(is_default && no_defaults))
   Xorriso_status_result(xorriso,filter,fp,flag&2);

 sprintf(line,"-prog %s\n",Text_shellsafe(xorriso->progname,sfe,0));
 Xorriso_status_result(xorriso,filter,fp,flag&2);

 sprintf(line,"-cd %s\n",
         (xorriso->wdi[0] ? Text_shellsafe(xorriso->wdi,sfe,0) : "'/'"));
 Xorriso_status_result(xorriso,filter,fp,flag&2);
 sprintf(line,"-cdx %s\n",
         (xorriso->wdx[0] ? Text_shellsafe(xorriso->wdx,sfe,0) : "'/'"));
 Xorriso_status_result(xorriso,filter,fp,flag&2);

 if(xorriso->ban_stdio_write) {
   sprintf(line,"-ban_stdio_write\n");
   Xorriso_status_result(xorriso,filter,fp,flag&2);
 }

 is_default= (xorriso->volid[0]==0);
 sprintf(line,"-V %s\n",Text_shellsafe(xorriso->volid,sfe,0));
 if(!(is_default && no_defaults))
   Xorriso_status_result(xorriso,filter,fp,flag&2);

 if(xorriso->do_joliet) {
   sprintf(line,"-J\n");
   Xorriso_status_result(xorriso,filter,fp,flag&2);
 }

 if(xorriso->do_global_uid) {
   sprintf(line,"-uid %lu\n", (unsigned long) xorriso->global_uid);
   Xorriso_status_result(xorriso,filter,fp,flag&2);
 }

 if(xorriso->do_global_gid) {
   sprintf(line,"-gid %lu\n", (unsigned long) xorriso->global_gid);
   Xorriso_status_result(xorriso,filter,fp,flag&2);
 }

 if(xorriso->allow_graft_points) {
   sprintf(line,"-graft-points\n");
   Xorriso_status_result(xorriso,filter,fp,flag&2);
 }

 if(xorriso->do_follow_links) {
   sprintf(line,"-f\n");
   Xorriso_status_result(xorriso,filter,fp,flag&2);
 }

 is_default= !!xorriso->do_overwrite;
 sprintf(line,"-overwrite %s\n",(xorriso->do_overwrite ? "on" : "off"));
 if(!(is_default && no_defaults))
   Xorriso_status_result(xorriso,filter,fp,flag&2);

 is_default= !xorriso->do_reassure;
 sprintf(line,"-reassure %s\n",(xorriso->do_reassure ? "on" : "off"));
 if(!(is_default && no_defaults))
   Xorriso_status_result(xorriso,filter,fp,flag&2);

 is_default= !xorriso->do_close;
 sprintf(line,"-close %s\n",(xorriso->do_close ? "on" : "off"));
 if(!(is_default && no_defaults))
   Xorriso_status_result(xorriso,filter,fp,flag&2);

 is_default= !xorriso->do_dummy;
 sprintf(line,"-dummy %s\n",(xorriso->do_dummy ? "on" : "off"));
 if(!(is_default && no_defaults))
   Xorriso_status_result(xorriso,filter,fp,flag&2);

 is_default= (xorriso->speed==0);
 sprintf(line,"-speed %dkB/s\n", xorriso->speed);
 if(!(is_default && no_defaults))
   Xorriso_status_result(xorriso,filter,fp,flag&2);

 is_default= (xorriso->fs==4*512);
 if((xorriso->fs/512)*512==xorriso->fs)
   sprintf(line,"-fs %dm\n", xorriso->fs/512);
 else
   sprintf(line,"-fs %dk\n", xorriso->fs*2);
 if(!(is_default && no_defaults))
   Xorriso_status_result(xorriso,filter,fp,flag&2);

 is_default= (strcmp(xorriso->report_about_text,"ALL")==0);
 sprintf(line,"-report_about %s\n",xorriso->report_about_text);
 if(!(is_default && no_defaults))
   Xorriso_status_result(xorriso,filter,fp,flag&2);
 
 is_default= (strcmp(xorriso->abort_on_text,"FATAL")==0);
 sprintf(line,"-abort_on %s\n",xorriso->abort_on_text);
 if(!(is_default && no_defaults))
   Xorriso_status_result(xorriso,filter,fp,flag&2);
 
 if(xorriso->status_history_max!=Xorriso_status_history_maX || !no_defaults) {
   sprintf(line,"-status_history_max %d\n",xorriso->status_history_max);
   Xorriso_status_result(xorriso,filter,fp,flag&2);
 }

#ifdef Xorriso_with_readlinE

 if((flag&8) && xorriso->status_history_max>0) {
   HIST_ENTRY **hl;
   int hc,i;

   hl= history_list();
   if(hl!=NULL) {
     for(hc= 0;hl[hc]!=NULL;hc++);
     if(hc>0)
       if(strcmp(hl[hc-1]->line,"-end")==0)
         hc--;
     if(hc>=xorriso->status_history_max)
       i= hc-xorriso->status_history_max;
     else
       i= 0;
     for(;i<hc;i++) {
       sprintf(line,"-history %s\n",Text_shellsafe(hl[i]->line,sfe,0));
       Xorriso_status_result(xorriso,filter,fp,flag&2);
     }   
   }
 }

#endif /* Xorriso_with_readlinE */

 if(strcmp(xorriso->indev,xorriso->outdev)==0) { 
   sprintf(line,"-dev %s\n", Text_shellsafe(xorriso->indev,sfe,0));
   Xorriso_status_result(xorriso,filter,fp,flag&2);
 } else {
   sprintf(line,"-indev %s\n", Text_shellsafe(xorriso->indev,sfe,0));
   Xorriso_status_result(xorriso,filter,fp,flag&2);
   sprintf(line,"-outdev %s\n", Text_shellsafe(xorriso->outdev,sfe,0));
   Xorriso_status_result(xorriso,filter,fp,flag&2);
 }

 return(1);
}


int Xorriso_exec(struct XorrisO *xorriso, char *cmd, int flag)
{
 char *spt,*cpt,**argv= NULL,errmsg[2*SfileadrL];
 int is_done= 0,argc= 0,widx= 0,cmd_l,pass,ret;

 cmd_l= strlen(cmd);
 if(cmd_l>SfileadrL) {
   sprintf(xorriso->info_text,
           "Command for external process too long : %d (max %d)",
           cmd_l, SfileadrL);
   Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
 }
 for(pass=0;pass<2;pass++) {
   is_done= 0;
   widx= 0;
   for(spt= cmd;!is_done;spt= cpt+1) {
     for(cpt= spt;*cpt!=0 && *cpt!=':' && *cpt!=' ';cpt++);
     if(*cpt==0)
       is_done= 1;
     if(pass==0) {
       argc++;
     } else {
       *cpt= 0;
       if(Sregex_string(&(argv[widx]),spt,0)<=0)
         {ret= -1; goto ex;}
       widx++;
     }
   }
   if(pass==0) {
     if(argc==0)
       {ret= 2; goto ex;}
     argv= TSOB_FELD(char *,argc+1);
     if(argv==NULL)
       {ret= -1; goto ex;}
     for(widx= 0;widx<argc+1;widx++)
       argv[widx]= NULL;
   }
 }
 ret= Exec_cmd(xorriso->progname,cmd,NULL,argv,errmsg,
               !!(xorriso->packet_output));
 if(ret<0)
   goto ex;
 if(ret>0) {
   for(widx=0; widx<cmd_l; widx++)
     if(cmd[widx]==0)
       cmd[widx]= ' ';
   sprintf(xorriso->info_text,"External process failed : %s",cmd);
   if(errmsg[0]!=0)
     sprintf(xorriso->info_text+strlen(xorriso->info_text),
             "message:  %s\n",errmsg);
   Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 1);
   {ret= 0; goto ex;}
 }
 ret= 1;
ex:
 if(argv!=NULL) {
   for(widx=0;widx<argc;widx++)
     Sregex_string(&(argv[widx]),NULL,0);
   free((char *) argv);
 }
 return(ret);
} 


int Xorriso__end_idx(int argc, char **argv, int idx, int flag)
{
 int i;

 for(i= idx; i<argc; i++)
   if(strcmp(argv[i], "--")==0)
 break;
 return(i);
}


int Xorriso_get_problem_status(struct XorrisO *xorriso, char severity[80],
                               int flag)
{
 strcpy(severity, xorriso->problem_status_text);
 return(xorriso->problem_status);
}


int Xorriso_set_problem_status(struct XorrisO *xorriso, char *severity, 
                               int flag)
{
 char *sev_text= "FATAL";
 int sev, ret;

 ret= Xorriso__text_to_sev(severity, &sev, 0);
 if(ret<=0)
   return(0);
 xorriso->problem_status= sev;
 strcpy(xorriso->problem_status_text, sev_text);
 return(1);
}


/* Note: It is ok to submit xorriso->info_text as msg_text here. */
/* flag: 
     bit0= for Xorriso_info() : use pager (as with result)
     bit1= for Xorriso_info() : permission to suppress output
     bit2..5= name prefix
       0="xorriso"
       1="libisofs"
       2="libburn"
       3="libisoburn"
       else: ""
*/
int Xorriso_msgs_submit(struct XorrisO *xorriso, 
                        int error_code, char msg_text[], int os_errno,
                        char severity[], int flag)
{
 int ret, lt, li, sev, i;
 char *sev_text= "FATAL", prefix[80];
 static char pfx_list[20][16]= {
                   "xorriso : ", "libisofs: ", "libburn : ", "libisoburn: ",
                    "", "", "", "", "", "", "", "", "", "", "", "" };

 /* Set problem status */
 ret= Xorriso__text_to_sev(severity, &sev, 0);
 if(ret<=0)
   Xorriso__text_to_sev(sev_text, &sev, 0);
 else
   sev_text= severity;
 if(xorriso->problem_status<sev) {
   xorriso->problem_status= sev;
   strcpy(xorriso->problem_status_text, sev_text);
 }

 /* Report problem event */
 if(sev<xorriso->report_about_severity && sev<xorriso->abort_on_severity)
   return(2);
 sprintf(prefix,"%s%s : ", pfx_list[(flag>>2)&15], sev_text);
 li= strlen(prefix);
 lt= strlen(msg_text);
 if(lt>sizeof(xorriso->info_text)-li-2)
   lt= sizeof(xorriso->info_text)-li-2;
 if(msg_text==xorriso->info_text) {
   for(i= lt; i>=0; i--)
     msg_text[i+li]= msg_text[i];
   for(i=0; i<li; i++)
     msg_text[i]= prefix[i];
 } else {
   strcpy(xorriso->info_text, prefix);
   strncpy(xorriso->info_text+li, msg_text, lt);
 }
 xorriso->info_text[li+lt]= '\n';
 xorriso->info_text[li+lt+1]= 0;
 Xorriso_info(xorriso,flag&3);
 if(os_errno>0) {
   sprintf(xorriso->info_text, "%ssys   : %s\n",
           pfx_list[(flag>>2)&15], strerror(os_errno));
   Xorriso_info(xorriso,flag&3);
 }
 return(1);   
}


int Xorriso_eval_problem_status(struct XorrisO *xorriso, int ret, int flag)
{
 static int sev= 0;

 if(sev==0)
   Xorriso__text_to_sev("SORRY", &sev, 0);

 Xorriso_process_msg_queues(xorriso, 0);
 if(ret>0 && xorriso->problem_status <= 0)
   return(1);

 if(xorriso->problem_status < xorriso->abort_on_severity &&
    xorriso->problem_status > 0) {
   if(xorriso->problem_status >= sev) {
     sprintf(xorriso->info_text,
             "xorriso : NOTE : Tolerated problem event of severity '%s'\n",
             xorriso->problem_status_text);
     Xorriso_info(xorriso, 0);/* submit not as problem event */
   }
   ret= 2;
 } else if(xorriso->problem_status > 0) {
   sprintf(xorriso->info_text,
           "xorriso : ABORT : -abort_on '%s' encountered '%s'",
           xorriso->abort_on_text, xorriso->problem_status_text);
   Xorriso_info(xorriso, 0);/* submit not as problem event */
   ret= -1;
 } else if(ret>0)
   ret= 1;
 return(ret);
}


/* ---------------------------- Options API ------------------------ */


/* Option -abort_on */
int Xorriso_option_abort_on(struct XorrisO *xorriso, char *severity, int flag)
{
 int ret, sev;

 ret= Xorriso__text_to_sev(severity, &sev, 0);
 if(ret<=0)
   return(ret);
 if(Sfile_str(xorriso->abort_on_text,severity,0)<=0)
   return(-1);
 xorriso->abort_on_severity= sev;
 return(1);
}


/* Option -add */
int Xorriso_option_add(struct XorrisO *xorriso, int argc, char **argv,
                       int *idx, int flag)
{
 int i, end_idx, ret;
 char target[SfileadrL], source[SfileadrL], *ept;

 end_idx= Xorriso__end_idx(argc, argv, *idx, 0);

 for(i= *idx; i<end_idx; i++) {
   if(Sfile_str(target,argv[i],0)<=0)
     {ret= -1; goto ex;}
   strcpy(source, argv[i]);
   if(xorriso->allow_graft_points) {
     ret= Fileliste__target_source_limit(target, '=', &ept, 0);
     if(ret>0) {
       *ept= 0;
       strcpy(source, ept+1);
     }
   }
   if(target[0]!='/') {
     ret= Sfile_prepend_path(xorriso->wdi, target, 0);
     if(ret<=0)
       goto ex;
   }
   if(source[0]!='/') {
     ret= Sfile_prepend_path(xorriso->wdx, source, 0);
     if(ret<=0)
       goto ex;
   }
   ret= Xorriso_graft_in(xorriso, source, target, 0);
   if(ret<=0)
     goto ex;
 } 
 ret= 1;
ex:;
 (*idx)= end_idx;
 return(ret);
}


/* Option -alter_date */
int Xorriso_option_alter_date(struct XorrisO *xorriso,
                               char *time_type, char *timestring,
                               int argc, char **argv, int *idx, int flag)
{
 int i, end_idx;

 end_idx= Xorriso__end_idx(argc, argv, *idx, 0);

 fprintf(stderr, ">>> XORRISO : decode timestring %s\n", timestring);
 fprintf(stderr, ">>> LIBISOFS : -alter_date %s %s  ",
                 time_type, timestring);
 for(i= *idx; i<end_idx; i++)
   fprintf(stderr, "%s ", argv[i]);
 fprintf(stderr, "\n");
 
 (*idx)= end_idx;
 return(1);
}


/* Option -ban_stdio_write */
int Xorriso_option_ban_stdio_write(struct XorrisO *xorriso, int flag)
{
 xorriso->ban_stdio_write= 1;
 return(1);
}


/* Option -blank */
int Xorriso_option_blank(struct XorrisO *xorriso, char *mode, int flag)
{
 fprintf(stderr, ">>> LIBISOBURN : would perform -blank %s  on %s",
         mode, xorriso->indev);
 return(1);
}


/* Option -cd alias -cdi */
int Xorriso_option_cdi(struct XorrisO *xorriso, char *iso_rr_path, int flag)
{
 char sfe[4*SfileadrL];
 int ret, l;

 if (strlen(iso_rr_path)>sizeof(xorriso->wdi)) {
   sprintf(xorriso->info_text,"-cdi: iso_rr_path too long (%d > %d)",
           strlen(iso_rr_path), sizeof(xorriso->wdi)-1);
   Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
   return(0);
 }
 sprintf(xorriso->info_text,"previous working directory:\n");
 Xorriso_info(xorriso,0);
 sprintf(xorriso->result_line,"%s/\n",Text_shellsafe(xorriso->wdi, sfe, 0));
 Xorriso_result(xorriso,0);
 if(strcmp(iso_rr_path,"/")==0) {
   strcpy(xorriso->wdi,"");
   Xorriso_option_pwdi(xorriso, 0);
   return(1);
 }

 ret= 1;
 /* >>> LIBISOFS: check whether directory exists in ISO image */;

 if(ret<=0) {
   sprintf(xorriso->info_text,
           "-cdi: not found or not a directory :\n%s",iso_rr_path);
   Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
   return(0);
 }
 if(Sfile_str(xorriso->wdi,iso_rr_path,0)<=0)
   return(-1);
 l= strlen(xorriso->wdi);
 while(l>0)
   if(xorriso->wdi[l-1]=='/')
     xorriso->wdi[--l]= 0;
   else
 break;
 Xorriso_option_pwdi(xorriso, 0);
 return(1);
}


/* Option -cdx */
int Xorriso_option_cdx(struct XorrisO *xorriso, char *disk_path, int flag)
{
 char sfe[4*SfileadrL];
 int ret, l;

 if (strlen(disk_path)>sizeof(xorriso->wdx)) {
   sprintf(xorriso->info_text,"-cdx: disk_path too long (%d > %d)",
           strlen(disk_path), sizeof(xorriso->wdx)-1);
   Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
   return(0);
 }
 sprintf(xorriso->info_text,"previous working directory on hard disk:\n");
 Xorriso_info(xorriso,0);
 sprintf(xorriso->result_line,"%s/\n",Text_shellsafe(xorriso->wdx, sfe, 0));
 Xorriso_result(xorriso,0);
 if(strcmp(disk_path,"/")==0) {
   strcpy(xorriso->wdx,"");
   Xorriso_option_pwdx(xorriso, 0);
   return(1);
 }

 ret= 1;
 ret= Sfile_type(disk_path,1|4|8);
 if(ret<0) {
   sprintf(xorriso->info_text,"-cdx: file not found :\n%s",disk_path);
   Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
   return(0);
 }
 if(ret!=2) {
   sprintf(xorriso->info_text,
           "-cdx: file is not a directory :\n%s",disk_path);
   Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
   return(0);
 }
 if(Sfile_str(xorriso->wdx,disk_path,0)<=0)
   return(-1);
 l= strlen(xorriso->wdx);
 while(l>0)
   if(xorriso->wdx[l-1]=='/')
     xorriso->wdx[--l]= 0;
   else
 break;
 Xorriso_option_pwdx(xorriso, 0);
 return(1);
}


/* Option -chgrp alias -chgrpi */
int Xorriso_option_chgrpi(struct XorrisO *xorriso, char *gid, char *path,
                          int argc, char **argv, int *idx, int flag)
{
 int i, end_idx;

 end_idx= Xorriso__end_idx(argc, argv, *idx, 0);

 fprintf(stderr, ">>> LIBISOFS : would perform -chgrpi %s %s  ", gid, path);
 for(i= *idx; i<end_idx; i++)
   fprintf(stderr, "%s ", argv[i]);
 fprintf(stderr, "\n");
 
 (*idx)= end_idx;
 return(1);
}


/* Option -chmod alias -chmodi */
int Xorriso_option_chmodi(struct XorrisO *xorriso, char *mode, char *path,
                          int argc, char **argv, int *idx, int flag)
{
 int i, end_idx;

 end_idx= Xorriso__end_idx(argc, argv, *idx, 0);

 fprintf(stderr, ">>> LIBISOFS : would perform -chmodi %s %s  ", mode, path);
 for(i= *idx; i<end_idx; i++)
   fprintf(stderr, "%s ", argv[i]);
 fprintf(stderr, "\n");
 
 (*idx)= end_idx;
 return(1);
}


/* Option -chown alias -chowni */
int Xorriso_option_chowni(struct XorrisO *xorriso, char *uid, char *path,
                          int argc, char **argv, int *idx, int flag)
{
 int i, end_idx;

 end_idx= Xorriso__end_idx(argc, argv, *idx, 0);

 fprintf(stderr, ">>> LIBISOFS : would perform -chowni %s %s  ", uid, path);
 for(i= *idx; i<end_idx; i++)
   fprintf(stderr, "%s ", argv[i]);
 fprintf(stderr, "\n");
 
 (*idx)= end_idx;
 return(1);
}


/* Option -close "on"|"off" */
int Xorriso_option_close(struct XorrisO *xorriso, char *mode, int flag)
{
 xorriso->do_close= !!strcmp(mode, "off");
 return(1);
}


/* Option -commit */
/* @param flag bit0= do not aquire outdrive as new indrive */
int Xorriso_option_commit(struct XorrisO *xorriso, int flag)
{
 int ret;
 char newdev[SfileadrL];

 if(!xorriso->volset_change_pending) {
   sprintf(xorriso->info_text,"-commit: No image modifications pending");
   Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "WARNING", 0);
   return(2);
 }

 /* >>> care for modifying */

 ret= Xorriso_write_growing(xorriso, 0);
 if(ret<=0)
   return(ret);
 xorriso->volset_change_pending= 0;

 if(flag&1)
   return(1);
 strcpy(newdev, xorriso->outdev);
 ret= Xorriso_option_dev(xorriso, newdev, 3);
 return(ret);
}


/* Option -cp_r alias -cp_ri */
int Xorriso_option_cp_ri(struct XorrisO *xorriso, int argc, char **argv,
                         int *idx, int flag)
{
 int i, end_idx;

 end_idx= Xorriso__end_idx(argc, argv, *idx, 0);

 fprintf(stderr, ">>> LIBISOFS : -cp_ri  X: ");
 for(i= *idx; i<end_idx-1; i++)
   fprintf(stderr, "%s ", argv[i]);
 fprintf(stderr, " -> I: %s", argv[end_idx-1]);
 fprintf(stderr, "\n");
 
 (*idx)= end_idx;
 return(1);
}


/* Option -cut_out */
int Xorriso_option_cut_out(struct XorrisO *xorriso, char *disk_path,
                off_t startbyte, off_t bytecount, char *iso_rr_path, int flag)
{

 fprintf(stderr, 
     ">>> LIBISOFS : would cut out from %s , byte %.f to %.f, and graft as %s",
     disk_path, (double) startbyte, (double) (startbyte+bytecount),
     iso_rr_path);

 return(1);
}


/* Options -dev , -indev, -outdev */
/** @param flag bit0=use as indev , bit1= use as outdev */
int Xorriso_option_dev(struct XorrisO *xorriso, char *adr, int flag)
{
 int ret;

 if(xorriso->ban_stdio_write && strncmp(adr, "stdio:", 6)==0) {
   sprintf(xorriso->info_text,
           "Drive address banned by -ban_stdio_write : '%s'",
           adr);
   Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
   return(0);
 }

 if((flag&3)==0)
   flag|= 3;
 if((flag&3)!=3) {
   /* <<< for now only -dev */;
   fprintf(stderr, ">>> XORRISO : would execute -%sdev %s\n",
           ((flag&3)==1 ? "in" : ((flag&3)==2 ? "out" : "")), adr);
   return(1);
 }

 if(xorriso->volset_change_pending && (flag&1)) {
   sprintf(xorriso->info_text,
           "%s: Image changes pending. -commit or -rollback first",
           (flag&2) ? "-dev" : "-indev");
   Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
   return(0);
 }

 if(adr[0]==0)
   ret= Xorriso_give_up_drive(xorriso, flag&3);
 else
   ret= Xorriso_aquire_drive(xorriso, adr, flag&3); 
 if(ret<0)
   return(ret);
 if(Sfile_str(xorriso->indev, adr, 0)<=0)
   return(-1);
 if(Sfile_str(xorriso->outdev, adr, 0)<=0)
   return(-1);
 return(1);
}


/* Option -devices */
int Xorriso_option_devices(struct XorrisO *xorriso, int flag)
{
 int ret;
 char sfe[4*SfileadrL];

 if(xorriso->volset_change_pending) {
   sprintf(xorriso->info_text,
           "-devices: Image changes pending. -commit or -rollback first");
   Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
   return(0);
 }
 xorriso->info_text[0]= 0;
 if(xorriso->in_drive_handle!=NULL || xorriso->out_drive_handle!=NULL) {
   if(xorriso->in_drive_handle == xorriso->out_drive_handle) {
     sprintf(xorriso->info_text, "Gave up -dev %s", 
             Text_shellsafe(xorriso->indev, sfe, 0));
     Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
   }else {
     if(xorriso->in_drive_handle) {
       sprintf(xorriso->info_text, "Gave up -indev %s", 
               Text_shellsafe(xorriso->indev, sfe, 0));
       Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
     }
     if(xorriso->out_drive_handle) {
       sprintf(xorriso->info_text, "Gave up -outdev %s", 
               Text_shellsafe(xorriso->outdev, sfe, 0));
       Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
     }
   }
   Xorriso_give_up_drive(xorriso, 3);
 }
 ret= Xorriso_show_devices(xorriso, 0);
 return(ret);
}


/* Option -dialog "on"|"off" */
int Xorriso_option_dialog(struct XorrisO *xorriso, char *mode, int flag)
{
 xorriso->dialog= !!strcmp(mode, "off");
 return(1);
}


/* Option -dummy "on"|"off" */
int Xorriso_option_dummy(struct XorrisO *xorriso, char *mode, int flag)
{
 xorriso->do_dummy= !!strcmp(mode, "off");
 return(1);
}


/* Option -eject */
int Xorriso_option_eject(struct XorrisO *xorriso, char *which, int flag)
{
 /* <<< should become handles */
 char *drive1="", *drive2="";

 if(strncmp(which,"in",2)==0)
   drive1= xorriso->indev;
 else if(strncmp(which,"out",3)==0)
   drive1= xorriso->outdev;
 else {
   drive1= xorriso->indev;
   drive2= xorriso->outdev;
 }
 if(drive1== xorriso->indev && xorriso->volset_change_pending) {
   sprintf(xorriso->info_text,
           "-eject: Image changes pending. -commit or -rollback first");
   Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
   return(0);
 }

 fprintf(stderr, ">>> LIBBURN : eject media in drive%s %s %s\n",
        (drive2[0]!=0 ? "s" : ""), drive1, drive2);

 return(1);
}


/* Option -end */
int Xorriso_option_end(struct XorrisO *xorriso, int flag)
{
 int ret;

 if(xorriso->volset_change_pending) {
   ret= Xorriso_option_commit(xorriso, 1);
   if(ret<=0)
     return(ret);
 }
 ret= Xorriso_give_up_drive(xorriso, 3);
 if(ret<=0)
   return(ret);
 return(1);
}


/* Option -f */
int Xorriso_option_f(struct XorrisO *xorriso, int flag)
{
 xorriso->do_follow_links= 1;
 return(1);
}


/* Option -find alias -findi */
int Xorriso_option_findi(struct XorrisO *xorriso, char *pattern, int flag)
{
 char sfe[4*SfileadrL];

 fprintf(stderr, ">>> XORRISO : filter by pattern %s\n", pattern);
 /* >>> prepare regex */

 fprintf(stderr, ">>> LIBISOFS : traverse ISO tree beginning at %s\n",
         Text_shellsafe(xorriso->wdi, sfe, 0));

 return(1);
}


/* Option -findx */
int Xorriso_option_findx(struct XorrisO *xorriso, char *pattern, int flag)
{
 char sfe[4*SfileadrL];

 fprintf(stderr, ">>> XORRISO : filter by pattern %s\n", pattern);
 /* >>> prepare regex */

 fprintf(stderr, ">>> XORRISO : traverse disk tree beginning at %s\n",
         Text_shellsafe(xorriso->wdx, sfe, 0));

 return(1);
}


/* Option -fs */
int Xorriso_option_fs(struct XorrisO *xorriso, char *size, int flag)
{
 double num;

 num= Scanf_io_size(size, 0);
 if(num < 4096 || num > 1024.0 * 1024.0 * 1024.0) {
   sprintf(xorriso->info_text, "-fs: wrong size %.f (allowed: %.f - %.f)",
           num, 4096.0, 1024.0 * 1024.0 * 1024.0);
   Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
   return(0);
 }
 xorriso->fs= num / 2048.0;
 return(1);
}


/* Option -gid */
int Xorriso_option_gid(struct XorrisO *xorriso, char *gid, int flag)
{
 double num;
 char text[80];
 struct group *grp;

 if(gid[0]==0 || strcmp(gid,"-")==0)
   xorriso->do_global_gid= 0;

 sscanf(gid, "%lf", &num);
 sprintf(text,"%.f",num);
 if(strcmp(text,gid)==0) {
   xorriso->global_gid= num;
   xorriso->do_global_gid= 1;
   return(1);
 }
 grp= getgrnam(gid);
 if(grp==NULL) {
   sprintf(xorriso->info_text, "-gid: Not a known group: '%s'", gid);
   Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
   return(0);
 }
 xorriso->global_gid= grp->gr_gid;
 xorriso->do_global_gid= 1;
 return(1);
}


/* Option -graft-points */
int Xorriso_option_graft_points(struct XorrisO *xorriso, int flag)
{
 xorriso->allow_graft_points= 1;
 return(1);
}


/* Option -help and part of -prog_help */
int Xorriso_option_help(struct XorrisO *xorriso, int flag)
{
 static char text[][80]={

#ifdef Xorriso_no_helP

"This binary program does not contain a help text.",
"If available, read: man 1 xorriso",

#else

"This program creates, loads, manipulates and writes ISO 9660 filesystem",
"images with Rock Ridge extensions. Write targets can be drives with optical",
"media or local filesystem objects.",
"",
"Preparation options:",
"Drive addresses are either /dev/... as listed with option -devices or",
"disk files with prefix \"stdio:\", e.g. stdio:/tmp/pseudo_drive .",
"  -dev address   Set input and output drive and load eventual ISO image.",
"                 Set the image expansion method to growing.",
"  -indev address  Set input drive and load eventual ISO image. Switch from",
"                 growing to modifying.",
"  -outdev address",
"                 Set output drive and switch from growing to modifying.",
"  -ban_stdio_write",
"                 Allow for writing only the usage of optical drives.",
"  -blank \"fast\"|\"all\"|\"format\"",
"                 Blank media resp. invalidate ISO image on media.",
"  -V volume_id   Specifies the volume ID text.",
"",
"  -J             Generate Joliet info additional to Rock Ridge info.",
"",
"  -uid uid       User id to be used for all iso_rr_paths.",
"  -gid gid       Group id for the same purpose.",
"",
"  -devices       Show list of available optical drives and their addresses.",
"",
"  -toc           Show media specific table of content. (MMC, not ISO 9660)",
"",
"  -print-size    Print the foreseeable consumption by next -commit.",
"",
"  -tell_media_space",
"                 Print foreseeable available space on output media",
"",
"Manipulation options:",
"disk_path is a path to an object in the local filesystem tree.",
"iso_rr_path is the Rock Ridge name of a file object in the ISO image.",
"pathspec is either a disk_path or (if allowed) a pair: iso_rr_path=disk_path",
"Options with variable length path list [...] need \"--\" as end mark",
"if they are followed by another option. In dialog and with options read from",
"files, the line end serves as such a mark. With program arguments this mark",
"can be omitted only with the last option in the list of arguments.",
"",
"  -add pathspec [...] Insert the given files or directory trees from",
"                 filesystem into the ISO image. Much like mkisofs.",
"  -path-list disk_path",
"                 Like -add but read the pathspecs from file disk_path.",
"  -graft-points  Allow pathspecs of form  iso_rr_path=disk_path",
"",
"  -cp_r disk_path [...] iso_rr_path",
"                 Insert the given files or directory trees from filesystem",
"                 into the ISO image.",
"  -rm iso_rr_path [...]",
"                 Delete the given files from the ISO image.",
"  -rm_r iso_rr_path [...]",
"                 Delete the given directory trees from ISO image.",
"  -mv iso_rr_path [...] iso_rr_path",
"                 Rename the given file objects in the ISO tree to the last",
"                 argument in the list.",
"  -chown uid iso_rr_path [...]",
"                 Equivalent to chown in the ISO image.",
"  -chgrp gid iso_rr_path [...]",
"                 Equivalent to chgrp in the ISO image.",
"  -chmod mode iso_rr_path [...]",
"                 Equivalent to chmod in the ISO image.",
"  -alter_date type timestring iso_rr_path [...]",
"                 Alter the date entries of a file in the ISO image. type is",
"                 one of \"a\", \"m\", \"b\" for:",
"                 access time, modification time, both times.",
"  -mkdir iso_rr_path [...]",
"                 Create empty directories if they do not exist yet",
"  -rmdir iso_rr_path [...]",
"                 Delete empty directories.",
"  --             Mark end of particular action argument list.",
"",
"  -f             Follow symbolic links within disk_path.",
"",
"  -overwrite \"on\"|\"off\"",
"                 Allow or disallow to overwrite existing files in ISO image.",
"  -reassure \"on\"|\"off\"",
"                 If \"on\" then ask the user for \"y\" or \"n\" with any",
"                 file before deleting or overwriting it in the ISO image.",
"",
"Write-to-media options:",
"",
"  -rollback      Discard the manipulated ISO image and reload it.",
"",
"  -commit        Perform the write operation and then perform -dev outdrive.",
"                 Hint: To perform a final write operation with no new -dev",
"                       and no new loading of image, execute option -end.",
"  -close \"on\"|\"off\"",
"                 If \"on\" then mark the written media as not appendable.",
"  -dummy \"on\"|\"off\"",
"                 If \"on\" simulate burning. Refuse if media cannot simulate.",
"  -speed number[\"k\"|\"m\"|\"[x]CD\"|\"[x]DVD\"]",
"                 Set the burn speed. Default is 0 = maximum speed.",
"  -fs number[\"k\"|\"m\"]",
"                 Set the size of the fifo buffer. (Default is 4m)",
"  -eject \"in\"|\"out\"|\"all\"",
"                 Immediately eject the media in -indev, resp. -outdev,",
"                 resp. both.",
"",
"Navigation options:",
"",
"  -cd iso_rr_path  Change working directory in the ISO image. iso_rr_paths",
"                 which do not begin with '/' will be inserted beginning at",
"                 the path given with -cd. -ls patterns will eventually",
"                 looked up at this path.",
"  -cdi disk_path   Same as -cd disk_path",
"  -cdx disk_path  Change the current working directory in the local",
"                 filesystem. disk_paths which do not begin with '/'",
"                 will be looked up beginning at the path given with -cdx.",
"                 -lsx patterns will eventually be looked up at this path.",
"  -pwd           tells the current working directory in the ISO image.",
"  -pwdi          same as -pwd.",
"  -pwdx          tells the current working directory in the local filesystem.",
"",
"  -ls pattern    lists files of the ISO image which match the given",
"                 shell parser pattern. (I.e. wildcards '*' '?')",
"  -lsi pattern   same as -ls.",
"  -lsx pattern   lists files of the local filesystem which match the given",
"                 shell parser pattern. (I.e. wildcards '*' '?')",
"",
"  -ls_l pattern  like -ls but also telling some file attributes.",
"  -ls_li pattern  same as -ls_l.",
"  -ls_lx pattern  like -lsx but also telling some file attributes.",
"",
"  -find  pattern  lists matching files below current working directory in",
"                 the ISO image.",
"  -findi pattern  same as -find.",
"  -findx pattern  lists matching files below current working directory in",
"                 the local filesystem.",
"",
"General options:",
"  -help       Print this text",
"  -abort_on severity   Set the threshhold for events to abort the program.",
"              Useful severities are: NEVER, ABORT, FATAL, SORRY, WARNING",
"  -report_about severity   Set the threshhold for events to be reported.",
"              Use -abort_on severities or: HINT, NOTE, UPDATE, DEBUG, ALL",
"  -dialog     after all arguments are processed, enter dialog mode.",
"              In this mode you may enter searchtexts or any of the options",
"              described here. One per line.",
"  -dialog_reset  Revoke -dialog (works only if given as argument)",
"  -page len width  Prompt user after len output lines (0=no prompt).",
"              width (default 80) can adjust line number computation",
"              to the output terminal's line width.",
#ifdef Xorriso_with_readlinE
"  -use_stdin  Use raw standard input even if libreadline is available",
"  -use_readline  Use libreadline for dialog if available",
"  -history text  Copy text into libreadline history. This command",
"              itself is not copied to the history list.",
#endif /* Xorriso_with_readlinE */
"  -pkt_output \"on\"|\"off\"  Direct output to stdout and prefix each line",
"              by a short header which tells channel id and a mode number.",
"              Each such output packet is finalized by a newline.",
"              Channel ids are 'R:' for result lines, 'I:' for notes",
"              and error messages, 'M:' for -mark texts. Bit 0 of the",
"              mode number tells whether the newline is also part of the",
"              packet payload. Example of a info message with newline:",
"                I:1: enter option text :",
"              -pkt_output:on is intended for use by frontend programs.",
"  -logfile channel fileaddress  Copy output of a channel to the given file.",
"              channel may be 'R','I','M' as with -pkt_output or '.'",
"              for the consolidated -pkt_output stream.",
"  -mark text  If text is not empty it will get put out each time an",
"              option is completed.",
"  -prog text  Use text as this program's name in subsequent messages",
"  -prog_help text  Use text as this program's name and perform -help",
"  -status mode|filter  Report the current settings of persistent options.",
"              Modes:",
"                 short... print only important or altered options",
"                 long ... print options even if they have default settings",
"                 long_history  like long plus -history: lines",
"              Filters begin with '-' and are compared literally against the",
"              output lines of -status long_history. A line is put out only",
"              if its start matches the filter.",
"  -status_history_max number  Maximum number of history lines to be reported",
"              with -status:long_history",
"  -options_from_file fileaddress",
"              Reads lines from the given file and executes them as program",
"              options.",
"  -no_rc      Only if used as first command line argument this option",
"              prevents reading and interpretation of startup files.",
"  -print text",
"              Print a text to result channel.",
"  -prompt text",
"              Wait for Enter key resp. for a line of input at stdin.",
"  # any text  Is ignored. In dialog mode the input line will be stored in",
"              the eventual readline history, nevertheless.", 
"  -version    Tell program and version number",
"  -end        End program immediately",
"",
"",
"Option -page causes a user prompt after the given number of result lines.",
"Empty input resumes output until the next prompt. Other input may be:",
"  @     suppresses paging until the current action is done",
"  @@    suppresses further result output but continues the action",
"  @@@   aborts the current action",
"  other aborts the current action and executes input as new",
"        option",
"",

#endif /* ! Xorriso_no_helP */

"@ENDE_OF_HELPTEXT_(HOPEFULLY_UNIQUELY_SILLY_TEXT)@"
 };

 char *tpt= NULL;
 int i,pass;

 Xorriso_restxt(xorriso,"\n"); 
 sprintf(xorriso->result_line,"usage: %s [settings|actions]\n",
         xorriso->progname); 
 Xorriso_result(xorriso,0);
 Xorriso_restxt(xorriso,"\n"); 
 for(pass=0;pass<1;pass++) {
   for(i=0;1;i++) {
     if(pass==0)
       tpt= text[i];
     
     if(strcmp(tpt,"@ENDE_OF_HELPTEXT_(HOPEFULLY_UNIQUELY_SILLY_TEXT)@")==0)
   break;
     sprintf(xorriso->result_line,"%s\n",tpt);
     Xorriso_result(xorriso,0);
     if(xorriso->request_to_abort)
       return(1);
   }
 }
 Xorriso_restxt(xorriso,"\n"); 
 return(1);
}


/* Option -history */
int Xorriso_option_history(struct XorrisO *xorriso, char *line, int flag)
{
 Xorriso_dialog_input(xorriso,line,strlen(line)+1,2);
 return(1);
}


/* Option -J */
int Xorriso_option_j_capital(struct XorrisO *xorriso, int flag)
{
 xorriso->do_joliet= 1;
 return(1);
}


/* Options -ls alias -lsi and ls_l alias ls_li */
/* @param flag bit0= long format (-ls_l) */
int Xorriso_option_lsi(struct XorrisO *xorriso, char *pattern, int flag)
{
 char sfe[4*SfileadrL];

 fprintf(stderr, ">>> XORRISO : filter by pattern %s\n", pattern);
 /* >>> prepare regex */

 fprintf(stderr, ">>> LIBISOFS : -ls of ISO directory %s\n",
         Text_shellsafe(xorriso->wdi, sfe, 0));

 return(1);
}


/* Options -lsx and -ls_lx */
/* @param flag bit0= long format (-ls_l) */
int Xorriso_option_lsx(struct XorrisO *xorriso, char *pattern, int flag)
{
 char sfe[4*SfileadrL];

 fprintf(stderr, ">>> XORRISO : filter by pattern %s\n", pattern);
 /* >>> prepare regex */

 fprintf(stderr, ">>> XORRISO : -ls of disk directory %s\n",
         Text_shellsafe(xorriso->wdx, sfe, 0));

 return(1);
}


/* Option -logfile */
int Xorriso_option_logfile(struct XorrisO *xorriso, char *channel,
                                                      char *fileadr, int flag)
{
 int hflag,channel_no= 0, ret;
   
 if(channel[0]==0) {
logfile_wrong_form:;
   sprintf(xorriso->info_text,"Wrong form. Correct would be: -logfile \".\"|\"R\"|\"I\"|\"M\" file_address");
   Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
   return(0);
 }
 hflag= 2;
 if(channel[0]=='R')
   channel_no= 1;
 else if(channel[0]=='I')
   channel_no= 2;
 else if(channel[0]=='M')
   channel_no= 3;
 else if(channel[0]=='.')
   hflag= 4;
 else
   goto logfile_wrong_form;
 if(strcmp(fileadr,"-")==0 || fileadr[0]==0)
     hflag|= (1<<15);
 xorriso->logfile[channel_no][0]= 0;
 ret= Write_to_channel(fileadr,channel_no,hflag);
 if(ret<=0) {
   sprintf(xorriso->info_text, "Cannot open logfile:  %s", fileadr);
   Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
 } else if(!(hflag&(1<<15)))
   if(Sfile_str(xorriso->logfile[channel_no], fileadr, 0)<=0)
     return(-1);
 return(ret>0);
}


/* Option -mark */
int Xorriso_option_mark(struct XorrisO *xorriso, char *mark, int flag)
{
 if(mark[0]==0)
   xorriso->mark_text[0]= 0;
 else
   strncpy(xorriso->mark_text,mark,sizeof(xorriso->mark_text)-1);
 xorriso->mark_text[sizeof(xorriso->mark_text)-1]= 0;
 return(1);
}


/* Option -mkdir alias -mkdiri */
int Xorriso_option_mkdiri(struct XorrisO *xorriso, int argc, char **argv,
                          int *idx, int flag)
{
 int i, end_idx;

 end_idx= Xorriso__end_idx(argc, argv, *idx, 0);

 fprintf(stderr, ">>> LIBISOFS : -mkdiri  ");
 for(i= *idx; i<end_idx; i++)
   fprintf(stderr, "%s ", argv[i]);
 fprintf(stderr, "\n");
 
 (*idx)= end_idx;
 return(1);
}


/* Option -mv alias -mvi */
int Xorriso_option_mvi(struct XorrisO *xorriso, int argc, char **argv,
                      int *idx, int flag)
{
 int i, end_idx;

 end_idx= Xorriso__end_idx(argc, argv, *idx, 0);

 fprintf(stderr, ">>> LIBISOFS : -mvi  I: ");
 for(i= *idx; i<end_idx-1; i++)
   fprintf(stderr, "%s ", argv[i]);
 fprintf(stderr, " -> I: %s", argv[end_idx-1]);
 fprintf(stderr, "\n");

 (*idx)= end_idx;
 return(1);
}


/* Option -no_rc */
int Xorriso_option_no_rc(struct XorrisO *xorriso, int flag)
{
 xorriso->no_rc= 1;
 return(1);
}


/* Option -options_from_file*/
int Xorriso_option_options_from_file(struct XorrisO *xorriso, char *adr,
                                     int flag)
/*
 bit0= called from Xorriso_prescan_args,
       therefore execute via that same function
*/
/*
return:
 <=0 error , 1 = success , 3 = end program run
*/
{
 int ret,linecount= 0, argc;
 FILE *fp= NULL;
 char line[4*SfileadrL], shellsafe[5*SfileadrL];
 char **argv= NULL;

 if(adr[0]==0) {
   sprintf(xorriso->info_text,"Empty file name given with -options_from_file");
   Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
   return(0);
 }
 Text_shellsafe(adr,shellsafe,0);
 if(xorriso->is_dialog) {
   sprintf(xorriso->info_text,"+ performing command lines from file %s :\n",
           shellsafe);
   Xorriso_info(xorriso,1);
 }
 fp= Afile_fopen(adr,"rb",((!!xorriso->packet_output)<<6));
 if(fp==NULL)
   return(0);
 while(1) {
   if(Sfile_fgets(line,sizeof(line),fp)==NULL) {
     ret= 1;
     if(ferror(fp))
       ret= 0;
 break;
   }
   linecount++;
   if(line[0]==0 || line[0]=='#')
 continue;

   if(flag&1) {
     ret= Sfile_make_argv(xorriso->progname, line, &argc, &argv, 4|8);
     if(ret<=0)
       goto ex;
     ret= Xorriso_prescan_args(xorriso,argc,argv,1);
     Sfile_make_argv("", "", &argc, &argv, 2); /* release memory */
     if(ret==0)
       {ret= 3; goto ex;}
     if(ret<0)
       goto ex;
   } else {
     if(xorriso->is_dialog) {
       sprintf(xorriso->info_text,"+ %d:  %s\n",linecount,line);
       Xorriso_info(xorriso,1);
     }
     ret= Xorriso_execute_option(xorriso,line,1|(1<<16));
     if(ret<=0 || ret==3)
       goto ex;
   }
 }
ex:;
 Xorriso_reset_counters(xorriso,1);
 if(fp!=NULL)
   fclose(fp);
 if(ret<=0) {
   sprintf(xorriso->info_text,
           "error triggered by line %d of file:\n    %s\n",
           linecount,shellsafe);
   Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 1);
 }
 return(ret);
}


/* Option -overwrite "on"|"off" */
int Xorriso_option_overwrite(struct XorrisO *xorriso, char *mode, int flag)
{
 xorriso->do_overwrite= !!strcmp(mode, "off");
 return(1);
}


/* Option -page */
int Xorriso_option_page(struct XorrisO *xorriso, int len, int width, int flag)
{
 if(len<0 || width<=0) {
   sprintf(xorriso->info_text,
             "Improper numeric value of arguments of -page:  %d  %d",
             len, width);
   Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
   return(0);
 }
 xorriso->result_page_length= len;
 xorriso->result_page_width= width;
 return(1);
}


/* Option -path-list */
int Xorriso_option_path_list(struct XorrisO *xorriso, char *adr, int flag)
{

 fprintf(stderr, ">>> XORRISO : read pathspecs from %s\n", adr);
 fprintf(stderr, ">>> LIBISOFS : insert pathspecs into ISO tree\n");

 return(1);
}


/* Option -pkt_output */
int Xorriso_option_pkt_output(struct XorrisO *xorriso, char *mode, int flag)
{
 if(strcmp(mode,"off")==0)
   xorriso->packet_output= 0;
 else
   xorriso->packet_output= 1;
 return(1);
}


/* Option -print */
int Xorriso_option_print(struct XorrisO *xorriso, char *text, int flag)
{
 sprintf(xorriso->result_line,"%s\n",text);
 Xorriso_result(xorriso,1);
 return(1);
}


/* Option -print-size */
int Xorriso_option_print_size(struct XorrisO *xorriso, int flag)
{
 int ret;

 if(!xorriso->volset_change_pending) {
   sprintf(xorriso->info_text,"-print-size: No image modifications pending");
   Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "WARNING", 0);
   sprintf(xorriso->result_line,"Image size   : 0\n");
   Xorriso_result(xorriso,0);
   return(2);
 }

 /* >>> care for modifying */

 ret= Xorriso_write_growing(xorriso, 1);
 if(ret<=0) {
   sprintf(xorriso->info_text,"-print-size: Failed to set up virtual -commit");
   Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
   return(0);
 }
 sprintf(xorriso->result_line,"Image size   : %d\n", ret);
 Xorriso_result(xorriso,0);
 return(1);
}


/* Option -prog */
int Xorriso_option_prog(struct XorrisO *xorriso, char *name, int flag)
{
 if(strlen(name)>=sizeof(xorriso->progname)) {
   sprintf(xorriso->info_text,
           "Name too long with option -prog (%d > %d)",
           strlen(name), sizeof(xorriso->progname)-1);
   Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
   return(0);
 }
 if(Sfile_str(xorriso->progname,name,0)<=0)
   return(-1);
 return(1);
}


/* Option -prog_help */
int Xorriso_option_prog_help(struct XorrisO *xorriso, char *name, int flag)
{
 int ret;

 ret= Xorriso_option_prog(xorriso, name, 0);
 if(ret<=0)
   return(ret);
 ret= Xorriso_option_help(xorriso, 0);
 return(ret);
}


/* Option -prompt */
int Xorriso_option_prompt(struct XorrisO *xorriso, char *text, int flag)
{
 int ret;
 char line[80];

 strncpy(xorriso->result_line,text,sizeof(xorriso->result_line)-1);
 xorriso->result_line[sizeof(xorriso->result_line)-1]= 0;
 Xorriso_result(xorriso,0);
 ret= Xorriso_dialog_input(xorriso, line, sizeof(line),1);
 return(ret);
}


/* Option -pwd alias -pwdi */
int Xorriso_option_pwdi(struct XorrisO *xorriso, int flag)
{
 sprintf(xorriso->info_text,"current working directory:\n");
 Xorriso_info(xorriso,0);
 sprintf(xorriso->result_line,"%s/\n",xorriso->wdi);
 Xorriso_result(xorriso,0);
 return(1);
}


/* Option -pwdx */
int Xorriso_option_pwdx(struct XorrisO *xorriso, int flag)
{
 sprintf(xorriso->info_text,"current working directory on hard disk:\n");
 Xorriso_info(xorriso,0);
 sprintf(xorriso->result_line,"%s/\n",xorriso->wdx);
 Xorriso_result(xorriso,0);
 return(1);
}


/* Option -reassure "on"|"off" */
int Xorriso_option_reassure(struct XorrisO *xorriso, char *mode, int flag)
{
 xorriso->do_reassure= !!strcmp(mode, "off");
 return(1);
}


/* Option -report_about */
int Xorriso_option_report_about(struct XorrisO *xorriso, char *severity,
                                int flag)
{
 int ret, sev;

 ret= Xorriso__text_to_sev(severity, &sev, 0);
 if(ret<=0)
   return(ret);
 if(Sfile_str(xorriso->report_about_text,severity,0)<=0)
   return(-1);
 xorriso->report_about_severity= sev;
 return(1);
}


/* Options -rm alias -rmi , and -rm_r aias -rm_ri */
/* @param flag bit0=recursive */
int Xorriso_option_rmi(struct XorrisO *xorriso, int argc, char **argv,
                       int *idx, int flag)
{
 int i, end_idx;

 end_idx= Xorriso__end_idx(argc, argv, *idx, 0);

 fprintf(stderr, ">>> LIBISOFS : -rm%si  ", ((flag&1) ? "_r" : ""));
 for(i= *idx; i<end_idx; i++)
   fprintf(stderr, "%s ", argv[i]);
 fprintf(stderr, "\n");
 
 (*idx)= end_idx;
 return(1);
}


/* Option -rmdir alias -rmdiri */
int Xorriso_option_rmdiri(struct XorrisO *xorriso, int argc, char **argv,
                          int *idx, int flag)
{
 int i, end_idx;

 end_idx= Xorriso__end_idx(argc, argv, *idx, 0);

 fprintf(stderr, ">>> LIBISOFS : -rmdiri  ");
 for(i= *idx; i<end_idx; i++)
   fprintf(stderr, "%s ", argv[i]);
 fprintf(stderr, "\n");
 
 (*idx)= end_idx;
 return(1);
}


/* Option -rollback */
int Xorriso_option_rollback(struct XorrisO *xorriso, int flag)
{
 int ret;
 char indev[SfileadrL];

 if(Sfile_str(indev, xorriso->indev, 0)<=0)
   return(-1);
 ret= Xorriso_give_up_drive(xorriso, 1);
 if(ret<=0)
   return(ret);
 ret= Xorriso_option_dev(xorriso, indev,
                         1|((xorriso->out_drive_handle==NULL)<<1));
 return(ret);
}


/* Option -speed */
int Xorriso_option_speed(struct XorrisO *xorriso, char *speed, int flag)
{
 int is_cd= 1, unit_found= 0;
 double num;
 char *cpt;

 if(speed[0]==0) {
   xorriso->speed= 0; /* full speed */
   return(1);
 }

 sscanf(speed,"%lf",&num);
 for(cpt= speed+strlen(speed)-1; cpt>=speed; cpt--)
   if(isdigit(*cpt) || *cpt=='.')
 break;
 cpt++;

 if(*cpt=='k' || *cpt=='K') {
   /* is merchand kilobyte, stays merchand kilobyte */
   unit_found= 1;
 } else if(*cpt=='m' || *cpt=='M') {
   num*= 1000;
   unit_found= 1;
 } else if(*cpt=='x' || *cpt=='X')
   cpt++;

 if(*cpt=='c' || *cpt=='C') {
cd_speed:;
   num*= 176.4;
 } else if(*cpt=='d' || *cpt=='D') {
dvd_speed:;
   num*= 1385;
 } else if (!unit_found) {

   /* >>> try to determine target media */;

   if(is_cd)
     goto cd_speed;
   else
     goto dvd_speed;
 }

 if(num> 2.0e9) {
   sprintf(xorriso->info_text,
           "-speed: Value too large or not recognizable: '%s'", speed);
   Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
   return(0);
 }
 xorriso->speed= num;
 if(xorriso->speed<num)
   xorriso->speed++;
 return(1);
}


/* Option -status */
int Xorriso_option_status(struct XorrisO *xorriso, char *mode, int flag)
{
 if(strcmp(mode,"short")==0)
   Xorriso_status(xorriso,NULL,NULL,1);
 else if(strcmp(mode,"long")==0)
   Xorriso_status(xorriso,NULL,NULL,0);
 else if(strcmp(mode,"long_history")==0)
   Xorriso_status(xorriso,NULL,NULL,8);
 else if(mode[0]=='-')
   Xorriso_status(xorriso,mode,NULL,8);
 else
   Xorriso_status(xorriso,NULL,NULL,1);
 return(1);
}


/* Option -status_history_max */
int Xorriso_option_status_history_max(struct XorrisO *xorriso, int num,
                                      int flag)
{
 if(num>=0 && num<1000000)
   xorriso->status_history_max= num;
 return(1);
}


/* Option -tell_media_space */
int Xorriso_option_tell_media_space(struct XorrisO *xorriso, int flag)
{
 int ret;

 ret= Xorriso_tell_media_space(xorriso, 0);
 if(ret<0) {
   sprintf(xorriso->info_text, "Cannot -tell_media_space");
   Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
   return(0);
 }
 sprintf(xorriso->result_line, "%d\n", ret);
 Xorriso_result(xorriso, 0);
 return(1);
}


/* Option -toc */
int Xorriso_option_toc(struct XorrisO *xorriso, int flag)
{
 int ret;

 ret= Xorriso_toc(xorriso, 0);
 return(ret);
}


/* Option -uid */
int Xorriso_option_uid(struct XorrisO *xorriso, char *uid, int flag)
{
 double num;
 char text[80];
 struct passwd *pwd;

 if(uid[0]==0 || strcmp(uid,"-")==0)
   xorriso->do_global_uid= 0;

 sscanf(uid, "%lf", &num);
 sprintf(text,"%.f",num);
 if(strcmp(text,uid)==0) {
   xorriso->global_uid= num;
   xorriso->do_global_uid= 1;
   return(1);
 }

 pwd= getpwnam(uid);
 if(pwd==NULL) {
   sprintf(xorriso->info_text, "-gid: Not a known user: '%s'", uid);
   Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
   return(0);
 }
 xorriso->global_uid= pwd->pw_uid;
 xorriso->do_global_uid= 1;
 return(1);
}


/* Option -use_readline */
int Xorriso_option_use_readline(struct XorrisO *xorriso, char *mode, int flag)
{
 if(strcmp(mode,"off")==0)
   xorriso->use_stdin= 1;
 else
   xorriso->use_stdin= 0;
 return(1);
}


/* Option -uid */
int Xorriso_option_v_capital(struct XorrisO *xorriso, char *volid, int flag)
{
 fprintf(stderr, ">>> LIBISOFS : -V %s\n", volid);
 return(1);
}


/* Option -version */
int Xorriso_option_version(struct XorrisO *xorriso, int flag)
{

 /* >>> print rather to result channel */;

 printf("xorriso %s : RockRidge filesystem manipulator\n", PROG_VERSION);
 printf("Copyright (C) 2007, Thomas Schmitt <scdbackup@gmx.net>, libburnia project\n");
 printf("Version timestamp :  %s\n",Xorriso_timestamP);
 printf("Build timestamp   :  %s\n",Xorriso_build_timestamP);

 return(1);
}


/* ---------------------------- End Options API ------------------------ */


int Xorriso_interpreter(struct XorrisO *xorriso,
                        int argc, char **argv, int *idx, int flag)
/*
return:
 <=0 error , 1 = success , 2 = problem event ignored , 3 = end program run
*/
/*
 bit0= recursion
*/
{
 int ret;
 int num1, num2;
 double d1, d2;
 char *cmd, *arg1, *arg2, *arg4;
 
 if(xorriso==NULL)
   return(0);
 if(xorriso->is_dialog) {
   xorriso->result_line_counter= xorriso->result_page_counter= 0;
   if(xorriso->result_page_length<0)
     xorriso->result_page_length= -xorriso->result_page_length;
 }

next_command:;
 xorriso->prepended_wd= 0;
 xorriso->request_to_abort= 0;
 Xorriso_set_problem_status(xorriso, "", 0);
 if((*idx)<argc)
   cmd= argv[*idx];
 else
   cmd= "";
 (*idx)++;

 if((*idx)<argc)
   arg1= argv[(*idx)];
 else
   arg1= "";
 if((*idx)+1<argc)
   arg2= argv[(*idx)+1];
 else
   arg2= "";

 ret= 1;
 if(cmd[0]=='#' || cmd[0]==0) {
   /* ignore comment line and empty option */; 

 } else if(strcmp(cmd,"-abort_on")==0) {
   (*idx)++;
   ret= Xorriso_option_abort_on(xorriso, arg1, 0);

 } else if(strcmp(cmd,"-add")==0) {
   ret= Xorriso_option_add(xorriso, argc, argv, idx, 0);

 } else if(strcmp(cmd,"-alter_date")==0) {
   (*idx)+= 2;
   ret= Xorriso_option_alter_date(xorriso, arg1, arg2, argc, argv, idx, 0);

 } else if(strcmp(cmd,"-ban_stdio_write")==0) {
   ret= Xorriso_option_ban_stdio_write(xorriso, 0);

 } else if(strcmp(cmd,"-blank")==0) {
   (*idx)++;
   ret= Xorriso_option_blank(xorriso, arg1, 0);

 } else if(strcmp(cmd,"-cd")==0 || strcmp(cmd,"-cdi")==0) {
   (*idx)++;
   ret= Xorriso_option_cdi(xorriso, arg1, 0);

 } else if(strcmp(cmd,"-cdx")==0) {
   (*idx)++;
   ret= Xorriso_option_cdx(xorriso, arg1, 0);

 } else if(strcmp(cmd,"-chgrp")==0 || strcmp(cmd,"-chgrpi")==0) {
   (*idx)+= 2;
   ret= Xorriso_option_chgrpi(xorriso, arg1, arg2, argc, argv, idx, 0);   

 } else if(strcmp(cmd,"-chmod")==0 || strcmp(cmd,"-chmodi")==0) {
   (*idx)+= 2;
   ret= Xorriso_option_chmodi(xorriso, arg1, arg2, argc, argv, idx, 0);   

 } else if(strcmp(cmd,"-chown")==0 || strcmp(cmd,"-chowni")==0) {
   (*idx)+= 2;
   ret= Xorriso_option_chowni(xorriso, arg1, arg2, argc, argv, idx, 0);   

 } else if(strcmp(cmd,"-commit")==0) {
   ret= Xorriso_option_commit(xorriso, 0);

 } else if(strcmp(cmd,"-cp_r")==0 || strcmp(cmd,"-cp_ri")==0) {
   ret= Xorriso_option_cp_ri(xorriso, argc, argv, idx, 0);

 } else if(strcmp(cmd,"-cut_out")==0) {
   (*idx)+= 2;
   d1= d2= -1;
   sscanf(arg2,"%lf", &d1);
   if((*idx)<argc)
     sscanf(argv[*idx],"%lf", &d2);
   if((*idx)+1<argc)
     arg4= argv[(*idx)+1];
   else
     arg4= "";
   (*idx)+= 2;
   ret= Xorriso_option_cut_out(xorriso, arg1, (off_t) d1, (off_t) d2, arg4, 0);

 } else if(strcmp(cmd,"-dev")==0) {
   (*idx)++;
   ret= Xorriso_option_dev(xorriso, arg1, 3);

 } else if(strcmp(cmd,"-devices")==0) {
   ret= Xorriso_option_devices(xorriso, 0);

 } else if(strcmp(cmd,"-dummy")==0) {
   (*idx)++;
   ret= Xorriso_option_dummy(xorriso, arg1, 0);

 } else if(strcmp(cmd,"-dialog")==0) {
   (*idx)++;
   ret= Xorriso_option_dialog(xorriso, arg1, 0);

 } else if(strcmp(cmd,"-eject")==0) {
   (*idx)++;
   ret= Xorriso_option_eject(xorriso, arg1, 0);

 } else if(strcmp(cmd,"-end")==0) {
   Xorriso_option_end(xorriso, 0);
   {ret= 3; goto ex;}

 } else if(strcmp(cmd,"-f")==0) {
   ret= Xorriso_option_f(xorriso, 0);

 } else if(strcmp(cmd,"-find")==0 || strcmp(cmd,"-findi")==0) {
   (*idx)++;
   ret= Xorriso_option_findi(xorriso, arg1, 0);

 } else if(strcmp(cmd,"-findx")==0) {
   (*idx)++;
   ret= Xorriso_option_findx(xorriso, arg1, 0);

 } else if(strcmp(cmd,"-fs")==0) {
   (*idx)++;
   ret= Xorriso_option_fs(xorriso, arg1, 0);

 } else if(strcmp(cmd,"-gid")==0) {
   (*idx)++;
   ret= Xorriso_option_gid(xorriso,arg1,0);

 } else if(strcmp(cmd,"-graft-points")==0 || strcmp(cmd,"-graft_points")==0) {
   ret= Xorriso_option_graft_points(xorriso, 0);

 } else if(strcmp(cmd,"-help")==0) {
   Xorriso_option_help(xorriso,0);

 } else if(strcmp(cmd,"-history")==0) {
   /* add to readline history */
   (*idx)++;
   ret= Xorriso_option_history(xorriso, arg1, 0);

 } else if(strcmp(cmd,"-indev")==0) {
   (*idx)++;
   ret= Xorriso_option_dev(xorriso, arg1, 1);

 } else if(strcmp(cmd,"-J")==0) {
   ret= Xorriso_option_j_capital(xorriso, 0);

 } else if(strcmp(cmd,"-ls")==0 || strcmp(cmd,"-lsi")==0 ||
           strcmp(cmd,"-ls_l")==0 || strcmp(cmd,"-ls_li")==0) {
   (*idx)++;
   ret= Xorriso_option_lsi(xorriso, arg1,
                          (strcmp(cmd,"-ls_l")==0 || strcmp(cmd,"-ls_li")==0));

 } else if(strcmp(cmd,"-lsx")==0 || strcmp(cmd,"-ls_ls")==0) {
   (*idx)++;
   ret= Xorriso_option_lsx(xorriso, arg1,strcmp(cmd,"-ls_lx")==0);

 } else if(strcmp(cmd,"-logfile")==0) {
   (*idx)+= 2;
   ret= Xorriso_option_logfile(xorriso, arg1, arg2, 0);
   
 } else if(strcmp(cmd,"-mark")==0) {
   (*idx)++;
   ret= Xorriso_option_mark(xorriso, arg1, 0);

 } else if(strcmp(cmd,"-mv")==0 || strcmp(cmd,"-mvi")==0) {
   ret= Xorriso_option_mvi(xorriso, argc, argv, idx, 0);

 } else if(strcmp(cmd,"-mkdir")==0 || strcmp(cmd,"-mkdiri")==0) {
   ret= Xorriso_option_mkdiri(xorriso, argc, argv, idx, 0);

 } else if(strcmp(cmd,"-no_rc")==0) {
   ret= Xorriso_option_no_rc(xorriso, 0);

 } else if(strcmp(cmd,"-options_from_file")==0) {
   (*idx)++;
   ret= Xorriso_option_options_from_file(xorriso,arg1,0);
   if(ret==3)
     goto ex;

 } else if(strcmp(cmd,"-options_from_file")==0) {
   (*idx)++;
   ret= Xorriso_option_overwrite(xorriso,arg1,0);

 } else if(strcmp(cmd,"-outdev")==0) {
   (*idx)++;
   ret= Xorriso_option_dev(xorriso, arg1, 1);

 } else if(strcmp(cmd,"-page")==0) {
   (*idx)+= 2;
   num1= num2= 0;
   sscanf(arg1,"%d",&num1);
   sscanf(arg2,"%d",&num2);
   if(num1<0)
     num1= 0;
   if(num2<=0)
     num2= 80;
   ret= Xorriso_option_page(xorriso, num1, num2, 0);

 } else if(strcmp(cmd,"-path-list")==0 || strcmp(cmd,"-path_list")==0) {
   (*idx)++;
   ret= Xorriso_option_path_list(xorriso, arg1, 0);

 } else if(strcmp(cmd,"-pkt_output")==0) {
   (*idx)++;
   ret=  Xorriso_option_pkt_output(xorriso, arg1, 0);

 } else if(strcmp(cmd,"-print")==0) {
   (*idx)++;
   ret= Xorriso_option_print(xorriso, arg1, 0);

 } else if(strcmp(cmd,"-print-size")==0 || strcmp(cmd,"-print_size")==0) {
   Xorriso_option_print_size(xorriso, 0);

 } else if(strcmp(cmd,"-prompt")==0) {
   (*idx)++;
   ret= Xorriso_option_prompt(xorriso, arg1, 0);

 } else if(strcmp(cmd,"-prog")==0) {
   (*idx)++;
   ret= Xorriso_option_prog(xorriso, arg1, 0);

 } else if(strcmp(cmd,"-pwd")==0 || strcmp(cmd,"-pwdi")==0) {
   Xorriso_option_pwdi(xorriso, 0);

 } else if(strcmp(cmd,"-pwdx")==0) { 
   Xorriso_option_pwdx(xorriso, 0);

 } else if(strcmp(cmd,"-reassure")==0) {
   (*idx)++;
   ret= Xorriso_option_reassure(xorriso, arg1, 0);

 } else if(strcmp(cmd,"-report_about")==0) {
   (*idx)++;
   ret= Xorriso_option_report_about(xorriso, arg1, 0);

 } else if(strcmp(cmd,"-rm")==0 || strcmp(cmd,"-rmi")==0) {
   ret= Xorriso_option_rmi(xorriso, argc, argv, idx, 0);

 } else if(strcmp(cmd,"-rm_r")==0 || strcmp(cmd,"-rm_ri")==0) {
   ret= Xorriso_option_rmi(xorriso, argc, argv, idx, 1);

 } else if(strcmp(cmd,"-rmdir")==0 || strcmp(cmd,"-rmdiri")==0) {
   ret= Xorriso_option_rmdiri(xorriso, argc, argv, idx, 0);

 } else if(strcmp(cmd,"-rollback")==0) {
   ret= Xorriso_option_rollback(xorriso, 0);

 } else if(strcmp(cmd,"-speed")==0) {
   (*idx)++;
   ret= Xorriso_option_speed(xorriso, arg1, 0);

 } else if(strcmp(cmd,"-status")==0) {
   (*idx)++;
   ret= Xorriso_option_status(xorriso, arg1, 0);

 } else if(strcmp(cmd,"-status_history_max")==0) {
   (*idx)++;
   sscanf(arg1,"%d",&num1);
   ret= Xorriso_option_status_history_max(xorriso, num1, 0);

 } else if(strcmp(cmd,"-tell_media_space")==0) {
   Xorriso_option_tell_media_space(xorriso, 0);

 } else if(strcmp(cmd,"-test")==0) { /* This option does not exist. */
   char line[4096],**hargv= NULL;
   int hargc, i;

   printf("XORRISO: -test : enter a line for test parsing\n");
   ret= Xorriso_dialog_input(xorriso,line,sizeof(line),4);
   if(ret<=0)
     goto ex;
   ret= Sfile_make_argv(xorriso->progname, line, &hargc, &hargv, 4|8);
   if(ret<=0) {
     fprintf(stderr, "--- Malformed quotation marking encountered\n");
     goto ex;
   }
   for(i=0; i<hargc; i++) {
     sprintf(xorriso->result_line,"%d : |%s|\n", i, hargv[i]);
     ret= Xorriso_result(xorriso,0);
     if(ret<=0)
       goto ex;
   }
   Sfile_make_argv(xorriso->progname, line, &hargc, &hargv, 2);

 } else if(strcmp(cmd,"-toc")==0) {
   Xorriso_option_toc(xorriso, 0);

 } else if(strcmp(cmd,"-uid")==0) {
   (*idx)++;
   ret= Xorriso_option_uid(xorriso,arg1,0);

 } else if(strcmp(cmd,"-V")==0) {
   (*idx)++;
   ret= Xorriso_option_v_capital(xorriso,arg1,0);

 } else if(strcmp(cmd,"-use_readline")==0) {
   (*idx)++;
   ret= Xorriso_option_use_readline(xorriso, arg1, 0);

 } else if(strcmp(cmd,"-version")==0){
   ret= Xorriso_option_version(xorriso, 0);

 } else if(strcmp(cmd,"--")==0){
   /* tis ok */;

 } else if(cmd[0]=='-') {
   sprintf(xorriso->info_text,
           "=== Input line beginning with '-' is not a known option\n");
   sprintf(xorriso->info_text+strlen(xorriso->info_text),
           "===  '%s'\n",cmd);
   Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
   {ret= 0; goto ex;}

 } else {

   /* >>> ??? pathspecs for option -add */;

   sprintf(xorriso->info_text, "Ignored argument : '%s'", cmd);
   Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "WARNING", 0);
 }

 ret= Xorriso_eval_problem_status(xorriso, ret, 0);
 if(ret<0)
   return(ret);

 if(*idx<argc)
   goto next_command;

ex:;
 if((!xorriso->is_dialog) && !(flag&1))
   Xorriso_mark(xorriso,0);
 fflush(stdout);
 return(ret);
}


int Xorriso_execute_option(struct XorrisO *xorriso, char *line, int flag)
/*
 bit0-bit15 are forwarded to Xorriso_interpreter
 
 bit16= no pageing of info lines
 bit17= print === bar even if xorriso->found<0
*/
{
 int ret,argc= 0, idx= 1;
 char **argv= NULL;
 double tdiff;
 struct timeval tv;
 struct timezone tz;

 gettimeofday(&tv,&tz);
 Xorriso_reset_counters(xorriso,1);
 xorriso->idle_time= 0.0;
 tdiff= tv.tv_sec+(1.e-6*(double) tv.tv_usec);

 /* parse line into args */
 ret= Sfile_make_argv(xorriso->progname, line, &argc, &argv, 4|8);
 if(ret<=0)
   goto ex;
 if(argc<2)
   {ret= 1; goto ex;}
 if(argv[1][0]=='#')
   {ret= 1; goto ex;}

 ret= Xorriso_interpreter(xorriso, argc, argv, &idx, flag&0xffff);
 if(ret<0)
   goto ex;
 gettimeofday(&tv,&tz);
 tdiff= tv.tv_sec+(1.e-6*(double) tv.tv_usec)-tdiff-xorriso->idle_time;
 if(tdiff<0.001)
   tdiff= 0.001;
 if(xorriso->error_count>0) {
   sprintf(xorriso->info_text,
           "----------------------------- %7.lf errors encountered\n",
           xorriso->error_count);
   Xorriso_info(xorriso,!(flag&(1<<16)));
 }

 /* ??? >>> print elapsed time  tdiff ? */;

 if((flag&(1<<17)) && !xorriso->bar_is_fresh) {
   sprintf(xorriso->info_text,"============================\n");
   Xorriso_info(xorriso,0);
   xorriso->bar_is_fresh= 1;
 }
 Xorriso_reset_counters(xorriso,1);
ex:;
 Sfile_make_argv("", "", &argc, &argv, 2); /* release memory */
 return(ret);
}


int Xorriso_dialog(struct XorrisO *xorriso, int flag)
{
 int ret,first_round;
 char line[2*SfileadrL];

 xorriso->is_dialog= 1;
 for(first_round= 1;1;first_round= 0) {
   if(xorriso->pending_option[0]!=0) {
     Xorriso_mark(xorriso,0);
     strcpy(line,xorriso->pending_option);
     xorriso->pending_option[0]= 0;
   } else {
     if(!xorriso->bar_is_fresh) {
       sprintf(xorriso->info_text,"============================\n");
       Xorriso_info(xorriso,0);
       xorriso->bar_is_fresh= 1;
     }
     sprintf(xorriso->info_text,"enter option and arguments :\n");
     Xorriso_info(xorriso,0);
     Xorriso_mark(xorriso,0);
     ret= Xorriso_dialog_input(xorriso,line,sizeof(line),4);
     if(ret<=0)
 break;
   }
   sprintf(xorriso->info_text,
           "==============================================================\n");
   Xorriso_info(xorriso,0);

   ret= Xorriso_execute_option(xorriso,line,1<<17);
   if(ret<0)
     goto ex;
   if(ret==3)
 break;
   xorriso->did_something_useful= 1;
 }
 ret= 1;
ex:;
 xorriso->is_dialog= 0;
 return(ret);
}


int Xorriso_prescan_args(struct XorrisO *xorriso, int argc, char **argv,
                         int flag)
/*
 bit0= do not interpret argv[1]
*/
/*
 return:
  <0  error
   0  end program
   1  ok, go on
*/
{
 int i,ret;
 char *cmd, *arg1;

 for(i=1+(flag&1);i<argc;i++) {
   cmd= argv[i];
   arg1= "";
   if(i+1<argc)
     arg1= argv[i+1];
   if(i>1)
     xorriso->did_something_useful= 1;
   if(i==1 && argc==2) {
     if(strcmp(cmd,"-prog_help")==0) {
       i++;
       Xorriso_option_prog_help(xorriso,arg1,0);
       xorriso->did_something_useful= 1;
       return(0);
     } else if(strcmp(cmd,"-help")==0) {
       Xorriso_option_help(xorriso,0);
       xorriso->did_something_useful= 1;
       return(0);
     } else if(strcmp(cmd,"-version")==0) {
       Xorriso_option_version(xorriso, 0);
       xorriso->did_something_useful= 1;
       return(0);
     }
   } else if(strcmp(cmd,"-no_rc")==0) {
     ret= Xorriso_option_no_rc(xorriso, 0);
     if(ret<=0)
       return(ret);
   }
 }
 return(1);
}


/** Load content startup files into preskin cache */
int Xorriso_read_rc(struct XorrisO *xorriso, int flag)
{
 int ret,i;

 i= xorriso->rc_filename_count-1;
 Sfile_home_adr_s(".xorrisorc", xorriso->rc_filenames[i],
                  sizeof(xorriso->rc_filenames[i]),0);
 for(i=0;i<xorriso->rc_filename_count;i++) {
   ret= Sfile_type(xorriso->rc_filenames[i],1|8);
   if(ret!=1)
 continue;
   ret= Xorriso_option_options_from_file(xorriso,xorriso->rc_filenames[i],0);
   if(ret!=1)
     return(ret);
 }
 return(1);
}


#ifdef Xorriso_with_maiN

int main(int argc, char **argv)
{

#else

int Xorriso_main(int argc, char **argv)
{

#endif /* Xorriso_with_maiN */

 int ret,i;
 struct XorrisO *xorriso= NULL;

 if(argc<2) {
   fprintf(stderr,
       "xorriso %s : RockRidge filesystem manipulator, libburnia project.\n\n",
       PROG_VERSION);
   fprintf(stderr,"usage : %s [options]\n",
           argv[0]);
   fprintf(stderr,"        More is told by option -help\n");
   exit(2);
 }
 ret= Xorriso_new(&xorriso,argv[0],0);
 if(ret<=0) {
   fprintf(stderr,"Creation of XorrisO object failed. (not enough memory ?)\n");
   exit(3);
 }

 /* The prescan of arguments performs actions which have to happen before
    the normal processing of startup files and arguments. Currently:
     -no_rc and single-argument runs like  -help or -version.
 */
 ret= Xorriso_prescan_args(xorriso,argc,argv,0);
 if(ret==0)
   goto end_sucessfully;
 if(ret<0)
   exit(5);

 ret= Xorriso_startup_libraries(xorriso, 0);
 if(ret<=0)
   exit(4);
 Xorriso_process_msg_queues(xorriso, 0);

 /* Interpret startup file */
 if(!xorriso->no_rc) {
   ret= Xorriso_read_rc(xorriso, 0);
   if(ret==3)
     goto end_sucessfully;
   if(ret<=0)
     exit(5);
 }

 /* Interpret program arguments */
 i= 1;
 ret= Xorriso_interpreter(xorriso,argc,argv,&i,0);
 if(ret==3)
   goto end_sucessfully;
 if(ret<=0)
   exit(5);
 
 if(xorriso->dialog) {
   ret= Xorriso_dialog(xorriso,0);
   if(ret<=0)
     exit(6);
 }
end_sucessfully:;
 Xorriso_process_msg_queues(xorriso, 0);
 Xorriso_destroy(&xorriso,0);
 exit(0);
}

