"Fossies" - the Fresh Open Source Software Archive

Member "bas-2.6/fs.c" (2 Jul 2019, 31371 Bytes) of package /linux/privat/bas-2.6.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "fs.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.5_vs_2.6.

    1 /* BASIC file system interface. */
    2 /* #includes */ /*{{{C}}}*//*{{{*/
    3 #include "config.h"
    4 
    5 #include <sys/time.h>
    6 #include <sys/types.h>
    7 #include <sys/stat.h>
    8 #include <assert.h>
    9 #include <errno.h>
   10 #include <fcntl.h>
   11 #ifdef HAVE_GETTEXT
   12 #include <libintl.h>
   13 #define _(String) gettext(String)
   14 #else
   15 #define _(String) String
   16 #endif
   17 #include <math.h>
   18 #include <signal.h>
   19 #include <stdio.h>
   20 #include <stdlib.h>
   21 #include <string.h>
   22 #include <termios.h>
   23 #include <time.h>
   24 #ifdef HAVE_TERMCAP_H
   25 #include <termcap.h>
   26 #endif
   27 #ifdef HAVE_CURSES_H
   28 #include <curses.h>
   29 #endif
   30 #include <unistd.h>
   31 
   32 #include "fs.h"
   33 
   34 #ifdef USE_DMALLOC
   35 #include "dmalloc.h"
   36 #endif
   37 /*}}}*/
   38 /* #defines */ /*{{{*/
   39 #define LINEWIDTH 80
   40 #define COLWIDTH  14
   41 /*}}}*/
   42 
   43 static struct FileStream **file;
   44 static int capacity;
   45 static int used;
   46 static struct termios origMode,rawMode;
   47 static const int open_mode[4]={ 0, O_RDONLY, O_WRONLY, O_RDWR };
   48 static struct sigaction old_sigint, old_sigquit;
   49 static int termchannel;
   50 
   51 const char *FS_errmsg;
   52 static char FS_errmsgbuf[80];
   53 volatile int FS_intr;
   54 
   55 static int size(int dev) /*{{{*/
   56 {
   57   if (dev>=capacity)
   58   {
   59     int i;
   60     struct FileStream **n;
   61 
   62     if ((n=(struct FileStream**)realloc(file,(dev+1)*sizeof(struct FileStream*)))==(struct FileStream**)0)
   63     {
   64       FS_errmsg=strerror(errno);
   65       return -1;
   66     }
   67     file=n;
   68     for (i=capacity; i<=dev; ++i) file[i]=(struct FileStream*)0;
   69     capacity=dev+1;
   70   }
   71   return 0;
   72 }
   73 /*}}}*/
   74 static int opened(int dev, int mode) /*{{{*/
   75 {
   76   int fd=-1;
   77 
   78   if (dev<0 || dev>=capacity || file[dev]==(struct FileStream*)0)
   79   {
   80     snprintf(FS_errmsgbuf,sizeof(FS_errmsgbuf),_("channel #%d not open"),dev);
   81     FS_errmsg=FS_errmsgbuf;
   82     return -1;
   83   }
   84   if (mode==-1) return 0;
   85   switch (mode)
   86   {
   87     case 0:
   88     {
   89       fd=file[dev]->outfd;
   90       if (fd==-1) snprintf(FS_errmsgbuf,sizeof(FS_errmsgbuf),_("channel #%d not opened for writing"),dev);
   91       break;
   92     }
   93     case 1:
   94     {
   95       fd=file[dev]->infd;
   96       if (fd==-1) snprintf(FS_errmsgbuf,sizeof(FS_errmsgbuf),_("channel #%d not opened for reading"),dev);
   97       break;
   98     }
   99     case 2:
  100     {
  101       fd=file[dev]->randomfd;
  102       if (fd==-1) snprintf(FS_errmsgbuf,sizeof(FS_errmsgbuf),_("channel #%d not opened for random access"),dev);
  103       break;
  104     }
  105     case 3:
  106     {
  107       fd=file[dev]->binaryfd;
  108       if (fd==-1) snprintf(FS_errmsgbuf,sizeof(FS_errmsgbuf),_("channel #%d not opened for binary access"),dev);
  109       break;
  110     }
  111     case 4:
  112     {
  113       fd=(file[dev]->randomfd!=-1?file[dev]->randomfd:file[dev]->binaryfd);
  114       if (fd==-1) snprintf(FS_errmsgbuf,sizeof(FS_errmsgbuf),_("channel #%d not opened for random or binary access"),dev);
  115       break;
  116     }
  117     default: assert(0);
  118   }
  119   if (fd==-1)
  120   {
  121     FS_errmsg=FS_errmsgbuf;
  122     return -1;
  123   }
  124   else return 0;
  125 }
  126 /*}}}*/
  127 static int refill(int dev) /*{{{*/
  128 {
  129   struct FileStream *f;
  130   ssize_t len;
  131 
  132   f=file[dev];
  133   f->inSize=0;
  134   len=read(f->infd,f->inBuf,sizeof(f->inBuf));
  135   if (len<=0)
  136   {
  137     f->inCapacity=0;
  138     FS_errmsg=(len==-1?strerror(errno):(const char*)0);
  139     return -1;
  140   }
  141   else
  142   {
  143     f->inCapacity=len;
  144     return 0;
  145   }
  146 }
  147 /*}}}*/
  148 static int edit(int chn, int output_nl) /*{{{*/
  149 {
  150   struct FileStream *f=file[chn];
  151   char *buf=f->inBuf;
  152   char ch;
  153   int r;
  154 
  155   for (buf=f->inBuf; buf<(f->inBuf+f->inCapacity); ++buf)
  156   {
  157     if (*buf>='\0' && *buf<' ')
  158     {
  159       FS_putChar(chn,'^');
  160       FS_putChar(chn,*buf?(*buf+'a'-1):'@');
  161     }
  162     else FS_putChar(chn,*buf);
  163   }
  164   do
  165   {
  166     FS_flush(chn);
  167     if ((r=read(f->infd,&ch,1))==-1)
  168     {
  169       f->inCapacity=0;
  170       FS_errmsg=strerror(errno);
  171       return -1;
  172     }
  173     else if (r==0 || (f->inCapacity==0 && ch==4))
  174     {
  175       FS_errmsg=(char*)0;
  176       return -1;
  177     }
  178     if (ch==rawMode.c_cc[VERASE])
  179     {
  180       if (f->inCapacity)
  181       {
  182         if (f->inBuf[f->inCapacity-1]>='\0' && f->inBuf[f->inCapacity-1]<' ') FS_putChars(chn,"\b\b  \b\b");
  183         else FS_putChars(chn,"\b \b");
  184         --f->inCapacity;
  185       }
  186     }
  187     else if ((f->inCapacity+1)<sizeof(f->inBuf))
  188     {
  189       if (ch!='\n')
  190       {
  191         if (ch>='\0' && ch<' ')
  192         {
  193           FS_putChar(chn,'^');
  194           FS_putChar(chn,ch?(ch+'a'-1):'@');
  195         }
  196         else FS_putChar(chn,ch);
  197       }
  198       else if (output_nl) FS_putChar(chn,'\n');
  199       f->inBuf[f->inCapacity++]=ch;
  200     }
  201   } while (ch!='\n');
  202   return 0;
  203 }
  204 /*}}}*/
  205 static int outc(int ch) /*{{{*/
  206 {
  207   struct FileStream *f;
  208 
  209   if (opened(termchannel,0)==-1) return -1;
  210   f=file[termchannel];
  211   if (f->outSize+1>=f->outCapacity && FS_flush(termchannel)==-1) return -1;
  212   f->outBuf[f->outSize++]=ch;
  213   FS_errmsg=(const char*)0;
  214   return ch;
  215 }
  216 /*}}}*/
  217 #ifdef HAVE_TGETENT
  218 static char *term,entrybuf[2048],*cap;
  219 static char *cl,*cm,*ce,*cr,*md,*me,*AF,*AB;
  220 static int Co,NC;
  221 
  222 static int mytputs(const char *str, int affcnt, int (*out)(int)) /*{{{*/
  223 {
  224 #ifdef TPUTS_RETURNS_VOID
  225   tputs(str,affcnt,out);
  226   return 0;
  227 #else
  228   return tputs(str,affcnt,out);
  229 #endif
  230 }
  231 /*}}}*/
  232 static int initTerminal(int chn) /*{{{*/
  233 {
  234   static int init=0;
  235 
  236   if (!init)
  237   {
  238     termchannel=chn;
  239     if ((term=getenv("TERM"))==(char*)0)
  240     {
  241       FS_errmsg=_("environment variable TERM is not set");
  242       return -1;
  243     }
  244     switch (tgetent(entrybuf,term))
  245     {
  246       case -1:
  247       {
  248         FS_errmsg=_("reading terminal description failed");
  249         return -1;
  250       }
  251       case 0:
  252       {
  253         sprintf(FS_errmsgbuf,_("unknown terminal type %s"),term);
  254         FS_errmsg=FS_errmsgbuf;
  255         return -1;
  256       }
  257       case 1:
  258       {
  259         cl=tgetstr("cl",&cap);
  260         cm=tgetstr("cm",&cap);
  261         ce=tgetstr("ce",&cap);
  262         cr=tgetstr("cr",&cap);
  263         md=tgetstr("md",&cap);
  264         me=tgetstr("me",&cap);
  265         AF=tgetstr("AF",&cap);
  266         AB=tgetstr("AB",&cap);
  267         Co=tgetnum("Co");
  268         if ((NC=tgetnum("NC"))==-1) NC=0;
  269         return 0;
  270       }
  271     }
  272     init=1;
  273   }
  274   return 0;
  275 }
  276 /*}}}*/
  277 static int cls(int chn) /*{{{*/
  278 {
  279   if (cl==(char*)0)
  280   {
  281     sprintf(FS_errmsgbuf,_("terminal type %s can not clear the screen"),term);
  282     FS_errmsg=FS_errmsgbuf;
  283     return -1;
  284   }
  285   if (mytputs(cl,0,outc)==-1) return -1;
  286   return 0;
  287 }
  288 /*}}}*/
  289 static int locate(int chn, int line, int column) /*{{{*/
  290 {
  291   termchannel=chn;
  292   if (cm==(char*)0)
  293   {
  294     sprintf(FS_errmsgbuf,_("terminal type %s can not position the cursor"),term);
  295     FS_errmsg=FS_errmsgbuf;
  296     return -1;
  297   }
  298   if (mytputs(tgoto(cm,column-1,line-1),0,outc)==-1) return -1;
  299   return 0;
  300 }
  301 /*}}}*/
  302 static int colour(int chn, int foreground, int background) /*{{{*/
  303 {
  304   if (AF && AB && Co>=8)
  305   {
  306     static int map[8]={ 0,4,2,6,1,5,3,7 };
  307 
  308     if (foreground!=-1)
  309     {
  310       if (md && me && !(NC&32))
  311       {
  312         if (foreground>7 && file[chn]->outforeground<=7)
  313         {
  314           if (mytputs(md,0,outc)==-1) return -1;
  315           /* all attributes are gone now, need to set background again */
  316           if (background==-1) background=file[chn]->outbackground;
  317         }
  318         else if (foreground<=7 && file[chn]->outforeground>7)
  319         {
  320           if (mytputs(me,0,outc)==-1) return -1;
  321         }
  322       }
  323       if (mytputs(tgoto(AF,0,map[foreground&7]),0,outc)==-1) return -1;
  324     }
  325     if (background!=-1)
  326     {
  327       if (mytputs(tgoto(AB,0,map[background&7]),0,outc)==-1) return -1;
  328     }
  329   }
  330   return 0;
  331 }
  332 /*}}}*/
  333 static int resetcolour(int chn) /*{{{*/
  334 {
  335   if (me) mytputs(me,0,outc);
  336   if (ce) mytputs(ce,0,outc);
  337   return 0;
  338 }
  339 /*}}}*/
  340 static void crlf(int chn) /*{{{*/
  341 {
  342   if (cr) mytputs(cr,0,outc);
  343   else outc('\r');
  344   outc('\n');
  345 }
  346 /*}}}*/
  347 #else
  348 static int initTerminal(int chn) /*{{{*/
  349 {
  350   termchannel=chn;
  351   return 0;
  352 }
  353 /*}}}*/
  354 static int cls(int chn) /*{{{*/
  355 {
  356   FS_errmsg=_("This installation does not support terminal handling");
  357   return -1;
  358 }
  359 /*}}}*/
  360 static int locate(int chn, int line, int column) /*{{{*/
  361 {
  362   FS_errmsg=_("This installation does not support terminal handling");
  363   return -1;
  364 }
  365 /*}}}*/
  366 static int colour(int chn, int foreground, int background) /*{{{*/
  367 {
  368   FS_errmsg=_("This installation does not support terminal handling");
  369   return -1;
  370 }
  371 /*}}}*/
  372 static int resetcolour(int chn) /*{{{*/
  373 {
  374   return 0;
  375 }
  376 /*}}}*/
  377 static void crlf(int chn) /*{{{*/
  378 {
  379   outc('\r');
  380   outc('\n');
  381 }
  382 /*}}}*/
  383 #endif
  384 static void sigintr(int sig) /*{{{*/
  385 {
  386   FS_intr=1;
  387   FS_allowIntr(0);
  388 }
  389 /*}}}*/
  390 
  391 int FS_opendev(int chn, int infd, int outfd) /*{{{*/
  392 {
  393   if (size(chn)==-1) return -1;
  394   if (file[chn]!=(struct FileStream*)0)
  395   {
  396     FS_errmsg=_("channel already open");
  397     return -1;
  398   }
  399   file[chn]=malloc(sizeof(struct FileStream));
  400   file[chn]->dev=1;
  401   if ((file[chn]->tty=(infd==0 ? isatty(infd) && isatty(outfd) : 0)))
  402   {
  403     if (tcgetattr(infd,&origMode)==-1)
  404     {
  405       FS_errmsg=strerror(errno);
  406       free(file[chn]);
  407       file[chn]=(struct FileStream*)0;
  408       return -1;
  409     }
  410     rawMode=origMode;
  411     rawMode.c_lflag&=~(ICANON|ECHO); /* IEXTEN would disable IUCLC, breaking UC only terminals */
  412     rawMode.c_cc[VMIN]=1;
  413     rawMode.c_cc[VTIME]=0;
  414     rawMode.c_oflag&=~ONLCR;
  415     if (tcsetattr(infd,TCSADRAIN,&rawMode)==-1)
  416     {
  417       FS_errmsg=strerror(errno);
  418       free(file[chn]);
  419       file[chn]=(struct FileStream*)0;
  420       return -1;
  421     }
  422     initTerminal(chn);
  423   }
  424   file[chn]->recLength=1;
  425   file[chn]->infd=infd;
  426   file[chn]->inSize=0;
  427   file[chn]->inCapacity=0;
  428   file[chn]->outfd=outfd;
  429   file[chn]->outPos=0;
  430   file[chn]->outLineWidth=LINEWIDTH;
  431   file[chn]->outColWidth=COLWIDTH;
  432   file[chn]->outCapacity=sizeof(file[chn]->outBuf);
  433   file[chn]->outSize=0;
  434   file[chn]->outforeground=-1;
  435   file[chn]->outbackground=-1;
  436   file[chn]->randomfd=-1;
  437   file[chn]->binaryfd=-1;
  438   FS_errmsg=(const char*)0;
  439   ++used;
  440   return 0;
  441 }
  442 /*}}}*/
  443 int FS_openin(const char *name) /*{{{*/
  444 {
  445   int chn,fd;
  446 
  447   if ((fd=open(name,O_RDONLY))==-1)
  448   {
  449     FS_errmsg=strerror(errno);
  450     return -1;
  451   }
  452   for (chn=0; chn<capacity; ++chn) if (file[chn]==(struct FileStream*)0) break;
  453   if (size(chn)==-1) return -1;
  454   file[chn]=malloc(sizeof(struct FileStream));
  455   file[chn]->recLength=1;
  456   file[chn]->dev=0;
  457   file[chn]->tty=0;
  458   file[chn]->infd=fd;
  459   file[chn]->inSize=0;
  460   file[chn]->inCapacity=0;
  461   file[chn]->outfd=-1;
  462   file[chn]->randomfd=-1;
  463   file[chn]->binaryfd=-1;
  464   FS_errmsg=(const char*)0;
  465   ++used;
  466   return chn;
  467 }
  468 /*}}}*/
  469 int FS_openinChn(int chn, const char *name, int mode) /*{{{*/
  470 {
  471   int fd;
  472   mode_t fl;
  473 
  474   if (size(chn)==-1) return -1;
  475   if (file[chn]!=(struct FileStream*)0)
  476   {
  477     FS_errmsg=_("channel already open");
  478     return -1;
  479   }
  480   fl=open_mode[mode];
  481   /* Serial devices on Linux should be opened non-blocking, otherwise the  */
  482   /* open() may block already.  Named pipes can not be opened non-blocking */
  483   /* in write-only mode, so first try non-blocking, then blocking.         */
  484   if ((fd=open(name,fl|O_NONBLOCK))==-1)
  485   {
  486     if (errno!=ENXIO || (fd=open(name,fl))==-1)
  487     {
  488       FS_errmsg=strerror(errno);
  489       return -1;
  490     }
  491   }
  492   else if (fcntl(fd,F_SETFL,(long)fl)==-1)
  493   {
  494     FS_errmsg=strerror(errno);
  495     close(fd);
  496     return -1;
  497   }
  498   file[chn]=malloc(sizeof(struct FileStream));
  499   file[chn]->recLength=1;
  500   file[chn]->dev=0;
  501   file[chn]->tty=0;
  502   file[chn]->infd=fd;
  503   file[chn]->inSize=0;
  504   file[chn]->inCapacity=0;
  505   file[chn]->outfd=-1;
  506   file[chn]->randomfd=-1;
  507   file[chn]->binaryfd=-1;
  508   FS_errmsg=(const char*)0;
  509   ++used;
  510   return chn;
  511 }
  512 /*}}}*/
  513 int FS_openout(const char *name) /*{{{*/
  514 {
  515   int chn,fd;
  516 
  517   if ((fd=open(name,O_WRONLY|O_TRUNC|O_CREAT,0666))==-1)
  518   {
  519     FS_errmsg=strerror(errno);
  520     return -1;
  521   }
  522   for (chn=0; chn<capacity; ++chn) if (file[chn]==(struct FileStream*)0) break;
  523   if (size(chn)==-1) return -1;
  524   file[chn]=malloc(sizeof(struct FileStream));
  525   file[chn]->recLength=1;
  526   file[chn]->dev=0;
  527   file[chn]->tty=0;
  528   file[chn]->infd=-1;
  529   file[chn]->outfd=fd;
  530   file[chn]->outPos=0;
  531   file[chn]->outLineWidth=LINEWIDTH;
  532   file[chn]->outColWidth=COLWIDTH;
  533   file[chn]->outSize=0;
  534   file[chn]->outCapacity=sizeof(file[chn]->outBuf);
  535   file[chn]->randomfd=-1;
  536   file[chn]->binaryfd=-1;
  537   FS_errmsg=(const char*)0;
  538   ++used;
  539   return chn;
  540 }
  541 /*}}}*/
  542 int FS_openoutChn(int chn, const char *name, int mode, int append) /*{{{*/
  543 {
  544   int fd;
  545   mode_t fl;
  546 
  547   if (size(chn)==-1) return -1;
  548   if (file[chn]!=(struct FileStream*)0)
  549   {
  550     FS_errmsg=_("channel already open");
  551     return -1;
  552   }
  553   fl=open_mode[mode]|(append?O_APPEND:0);
  554   /* Serial devices on Linux should be opened non-blocking, otherwise the  */
  555   /* open() may block already.  Named pipes can not be opened non-blocking */
  556   /* in write-only mode, so first try non-blocking, then blocking.         */
  557   if ((fd=open(name,fl|O_CREAT|(append?0:O_TRUNC)|O_NONBLOCK,0666))==-1)
  558   {
  559     if (errno!=ENXIO || (fd=open(name,fl|O_CREAT|(append?0:O_TRUNC),0666))==-1)
  560     {
  561       FS_errmsg=strerror(errno);
  562       return -1;
  563     }
  564   }
  565   else if (fcntl(fd,F_SETFL,(long)fl)==-1)
  566   {
  567     FS_errmsg=strerror(errno);
  568     close(fd);
  569     return -1;
  570   }
  571   file[chn]=malloc(sizeof(struct FileStream));
  572   file[chn]->recLength=1;
  573   file[chn]->dev=0;
  574   file[chn]->tty=0;
  575   file[chn]->infd=-1;
  576   file[chn]->outfd=fd;
  577   file[chn]->outPos=0;
  578   file[chn]->outLineWidth=LINEWIDTH;
  579   file[chn]->outColWidth=COLWIDTH;
  580   file[chn]->outSize=0;
  581   file[chn]->outCapacity=sizeof(file[chn]->outBuf);
  582   file[chn]->randomfd=-1;
  583   file[chn]->binaryfd=-1;
  584   FS_errmsg=(const char*)0;
  585   ++used;
  586   return chn;
  587 }
  588 /*}}}*/
  589 int FS_openrandomChn(int chn, const char *name, int mode, int recLength) /*{{{*/
  590 {
  591   int fd;
  592 
  593   assert(chn>=0);
  594   assert(name!=(const char*)0);
  595   assert(recLength>0);
  596   if (size(chn)==-1) return -1;
  597   if (file[chn]!=(struct FileStream*)0)
  598   {
  599     FS_errmsg=_("channel already open");
  600     return -1;
  601   }
  602   if ((fd=open(name,open_mode[mode]|O_CREAT,0666))==-1)
  603   {
  604     FS_errmsg=strerror(errno);
  605     return -1;
  606   }
  607   file[chn]=malloc(sizeof(struct FileStream));
  608   file[chn]->recLength=recLength;
  609   file[chn]->dev=0;
  610   file[chn]->tty=0;
  611   file[chn]->infd=-1;
  612   file[chn]->outfd=-1;
  613   file[chn]->randomfd=fd;
  614   file[chn]->recBuf=malloc(recLength);
  615   memset(file[chn]->recBuf,0,recLength);
  616   StringField_new(&file[chn]->field);
  617   file[chn]->binaryfd=-1;
  618   FS_errmsg=(const char*)0;
  619   ++used;
  620   return chn;
  621 }
  622 /*}}}*/
  623 int FS_openbinaryChn(int chn, const char *name, int mode) /*{{{*/
  624 {
  625   int fd;
  626 
  627   assert(chn>=0);
  628   assert(name!=(const char*)0);
  629   if (size(chn)==-1) return -1;
  630   if (file[chn]!=(struct FileStream*)0)
  631   {
  632     FS_errmsg=_("channel already open");
  633     return -1;
  634   }
  635   if ((fd=open(name,open_mode[mode]|O_CREAT,0666))==-1)
  636   {
  637     FS_errmsg=strerror(errno);
  638     return -1;
  639   }
  640   file[chn]=malloc(sizeof(struct FileStream));
  641   file[chn]->recLength=1;
  642   file[chn]->dev=0;
  643   file[chn]->tty=0;
  644   file[chn]->infd=-1;
  645   file[chn]->outfd=-1;
  646   file[chn]->randomfd=-1;
  647   file[chn]->binaryfd=fd;
  648   FS_errmsg=(const char*)0;
  649   ++used;
  650   return chn;
  651 }
  652 /*}}}*/
  653 int FS_freechn(void) /*{{{*/
  654 {
  655   int i;
  656 
  657   for (i=0; i<capacity && file[i]; ++i);
  658   if (size(i)==-1) return -1;
  659   return i;
  660 }
  661 /*}}}*/
  662 int FS_flush(int dev) /*{{{*/
  663 {
  664   ssize_t written;
  665   size_t offset;
  666 
  667   if (file[dev]==(struct FileStream*)0)
  668   {
  669     FS_errmsg=_("channel not open");
  670     return -1;
  671   }
  672   offset=0;
  673   while (offset<file[dev]->outSize)
  674   {
  675     written=write(file[dev]->outfd,file[dev]->outBuf+offset,file[dev]->outSize-offset);
  676     if (written==-1)
  677     {
  678       FS_errmsg=strerror(errno);
  679       return -1;
  680     }
  681     else offset+=written;
  682   }
  683   file[dev]->outSize=0;
  684   FS_errmsg=(const char*)0;
  685   return 0;
  686 }
  687 /*}}}*/
  688 int FS_close(int dev) /*{{{*/
  689 {
  690   if (file[dev]==(struct FileStream*)0)
  691   {
  692     FS_errmsg=_("channel not open");
  693     return -1;
  694   }
  695   if (file[dev]->outfd>=0)
  696   {
  697     if (file[dev]->tty && (file[dev]->outforeground!=-1 || file[dev]->outbackground!=-1)) resetcolour(dev);
  698     FS_flush(dev);
  699     close(file[dev]->outfd);
  700   }
  701   if (file[dev]->randomfd>=0)
  702   {
  703     StringField_destroy(&file[dev]->field);
  704     free(file[dev]->recBuf);
  705     close(file[dev]->randomfd);
  706   }
  707   if (file[dev]->binaryfd>=0)
  708   {
  709     close(file[dev]->binaryfd);
  710   }
  711   if (file[dev]->tty) tcsetattr(file[dev]->infd,TCSADRAIN,&origMode);
  712   if (file[dev]->infd>=0) close(file[dev]->infd);
  713   free(file[dev]);
  714   file[dev]=(struct FileStream*)0;
  715   FS_errmsg=(const char*)0;
  716   if (--used==0)
  717   {
  718     free(file);
  719     capacity=0;
  720   }
  721   return 0;
  722 }
  723 /*}}}*/
  724 int FS_istty(int chn) /*{{{*/
  725 {
  726   return (file[chn] && file[chn]->tty);
  727 }
  728 /*}}}*/
  729 int FS_lock(int chn, off_t offset, off_t length, int mode, int w) /*{{{*/
  730 {
  731   int fd;
  732   struct flock recordLock;
  733 
  734   if (file[chn]==(struct FileStream*)0)
  735   {
  736     FS_errmsg=_("channel not open");
  737     return -1;
  738   }
  739   if ((fd=file[chn]->infd)==-1)
  740   if ((fd=file[chn]->outfd)==-1)
  741   if ((fd=file[chn]->randomfd)==-1)
  742   if ((fd=file[chn]->binaryfd)==-1) assert(0);
  743   recordLock.l_whence=SEEK_SET;
  744   recordLock.l_start=offset;
  745   recordLock.l_len=length;
  746   switch (mode)
  747   {
  748     case FS_LOCK_SHARED:    recordLock.l_type=F_RDLCK; break;
  749     case FS_LOCK_EXCLUSIVE: recordLock.l_type=F_WRLCK; break;
  750     case FS_LOCK_NONE:      recordLock.l_type=F_UNLCK; break;
  751     default: assert(0);
  752   }
  753   if (fcntl(fd,w ? F_SETLKW : F_SETLK,&recordLock)==-1)
  754   {
  755     FS_errmsg=strerror(errno);
  756     return -1;
  757   }
  758   return 0;
  759 }
  760 /*}}}*/
  761 int FS_truncate(int chn) /*{{{*/
  762 {
  763   int fd;
  764   off_t o;
  765 
  766   if (file[chn]==(struct FileStream*)0)
  767   {
  768     FS_errmsg=_("channel not open");
  769     return -1;
  770   }
  771   if ((fd=file[chn]->infd)==-1)
  772   if ((fd=file[chn]->outfd)==-1)
  773   if ((fd=file[chn]->randomfd)==-1)
  774   if ((fd=file[chn]->binaryfd)==-1) assert(0);
  775   if ((o=lseek(fd,0,SEEK_CUR))==(off_t)-1 || ftruncate(fd,o+1)==-1)
  776   {
  777     FS_errmsg=strerror(errno);
  778     return -1;
  779   }
  780   return 0;
  781 }
  782 /*}}}*/
  783 void FS_shellmode(int dev) /*{{{*/
  784 {
  785   struct sigaction interrupt;
  786 
  787   if (file[dev]->tty) tcsetattr(file[dev]->infd,TCSADRAIN,&origMode);
  788   interrupt.sa_flags=0;
  789   sigemptyset(&interrupt.sa_mask);
  790   interrupt.sa_handler=SIG_IGN;
  791   sigaction(SIGINT,&interrupt,&old_sigint);
  792   sigaction(SIGQUIT,&interrupt,&old_sigquit);
  793 }
  794 /*}}}*/
  795 void FS_fsmode(int chn) /*{{{*/
  796 {
  797   if (file[chn]->tty) tcsetattr(file[chn]->infd,TCSADRAIN,&rawMode);
  798   sigaction(SIGINT,&old_sigint,(struct sigaction *)0);
  799   sigaction(SIGQUIT,&old_sigquit,(struct sigaction *)0);
  800 }
  801 /*}}}*/
  802 void FS_xonxoff(int chn, int on) /*{{{*/
  803 {
  804   if (file[chn]->tty)
  805   {
  806     if (on) rawMode.c_iflag|=(IXON|IXOFF);
  807     else rawMode.c_iflag&=~(IXON|IXOFF);
  808     tcsetattr(file[chn]->infd,TCSADRAIN,&rawMode);
  809   }
  810 }
  811 /*}}}*/
  812 int FS_put(int chn) /*{{{*/
  813 {
  814   ssize_t offset,written;
  815 
  816   if (opened(chn,2)==-1) return -1;
  817   offset=0;
  818   while (offset<file[chn]->recLength)
  819   {
  820     written=write(file[chn]->randomfd,file[chn]->recBuf+offset,file[chn]->recLength-offset);
  821     if (written==-1)
  822     {
  823       FS_errmsg=strerror(errno);
  824       return -1;
  825     }
  826     else offset+=written;
  827   }
  828   FS_errmsg=(const char*)0;
  829   return 0;
  830 }
  831 /*}}}*/
  832 int FS_putChar(int dev, char ch) /*{{{*/
  833 {
  834   struct FileStream *f;
  835 
  836   if (opened(dev,0)==-1) return -1;
  837   f=file[dev];
  838   if (ch=='\n') f->outPos=0;
  839   if (ch=='\b' && f->outPos) --f->outPos;
  840   if (f->outSize+2>=f->outCapacity && FS_flush(dev)==-1) return -1;
  841   if (f->outLineWidth && f->outPos==f->outLineWidth)
  842   {
  843     if (FS_istty(dev)) crlf(dev);
  844     else f->outBuf[f->outSize++]='\n';
  845     f->outPos=0;
  846   }
  847   if (FS_istty(dev) && ch=='\n') crlf(dev);
  848   else f->outBuf[f->outSize++]=ch;
  849   if (ch!='\n' && ch!='\b') ++f->outPos;
  850   FS_errmsg=(const char*)0;
  851   return 0;
  852 }
  853 /*}}}*/
  854 int FS_putChars(int dev, const char *chars) /*{{{*/
  855 {
  856   while (*chars) if (FS_putChar(dev,*chars++)==-1) return -1;
  857   return 0;
  858 }
  859 /*}}}*/
  860 int FS_putString(int dev, const struct String *s) /*{{{*/
  861 {
  862   size_t len=s->length;
  863   const char *c=s->character;
  864 
  865   while (len) if (FS_putChar(dev,*c++)==-1) return -1; else --len;
  866   return 0;
  867 }
  868 /*}}}*/
  869 int FS_putItem(int dev, const struct String *s) /*{{{*/
  870 {
  871   struct FileStream *f;
  872 
  873   if (opened(dev,0)==-1) return -1;
  874   f=file[dev];
  875   if (f->outPos && f->outLineWidth && f->outPos+s->length>f->outLineWidth) FS_nextline(dev);
  876   return FS_putString(dev, s);
  877 }
  878 /*}}}*/
  879 int FS_putbinaryString(int chn, const struct String *s) /*{{{*/
  880 {
  881   if (opened(chn,3)==-1) return -1;
  882   if (s->length && write(file[chn]->binaryfd,s->character,s->length)!=s->length)
  883   {
  884     FS_errmsg=strerror(errno);
  885     return -1;
  886   }
  887   return 0;
  888 }
  889 /*}}}*/
  890 int FS_putbinaryInteger(int chn, long int x) /*{{{*/
  891 {
  892   char s[sizeof(long int)];
  893   int i;
  894 
  895   if (opened(chn,3)==-1) return -1;
  896   for (i=0; i<sizeof(x); ++i,x>>=8) s[i]=(x&0xff);
  897   if (write(file[chn]->binaryfd,s,sizeof(s))!=sizeof(s))
  898   {
  899     FS_errmsg=strerror(errno);
  900     return -1;
  901   }
  902   return 0;
  903 }
  904 /*}}}*/
  905 int FS_putbinaryReal(int chn, double x) /*{{{*/
  906 {
  907   if (opened(chn,3)==-1) return -1;
  908   if (write(file[chn]->binaryfd,&x,sizeof(x))!=sizeof(x))
  909   {
  910     FS_errmsg=strerror(errno);
  911     return -1;
  912   }
  913   return 0;
  914 }
  915 /*}}}*/
  916 int FS_getbinaryString(int chn, struct String *s) /*{{{*/
  917 {
  918   ssize_t len;
  919 
  920   if (opened(chn,3)==-1) return -1;
  921   if (s->length && (len=read(file[chn]->binaryfd,s->character,s->length))!=s->length)
  922   {
  923     if (len==-1) FS_errmsg=strerror(errno);
  924     else FS_errmsg=_("End of file");
  925     return -1;
  926   }
  927   return 0;
  928 }
  929 /*}}}*/
  930 int FS_getbinaryInteger(int chn, long int *x) /*{{{*/
  931 {
  932   char s[sizeof(long int)];
  933   int i;
  934   ssize_t len;
  935 
  936   if (opened(chn,3)==-1) return -1;
  937   if ((len=read(file[chn]->binaryfd,s,sizeof(s)))!=sizeof(s))
  938   {
  939     if (len==-1) FS_errmsg=strerror(errno);
  940     else FS_errmsg=_("End of file");
  941     return -1;
  942   }
  943   *x=(s[sizeof(x)-1]<0) ? -1 : 0;
  944   for (i=sizeof(s)-1; i>=0; --i) *x=(*x<<8)|(s[i]&0xff);
  945   return 0;
  946 }
  947 /*}}}*/
  948 int FS_getbinaryReal(int chn, double *x) /*{{{*/
  949 {
  950   ssize_t len;
  951 
  952   if (opened(chn,3)==-1) return -1;
  953   if ((len=read(file[chn]->binaryfd,x,sizeof(*x)))!=sizeof(*x))
  954   {
  955     if (len==-1) FS_errmsg=strerror(errno);
  956     else FS_errmsg=_("End of file");
  957     return -1;
  958   }
  959   return 0;
  960 }
  961 /*}}}*/
  962 int FS_nextcol(int dev) /*{{{*/
  963 {
  964   struct FileStream *f;
  965 
  966   if (opened(dev,0)==-1) return -1;
  967   f=file[dev];
  968   if
  969   (
  970     f->outPos%f->outColWidth
  971     && f->outLineWidth
  972     && ((f->outPos/f->outColWidth+2)*f->outColWidth)>f->outLineWidth
  973   )
  974   {
  975     return FS_putChar(dev,'\n');
  976   }
  977   if (!(f->outPos%f->outColWidth) && FS_putChar(dev,' ')==-1) return -1;
  978   while (f->outPos%f->outColWidth) if (FS_putChar(dev,' ')==-1) return -1;
  979   return 0;
  980 }
  981 /*}}}*/
  982 int FS_nextline(int dev) /*{{{*/
  983 {
  984   struct FileStream *f;
  985 
  986   if (opened(dev,0)==-1) return -1;
  987   f=file[dev];
  988   if
  989   (
  990     f->outPos
  991     && FS_putChar(dev,'\n')==-1
  992   ) return -1;
  993   return 0;
  994 }
  995 /*}}}*/
  996 int FS_tab(int dev, int position) /*{{{*/
  997 {
  998   struct FileStream *f=file[dev];
  999 
 1000   if (f->outLineWidth && position>=f->outLineWidth) position=f->outLineWidth-1;
 1001   while (f->outPos<(position-1)) if (FS_putChar(dev,' ')==-1) return -1;
 1002   return 0;
 1003 }
 1004 /*}}}*/
 1005 int FS_width(int dev, int width) /*{{{*/
 1006 {
 1007   if (opened(dev,0)==-1) return -1;
 1008   if (width<0)
 1009   {
 1010     FS_errmsg=_("negative width");
 1011     return -1;
 1012   }
 1013   file[dev]->outLineWidth=width;
 1014   return 0;
 1015 }
 1016 /*}}}*/
 1017 int FS_zone(int dev, int zone) /*{{{*/
 1018 {
 1019   if (opened(dev,0)==-1) return -1;
 1020   if (zone<=0)
 1021   {
 1022     FS_errmsg=_("non-positive zone width");
 1023     return -1;
 1024   }
 1025   file[dev]->outColWidth=zone;
 1026   return 0;
 1027 }
 1028 /*}}}*/
 1029 int FS_cls(int chn) /*{{{*/
 1030 {
 1031   struct FileStream *f;
 1032 
 1033   if (opened(chn,0)==-1) return -1;
 1034   f=file[chn];
 1035   if (!f->tty)
 1036   {
 1037     FS_errmsg=_("not a terminal");
 1038     return -1;
 1039   }
 1040   if (cls(chn)==-1) return -1;
 1041   if (FS_flush(chn)==-1) return -1;
 1042   f->outPos=0;
 1043   return 0;
 1044 }
 1045 /*}}}*/
 1046 int FS_locate(int chn, int line, int column) /*{{{*/
 1047 {
 1048   struct FileStream *f;
 1049 
 1050   if (opened(chn,0)==-1) return -1;
 1051   f=file[chn];
 1052   if (!f->tty)
 1053   {
 1054     FS_errmsg=_("not a terminal");
 1055     return -1;
 1056   }
 1057   if (locate(chn,line,column)==-1) return -1;
 1058   if (FS_flush(chn)==-1) return -1;
 1059   f->outPos=column-1;
 1060   return 0;
 1061 }
 1062 /*}}}*/
 1063 int FS_colour(int chn, int foreground, int background) /*{{{*/
 1064 {
 1065   struct FileStream *f;
 1066 
 1067   if (opened(chn,0)==-1) return -1;
 1068   f=file[chn];
 1069   if (!f->tty)
 1070   {
 1071     FS_errmsg=_("not a terminal");
 1072     return -1;
 1073   }
 1074   if (colour(chn,foreground,background)==-1) return -1;
 1075   f->outforeground=foreground;
 1076   f->outbackground=background;
 1077   return 0;
 1078 }
 1079 /*}}}*/
 1080 int FS_getChar(int dev) /*{{{*/
 1081 {
 1082   struct FileStream *f;
 1083 
 1084   if (opened(dev,1)==-1) return -1;
 1085   f=file[dev];
 1086   if (f->inSize==f->inCapacity && refill(dev)==-1) return -1;
 1087   FS_errmsg=(const char*)0;
 1088   if (f->inSize+1==f->inCapacity)
 1089   {
 1090     char ch=f->inBuf[f->inSize];
 1091 
 1092     f->inSize=f->inCapacity=0;
 1093     return ch;
 1094   }
 1095   else return f->inBuf[f->inSize++];
 1096 }
 1097 /*}}}*/
 1098 int FS_get(int chn) /*{{{*/
 1099 {
 1100   ssize_t offset,rd;
 1101 
 1102   if (opened(chn,2)==-1) return -1;
 1103   offset=0;
 1104   while (offset<file[chn]->recLength)
 1105   {
 1106     rd=read(file[chn]->randomfd,file[chn]->recBuf+offset,file[chn]->recLength-offset);
 1107     if (rd==-1)
 1108     {
 1109       FS_errmsg=strerror(errno);
 1110       return -1;
 1111     }
 1112     else offset+=rd;
 1113   }
 1114   FS_errmsg=(const char*)0;
 1115   return 0;
 1116 }
 1117 /*}}}*/
 1118 int FS_inkeyChar(int dev, int ms) /*{{{*/
 1119 {
 1120   struct FileStream *f;
 1121   char c;
 1122   ssize_t len;
 1123 #ifdef USE_SELECT
 1124   fd_set just_infd;
 1125   struct timeval timeout;
 1126 #else
 1127   struct termios timedread;
 1128 #endif
 1129 
 1130   if (opened(dev,1)==-1) return -1;
 1131   f=file[dev];
 1132   if (f->inSize<f->inCapacity) return f->inBuf[f->inSize++];
 1133 
 1134 #ifdef USE_SELECT
 1135   FD_ZERO(&just_infd);
 1136   FD_SET(f->infd,&just_infd);
 1137   timeout.tv_sec=ms/1000;
 1138   timeout.tv_usec=(ms%1000)*1000;
 1139   switch (select(f->infd+1,&just_infd,(fd_set*)0,(fd_set*)0,&timeout))
 1140   {
 1141     case 1:
 1142     {
 1143       FS_errmsg=(const char*)0;
 1144       len=read(f->infd,&c,1);
 1145       return (len==1?c:-1);
 1146     }
 1147     case 0:
 1148     {
 1149       FS_errmsg=(const char*)0;
 1150       return -1;
 1151     }
 1152     case -1:
 1153     {
 1154       FS_errmsg=strerror(errno);
 1155       return -1;
 1156     }
 1157     default: assert(0);
 1158   }
 1159   return 0;
 1160 #else
 1161   timedread=rawMode;
 1162   timedread.c_cc[VMIN]=0;
 1163   timedread.c_cc[VTIME]=(ms?ms:100)/100;
 1164   if (tcsetattr(f->infd,TCSADRAIN,&timedread)==-1)
 1165   {
 1166     FS_errmsg=strerror(errno);
 1167     return -1;
 1168   }
 1169   FS_errmsg=(const char*)0;
 1170   len=read(f->infd,&c,1);
 1171   tcsetattr(f->infd,TCSADRAIN,&rawMode);
 1172   if (len==-1)
 1173   {
 1174     FS_errmsg=strerror(errno);
 1175     return -1;
 1176   }
 1177   return (len==1?c:-1);
 1178 #endif
 1179 }
 1180 /*}}}*/
 1181 void FS_sleep(double s) /*{{{*/
 1182 {
 1183 #ifdef HAVE_NANOSLEEP
 1184   struct timespec p;
 1185 
 1186   p.tv_sec=floor(s);
 1187   p.tv_nsec=1000000000*(s-floor(s));
 1188 
 1189   nanosleep(&p,(struct timespec*)0);
 1190 #else
 1191   sleep((int)s);
 1192 #endif
 1193 }
 1194 /*}}}*/
 1195 int FS_eof(int chn) /*{{{*/
 1196 {
 1197   struct FileStream *f;
 1198 
 1199   if (opened(chn,1)==-1) return -1;
 1200   f=file[chn];
 1201   if (f->inSize==f->inCapacity && refill(chn)==-1) return 1;
 1202   return 0;
 1203 }
 1204 /*}}}*/
 1205 long int FS_loc(int chn) /*{{{*/
 1206 {
 1207   int fd;
 1208   off_t cur,offset=0;
 1209 
 1210   if (opened(chn,-1)==-1) return -1;
 1211   if (file[chn]->infd!=-1) { fd=file[chn]->infd; offset=-file[chn]->inCapacity+file[chn]->inSize; }
 1212   else if (file[chn]->outfd!=-1) { fd=file[chn]->outfd; offset=file[chn]->outSize; }
 1213   else if (file[chn]->randomfd!=-1) fd=file[chn]->randomfd;
 1214   else fd=file[chn]->binaryfd;
 1215   assert(fd!=-1);
 1216   if ((cur=lseek(fd,0,SEEK_CUR))==-1)
 1217   {
 1218     FS_errmsg=strerror(errno);
 1219     return -1;
 1220   }
 1221   return (cur+offset)/file[chn]->recLength;
 1222 }
 1223 /*}}}*/
 1224 long int FS_lof(int chn) /*{{{*/
 1225 {
 1226   struct stat buf;
 1227   int fd;
 1228 
 1229   if (opened(chn,-1)==-1) return -1;
 1230   if (file[chn]->infd!=-1) fd=file[chn]->infd;
 1231   else if (file[chn]->outfd!=-1) fd=file[chn]->outfd;
 1232   else if (file[chn]->randomfd!=-1) fd=file[chn]->randomfd;
 1233   else fd=file[chn]->binaryfd;
 1234   assert(fd!=-1);
 1235   if (fstat(fd,&buf)==-1)
 1236   {
 1237     FS_errmsg=strerror(errno);
 1238     return -1;
 1239   }
 1240   return buf.st_size/file[chn]->recLength;
 1241 }
 1242 /*}}}*/
 1243 long int FS_recLength(int chn) /*{{{*/
 1244 {
 1245   if (opened(chn,2)==-1) return -1;
 1246   return file[chn]->recLength;
 1247 }
 1248 /*}}}*/
 1249 void FS_field(int chn, struct String *s, long int position, long int length) /*{{{*/
 1250 {
 1251   assert(file[chn]);
 1252   String_joinField(s,&file[chn]->field,file[chn]->recBuf+position,length);
 1253 }
 1254 /*}}}*/
 1255 int FS_seek(int chn, long int record) /*{{{*/
 1256 {
 1257   if (opened(chn,2)!=-1)
 1258   {
 1259     if (lseek(file[chn]->randomfd,(off_t)record*file[chn]->recLength,SEEK_SET)!=-1) return 0;
 1260     FS_errmsg=strerror(errno);
 1261   }
 1262   else if (opened(chn,4)!=-1)
 1263   {
 1264     if (lseek(file[chn]->binaryfd,(off_t)record,SEEK_SET)!=-1) return 0;
 1265     FS_errmsg=strerror(errno);
 1266   }
 1267   return -1;
 1268 }
 1269 /*}}}*/
 1270 int FS_appendToString(int chn, struct String *s, int output_nl) /*{{{*/
 1271 {
 1272   size_t new;
 1273   char *n;
 1274   struct FileStream *f=file[chn];
 1275   int c;
 1276 
 1277   if (f->tty && f->inSize==f->inCapacity)
 1278   {
 1279     if (edit(chn,output_nl)==-1) return (FS_errmsg ? -1 : 0);
 1280   }
 1281   do
 1282   {
 1283     n=f->inBuf+f->inSize;
 1284     while (1)
 1285     {
 1286       if (n==f->inBuf+f->inCapacity) break;
 1287       c=*n++;
 1288       if (c=='\n') break;
 1289     }
 1290     new=n-(f->inBuf+f->inSize);
 1291     if (new)
 1292     {
 1293       size_t offset=s->length;
 1294 
 1295       if (String_size(s,offset+new)==-1)
 1296       {
 1297         FS_errmsg=strerror(errno);
 1298         return -1;
 1299       }
 1300       memcpy(s->character+offset,f->inBuf+f->inSize,new);
 1301       f->inSize+=new;
 1302       if (*(n-1)=='\n')
 1303       {
 1304         if (f->inSize==f->inCapacity) f->inSize=f->inCapacity=0;
 1305         if (s->length>=2 && s->character[s->length-2]=='\r')
 1306         {
 1307           s->character[s->length-2]='\n';
 1308           --s->length;
 1309         }
 1310         return 0;
 1311       }
 1312     }
 1313     if ((c=FS_getChar(chn))>=0) String_appendChar(s,c);
 1314     if (c=='\n')
 1315     {
 1316       if (s->length>=2 && s->character[s->length-2]=='\r')
 1317       {
 1318         s->character[s->length-2]='\n';
 1319         --s->length;
 1320       }
 1321       return 0;
 1322     }
 1323   } while (c!=-1);
 1324   return (FS_errmsg ? -1 : 0);
 1325 }
 1326 /*}}}*/
 1327 void FS_closefiles(void) /*{{{*/
 1328 {
 1329   int i;
 1330 
 1331   for (i=0; i<capacity; ++i) if (file[i] && !file[i]->dev) FS_close(i);
 1332 }
 1333 /*}}}*/
 1334 int FS_charpos(int chn) /*{{{*/
 1335 {
 1336   if (file[chn]==(struct FileStream*)0)
 1337   {
 1338     FS_errmsg=_("channel not open");
 1339     return -1;
 1340   }
 1341   return (file[chn]->outPos);
 1342 }
 1343 /*}}}*/
 1344 int FS_copy(const char *from, const char *to) /*{{{*/
 1345 {
 1346   int infd,outfd;
 1347   char buf[4096];
 1348   ssize_t inlen,outlen=-1;
 1349 
 1350   if ((infd=open(from,O_RDONLY))==-1)
 1351   {
 1352     FS_errmsg=strerror(errno);
 1353     return -1;
 1354   }
 1355   if ((outfd=open(to,O_WRONLY|O_CREAT|O_TRUNC,0666))==-1)
 1356   {
 1357     FS_errmsg=strerror(errno);
 1358     return -1;
 1359   }
 1360   while ((inlen=read(infd,&buf,sizeof(buf)))>0)
 1361   {
 1362     ssize_t off=0;
 1363 
 1364     while (inlen && (outlen=write(outfd,&buf+off,inlen))>0)
 1365     {
 1366       off+=outlen;
 1367       inlen-=outlen;
 1368     }
 1369     if (outlen==-1)
 1370     {
 1371       FS_errmsg=strerror(errno);
 1372       close(infd);
 1373       close(outfd);
 1374       return -1;
 1375     }
 1376   }
 1377   if (inlen==-1)
 1378   {
 1379     FS_errmsg=strerror(errno);
 1380     close(infd);
 1381     close(outfd);
 1382     return -1;
 1383   }
 1384   if (close(infd)==-1)
 1385   {
 1386     FS_errmsg=strerror(errno);
 1387     close(outfd);
 1388     return -1;
 1389   }
 1390   if (close(outfd)==-1)
 1391   {
 1392     FS_errmsg=strerror(errno);
 1393     return -1;
 1394   }
 1395   return 0;
 1396 }
 1397 /*}}}*/
 1398 int FS_portInput(int address) /*{{{*/
 1399 {
 1400   FS_errmsg=_("Direct port access not available");
 1401   return -1;
 1402 }
 1403 /*}}}*/
 1404 int FS_memInput(int address) /*{{{*/
 1405 {
 1406   FS_errmsg=_("Direct memory access not available");
 1407   return -1;
 1408 }
 1409 /*}}}*/
 1410 int FS_portOutput(int address, int value) /*{{{*/
 1411 {
 1412   FS_errmsg=_("Direct port access not available");
 1413   return -1;
 1414 }
 1415 /*}}}*/
 1416 int FS_memOutput(int address, int value) /*{{{*/
 1417 {
 1418   FS_errmsg=_("Direct memory access not available");
 1419   return -1;
 1420 }
 1421 /*}}}*/
 1422 void FS_allowIntr(int on) /*{{{*/
 1423 {
 1424   struct sigaction breakact;
 1425 
 1426   breakact.sa_handler=on ? sigintr : SIG_IGN;
 1427   sigemptyset(&breakact.sa_mask);
 1428   sigaddset(&breakact.sa_mask,SIGINT);
 1429   breakact.sa_flags=0;
 1430   sigaction(SIGINT,&breakact,(struct sigaction *)0);
 1431 }
 1432 /*}}}*/