"Fossies" - the Fresh Open Source Software Archive

Member "alec64-1.13/src/1541.c" (27 Sep 1996, 76413 Bytes) of package /linux/misc/old/alec64-1.13.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.

    1 /*
    2  *  The C64 emulator
    3  *
    4  *  Copyright 1992-96 by ALE.
    5  *  written by Andreas Arens.
    6  *
    7  *  DOS 2.6 single drive file io emulation
    8  *------------------------------------------------------------------------------
    9  * $Id: 1541.c,v 1.23 1996/09/27 23:40:07 ari Exp root $
   10  * $Log: 1541.c,v $
   11  * Revision 1.23  1996/09/27 23:40:07  ari
   12  * Support for filenames starting with '@'. Formating D64 added.
   13  *
   14  * Revision 1.22  1996/08/12 01:10:31  ari
   15  * Write protect and block-write support added.
   16  *
   17  * Revision 1.21  1996/07/06 22:54:31  ari
   18  * Moved structures into own headerfile, D64 block-write support.
   19  *
   20  * Revision 1.20  1996/07/05 01:40:28  ari
   21  * Much rewritten, more D64 support.
   22  *
   23  * Revision 1.19  1996/06/20 21:01:23  ari
   24  * started implement D64 support, Changed IEC_STATUS.
   25  *
   26  * Revision 1.18  1996/06/16 17:09:35  ari
   27  * Full x00 support, bug fixes.
   28  *
   29  * Revision 1.17  1995/06/01  12:07:28  ari
   30  * fixed treatment of channel 0 and 1 for non-prog files
   31  *
   32  * Revision 1.16  1995/05/03  21:22:17  ari
   33  * allowed explict types on channel 0 and 1
   34  *
   35  * Revision 1.15  1995/02/13  11:27:22  ari
   36  * second linux port ( by ari ) integration
   37  *
   38  * Revision 1.14  1994/07/16  13:58:42  ari
   39  * new go32: avoid duplicate define.
   40  *
   41  * Revision 1.13  1993/12/30  11:48:12  ari
   42  * go32 changes
   43  *
   44  * Revision 1.12  1993/09/17  11:28:20  ari
   45  * full file type support for non-dirfile unix filesystems
   46  *
   47  * Revision 1.11  1993/09/07  21:41:25  ari
   48  * fixed rename, added multifile scratch with ',', added copy
   49  *
   50  * Revision 1.10  1993/09/04  14:25:42  ari
   51  * support for dirfiles ( required for msdos )
   52  *
   53  * Revision 1.9  1993/08/31  20:30:03  ari
   54  * go32 initial support
   55  *
   56  * Revision 1.8  1993/06/13  11:52:59  ari
   57  * enhanced filename processing, unique printfile name generation
   58  *
   59  * Revision 1.7  1993/05/08  21:46:37  ari
   60  * implemented scratch
   61  *
   62  * Revision 1.6  1993/01/05  12:41:24  ari
   63  * added SCCS string
   64  *
   65  * Revision 1.4  1992/07/28  19:43:33  ari
   66  * Warnings removed.
   67  *
   68  * Revision 1.3  1992/07/20  04:15:46  ari
   69  * Unused variables removed.
   70  *
   71  * Revision 1.2  1992/07/13  04:36:26  ari
   72  * IEC-OPEN "*" added.
   73  *
   74  * Revision 1.1  1992/07/11  21:52:24  ari
   75  * Initial revision
   76  *
   77  *------------------------------------------------------------------------------
   78  */
   79 
   80 #include "config.h"
   81 #include "md.h"
   82 
   83 #include <fcntl.h>
   84 #include <sys/types.h>
   85 #include <sys/stat.h>
   86 #ifndef __GO32__
   87 #   if defined(SPARC) || defined(__linux__)
   88 #   include <sys/vfs.h>
   89 #   else
   90 #   include <sys/statfs.h>
   91 #   endif
   92 #   include <sys/utsname.h>
   93 #else
   94 #   include <sys/file.h>
   95 #   ifndef S_ISREG
   96 #   define S_ISREG(x) (x & S_IFREG)
   97 #   endif
   98 #   define S_ISUID  1
   99 #   define S_ISGID  2
  100 #   include <dos.h>
  101 #endif
  102 #include <dirent.h>
  103 #include <stdio.h>
  104 #include <string.h>
  105 #include <stdlib.h>
  106 #include <unistd.h>
  107 
  108 #include "1541.h"
  109 
  110 /*----------------------------------------------------------------------------*/
  111 
  112 #define noDEBUG_BLOCK_CMDS
  113 
  114 /*----------------------------------------------------------------------------*/
  115 
  116 static struct c4entry * c4dhook = NULL;
  117 static int nc4d = 0;
  118 static int dirgetidx = -1;
  119 static int findfileidx = -1;
  120 static char dirgetbuf[32];
  121 static int dirisopen = 0;
  122 static int dirlen;
  123 static int dirpos;
  124 static int dirnmatch = 0;
  125 static char dirmatch[32];
  126 static char dirintro[] = "\001\010\001\001\000\000\022\"";
  127             /*      ^-- 004, but helps ,8,1 kernel */
  128 
  129 #ifdef DIRFILE
  130 static int nc4wr = 0;
  131 static struct c4entry c4wrhook[16];
  132 static char dirfilebuf[256];
  133 #endif
  134 
  135 char *FloppyImage = NULL;
  136 int ImageRO = 0;
  137 
  138 static int ImageFD = -1;
  139 static unsigned char *ImageData = NULL;
  140 static unsigned char *ImageErrInfo;
  141 static int ImageDataSize = 0;
  142 static unsigned char ImageFlags[802];
  143 static int d64_has_errinfo = 0;
  144 static int d64_tracks = 0;
  145 static struct BAM *d64_BAM;
  146 
  147 static int emu_mode = 0;
  148 int IEC_Status;             /* status of last TALK,LISTEN,... */
  149 
  150 #define IEC_SetStatus(x)    (IEC_Status = x) 
  151 
  152 void Init_IECDos();
  153 
  154 #ifdef PRINTER_SUPPORT
  155 void ClosePrinter();
  156 static char PrintFile[32];
  157 static int printer_unit;
  158 static int printer_cmd;
  159 static int printer_open = 0;
  160 static int printer_fd;
  161 char *printer_printcmd = DEF_PRINTCMD;
  162 #endif
  163 
  164 static int globflags;       /* bus flags */
  165 static int aktunit;     /* c64 */
  166 
  167 #ifndef __GO32__
  168 static mode_t UMask;
  169 #endif
  170 
  171 static int unit;
  172 static int channel;
  173 static char filenamebuf[NCHAN][64];    /* buffer for filenames */
  174 static int filenamelen[NCHAN];
  175 static char unixname[NCHAN][32];
  176 static long filelen[NCHAN];
  177 static long filepos[NCHAN];
  178 static int chfd[NCHAN];
  179 static int fmod[NCHAN];
  180 static int flags[NCHAN];
  181 static char chanbuf[NCHAN][256];
  182 static int chanbufp[NCHAN];
  183 static long chanpos[NCHAN];
  184 static int errorcode;
  185 static int errortrack;
  186 static int errorsector;
  187 char errorbuf[64];
  188 
  189 static int ftype;
  190 static int typemode;           /* after '=' */
  191 static int openmode;
  192 static int overwrite;          /* starts with '@' */
  193 static int dir;                /* starts with '$' */
  194 static int chanopen;
  195 static char nbuf[34];
  196 static struct pc64entry pc64header;
  197 
  198 #ifdef __GO32__
  199 static char *emulver = "@(#) ALE DOSEMUL V1.9.5 MSDOS";
  200 #else
  201 static char *emulver = "@(#) ALE DOSEMUL V1.9.5 UNIX";
  202 #endif
  203 static char *errors[] = {
  204     "OK",
  205     "FILES SCRATCHED",
  206     "",
  207     "UNIMPLEMENTED FEATURE",
  208     "",
  209     "",
  210     "",
  211     "",
  212     "",
  213     "",
  214     "",
  215     "",
  216     "",
  217     "",
  218     "",
  219     "",
  220     "",
  221     "",
  222     "",
  223     "",
  224     "READ ERROR",
  225     "READ ERROR",
  226     "READ ERROR",
  227     "READ ERROR",
  228     "READ ERROR",
  229     "WRITE ERROR",
  230     "WRITE PROTECT ON",
  231     "READ ERROR",
  232     "WRITE ERROR",
  233     "DISK ID MISMATCH",
  234     "SYNTAX ERROR",
  235     "SYNTAX ERROR",
  236     "SYNTAX ERROR",
  237     "SYNTAX ERROR",
  238     "SYNTAX ERROR",
  239     "",
  240     "",
  241     "",
  242     "",
  243     "FILE NOT FOUND",
  244     "",
  245     "",
  246     "",
  247     "",
  248     "",
  249     "",
  250     "",
  251     "",
  252     "",
  253     "",
  254     "RECORD NOT PRESENT",
  255     "OVERFLOW IN RECORD",
  256     "FILE TO LARGE",
  257     "",
  258     "",
  259     "",
  260     "",
  261     "",
  262     "",
  263     "",
  264     "WRITE FILE OPEN",
  265     "FILE NOT OPEN",
  266     "FILE NOT FOUND",
  267     "FILE EXISTS",
  268     "FILE TYPE MISMATCH",
  269     "NO BLOCK",
  270     "ILLEGAL TRACK OR SECTOR",
  271     "ILLEGAL SYSTEM T OR S",
  272     "",
  273     "",
  274     "NO CHANNEL",
  275     "DIR ERROR",
  276     "DISK FULL",
  277     "",
  278     "DRIVE NOT READY",
  279     "FORMAT SPEED ERROR"
  280 };
  281 
  282 static int ZBR_ns[43] = {
  283      0,
  284     21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
  285     19, 19, 19, 19, 19, 19, 19,
  286     18, 18, 18, 18, 18, 18,
  287     17, 17, 17, 17, 17,
  288     17, 17, 17, 17, 17, 17, 17
  289 };
  290 
  291 static int ZBR_st[43] = {
  292       0,
  293       0,  21,  42,  63,  84, 105, 126, 147, 168, 189, 210, 231, 252, 273, 294, 315, 336,
  294     357, 376, 395, 414, 433, 452, 471,
  295     490, 508, 526, 544, 562, 580,
  296     598, 615, 632, 649, 666,
  297     683, 700, 717, 734, 751, 768, 785
  298 };
  299 
  300 static int D64EIMap[] = {
  301      0,
  302      0, /*  1: OK */
  303     20, /*  2: block header not found */
  304     21, /*  3: sync not found */
  305     22, /*  4: data block not found */
  306     23, /*  5: data checksum error */
  307      0, /*  6: unused */
  308     25, /*  7: verify failed */
  309     26, /*  8: write protect on */
  310     27, /*  9: header checksum error */
  311      0, /* 10: unused */
  312     29, /* 11: ID mismatch */
  313      0, /* 12: unused */
  314      0, /* 13: unused */
  315      0, /* 14: unused */
  316     74, /* 15: drive not ready (or present!) */
  317 };
  318 
  319 static int ErrInfo2Error(int ei) {
  320     return D64EIMap[ei & 15];
  321 }
  322 
  323 /*
  324  *  Print an unimplemented command.
  325  */
  326 static void NotImplemented(CONST unsigned char* cmd)
  327 {
  328 #ifndef __GO32__
  329     printf("1541: not implemented '");
  330     while (*cmd) {
  331     if (' ' <= *cmd && *cmd < 127)
  332         printf("%c", *cmd);
  333     else
  334         printf("\\%02x", *cmd);
  335     ++cmd;
  336     }
  337     printf("'\n");
  338 #endif
  339 }
  340 
  341 #ifdef __GO32__
  342 int freeblks(char *n)
  343 {
  344     union REGS in, out;
  345     unsigned long bytes = 0;
  346 
  347     memset(&in, 0, sizeof(in));
  348     in.h.ah = 0x36;
  349     intdos(&in, &out);
  350     if (out.x.ax != 0xffff)
  351     bytes = out.x.bx * out.x.ax * out.x.cx;
  352     return (int)(bytes / 254);
  353 }
  354 
  355 char *systemname(void)
  356 {
  357     return "dos";
  358 }
  359 
  360 #else
  361 
  362 int freeblks(char *n)
  363 {
  364     struct statfs sfs;
  365 
  366 #ifdef __linux__
  367     if (!statfs(n,&sfs))
  368     return sfs.f_bsize * sfs.f_bavail / 256;
  369 #else
  370     if (!statfs(n,&sfs,sizeof(sfs),0)) {
  371     /* sfs.f_bsize is correctly set to 1024, but
  372        sfs.f_bfree returns the number of free 512 byte blocks... */
  373     return sfs.f_bfree * 512 / 254;
  374     }
  375 #endif
  376     return 0;
  377 }
  378 
  379 char *systemname(void)
  380 {
  381     static struct utsname uts;
  382 
  383     if (uname(&uts) == -1)
  384     strcpy(uts.sysname,"unix");
  385     return uts.sysname;
  386 }
  387 #endif
  388 
  389 static char asctocbm(unsigned char c)
  390 {
  391     if (c >= 'a' && c <= 'z')
  392     return c & ~0x20;
  393     if (c >= 'A' && c <= 'Z')
  394     return c | 0x80;
  395     return c;
  396 }
  397 
  398 static char cbmtoasc(unsigned char c)
  399 {
  400     if (c >= ('A' | 0x80) && c <= ('Z' | 0x80))
  401     return c & 0x7f;
  402     if (c >= 'A' && c <= 'Z')
  403     return c | 0x20;
  404     return c;
  405 }
  406 
  407 static char *strcbm2asc(char *s)
  408 {
  409     char *s2 = s;
  410 
  411     while (*s2)
  412     *s2++ = cbmtoasc(*s2);
  413     return s;
  414 }
  415 
  416 static char *strasc2cbm(char *s)
  417 {
  418     char *s2 = s;
  419 
  420     while (*s2)
  421     *s2++ = asctocbm(*s2);
  422     return s;
  423 }
  424 
  425 
  426 #ifdef ALWAYS_SAVE_P00
  427 /*
  428  *  Convert CBM name to P00 name.
  429  *  (16 character C64 character set to 8 characters limited ASCII set).
  430  *  by johns
  431  */
  432 static char *cbm2P00name(const char *cbm)
  433 {
  434     static char p00[16];
  435     char buf[16];
  436     char *dst;
  437     int i, l;
  438     unsigned char uc;
  439 
  440     dst = buf;
  441     /*
  442     **  1) Convert to lowercase, underscore and numbers only.
  443     */
  444     do {
  445     switch (*cbm) {
  446         case '\0':
  447         break;
  448         case 'a' ... 'z':
  449         case '0' ... '9':       /* lowercase and numbers ok */
  450         *dst++ = *cbm++;
  451         break;
  452         case 'A' ... 'Z':       /* uppercase -> lowercase */
  453         *dst++ = *cbm++ + ' ';
  454         break;
  455         case '-':
  456         case ' ':           /* spaces -> underscore */
  457         *dst++ = '_';
  458         /* fall through */
  459         default:
  460             cbm++;
  461         break;
  462     }
  463     } while (*cbm);
  464 
  465     l = dst - buf;
  466     if (l > 8) {
  467     /*
  468      *  2) Reduce to 8 characters. (remove from end)
  469      */
  470     memset(buf + l, 0, 16 - l);
  471 
  472     /*
  473      *  2a) Remove whitspace.
  474      */
  475     for (i = 15; i >= 0 && l > 8; --i) {
  476         if (buf[i] == '_') {
  477         buf[i] = '\0';
  478         --l;
  479         }
  480     }
  481     
  482     /*
  483      *  2b) Remove vocals.
  484      */
  485     for (i = 15; i >= 0 && l > 8; --i) {
  486         uc = (unsigned char)buf[i] & (unsigned char)0xDF;
  487         if (uc == 'a' || uc == 'e' || uc == 'i' || uc == 'o' || uc == 'u') {
  488         buf[i] = '\0';
  489         --l;
  490         }
  491     }
  492     
  493     /*
  494      *  2c) Remove characters.
  495      */
  496     for (i = 15; i >= 0 && l > 8; --i) {
  497         if ((buf[i] >= 'a' && buf[i] <= 'z') || (buf[i] >= 'A' && buf[i] <= 'Z')) {
  498         buf[i] = '\0';
  499         --l;
  500         }
  501     }
  502 
  503     /*
  504      *  2d) Remove digits.
  505      */
  506     for (i = 15; i >= 0 && l > 8; --i) {
  507         if (buf[i] >= '0' && buf[i] <= '9') {
  508         buf[i] = '\0';
  509         --l;
  510         }
  511     }
  512 
  513     /*
  514      *  2e) Pack the name.
  515      */
  516     dst = buf;
  517     for (i = 0; i < 16; ++i) {
  518         if (buf[i])
  519         *dst++ = buf[i];
  520     }
  521     if (dst - buf != l) {
  522         Cleanup();
  523         abort();
  524     }
  525     }
  526     if (l == 0) {
  527     /*
  528      *  Empty name.
  529      */
  530     p00[0] = '_';
  531     p00[1] = '\0';
  532     } else {
  533     memcpy(p00, buf, l);
  534     p00[l] = '\0';
  535     }
  536     return p00;
  537 }
  538 
  539 static char *MakeP00(char *nam)
  540 {
  541     char *cp, *cp2;
  542 
  543     cp = cbm2P00name(nam);
  544     cp2 = cp + strlen(cp);
  545     *cp2++ = '.';
  546     *cp2++ = (unsigned char)ftype | (unsigned char)0x20;
  547     strcpy(cp2, "00");
  548     while (access(cp, 0) != -1) {
  549     cp2[1]++;
  550     if (cp2[1] == '9' + 1) {
  551         cp2[1] = '0';
  552         cp2[0]++;
  553     }
  554     }
  555     return cp;
  556 }
  557 #endif
  558 
  559 static void ReWriteImage(void)
  560 {
  561     int i;
  562 
  563     if (ImageRO || ImageFD < 0 || !ImageData)
  564     return;
  565     for (i = 0; i < 802; i++) {
  566     if ((ImageFlags[i] & IF_DIRTY)) {
  567         if (i * 256 < ImageDataSize) {
  568         if (lseek(ImageFD, i * 256, SEEK_SET) >= 0)
  569             write(ImageFD, ImageData + i * 256, 256);
  570         }
  571         ImageFlags[i] &= ~IF_DIRTY;
  572     }
  573     }
  574 }
  575 
  576 static int BAM_alloc(unsigned int track, unsigned int sector)
  577 {
  578     struct BAM_track *trackmap;
  579 
  580     if (--track < 35)   /* no BAM support for tracks behind 35 */
  581     {
  582     trackmap = d64_BAM->bam + track;
  583     if ((trackmap->bitmap[sector >> 3] & ((unsigned char)1 << (sector & 7))) != 0) {
  584         trackmap->bitmap[sector >> 3] &= (unsigned char)~((unsigned char)1 << (sector & 7));
  585         trackmap->freecnt--;
  586         if (!ImageRO)
  587         ImageFlags[ZBR_st[18]] |= IF_DIRTY;
  588         return 1;
  589     }
  590     }
  591     return 0;
  592 }
  593 
  594 static int BAM_free(unsigned int track, unsigned int sector)
  595 {
  596     struct BAM_track *trackmap;
  597 
  598     if (--track < 35)   /* no BAM support for tracks behind 35 */
  599     {
  600     trackmap = d64_BAM->bam + track;
  601     if ((trackmap->bitmap[sector >> 3] & ((unsigned char)1 << (sector & 7))) == 0) {
  602         trackmap->bitmap[sector >> 3] |= (unsigned char)1 << (sector & 7);
  603         trackmap->freecnt++;
  604         if (!ImageRO)
  605         ImageFlags[ZBR_st[18]] |= IF_DIRTY;
  606         return 1;
  607     }
  608     }
  609     return 0;
  610 }
  611 
  612 static int BAM_find_free_sector_on_track(unsigned int track, unsigned int sector)
  613 {
  614     unsigned int shift, i, s;
  615 
  616     shift = 0;
  617     while (shift < 3) {
  618     for (i = 0; i < ZBR_ns[track]; i += 3) {
  619         s = sector + i + shift;
  620         if (s >= ZBR_ns[track])
  621         s -= ZBR_ns[track];
  622         if (BAM_alloc(track, s))
  623         return s;
  624     }
  625     shift++;
  626     }
  627     return -1;
  628 }
  629 
  630 static int BAM_next_free_sector(unsigned int *track, unsigned int *sector)
  631 {
  632     unsigned int t, s = -1;
  633 
  634     t = *track;
  635     if (t == 18) {      /* directory */
  636     s = BAM_find_free_sector_on_track(t, *sector);
  637     if (s == -1) {
  638         *track = 0;
  639         *sector = 0;
  640         return 0;
  641     }
  642     *sector = s;
  643     return 1;
  644     } else if (t < 18) {    /* lower half */
  645     while (t > 0) {
  646         s = BAM_find_free_sector_on_track(t, *sector);
  647         if (s != -1)
  648         break;
  649         *sector = 0;
  650         t--;
  651     }
  652     if (s == -1) {
  653         t = *track + 1;
  654         while (t < 36) {
  655         if (t != 18)    /* FIXME: this is BETTER then original, which CAN return tracks from directory */
  656             s = BAM_find_free_sector_on_track(t, *sector);
  657         if (s != -1)
  658             break;
  659         t++;
  660         }
  661     }
  662     if ( s == -1) {
  663         *track = 0;
  664         *sector = 0;
  665         return 0;
  666     }
  667     *sector = s;
  668     *track = t;
  669     return 1;
  670     } else {
  671     while (t < 36) {
  672         s = BAM_find_free_sector_on_track(t, *sector);
  673         if (s != -1)
  674         break;
  675         *sector = 0;
  676         t++;
  677     }
  678     if (s == -1) {
  679         t = *track - 1;
  680         while (t > 0) {
  681         if (t != 18)    /* FIXME: this is BETTER then original, which CAN return tracks from directory */
  682             s = BAM_find_free_sector_on_track(t, *sector);
  683         if (s != -1)
  684             break;
  685         t--;
  686         }
  687     }
  688     if ( s == -1) {
  689         *track = 0;
  690         return 0;
  691     }
  692     *sector = s;
  693     *track = t;
  694     return 1;
  695     }
  696 }
  697 
  698 /* 
  699  * Returns the absolute sector of of a given track/sector pair
  700  * This asumes standard 2A format ZBR
  701  */
  702 int AbsoluteSector(unsigned int track, unsigned int sector)
  703 {
  704     if (track == 0 || track > d64_tracks || sector >= ZBR_ns[track])
  705     return -1;
  706     return ZBR_st[track] + sector;
  707 }
  708 
  709 /*
  710  * Returns the pointer to a sector
  711  */
  712 unsigned char *SectorPointer(unsigned int track, unsigned int sector)
  713 {
  714     int i;
  715 
  716     i = AbsoluteSector(track, sector);
  717     if (i < 0)
  718     return NULL;
  719     return ImageData + i * 256;
  720 }
  721 
  722 /*
  723  * Returns the error to a sector
  724  */
  725 int SectorError(unsigned int track, unsigned int sector)
  726 {
  727     int i;
  728 
  729     i = AbsoluteSector(track, sector);
  730     if (i < 0)
  731     return 4;           /* NO BLOCK */
  732     if (d64_has_errinfo)
  733     return ImageErrInfo[i];
  734     return 1;
  735 }
  736 
  737 /*
  738  * Handle changed sector
  739  */
  740 void SectorChanged(unsigned int track,unsigned int sector)
  741 {
  742     int i;
  743 
  744     i = AbsoluteSector(track, sector);
  745 
  746     ImageFlags[i] |= IF_DIRTY;
  747     ReWriteImage();
  748 }
  749 
  750 /***** simple_match *****
  751  *
  752  * look for match 'string' 'pattern'
  753  * Pattern may be:  ?       matches a single char
  754  *                  *       matches any number of chars (even 0)
  755  * TRUE: if pattern matches string
  756  * FALSE: if not
  757  */
  758 
  759 int simple_match(char *s, char *p)
  760 {
  761     while (*p)
  762     {
  763     switch (*p)
  764     {
  765         case '?':   if (*s++ == '\0')
  766                 return 0;
  767             p++;
  768             break;
  769 
  770         case '*':   /* next 4 lines only for speed. only p++ necessary */
  771             while (*++p == '*')
  772                 ;
  773             if (*p == '\0')
  774                 return 1;
  775 
  776             while (!simple_match(s, p))
  777                 if (*s++ == '\0')
  778                 return 0;
  779             return 1;
  780 
  781         case '\\':  if (*++p == '\0')
  782                 break;
  783 
  784         default:    if (((unsigned char)*s++ & (unsigned char)0xDF) != ((unsigned char)*p++ & (unsigned char)0xDF))
  785                 return 0;
  786     }
  787     }
  788     return *s ? 0 : 1;
  789 }
  790 
  791 static int stat_2_mode(struct stat *st)
  792 {
  793     mode_t m;
  794     int blks;
  795 
  796     if (S_ISDIR(st->st_mode))
  797     return TYPE_DIR;
  798     blks = (st->st_size + 253) / 254;
  799     if (blks >= 0x10000)
  800     return TYPE_BIG;
  801     if (st->st_mode == S_IFREG)     /* '==', not '&' */
  802     return TYPE_D;
  803     m = st->st_mode & STAT_MASK;
  804     switch (m) {
  805     case STAT_PRG:
  806         return TYPE_P;
  807     case STAT_SEQ:
  808         return TYPE_S;
  809     case STAT_USR:
  810         return TYPE_U;
  811     case STAT_REL:
  812         return TYPE_L;
  813     default:
  814         return TYPE_NOTHING;
  815     }
  816 }
  817 
  818 static int stat_2_lock(struct stat *st)
  819 {
  820     return ((st->st_mode & S_IWUSR) == 0);
  821 }
  822 
  823 static int mode_2_stat(int m)
  824 {
  825     switch (m) {
  826     case TYPE_P:
  827         return STAT_PRG;
  828     case TYPE_S:
  829         return STAT_SEQ;
  830     case TYPE_U:
  831         return STAT_USR;
  832     case TYPE_L:
  833         return STAT_REL;
  834     case TYPE_D:
  835         return -2;
  836     default:
  837         return -1;
  838     }
  839 }
  840 
  841 static int is_pc64(char *name, struct stat *st)
  842 {
  843     int i, typ = TYPE_NOTHING;
  844     char *cp;
  845 
  846     if (S_ISDIR(st->st_mode))
  847     return TYPE_NOTHING;    /* not handled by us.. */
  848     cp = strchr(name,'.');
  849     if (!cp)
  850     return TYPE_NOTHING;
  851     switch((cp[1] & 0xDF)) {
  852     case 'P':
  853         typ = TYPE_P;
  854         break;
  855     case 'S':
  856         typ = TYPE_S;
  857         break;
  858     case 'U':
  859         typ = TYPE_U;
  860         break;
  861     case 'D':
  862         typ = TYPE_D;
  863         break;
  864     case 'L':
  865         typ = TYPE_L;
  866         break;
  867     default:
  868         return TYPE_NOTHING;
  869     }
  870     if (cp[4] || cp[2] < '0' || cp[2] > '9' || cp[3] < '0' || cp[3] > '9')
  871         return TYPE_NOTHING;
  872     i = open(name, O_RDONLY|BINARY_FILE);
  873     if (i == -1)
  874     return TYPE_NOTHING;
  875     if (read(i, &pc64header, sizeof(pc64header)) != sizeof(pc64header)) {
  876     close(i);
  877     return TYPE_NOTHING;
  878     }
  879     close(i);
  880     if (strcmp(pc64header.detect, PC64ID))
  881         return TYPE_NOTHING;
  882     return typ;
  883 }
  884 
  885 #ifdef DIRFILE
  886 static char * nextfreeosname(void)
  887 {
  888     static char osfnbuf[24];
  889     int i;
  890 
  891     for (i=1;;i++)
  892     {
  893     sprintf(osfnbuf, "%08d.c64",i);
  894     if (access(osfnbuf, 0) == -1)
  895         break;
  896     }
  897     return osfnbuf;
  898 }
  899 
  900 static int MakeDirEntry(char *n, int mode)
  901 {
  902     if (nc4wr == 15)
  903     return -1;
  904     switch(mode) {
  905     case TYPE_P:
  906     case TYPE_S:
  907     case TYPE_U:
  908     case TYPE_D:
  909     /* FIXME: TYPE_L */
  910         break;
  911     default:
  912         return -1;
  913     }
  914     c4wrhook[nc4wr].mode = mode;
  915     strcpy(c4wrhook[nc4wr].name, n);
  916     strcpy(c4wrhook[nc4wr].u.osname, nextfreeosname());
  917     nc4wr++;
  918     return nc4wr - 1;
  919 }
  920 
  921 static void DeleteDirEntry(int i)
  922 {
  923     if (i >= 0 && nc4wr > i) {
  924     if (i + 1 == nc4wr)
  925         nc4wr--;
  926     else
  927         c4wrhook[i] = c4wrhook[--nc4wr];
  928     }
  929 }
  930 
  931 static char * getdirfileentry(FILE *fp)
  932 {
  933     int l, i;
  934     char *cp, *strtok();
  935 
  936     for (;;) {
  937     if (fgets(dirfilebuf,256,fp)) {
  938         l = strlen(dirfilebuf);
  939         while (l && (dirfilebuf[l-1] == '\r' || dirfilebuf[l-1] == '\n' || dirfilebuf[l-1] == ' ' || dirfilebuf[l-1] == '\t'))
  940         dirfilebuf[--l] = 0;
  941         if (dirfilebuf[l-1] != '"')
  942         continue;
  943         cp = dirfilebuf;
  944         while (*cp && ( *cp == ' ' || *cp == '\t' ))
  945         cp++;
  946         if (*cp == 0 || *cp == '#' )
  947         continue;
  948         cp = strtok(cp," \t");
  949         if (cp) {
  950         strcpy(dirfilebuf,cp);  /* may copy on itself (usual, worst case) */
  951         i = strlen(dirfilebuf);
  952         cp = strtok(NULL," \t");
  953         if (cp) {
  954             dirfilebuf[i++] = ' ';
  955             strcpy(dirfilebuf+i,cp);
  956             cp = cp + strlen(cp)+1;
  957             while (dirfilebuf+l-1 > cp && *cp != '"')
  958             cp++;
  959             if (dirfilebuf+l-1 == cp)
  960             continue;
  961             cp++;
  962             if (dirfilebuf+l-1 == cp)
  963             continue;
  964             cp[strlen(cp)-1] = 0;
  965             return cp;
  966         } else
  967             continue;
  968         } else
  969         continue;
  970     } else
  971         return NULL;
  972     }
  973 }
  974 
  975 static void rewrite_dir_file()          /* rewrite the directory after write operation */
  976 {
  977     FILE *fp;
  978     int i;
  979     char *cp;
  980 
  981     if (emu_mode == EMU_MODE_DIRFILE) {
  982     fp = fopen(DIRFILENAME, "w");
  983     if (!fp)
  984         return;
  985     for (i = 0; i < nc4d; i++) {
  986         if (c4dhook[i].mode == TYPE_P)
  987         cp = "prg";
  988         else if (c4dhook[i].mode == TYPE_S)
  989         cp = "seq";
  990         else if (c4dhook[i].mode == TYPE_U)
  991         cp = "usr";
  992         else if (c4dhook[i].mode == TYPE_D)
  993         cp = "del";
  994         /* FIXME: TYPE_L */
  995         else
  996         continue;
  997         fprintf(fp, "%s %s \"%s\"\n", c4dhook[i].u.osname, cp, c4dhook[i].name);
  998     }
  999     if (nc4wr) {
 1000         for (i = 0; i < nc4wr; i++) {
 1001         if (c4wrhook[i].mode == TYPE_P)
 1002             cp = "prg";
 1003         else if (c4wrhook[i].mode == TYPE_S)
 1004             cp = "seq";
 1005         else if (c4wrhook[i].mode == TYPE_U)
 1006             cp = "usr";
 1007         else if (c4wrhook[i].mode == TYPE_D)
 1008             cp = "del";
 1009         /* FIXME: TYPE_L */
 1010         else
 1011             continue;
 1012         fprintf(fp, "%s %s \"%s\"\n", c4wrhook[i].u.osname, cp, c4wrhook[i].name);
 1013         }
 1014         nc4wr = 0;
 1015     }
 1016     fclose(fp);
 1017     }
 1018 }
 1019 
 1020 static int read_dir_file(void)
 1021 {
 1022     char *cp;
 1023     FILE *fp;
 1024     int cnt, i;
 1025     struct stat st;
 1026 
 1027     fp = fopen(DIRFILENAME, "r");
 1028     if (fp) {
 1029     emu_mode = EMU_MODE_DIRFILE;
 1030     cnt = 0;
 1031     while (getdirfileentry(fp)) {
 1032         cp = strchr(dirfilebuf, ' ');
 1033         if (!cp)
 1034         continue;
 1035         *cp++ = 0;
 1036         if (stat(dirfilebuf, &st))       /* something illegal.. */
 1037         continue;
 1038         if (!strcmp(cp, "prg"))
 1039         ;
 1040         else if (!strcmp(cp, "seq"))
 1041         ;
 1042         else if (!strcmp(cp, "usr"))
 1043         ;
 1044         else if (!strcmp(cp, "del"))
 1045         ;
 1046         /* FIXME: TYPE_L */
 1047         else 
 1048         continue;
 1049         cnt++;
 1050     }
 1051     c4dhook = (struct c4entry *)malloc((cnt + 1) * sizeof(struct c4entry));
 1052     if (!c4dhook) {
 1053         Cleanup();
 1054         fprintf(stderr, "NO MEM!\n");
 1055         abort();
 1056     }
 1057     rewind(fp);
 1058     i = 0;
 1059     while ((cp = getdirfileentry(fp))) {
 1060         strncpy(c4dhook[i].name, cp, 16);
 1061         c4dhook[i].name[16] = 0;    /* trust noone ... */
 1062         cp = strchr(dirfilebuf, ' ');
 1063         *cp++ = 0;
 1064         if (stat(dirfilebuf, &st))       /* something illegal.. */
 1065         continue;
 1066         strncpy(c4dhook[i].u.osname, dirfilebuf, 16);
 1067         c4dhook[i].u.osname[16] = 0;    /* trust noone ... */
 1068         c4dhook[i].size = st.st_size;
 1069         if (!strcmp(cp, "prg"))
 1070         c4dhook[i].mode = TYPE_P;           /* 0 = big, 1 = dir */
 1071         else if (!strcmp(cp, "seq"))
 1072         c4dhook[i].mode = TYPE_S;
 1073         else if (!strcmp(cp, "usr"))
 1074         c4dhook[i].mode = TYPE_U;
 1075         else if (!strcmp(cp, "del"))
 1076         c4dhook[i].mode = TYPE_D;
 1077         /* FIXME: TYPE_L */
 1078         else {
 1079         Cleanup();
 1080         abort();
 1081         }
 1082         c4dhook[i].size = st.st_size;
 1083         i++;
 1084     }
 1085     c4dhook[i].name[0] = 0;
 1086     c4dhook[i].mode = 0;
 1087     fclose(fp);
 1088     nc4d = cnt;
 1089     return 1;
 1090     }
 1091     return 0;
 1092 }
 1093 #endif
 1094 
 1095 
 1096 static int read_fs_dir(void)
 1097 {
 1098     DIR *dirp;
 1099     struct dirent *dp;
 1100     int tmp;
 1101     int cnt;
 1102     struct stat st;
 1103     int i;
 1104 
 1105     emu_mode = EMU_MODE_FILESYS;
 1106     dirp = opendir(".");
 1107     if (!dirp)
 1108     return 0;
 1109 
 1110     cnt = 0;
 1111     while ((dp = readdir(dirp)) != NULL) {
 1112     if (!strcmp(dp->d_name, "."))
 1113         continue;
 1114     if (!strcmp(dp->d_name, ".."))
 1115         continue;
 1116     if (stat(dp->d_name, &st))       /* something illegal.. */
 1117         continue;
 1118     if (!(S_ISREG(st.st_mode)) && !(S_ISDIR(st.st_mode))) 
 1119         continue;
 1120     if (stat_2_mode(&st) == TYPE_NOTHING)
 1121         continue;
 1122     cnt++;
 1123     }
 1124     c4dhook = (struct c4entry *)malloc((cnt + 1) * sizeof(struct c4entry));
 1125     if (!c4dhook) {
 1126     Cleanup();
 1127     fprintf(stderr, "NO MEM!\n");
 1128     abort();
 1129     }
 1130     rewinddir(dirp);
 1131     i = 0;
 1132     while (i < cnt && (dp = readdir(dirp)) != NULL) {
 1133     if (!strcmp(dp->d_name, "."))
 1134         continue;
 1135     if (!strcmp(dp->d_name, ".."))
 1136         continue;
 1137     if (stat(dp->d_name, &st))       /* something illegal.. */
 1138         continue;
 1139     if (!(S_ISREG(st.st_mode)) && !(S_ISDIR(st.st_mode))) 
 1140         continue;
 1141     if ((tmp = is_pc64(dp->d_name, &st)) != TYPE_NOTHING) {
 1142         c4dhook[i].mode = tmp;
 1143         c4dhook[i].flags = FLG_PC64;
 1144         c4dhook[i].size = st.st_size - sizeof(struct pc64entry);
 1145         strcbm2asc(pc64header.name);
 1146         strcpy(c4dhook[i].name, pc64header.name);
 1147         strncpy(c4dhook[i].u.osname ,dp->d_name, 16);
 1148         c4dhook[i].u.osname[16] = 0;
 1149         if (tmp == TYPE_L) {
 1150         c4dhook[i].recordsize = pc64header.recordsize;
 1151         c4dhook[i].flags |= FLG_REL;
 1152         }
 1153     } else {
 1154         if ((tmp = stat_2_mode(&st)) == TYPE_NOTHING)
 1155         continue;
 1156         strncpy(c4dhook[i].name, dp->d_name, 16);
 1157         c4dhook[i].name[16] = 0;    /* trust noone ... */
 1158         strcpy(c4dhook[i].u.osname, c4dhook[i].name);   /* now always set the osname for PC64 support */
 1159         c4dhook[i].mode = tmp;
 1160         c4dhook[i].flags = 0;
 1161         c4dhook[i].size = st.st_size;
 1162         if ( c4dhook[i].mode == TYPE_L) {
 1163         unsigned char rlbuf[4];
 1164         tmp = open(dp->d_name, O_RDONLY|BINARY_FILE);
 1165         if (tmp == -1)
 1166             continue;
 1167         if (read(tmp, rlbuf, 4) != 4) {
 1168             close(tmp);
 1169             continue;
 1170         }
 1171         close(tmp);
 1172         if (strncmp((char *)rlbuf, "r64", 3))
 1173             continue;
 1174         if (rlbuf[3] == 0 || rlbuf[3] > 253)
 1175             continue;
 1176         c4dhook[i].recordsize = rlbuf[3];
 1177         c4dhook[i].flags |= FLG_REL;
 1178         }
 1179     }
 1180     if (stat_2_lock(&st)) c4dhook[i].flags |= FLG_LOCK;
 1181     i++;
 1182     }
 1183     c4dhook[i].name[0] = 0;
 1184     c4dhook[i].mode = 0;
 1185     closedir(dirp);
 1186     nc4d = cnt;
 1187     return 1;
 1188 }
 1189 
 1190 static void read_d64_dir(void)
 1191 {
 1192     struct FileEntry *dir;
 1193     int track, sector;
 1194     int i, j, abssec, cnt;
 1195     d64_BAM = (struct BAM *)(ImageData + AbsoluteSector(18, 0) * 256);
 1196 
 1197     cnt = 0;
 1198     for (track = d64_BAM->dirstart.track, sector = d64_BAM->dirstart.sector;
 1199             (abssec = AbsoluteSector(track, sector)) != -1;
 1200                  track = dir[0].dirnext.track, sector = dir[0].dirnext.sector) {
 1201     if ((ImageFlags[abssec] && IF_USED))
 1202         break;
 1203     ImageFlags[abssec] |= IF_USED;
 1204     dir = (struct FileEntry *)(ImageData + abssec * 256);
 1205     for (i = 0; i < 8; i++) {
 1206         if (dir[i].type != 0) {
 1207         switch (dir[i].type & (unsigned char)0x8F) {
 1208             case 0x80:
 1209             case 0x81:
 1210             case 0x82:
 1211             case 0x83:
 1212             case 0x84:
 1213             cnt++;
 1214             default:
 1215             break;
 1216         }
 1217         }
 1218     }
 1219     }
 1220     c4dhook = (struct c4entry *)malloc((cnt + 1) * sizeof(struct c4entry));
 1221     if (!c4dhook) {
 1222     Cleanup();
 1223     fprintf(stderr, "NO MEM!\n");
 1224     abort();
 1225     }
 1226     for (i = 0; i < 802; i++)
 1227     ImageFlags[i] &= ~IF_USED;
 1228     cnt = 0;
 1229     for (track = d64_BAM->dirstart.track, sector = d64_BAM->dirstart.sector;
 1230             (abssec = AbsoluteSector(track, sector)) != -1;
 1231                  track = dir[0].dirnext.track, sector = dir[0].dirnext.sector) {
 1232     if ((ImageFlags[abssec] && IF_USED))
 1233         break;
 1234     ImageFlags[abssec] |= IF_USED;
 1235     dir = (struct FileEntry *)(ImageData + abssec * 256);
 1236     for (i = 0; i < 8; i++) {
 1237         if (dir[i].type != 0) {
 1238         c4dhook[cnt].u.d64.starttrack = dir[i].datastart.track;
 1239         c4dhook[cnt].u.d64.startsector = dir[i].datastart.sector;
 1240         c4dhook[cnt].size = (dir[i].size[0] + dir[i].size[1] * 256) * 254;
 1241         for (j = 0; j < 16 && dir[i].name[j] != (unsigned char)0xA0; j++)
 1242             c4dhook[cnt].name[j] = cbmtoasc(dir[i].name[j]);
 1243         c4dhook[cnt].name[j] = 0;
 1244         c4dhook[cnt].u.osname[0] = 0;
 1245         c4dhook[cnt].flags = (dir[i].type & (unsigned char)0x40) ? FLG_LOCK : 0; 
 1246         c4dhook[cnt].recordsize = 0;
 1247         /* FIXME: FLG_UNCLOSED! */
 1248         switch (dir[i].type & (unsigned char)0x8F) {
 1249             case 0x80:
 1250             c4dhook[cnt++].mode = TYPE_D;
 1251             break;
 1252             case 0x81:
 1253             c4dhook[cnt++].mode = TYPE_S;
 1254             break;
 1255             case 0x82:
 1256             c4dhook[cnt++].mode = TYPE_P;
 1257             break;
 1258             case 0x83:
 1259             c4dhook[cnt++].mode = TYPE_U;
 1260             break;
 1261             case 0x84:
 1262             c4dhook[cnt].recordsize = dir[i].recordsize;
 1263             c4dhook[cnt].u.d64.sidetrack = dir[i].sidestart.track;
 1264             c4dhook[cnt].u.d64.sidesector = dir[i].sidestart.sector;
 1265             c4dhook[cnt++].mode = TYPE_L;
 1266             c4dhook[cnt].flags |= FLG_REL; 
 1267             break;
 1268             default:
 1269             break;
 1270         }
 1271         }
 1272     }
 1273     }
 1274     for (i = 0; i < 802; i++)
 1275     ImageFlags[i] &= ~IF_USED;
 1276     c4dhook[cnt].name[0] = 0;
 1277     c4dhook[cnt].mode = 0;
 1278     nc4d = cnt;
 1279 }
 1280 
 1281 static int read_the_dir(void)
 1282 {
 1283     if (c4dhook) {
 1284     free(c4dhook);
 1285     c4dhook = NULL;
 1286     }
 1287     nc4d = 0;
 1288     dirgetidx = -1;
 1289 
 1290     if (emu_mode == EMU_MODE_D64) {
 1291     read_d64_dir();
 1292     return 1;
 1293     }
 1294 #ifdef DIRFILE
 1295     if (read_dir_file())
 1296     return 1;
 1297 #endif
 1298     emu_mode = EMU_MODE_FILESYS;
 1299     return read_fs_dir();
 1300 }
 1301 
 1302 static int ndirmatch(void)
 1303 {
 1304     int i, fnd;
 1305 
 1306     fnd = 0;
 1307     for (i = 0; i < nc4d; i++) {
 1308     if (simple_match(c4dhook[i].name, dirmatch)) {
 1309         if (typemode && c4dhook[i].mode != typemode)
 1310         continue;
 1311         fnd++;
 1312     }
 1313     }
 1314     return fnd;
 1315 }
 1316 
 1317 char *findfile(int ch, char *n)
 1318 {
 1319     int i;
 1320 
 1321     if (n && *n) {
 1322     for (i = 0; i < nc4d; i++) {
 1323         if (simple_match(c4dhook[i].name, n)) {
 1324         if (c4dhook[i].mode != TYPE_D) {
 1325             findfileidx = i;
 1326             return strcpy(unixname[ch], c4dhook[i].u.osname);
 1327         }
 1328         }
 1329     }
 1330     }
 1331     findfileidx = -1;
 1332     return NULL;
 1333 }
 1334 
 1335 int dirgetfirst(char *n)
 1336 {
 1337     strncpy(dirgetbuf, n, 32);
 1338     dirgetbuf[31] = 0;
 1339     for (dirgetidx = 0; dirgetidx < nc4d; dirgetidx++) {
 1340     if (simple_match(c4dhook[dirgetidx].name, dirgetbuf))
 1341         break;
 1342     }
 1343     if (dirgetidx == nc4d)
 1344         dirgetidx = -1;
 1345     return dirgetidx;
 1346 }
 1347 
 1348 int dirgetnext(void)
 1349 {
 1350     while (dirgetidx >= 0 && ++dirgetidx < nc4d) {
 1351     if (simple_match(c4dhook[dirgetidx].name, dirgetbuf))
 1352         break;
 1353     }
 1354     if (dirgetidx == nc4d)
 1355         dirgetidx = -1;
 1356     return dirgetidx;
 1357 }
 1358 
 1359 static void setshort(unsigned char *p, int i)
 1360 {
 1361     *p++ = i & 0xff;
 1362     *p = i >> 8;
 1363 }
 1364 
 1365 static void setheadline(unsigned char *bp)
 1366 {
 1367     unsigned char *cp;
 1368     int i;
 1369 
 1370     memcpy(bp, dirintro, 8);
 1371     if (emu_mode == EMU_MODE_D64) {
 1372     strcpy(bp + 8,"                \" ");
 1373     cp = d64_BAM->diskname;
 1374     i = 8;
 1375     while (*cp != (unsigned char)0xA0 && i < 24)
 1376         bp[i++] = *cp++;
 1377     memcpy(bp + 26, d64_BAM->diskid, 5);
 1378     bp[31] = 0;
 1379     for (i = 26; i < 31; i++)
 1380         if (bp[i] == (unsigned char)0xA0)
 1381         bp[i] = ' ';
 1382     } else {
 1383     strcpy(bp + 8,"           (ALE)");
 1384     cp = systemname();
 1385     i = 8;
 1386     while (*cp)
 1387         bp[i++] = asctocbm(*cp++);
 1388     strcpy(bp + 24,"\" 64 2A");
 1389     }
 1390 }
 1391 
 1392 static void setstopline(char *bp)
 1393 {
 1394     int blfree, t;
 1395 
 1396     setshort(bp, 257);
 1397     if (emu_mode == EMU_MODE_D64) {
 1398     for (blfree = t = 0; t < 35; t++)
 1399         if (t != d64_BAM->dirstart.track - 1)
 1400         blfree += d64_BAM->bam[t].freecnt;
 1401     setshort(bp + 2, blfree);
 1402     strcpy(bp + 4, "BLOCKS FREE.             ");
 1403     } else {
 1404     blfree = freeblks(".");
 1405     if (blfree >= 64000) {      /* kilo blocks... */
 1406         blfree /= 1024;
 1407         if (blfree >= 64000) {
 1408         setshort(bp + 2, blfree / 1024);
 1409         strcpy(bp + 4, "MEGA BLOCKS FREE.        ");
 1410         } else {
 1411         setshort(bp + 2, blfree);
 1412         strcpy(bp + 4, "KILO BLOCKS FREE.        ");
 1413         }
 1414     } else {
 1415         setshort(bp + 2, blfree);
 1416         strcpy(bp + 4, "BLOCKS FREE.             ");
 1417     }
 1418     }
 1419     setshort(bp + 30, 0);
 1420 }
 1421  
 1422 static void setentry(char *cp) 
 1423 {
 1424     int blks, i;
 1425     char *np;
 1426     int nspaces;
 1427     int mode;
 1428     struct c4entry *c4;
 1429 
 1430     i = dirisopen - 1;
 1431     do {
 1432     while (!simple_match(c4dhook[i].name, dirmatch))
 1433         i++;
 1434     } while (typemode && c4dhook[i].mode != typemode);
 1435     c4 = c4dhook + i;
 1436     dirisopen = i + 2;
 1437     mode = c4->mode;
 1438     np = c4->name;
 1439     setshort(cp, 257);   /* 0101 */
 1440     if (mode == TYPE_BIG) {
 1441     setshort(cp + 2, 0);
 1442     nspaces = 3;
 1443     } else {
 1444     blks = (c4->size + 253) / 254;
 1445     setshort(cp + 2, blks);
 1446     if (blks < 10) nspaces = 3;
 1447     else if (blks < 100) nspaces = 2;
 1448     else if (blks < 1000) nspaces = 1;
 1449     else nspaces = 0;
 1450     }
 1451     strcpy(cp + 4, "   \"" + 3 - nspaces);
 1452     i = 5 + nspaces;
 1453     while (*np)
 1454     cp[i++] = asctocbm(*np++);
 1455     cp[i++] = '"';
 1456     while (i < (22 + nspaces)) {
 1457     cp[i++] = ' ';
 1458     }
 1459     cp[i++] = ':';
 1460     switch(mode) {
 1461     case TYPE_BIG:
 1462         strcpy(cp + i, "BIG");
 1463         break;
 1464     case TYPE_DIR:
 1465         strcpy(cp + i, "DIR");
 1466         break;
 1467     case TYPE_P:
 1468         strcpy(cp + i, "PRG");
 1469         break;
 1470     case TYPE_S:
 1471         strcpy(cp + i, "SEQ");
 1472         break;
 1473     case TYPE_U:
 1474         strcpy(cp + i, "USR");
 1475         break;
 1476     case TYPE_D:
 1477         strcpy(cp + i, "DEL");
 1478         break;
 1479     case TYPE_L:
 1480         strcpy(cp + i, "REL");
 1481         break;
 1482     default:
 1483         Cleanup();
 1484         abort();
 1485     }
 1486     i += 3;
 1487     if ((c4->flags & FLG_LOCK))
 1488     cp[i++] = '<';
 1489     else
 1490     cp[i++] = ' ';
 1491 
 1492     while (i < 31)
 1493     cp[i++] = ' ';
 1494     cp[i] = 0;
 1495 }
 1496 
 1497 
 1498 int open1541dir(char *n, int ch)
 1499 {
 1500     if (dirisopen)
 1501     return 1;
 1502     if (n == NULL || *n == 0)
 1503     strcpy(dirmatch, "*");
 1504     else
 1505     strncpy(dirmatch, n, 32);
 1506     dirnmatch = ndirmatch();
 1507 
 1508     dirlen = dirnmatch * 32 + 64;
 1509     dirisopen = 1;
 1510     dirpos = 0;
 1511     chfd[ch] = -4;      /* a directory */
 1512     return 0;
 1513 }
 1514 
 1515 void close1541dir(int ch)
 1516 {
 1517     dirisopen = 0;
 1518     chfd[ch] = -1;
 1519 }
 1520 
 1521 int read1541dirblock(int ch)
 1522 {
 1523     int nread;          /* max 8 per block */
 1524 
 1525     nread = 0;
 1526     if (dirpos == 0) {
 1527     setheadline(chanbuf[ch]);
 1528     dirpos += 32;
 1529     nread++;
 1530     }
 1531     while ((nread < 8) && (dirpos < (dirlen - 32))) {
 1532     setentry(chanbuf[ch] + (nread * 32));
 1533     dirpos += 32;
 1534     nread++;
 1535     }
 1536     if ((nread < 8) && dirpos == (dirlen - 32)) {
 1537     setstopline(chanbuf[ch] + (nread * 32));
 1538     dirpos += 32;
 1539     nread++;
 1540     }
 1541     return nread * 32;
 1542 }
 1543 
 1544 void SetError(int e, int t, int s)
 1545 {
 1546     LedOff();
 1547     if (e) {
 1548     if ((e != 73 && e != 1 && e != 65) || (e == 65 && t == 0)) {
 1549         globflags |= F_ERRORMSG;
 1550         LedFlash();
 1551     }
 1552     }
 1553     errorcode = e;
 1554     errortrack = t;
 1555     errorsector = s;
 1556     sprintf(errorbuf, "%02d,%s,%02d,%02d\r",
 1557     e, errors[e], errortrack, errorsector);
 1558 #if defined(X11) || defined(SVGALIB)
 1559     if (e && e != 73 && e != 1 && e != 65) {    /* NO ERROR, RESET, SCRATCH */
 1560     printf("1541 Error: %s\n", errorbuf);
 1561     } else if (e == 1 && t == 0) {
 1562     printf("1541 Warning: %s\n", errorbuf);
 1563     } else if (e == 65 && t == 0) {
 1564     printf("1541 Error: %s\n", errorbuf);
 1565     }
 1566 #endif
 1567 }
 1568 
 1569 static int MountD64(void)
 1570 {
 1571     char *cp;
 1572     struct stat st;
 1573     int i;
 1574 
 1575     if (ImageFD >= 0)
 1576     close(ImageFD);
 1577     if (ImageData) {
 1578     free(ImageData);
 1579     ImageData = NULL;
 1580     ImageDataSize = 0;
 1581     }
 1582     ImageFD = -1;
 1583     ImageRO = 0;
 1584     d64_has_errinfo = 0;
 1585     d64_tracks = 0;
 1586     if (!FloppyImage || access(FloppyImage, R_OK) < 0 || stat(FloppyImage, &st))
 1587     return 0;
 1588     cp = strrchr(FloppyImage, '.');
 1589     if (!cp || (strcmp(cp, ".d64") && strcmp(cp, ".D64")))
 1590     return 0;
 1591     if (!S_ISREG(st.st_mode))
 1592     return 0;
 1593     ImageDataSize = st.st_size;
 1594     switch (ImageDataSize) {
 1595     case D64_35_EINFO_SIZE:
 1596         d64_has_errinfo = 1;
 1597     case D64_35_SIZE:
 1598         d64_tracks = 35;
 1599         break;
 1600     case D64_40_EINFO_SIZE:
 1601         d64_has_errinfo = 1;
 1602     case D64_40_SIZE:
 1603         d64_tracks = 40;
 1604         break;
 1605     case D64_42_EINFO_SIZE:
 1606         d64_has_errinfo = 1;
 1607     case D64_42_SIZE:
 1608         d64_tracks = 42;
 1609         break;
 1610     default:
 1611         ImageDataSize = 0;
 1612         break;
 1613     }
 1614     if (!ImageDataSize)
 1615     return 0;
 1616     ImageData = malloc(ImageDataSize);
 1617     if (!ImageData) {
 1618     ImageDataSize = 0;
 1619     return 0;
 1620     }
 1621     if (access(FloppyImage, W_OK) < 0)  /* don't optimize here! Under Unix eaccess()/open()
 1622                    with saved ids may grant us more then we want the user to give! */
 1623     ImageRO = 1;
 1624     ImageFD = open(FloppyImage, (ImageRO ? O_RDONLY : O_RDWR)|BINARY_FILE);
 1625     if (ImageFD < 0 || read(ImageFD, ImageData, ImageDataSize) != ImageDataSize) {
 1626     free(ImageData);
 1627     ImageData = NULL;
 1628     ImageDataSize = 0;
 1629     if (ImageFD >= 0)
 1630         close(ImageFD);
 1631     ImageFD = -1;
 1632     ImageRO = 0;
 1633     return 0;
 1634     }
 1635     if (ImageRO) {
 1636     close(ImageFD);
 1637     ImageFD = -1;
 1638     }
 1639     if (d64_has_errinfo) {
 1640     i = ImageDataSize / 257;
 1641     ImageErrInfo = ImageData + i * 256;
 1642     }
 1643     d64_BAM = (struct BAM *)(ImageData + AbsoluteSector(18, 0) * 256);
 1644     memset(ImageFlags, 0, 802);
 1645     return 1;
 1646 }
 1647 
 1648 int ParseFilename(char *name, int len, int getmode)
 1649 {
 1650     char *cp2;
 1651     char *cp = name;
 1652     unsigned char c;
 1653     int drive;
 1654 
 1655     ftype = TYPE_NOTHING;
 1656     openmode = MODE_NOTHING;
 1657     typemode = TYPE_NOTHING;
 1658     chanopen = 0;
 1659     nbuf[0] = 0;
 1660     name[len] = 0;
 1661 
 1662    // printf("ParseFileName: '%s'", name);
 1663 
 1664     /* check filename for filetype, openmode,
 1665        overwrite flag, or directory request. */
 1666     if (*cp == '@') {
 1667     overwrite = 1;
 1668     dir = 0;
 1669     cp++;
 1670     } else {
 1671     overwrite = 0;
 1672     if (*cp == '$') {
 1673         dir = 1;
 1674         cp++;
 1675         cp2 = cp;
 1676         while (*cp >= '0' && *cp <= '9')
 1677         cp++;
 1678         if (*cp == ':' && cp != cp2)        /* parse the drive */
 1679         cp = cp2;
 1680     } else {
 1681         dir = 0;
 1682         if (*cp == '#') {
 1683         /* FIXME: we ignore all buffer number args here! */
 1684         strcpy(nbuf,"#");
 1685         chanopen = 1;
 1686         return 0;
 1687         }
 1688     }
 1689     }
 1690     cp2 = strchr(cp, ':');
 1691     if (cp2) {
 1692     *cp2++ = 0;
 1693     drive = atoi(cp);
 1694     if (drive < 0 || drive > 9) {
 1695         SetError(74, 0, 0);
 1696         return 1;
 1697     }
 1698     cp = cp2;
 1699     } else if (overwrite) {
 1700     overwrite = 0;      /* mimic 1541 behaviour: '@' is global overwrite only before ':'
 1701                    or when explicitly checked by write commands, but can normally
 1702                    used to load files */
 1703     cp--;
 1704     }
 1705     if (getmode) {
 1706     if ((cp2 = strchr(cp, '='))) {
 1707         *cp2++ = 0;
 1708         typemode = *cp2 & 0x7f;
 1709         switch (typemode) {
 1710         case TYPE_P:
 1711         case TYPE_S:
 1712         case TYPE_U:
 1713         case TYPE_D:
 1714         case TYPE_L:
 1715             break;
 1716         default:    /* including 0 */
 1717             SetError(33, 0, 0);
 1718             return 1;
 1719         }
 1720         if (cp2[1]) {
 1721         SetError(33, 0, 0);
 1722         return 1;
 1723         }
 1724     }
 1725     cp2 = strchr(cp, ',');
 1726     if (cp2) {
 1727         *cp2++ = 0;
 1728         /* FIXME: insert drivedir... - ??? - */
 1729         if (dir || strlen(cp) > 30) {
 1730         SetError(33, 0, 0);
 1731         return 1;
 1732         }
 1733         ftype = cp2[0] & 0x7f;
 1734         switch (ftype) {
 1735         case TYPE_P:
 1736         case TYPE_S:
 1737         case TYPE_U:
 1738         case TYPE_D:
 1739         case TYPE_L:
 1740             break;
 1741         default:
 1742             ftype = TYPE_NOTHING;
 1743             break;
 1744         }
 1745         if (ftype != TYPE_NOTHING)
 1746         {
 1747         cp2 = strchr(cp2, ',');
 1748         if (!cp2) {
 1749             if (ftype == TYPE_L) {
 1750             SetError(33, 0, 0);
 1751             return 1;
 1752             }
 1753         } else {
 1754             if (cp2[1])
 1755              openmode = ((unsigned char *)cp2)[1];
 1756 
 1757             if (ftype != TYPE_L && openmode)
 1758             {
 1759             openmode &= 0x7f;
 1760             switch(openmode) {
 1761                 case MODE_R:
 1762                 case MODE_W:
 1763                 case MODE_A:
 1764                 case MODE_M:
 1765                 break;
 1766                 default:
 1767                 openmode = MODE_NOTHING;
 1768                 break;
 1769             }
 1770             } else {
 1771             if (openmode == 0 || openmode > 253) {
 1772                 SetError(33, 0, 0);
 1773                 return 1;
 1774             }
 1775             }
 1776         }
 1777         }
 1778     }
 1779     }
 1780     /* Now translate the filename ... */
 1781     cp2 = nbuf;
 1782     while ( (c = (unsigned char)(*cp++)) ) {
 1783     if (c >= 'A' && c <= 'Z')
 1784         c |= 0x20;
 1785     else if (c >= ('A'|0x80) && c <= ('Z'|0x80))
 1786         c &= 0x7f;
 1787     *cp2++ = c;
 1788     if (c == '*')   /* ignore anything after '*' */
 1789         break;
 1790     }
 1791     *cp2 = 0;
 1792     
 1793     // printf(" -> '%s' '%x' '%x' (%d)\n", nbuf, dir ? typemode : ftype, openmode, dir);
 1794 
 1795     return 0;
 1796 }
 1797 
 1798 static int get_num_arg(char **cpp, int colon)
 1799 {
 1800     char *cp = *cpp;
 1801     int n = 0;
 1802 
 1803     if (!colon && *cp == ':')
 1804     return -1;
 1805     if (colon && *cp == ',')
 1806     return -1;
 1807     if (*cp == ':' || *cp == ',') {
 1808     cp++;
 1809     if (!*cp || (*cp != ' ' && *cp != 0x1d && (*cp < '0' || *cp > '9')))
 1810         return -1;
 1811     }
 1812     while (*cp && (*cp == ' ' || *cp == 0x1d))
 1813     cp++;
 1814     if (!*cp || *cp < '0' || *cp > '9')
 1815     return -1;
 1816     n = *cp++ - '0';
 1817     while (*cp >= '0' && *cp <= '9') {
 1818     n *= 10;
 1819     n += *cp++ - '0';
 1820     }
 1821     *cpp = cp;
 1822     return n;
 1823 } 
 1824 
 1825 // D64 MOUNT/UMOUNT Support:
 1826 // g:dir    -> chdir() to dir
 1827 // g:file.d64   -> mount d64 file
 1828 // g:.      -> unmount d64 file and use current dir again
 1829 int cmd_go(char *cmd)
 1830 {
 1831     char *cp;
 1832     struct stat st;
 1833     static char FIbuf[128];
 1834 
 1835     cp = strchr(cmd, ':');
 1836     if (!cp) {
 1837     SetError(34, 0, 0);
 1838     return 0;
 1839     }
 1840     cp++;
 1841     if (!*cp) {
 1842     SetError(30, 0, 0);
 1843     return 0;
 1844     }
 1845     strcbm2asc(cp);
 1846     if (stat(cp, &st)) {
 1847     SetError(62, 0, 0);
 1848     return 0;
 1849     }
 1850     if (S_ISDIR(st.st_mode)) {
 1851     if (chdir(cp)) {
 1852         SetError(62, 0, 0);
 1853         return 0;
 1854     }
 1855     FloppyImage = NULL;
 1856     emu_mode = EMU_MODE_FILESYS;
 1857     read_the_dir();
 1858     SetError(0, 0, 0);
 1859     return 1;
 1860     }
 1861     FloppyImage = cp;
 1862     if (MountD64()) {
 1863     strncpy(FIbuf, cp, 127);
 1864     FIbuf[127] = 0;
 1865     FloppyImage = FIbuf;
 1866     emu_mode = EMU_MODE_D64;
 1867     read_the_dir();
 1868     SetError(0, 0, 0);
 1869     return 1;
 1870     }
 1871     emu_mode = EMU_MODE_FILESYS;
 1872     FloppyImage = NULL;
 1873     SetError(62, 0, 0);
 1874     return 0;
 1875 }
 1876 
 1877 static int cmd_scratch(char *cmd)
 1878 {
 1879     char *cp, *cp2, *cp3;
 1880     int i, idx, tpmod;
 1881 
 1882     cp = strchr(cmd, ':');
 1883     if (!cp) {
 1884     SetError(34, 0, 0);
 1885     return 0;
 1886     }
 1887     cp++;
 1888     if (!*cp) {
 1889     SetError(30, 0, 0);
 1890     return 0;
 1891     }
 1892     if (emu_mode == EMU_MODE_D64) {
 1893     SetError(3, 0, 0);  /* unimplemented */
 1894     return 0;
 1895     }
 1896     strcbm2asc(cp);
 1897     for (i = 0; ;) {
 1898     cp3 = strchr(cp, ',');
 1899     if (cp3)
 1900         *cp3++ = 0;
 1901     tpmod = TYPE_NOTHING;
 1902     if ((cp2 = strchr(cp, '='))) {
 1903         *cp2++ = 0;
 1904         tpmod = *cp2 & 0x5f;
 1905         switch(tpmod) {
 1906             case TYPE_P:
 1907             case TYPE_S:
 1908             case TYPE_U:
 1909             case TYPE_D:
 1910             case TYPE_L:
 1911             break;
 1912             default:
 1913             SetError(34, 0, 0);
 1914             return 0;
 1915         }
 1916     }
 1917     if (strlen(cp) > 16)        /* no error here ... */
 1918         cp[16] = 0;
 1919     idx = dirgetfirst(cp);
 1920     while (idx >= 0) {
 1921         if (!tpmod || c4dhook[idx].mode == tpmod)
 1922         {
 1923         if (!(c4dhook[idx].flags & FLG_LOCK))
 1924         {
 1925             c4dhook[idx].mode = -1;
 1926             unlink(c4dhook[idx].u.osname);
 1927             i++;
 1928         }
 1929         }
 1930         idx = dirgetnext();
 1931     }
 1932     if (cp3 == NULL || *cp3 == 0)
 1933         break;
 1934     else
 1935         cp = cp3;
 1936     }
 1937 #ifdef DIRFILE
 1938     if (emu_mode == EMU_MODE_DIRFILE && i)
 1939     rewrite_dir_file();
 1940 #endif
 1941     SetError(1, i, 0);
 1942     return 1;
 1943 }
 1944 
 1945 static int cmd_rename(char *cmd)
 1946 {
 1947     char *cp, *cp2, *cp3;
 1948     int i, idx;
 1949 
 1950     cp = strchr(cmd, ':');
 1951     if (!cp) {
 1952     SetError(34, 0, 0);
 1953     return 0;
 1954     }
 1955     cp++;
 1956     if (!*cp) {
 1957     SetError(30, 0, 0);
 1958     return 0;
 1959     }
 1960     cp2 = strchr(cp, '=');
 1961     if (!*cp2) {
 1962     SetError(30, 0, 0);
 1963     return 0;
 1964     }
 1965     *cp2++ = 0;
 1966     cp3 = strchr(cp2, ':');
 1967     if (cp3)
 1968     cp2 = cp3 + 1;
 1969     if (!*cp2) {            /* strange, but as the original */
 1970     SetError(62, 0, 0);
 1971     return 0;
 1972     }
 1973     strcbm2asc(cp);
 1974     if (strlen(cp) > 16)
 1975     cp[16] = 0;
 1976     strcbm2asc(cp2);
 1977     if (strlen(cp2) > 16)
 1978     cp2[16] = 0;
 1979     if (strchr(cp, '*') || strchr(cp, '?') || strchr(cp, ',')) {
 1980     SetError(30, 0, 0);
 1981     return 0;
 1982     }
 1983     if (strchr(cp2, '*') || strchr(cp2, '?') || strchr(cp2, ',')) {
 1984     SetError(30, 0, 0);
 1985     return 0;
 1986     }
 1987     idx = dirgetfirst(cp);
 1988     if (idx >= 0) {
 1989     SetError(63, 0, 0);
 1990     return 0;
 1991     }
 1992     i = dirgetfirst(cp2);
 1993     if (i < 0) {
 1994     SetError(62, 0, 0);
 1995     return 0;
 1996     }
 1997 #ifdef DIRFILE
 1998     if (emu_mode == EMU_MODE_DIRFILE) {
 1999     strcpy(c4dhook[i].name, c4dhook[idx].name);
 2000     rewrite_dir_file();
 2001     } else
 2002 #endif
 2003     {
 2004     if (emu_mode == EMU_MODE_D64 || ((c4dhook[i].flags & FLG_PC64))) {
 2005         SetError(3, 0, 0);  /* unimplemented */
 2006         return 0;
 2007     }
 2008     rename(c4dhook[i].u.osname, cp);
 2009     }
 2010     SetError(0, 0, 0);
 2011     return 1;
 2012 }
 2013 
 2014 static int filecopy(char *osname, int srcidx, int append, int overwrite)
 2015 {
 2016     char cpbuf[1024];
 2017     int fdi, fdo, size;
 2018     struct stat st;
 2019 
 2020     if ((c4dhook[srcidx].flags & FLG_PC64))
 2021     return 3;                   /* FIXME: unimplemented */
 2022 
 2023     if (emu_mode == EMU_MODE_D64)
 2024     return 3;                   /* FIXME: unimplemented */
 2025 
 2026     if (append && overwrite)
 2027     return 2;
 2028     if (stat(c4dhook[srcidx].u.osname, &st))
 2029     return 1;
 2030 #ifndef __GO32__
 2031     if (
 2032 #ifdef DIRFILE
 2033     emu_mode == EMU_MODE_FILESYS &&
 2034 #endif
 2035                st.st_mode == S_IFREG)   /* TYPE_D file open ... */
 2036     chmod(c4dhook[srcidx].u.osname, 0600);
 2037 #endif
 2038     fdi = open(c4dhook[srcidx].u.osname, O_RDONLY|BINARY_FILE);
 2039 #ifndef __GO32__
 2040     if (
 2041 #ifdef DIRFILE
 2042     emu_mode == EMU_MODE_FILESYS &&
 2043 #endif
 2044                st.st_mode == S_IFREG)
 2045     chmod(c4dhook[srcidx].u.osname, 0);
 2046 #endif
 2047 
 2048     if (fdi < 0)
 2049     return 1;
 2050     if (fstat(fdi, &st)) {
 2051     close(fdi);
 2052     return 1;
 2053     }
 2054     fdo = open(osname, O_WRONLY|BINARY_FILE|O_CREAT|(append ? O_APPEND : 0)|(overwrite ? O_TRUNC : 0),
 2055 #ifdef __GO32__
 2056         0666
 2057 #else
 2058     0666 & UMask
 2059 #endif
 2060     );
 2061     if (fdo < 0) {
 2062     close(fdi);
 2063     return 2;
 2064     }
 2065     while ((size = read(fdi, cpbuf, 1024)) > 0)     /* FIXME: check errors here */
 2066     write(fdo, cpbuf, size);
 2067     close(fdi);
 2068     close(fdo);
 2069 #ifndef __GO32__
 2070     chmod(osname, st.st_mode);              /* FIXME: check match with append */
 2071 #endif
 2072     return 0;
 2073 }
 2074 
 2075 static int cmd_concat(char *target, char *cmd)
 2076 {
 2077     SetError(3, 0, 0);  /* unimplemented */
 2078     return 0;
 2079 }
 2080 
 2081 static int cmd_copy(char *cmd)
 2082 {
 2083     char *cp, *cp2, *cp3;
 2084     int i, idx, tpmod;
 2085 
 2086     cp = strchr(cmd, ':');
 2087     if (!cp) {
 2088     SetError(34, 0, 0);
 2089     return 0;
 2090     }
 2091     cp++;
 2092     if (!*cp) {
 2093     SetError(30, 0, 0);
 2094     return 0;
 2095     }
 2096     cp2 = strchr(cp, '=');
 2097     if (!*cp2) {
 2098     SetError(30, 0, 0);
 2099     return 0;
 2100     }
 2101     *cp2++ = 0;
 2102     if (!*cp2) {            /* strange, but as the original */
 2103     SetError(62, 0, 0);
 2104     return 0;
 2105     }
 2106     if (strlen(cp) > 16)
 2107     cp[16] = 0;
 2108     strcbm2asc(cp);
 2109     if (strchr(cp, '*') || strchr(cp, '?') || strchr(cp, ',')) {
 2110     SetError(30, 0, 0);
 2111     return 0;
 2112     }
 2113 
 2114     if (strchr(cp2, ','))   /* concat */
 2115     return cmd_concat(cp, cp2);
 2116 
 2117     cp3 = strchr(cp2, ':');
 2118     if (cp3)
 2119     cp2 = cp3 + 1;
 2120     if (!*cp2) {        /* strange, but as the original */
 2121     SetError(62, 0, 0);
 2122     return 0;
 2123     }
 2124     if (strlen(cp2) > 16)
 2125     cp2[16] = 0;
 2126     strcbm2asc(cp2);
 2127     if (strchr(cp2, '*') || strchr(cp2, '?')) {
 2128     SetError(30, 0, 0);
 2129     return 0;
 2130     }
 2131     tpmod = i = -1;
 2132     if (*cp == '@') {
 2133     cp++;
 2134     i = dirgetfirst(cp);
 2135     if (i >= 0 && (c4dhook[i].flags & FLG_LOCK))
 2136     {
 2137         SetError(26, 0, 0); /* write protect */
 2138         return 0;
 2139     }
 2140     } else if (dirgetfirst(cp) >= 0) {
 2141     SetError(63, 0, 0);
 2142     return 0;
 2143     }
 2144     idx = dirgetfirst(cp2);
 2145     if (idx < 0) {
 2146     SetError(62, 0, 0);
 2147     return 0;
 2148     }
 2149 #ifdef DIRFILE
 2150     if (emu_mode == EMU_MODE_DIRFILE) {
 2151     if (i >= 0) {
 2152         cp = c4dhook[i].u.osname;
 2153     } else {
 2154         tpmod = MakeDirEntry(cp, c4dhook[idx].mode);
 2155         if (tpmod == -1) {
 2156         SetError(72, 0, 0); /* disk full */
 2157         return 0;
 2158         }
 2159         cp = c4wrhook[tpmod].u.osname;
 2160     }
 2161     }
 2162 #endif
 2163     if ((idx = filecopy(cp, idx, 0, i >= 0))) {
 2164 #ifdef DIRFILE
 2165     if (emu_mode == EMU_MODE_DIRFILE && tpmod != -1)
 2166         DeleteDirEntry(tpmod);
 2167 #endif
 2168     switch (idx) {
 2169         case 1:
 2170         SetError(62, 0, 0);
 2171         return 0;
 2172         case 3:
 2173         SetError(3, 0, 0);
 2174         return 0;
 2175         case 2:
 2176         default:
 2177         SetError(25, 0, 0);
 2178         return 0;
 2179     }
 2180     }
 2181 #ifdef DIRFILE
 2182     if (emu_mode == EMU_MODE_DIRFILE)
 2183     rewrite_dir_file();
 2184 #endif
 2185     return 1;
 2186 }
 2187 
 2188 /* JOHNS: I need this global!! */
 2189 int cmd_new(char *cmd)
 2190 {
 2191     char *cp, *cp2;
 2192     unsigned char id[2];
 2193     int i, s, has_id = 0;
 2194 
 2195     if (emu_mode == EMU_MODE_D64) {
 2196     cp = strchr(cmd, ':');
 2197     if (!cp) {
 2198         SetError(34, 0, 0);
 2199         return 0;
 2200     }
 2201     cp++;
 2202     if (!*cp) {
 2203         SetError(30, 0, 0);
 2204         return 0;
 2205     }
 2206     cp2 = strchr(cmd, ',');
 2207     if (cp2) {      /* low level format */
 2208         if (cp2 == cp || strlen(cp2) < 3) {
 2209         SetError(34, 0, 0);
 2210         return 0;
 2211         }
 2212         has_id = 1;
 2213         *cp2 = 0;
 2214         id[0] = cp2[1];
 2215         id[1] = cp2[2];
 2216     } else {
 2217         cp2 = cp + strlen(cp);
 2218         id[0] = d64_BAM->diskid[0];
 2219         id[1] = d64_BAM->diskid[1];
 2220     }
 2221     if (ImageRO) {
 2222         SetError(26, 0, 0); /* write protect */
 2223         return 0;
 2224     }
 2225     if (!has_id && d64_has_errinfo) {
 2226         i = AbsoluteSector(18, 0);
 2227         if (ImageErrInfo[i] != 1) {
 2228         SetError(ErrInfo2Error(ImageErrInfo[i]), 0, 0);
 2229         return 0;
 2230         }
 2231         if (ImageErrInfo[i + 1] != 1) {
 2232         SetError(ErrInfo2Error(ImageErrInfo[i + 1]), 0, 0);
 2233         return 0;
 2234         }
 2235     }
 2236     memset(d64_BAM, 0, 512);        /* BAM and first directory sector */
 2237     ((unsigned char *)d64_BAM)[257] = 1;    /* empty directory */
 2238 
 2239     d64_BAM->dirstart.track = 18;
 2240     d64_BAM->dirstart.sector = 1;
 2241     memset(d64_BAM->diskname, 0xA0, 27);    /* preset name data */
 2242     i = 0;
 2243     while (cp < cp2 && i < 16)
 2244         d64_BAM->diskname[i++] = *cp++;
 2245     d64_BAM->diskid[0] = id[0];
 2246     d64_BAM->diskid[1] = id[1];
 2247     d64_BAM->dosversion[0] = '2';
 2248     d64_BAM->dosversion[1] = d64_BAM->format = 'A';
 2249     for (i = 1; i < 36; i++)
 2250         for (s = 0; s < ZBR_ns[i]; s++) {
 2251         BAM_free(i, s);
 2252         if (has_id && d64_has_errinfo)
 2253             ImageErrInfo[ZBR_st[i] + s] = 1;
 2254         }
 2255     BAM_alloc(18, 0);
 2256     BAM_alloc(18, 1);
 2257     ImageFlags[ZBR_st[18] + 1] |= IF_DIRTY;     /* first directory block */
 2258     ReWriteImage();
 2259     if (has_id && d64_has_errinfo) {
 2260         i = ImageDataSize / 257;
 2261         if (lseek(ImageFD, i * 256, SEEK_SET) >= 0)
 2262         write(ImageFD, ImageErrInfo, i);
 2263     }
 2264     return 1;
 2265     } else {    /* not EMU_MODE_D64 */
 2266     return 1;   /* just ok */
 2267     }
 2268 }
 2269 
 2270 static int cmd_block_read(char *arg, int bug)
 2271 {
 2272     int i, chan, drv, t, s;
 2273 
 2274     while (*arg && *arg != ' ' && *arg != ':' && *arg != 0x1d)
 2275     arg++;
 2276     if (!*arg) {
 2277     SetError(30, 0, 0);
 2278     return 0;
 2279     }
 2280     chan = get_num_arg(&arg, 1);
 2281     if (chan < 0 || chan >= NCHAN) {
 2282     SetError(30, 0, 0);
 2283     return 0;
 2284     }
 2285     drv = get_num_arg(&arg, 0);
 2286     if (drv < 0) {
 2287     SetError(30, 0, 0);
 2288     return 0;
 2289     }
 2290     t = get_num_arg(&arg, 0);
 2291     if (t < 0) {
 2292     SetError(30, 0, 0);
 2293     return 0;
 2294     }
 2295     s = get_num_arg(&arg, 0);
 2296     if (s < 0) {
 2297     s = 0;
 2298     // SetError(30, 0, 0);
 2299     // return 0;
 2300     }
 2301     if (chfd[chan] != -6) {
 2302     SetError(70, 0, 0);
 2303     return 0;
 2304     }
 2305 
 2306 #ifdef DEBUG_BLOCK_CMDS
 2307     printf("B-R: %d %d %d %d\n", chan, drv, t, s);
 2308 #endif
 2309 
 2310     if (emu_mode == EMU_MODE_D64) {
 2311     i = AbsoluteSector(t, s);
 2312     if (i < 0) {
 2313         SetError(66, t, s);
 2314         return 0;
 2315     }
 2316     memcpy(chanbuf[chan], ImageData + i * 256, 256);
 2317     if (d64_has_errinfo) {
 2318         i = ImageErrInfo[i];
 2319         if (i != 1) {
 2320         SetError(ErrInfo2Error(i), 0, 0);
 2321         chanpos[chan] = filelen[chan] = 0;
 2322         return 0;
 2323         }
 2324     }
 2325     if (bug) {
 2326         filelen[chan] =  chanbuf[chan][0];
 2327         chanpos[chan] = 0;
 2328         chanbufp[chan] = 0;
 2329         return 1;
 2330     }
 2331     } else
 2332     memset(chanbuf[chan], 0, 256);
 2333     filelen[chan] =  256;
 2334     chanpos[chan] = 0;
 2335     chanbufp[chan] = 0;
 2336     return 1;
 2337 }
 2338 
 2339 static int cmd_block_write(char *arg, int bug)
 2340 {
 2341     int i, chan, drv, t, s;
 2342 
 2343     while (*arg && *arg != ' ' && *arg != ':' && *arg != 0x1d)
 2344     arg++;
 2345     if (!*arg) {
 2346     SetError(30, 0, 0);
 2347     return 0;
 2348     }
 2349     chan = get_num_arg(&arg, 1);
 2350     if (chan < 0 || chan >= NCHAN) {
 2351     SetError(30, 0, 0);
 2352     return 0;
 2353     }
 2354     drv = get_num_arg(&arg, 0);
 2355     if (drv < 0) {
 2356     SetError(30, 0, 0);
 2357     return 0;
 2358     }
 2359     t = get_num_arg(&arg, 0);
 2360     if (t < 0) {
 2361     SetError(30, 0, 0);
 2362     return 0;
 2363     }
 2364     s = get_num_arg(&arg, 0);
 2365     if (s < 0) {
 2366     s = 0;
 2367     // SetError(30, 0, 0);
 2368     // return 0;
 2369     }
 2370     if (chfd[chan] != -6) {
 2371     SetError(70, 0, 0);
 2372     return 0;
 2373     }
 2374 
 2375 #ifdef DEBUG_BLOCK_CMDS
 2376     printf("B-W: %d %d %d %d\n", chan, drv, t, s);
 2377 #endif
 2378 
 2379     if (emu_mode == EMU_MODE_D64) {
 2380     i = AbsoluteSector(t, s);
 2381     if (i < 0) {
 2382         SetError(66, t, s);
 2383         return 0;
 2384     }
 2385     if (d64_has_errinfo) {
 2386         i = ImageErrInfo[i];
 2387         if (i != 1) {
 2388         SetError(ErrInfo2Error(i), 0, 0);
 2389         return 0;
 2390         }
 2391     }
 2392     if (ImageRO) {
 2393         SetError(26, 0, 0); /* write protect */
 2394         return 0;
 2395     }
 2396     if (bug)
 2397         memcpy(ImageData + i * 256, chanbuf[chan], chanbuf[chan][0]);
 2398     else
 2399         memcpy(ImageData + i * 256, chanbuf[chan], 256);
 2400     ImageFlags[i] |= IF_DIRTY;
 2401     ReWriteImage();
 2402     }
 2403     return 1;
 2404 }
 2405 
 2406 static int cmd_block_pointer(char *arg)
 2407 {
 2408     int chan, pos;
 2409 
 2410     while (*arg && *arg != ' ' && *arg != ':' && *arg != 0x1d)
 2411     arg++;
 2412     if (!*arg) {
 2413     SetError(30, 0, 0);
 2414     return 0;
 2415     }
 2416     chan = get_num_arg(&arg, 1);
 2417     if (chan < 0 || chan >= NCHAN) {
 2418     SetError(30, 0, 0);
 2419     return 0;
 2420     }
 2421     pos = get_num_arg(&arg, 0);
 2422     if (pos < 0 || pos > 255) {
 2423     SetError(30, 0, 0);
 2424     return 0;
 2425     }
 2426     if (chfd[chan] != -6) {
 2427     SetError(70, 0, 0);
 2428     return 0;
 2429     }
 2430 
 2431 #ifdef DEBUG_BLOCK_CMDS
 2432     printf("B-P: %d %d\n", chan, pos);
 2433 #endif
 2434 
 2435     chanpos[chan] = pos;
 2436     chanbufp[chan] = pos;
 2437     return 1;
 2438 }
 2439 
 2440 static void cmd_block_allocate(char *arg)
 2441 {
 2442     int drv, t, t2, s, s2;
 2443 
 2444     while (*arg && *arg != ' ' && *arg != ':' && *arg != 0x1d)
 2445     arg++;
 2446     if (!*arg) {
 2447     SetError(30, 0, 0);
 2448     return;
 2449     }
 2450     drv = get_num_arg(&arg, 1);
 2451     if (drv < 0) {
 2452     SetError(30, 0, 0);
 2453     return;
 2454     }
 2455     t = get_num_arg(&arg, 0);
 2456     if (t < 0) {
 2457     SetError(30, 0, 0);
 2458     return;
 2459     }
 2460     s = get_num_arg(&arg, 0);
 2461     if (s < 0) {
 2462     SetError(30, 0, 0);
 2463     return;
 2464     }
 2465     if (t < 1 || t > 35 || s >= ZBR_ns[t]) {
 2466     SetError(66, t, s);
 2467     return;
 2468     }
 2469 
 2470 #ifdef DEBUG_BLOCK_CMDS
 2471     printf("B-A: %d %d %d\n", drv, t, s);
 2472 #endif
 2473 
 2474     if (emu_mode != EMU_MODE_D64) {
 2475     SetError(0, 0, 0);  /* let it be ok */
 2476     return;
 2477     }
 2478 
 2479     if (ImageRO) {
 2480     SetError(26, 0, 0); /* write protect */
 2481     return;
 2482     }
 2483     t2 = t;
 2484     s2 = s;
 2485     BAM_next_free_sector(&t2, &s2);
 2486     if (t2 == t && s2 == s)
 2487     SetError(0, 0, 0);
 2488     else {
 2489     SetError(65, t2, s2);
 2490     if (t2 != 0)
 2491         BAM_free(t2, s2);   /* free it, since this was no real alloc */
 2492     }
 2493     ReWriteImage(); /* BAM */
 2494 }
 2495 
 2496 static void cmd_block_free(char *arg)
 2497 {
 2498     int drv, t, s;
 2499 
 2500     while (*arg && *arg != ' ' && *arg != ':' && *arg != 0x1d)
 2501     arg++;
 2502     if (!*arg) {
 2503     SetError(30, 0, 0);
 2504     return;
 2505     }
 2506     drv = get_num_arg(&arg, 1);
 2507     if (drv < 0) {
 2508     SetError(30, 0, 0);
 2509     return;
 2510     }
 2511     t = get_num_arg(&arg, 0);
 2512     if (t < 0) {
 2513     SetError(30, 0, 0);
 2514     return;
 2515     }
 2516     s = get_num_arg(&arg, 0);
 2517     if (s < 0) {
 2518     SetError(30, 0, 0);
 2519     return;
 2520     }
 2521     if (t < 1 || t > 35 || s >= ZBR_ns[t]) {
 2522     SetError(66, t, s);
 2523     return;
 2524     }
 2525 
 2526 #ifdef DEBUG_BLOCK_CMDS
 2527     printf("B-F: %d %d %d\n", drv, t, s);
 2528 #endif
 2529 
 2530     if (emu_mode != EMU_MODE_D64) {
 2531     SetError(0, 0, 0);  /* let it be ok */
 2532     return;
 2533     }
 2534 
 2535     if (ImageRO) {
 2536     SetError(26, 0, 0); /* write protect */
 2537     return;
 2538     }
 2539     if (t != 18)
 2540     BAM_free(t, s);
 2541     SetError(0, 0, 0);
 2542     ReWriteImage(); /* BAM */
 2543 }
 2544 
 2545 /* Execute a command channel string */
 2546 static void PerformCommand(char *cmd, int len)
 2547 {
 2548     char *cp;
 2549 
 2550     if (len) {
 2551     cmd[len] = 0;
 2552     if (*cmd == 'U') {
 2553         if (cmd[1] == 'J' || cmd[1] == ':') {
 2554         Init_IECDos();
 2555         return;
 2556         }
 2557         if (cmd[1] == '9' || cmd[1] == 'I') {
 2558         SetError(0, 0, 0);
 2559         return;
 2560         }
 2561         if (cmd[1] == '1' || cmd[1] == 'A') {
 2562         if (!cmd_block_read(cmd + 2, 0))
 2563             return;
 2564         SetError(0, 0, 0);
 2565         return;
 2566         }
 2567         if (cmd[1] == '2' || cmd[1] == 'B') {
 2568         if (!cmd_block_write(cmd + 2, 0))
 2569             return;
 2570         SetError(0, 0, 0);
 2571         return;
 2572         }
 2573         if (cmd[1] == '0' && cmd[2] == '>' && cmd[3] < 31) {
 2574         unit = cmd[3];
 2575         SetError(0, 0, 0);
 2576         return;
 2577         }
 2578 #ifdef PRINTER_SUPPORT
 2579         if (cmd[1] == 'P') {                                /* ALEEXTENSION: "up" Close Printer and send job */
 2580         if (printer_open && printer_cmd == -1) 
 2581             ClosePrinter();
 2582         SetError(0, 0, 0);
 2583         return;
 2584         }
 2585 #endif
 2586         SetError(31, 0, 0);
 2587         return;
 2588     }
 2589     if (*cmd == 'I' || *cmd == 'V') {
 2590         SetError(0, 0, 0);
 2591         return;
 2592     }
 2593     if (*cmd == 'N') {          /* new */
 2594         if (!cmd_new(cmd))
 2595         return;
 2596         read_the_dir();
 2597         SetError(0, 0, 0);
 2598         return;
 2599     }
 2600     if (*cmd == 'G') {          /* change directory ... */
 2601         cmd_go(cmd);
 2602         return;
 2603     }
 2604     if (*cmd == 'S') {          /* scratch */
 2605         if (cmd_scratch(cmd))
 2606         read_the_dir();
 2607         return;
 2608     }
 2609     if (*cmd == 'R') {          /* rename */
 2610         if (!cmd_rename(cmd))
 2611         return;
 2612         read_the_dir();
 2613         SetError(0, 0, 0);
 2614         return;
 2615     }
 2616     if (*cmd == 'C') {          /* copy, concat */
 2617         if (!cmd_copy(cmd))
 2618         return;
 2619         read_the_dir();
 2620         SetError(0, 0, 0);
 2621         return;
 2622     }
 2623     if (*cmd == 'P') {      /* goto record */
 2624         SetError(3, 0, 0);
 2625         return;
 2626     }
 2627     if (cmd[0] == 'B') {        /* block operation */
 2628         cp = strchr(cmd, '-');
 2629         if (!cp) {
 2630         SetError(31, 0, 0);
 2631         return;
 2632         }
 2633         cp++;
 2634         switch(*cp) {
 2635         case 'R':
 2636             if (cmd_block_read(cp + 1, 1))
 2637             SetError(0, 0, 0);
 2638             break;
 2639         case 'W':
 2640             if (cmd_block_write(cp + 1, 1))
 2641             SetError(0, 0, 0);
 2642             break;
 2643         case 'P':
 2644             if (cmd_block_pointer(cp + 1))
 2645             SetError(0, 0, 0);
 2646             break;
 2647         case 'A':
 2648             cmd_block_allocate(cp + 1);
 2649             break;
 2650         case 'F':
 2651             cmd_block_free(cp + 1);
 2652             break;
 2653         case 'E':
 2654             VicMessage("FAST-LOADER detected",60*5);
 2655             NotImplemented(cmd);
 2656             SetError(3, 0, 0);
 2657             break;
 2658         default:
 2659             SetError(31, 0, 0);
 2660             break;
 2661         }
 2662         return;
 2663     }
 2664     if (cmd[0] == 'M') {        /* memory operation */
 2665         VicMessage("FAST-LOADER detected",60*5);
 2666         NotImplemented(cmd);
 2667         SetError(3, 0, 0);
 2668         return;
 2669     }
 2670     }
 2671     SetError(31, 0, 0);
 2672 }
 2673 
 2674 
 2675 void SetCmdChannel(char *buf, int len)
 2676 {
 2677     memcpy(chanbuf[CMD_CHAN], buf, len);
 2678     chanbufp[CMD_CHAN] = 0;
 2679     chanpos[CMD_CHAN] = 0;
 2680     filelen[CMD_CHAN] = len;
 2681     SetError(0, 0, 0);          /* next error */
 2682 }
 2683 
 2684 void Init_IECDos(void)
 2685 {
 2686     int i;
 2687 
 2688     for (i = 0; i < NCHAN; i++) {
 2689     flags[i] = 0;
 2690     chfd[i] = -1;
 2691     }
 2692     unit = DEF_UNIT;
 2693 #ifdef PRINTER_SUPPORT
 2694     printer_unit = DEF_PRINTER;
 2695 #endif
 2696 #ifndef __GO32__
 2697     umask(UMask = umask(0));
 2698     UMask ^= 0666;
 2699 #endif
 2700     globflags = 0;
 2701     if (FloppyImage) {
 2702     if (MountD64())
 2703         emu_mode = EMU_MODE_D64;
 2704     else {
 2705         FloppyImage = NULL;
 2706         emu_mode = EMU_MODE_FILESYS;
 2707     }
 2708     } else
 2709     emu_mode = EMU_MODE_FILESYS;
 2710     read_the_dir();
 2711     errors[73] = emulver + 5;
 2712     SetError(73, 0, 0);
 2713 }
 2714 
 2715 void ReadABlock(int ch)
 2716 {
 2717     int bl;
 2718     struct DataBlock *db;
 2719     
 2720     if (chfd[ch] == -4) {       /* Read from directory */
 2721     bl = read1541dirblock(ch);
 2722     if (bl) {
 2723         filepos[ch] += bl;
 2724         chanbufp[ch] = 0;
 2725         filelen[ch] = filepos[ch];
 2726     }
 2727     } else if (emu_mode == EMU_MODE_D64) {
 2728     db = (struct DataBlock *)(chanbuf[ch]);
 2729     bl = AbsoluteSector(db->datanext.track, db->datanext.sector);
 2730     if (bl == -1) {
 2731         SetError(66, db->datanext.track, db->datanext.sector);
 2732         chanpos[ch] = filelen[ch] = 0;
 2733         return;
 2734     }
 2735     memcpy(chanbuf[ch], ImageData + bl * 256, 256);
 2736     if (d64_has_errinfo) {
 2737         if (ImageErrInfo[bl] != 1) {
 2738         SetError(ErrInfo2Error(ImageErrInfo[bl]), 0, 0);
 2739         chanpos[ch] = filelen[ch] = 0;
 2740         return;
 2741         }
 2742     }
 2743     if (db->datanext.track == 0) {  /* last sector */
 2744         filelen[ch] = db->datanext.sector + 1;
 2745     } else {
 2746         filelen[ch] = 257;
 2747     }
 2748     chanpos[ch] = 2;
 2749     chanbufp[ch] = 2;
 2750     } else if (filelen[ch] > filepos[ch]) {
 2751     bl = filelen[ch] - filepos[ch];
 2752     if (bl > 256)
 2753         bl = 256;
 2754     read(chfd[ch], chanbuf[ch], bl);
 2755     filepos[ch] += bl;
 2756     chanbufp[ch] = 0;
 2757     }
 2758 }
 2759 
 2760 void WriteABlock(int ch)
 2761 {
 2762     write(chfd[ch], chanbuf[ch], chanbufp[ch]);
 2763     filepos[ch] += chanbufp[ch];
 2764     chanbufp[ch] = 0;
 2765 }
 2766 
 2767 int DoOpenFile(int ch, char *name)
 2768 {
 2769     struct stat st;
 2770     int i;
 2771     int fmd;
 2772 
 2773     /* FIXME : TYPE_L support */
 2774 
 2775 #if defined(JOHNS)
 2776     printf("Open C64 `%s' %d\n", name, ch);  /* DEBUG */
 2777 #endif
 2778     /* Really open the file on disk */
 2779     if (ch == CMD_CHAN) {
 2780     fmod[ch] = 0;
 2781     chfd[ch] = -2;
 2782     if (filenamelen[ch])
 2783         PerformCommand(filenamebuf[ch], filenamelen[ch]);
 2784     return 0;
 2785     }
 2786 
 2787     if (ParseFilename(filenamebuf[ch], filenamelen[ch], 1))
 2788     return 1;
 2789 
 2790     if (!dir && !nbuf[0]) {
 2791     SetError(34, 0, 0);
 2792     return 1;
 2793     }
 2794 
 2795     if (chanopen) {
 2796     flags[ch] = F_CHANOPEN;
 2797     chfd[ch] = -6;
 2798     filepos[ch] = 0;
 2799     chanpos[ch] = 0;
 2800     filelen[ch] = 256;
 2801     chanbuf[ch][0] = ch;
 2802     SetError(0, 0, 0);
 2803     return 0;
 2804     }
 2805     if (ftype == TYPE_NOTHING) ftype = TYPE_P;
 2806     if (openmode == MODE_NOTHING) openmode = (ch == 1 ? MODE_W : MODE_R);
 2807 
 2808     if (ch == 0 && ftype == TYPE_P && openmode == MODE_R) { /* always read */
 2809     chfd[ch] = -1;
 2810 
 2811     if (dir) {
 2812         if (open1541dir(nbuf, ch)) {
 2813         SetError(71, 0, 0);       /* another dir is open */
 2814         return 1;
 2815         }
 2816         flags[ch] = F_READ;
 2817         filepos[ch] = 0;
 2818         chanpos[ch] = 0;
 2819         ReadABlock(ch);
 2820         SetError(0, 0, 0);
 2821         return 0;
 2822     }
 2823     if (overwrite) {
 2824         SetError(33, 0, 0);
 2825         return 1;
 2826     }
 2827     if (!findfile(ch, nbuf)) {
 2828         SetError(62, 0, 0);
 2829         return 1;
 2830     }
 2831     if (c4dhook[findfileidx].mode != ftype) {
 2832         SetError(64, 0, 0);
 2833         return 1;
 2834     }
 2835     flags[ch] = F_READ;
 2836     if (emu_mode == EMU_MODE_D64) {
 2837         chfd[ch] = -5;
 2838         filepos[ch] = 0;
 2839         chanpos[ch] = 256;
 2840         chanbuf[ch][0] = c4dhook[findfileidx].u.d64.starttrack;
 2841         chanbuf[ch][1] = c4dhook[findfileidx].u.d64.startsector;
 2842         SetError(0, 0, 0);
 2843         ReadABlock(ch);
 2844         return (errorcode != 0);
 2845     }
 2846 #ifdef __GO32__
 2847     chfd[ch] = open(unixname[ch], O_RDONLY|BINARY_FILE);
 2848 #else
 2849     if ((c4dhook[findfileidx].flags & FLG_PC64) == 0
 2850 #ifdef DIRFILE
 2851         && emu_mode == EMU_MODE_FILESYS
 2852 #endif
 2853         && ftype == TYPE_D)
 2854         chmod(unixname[ch],0600);
 2855     chfd[ch] = open(unixname[ch], O_RDONLY);
 2856     if ((c4dhook[findfileidx].flags & FLG_PC64) == 0
 2857 #ifdef DIRFILE
 2858         && emu_mode == EMU_MODE_FILESYS
 2859 #endif
 2860         && ftype == TYPE_D)
 2861         chmod(unixname[ch], 0);
 2862 #endif
 2863     fmod[ch] = O_RDONLY;
 2864     if (chfd[ch] != -1)
 2865         if (fstat(chfd[ch], &st) != -1) {
 2866         filelen[ch] = st.st_size;
 2867         if ((c4dhook[findfileidx].flags & FLG_PC64)) {
 2868             filelen[ch] -= sizeof(struct pc64entry);
 2869             lseek(chfd[ch], sizeof(struct pc64entry), SEEK_SET);
 2870         } else if ((c4dhook[findfileidx].flags & FLG_REL) 
 2871 #ifdef DIRFILE
 2872                 && emu_mode == EMU_MODE_FILESYS
 2873 #endif
 2874                         ) {
 2875             filelen[ch] -= 4;
 2876             lseek(chfd[ch], 4, SEEK_SET);
 2877         }
 2878         filepos[ch] = 0;
 2879         ReadABlock(ch);
 2880         chanpos[ch] = 0;
 2881         SetError(0, 0, 0);
 2882         return 0;
 2883         }
 2884     SetError(62, 0, 0);
 2885     return 1;
 2886     } else if (ch == 1 && ftype == TYPE_P && openmode == MODE_W) { /* always write */
 2887 
 2888     if (!overwrite && nbuf[0] == '@') {
 2889         /* overwrite w/o ':', no longer detected by ParseFileName() to mimic 1541 behaviour */
 2890         i = 0;
 2891         if (!nbuf[1]) {
 2892         SetError(34, 0, 0);
 2893         return 1;
 2894         }
 2895         do {
 2896         nbuf[i] = nbuf[i + 1];
 2897         i++;
 2898         } while (nbuf[i]);
 2899         overwrite = 1;
 2900     }
 2901 
 2902     if (emu_mode == EMU_MODE_D64) {         /* for now! */
 2903         SetError(26, 0, 0); /* write protect */
 2904         return 1;
 2905     }
 2906 
 2907     if (strchr(nbuf, '*') || strchr(nbuf, '?'))     /* has patterns */
 2908     {
 2909         if (!findfile(ch, nbuf)) {
 2910         SetError(62, 0, 0);
 2911         return 1;
 2912         }
 2913         if (!overwrite) {
 2914         SetError(63, 0, 0);
 2915         return 1;
 2916         }
 2917         if (c4dhook[findfileidx].mode != ftype) {
 2918         SetError(64, 0, 0);
 2919         return 1;
 2920         }
 2921         if ((c4dhook[findfileidx].flags & FLG_LOCK)) {
 2922         SetError(26, 0, 0); /* write protect */
 2923         return 1;
 2924         }
 2925     } else {
 2926 #ifdef DIRFILE
 2927         if (emu_mode == EMU_MODE_DIRFILE) {
 2928         if (!findfile(ch, nbuf)) {
 2929             i = MakeDirEntry(nbuf, ftype);
 2930             if (i == -1) {
 2931             SetError(72, 0, 0);
 2932             return 1;
 2933             }
 2934             strcpy(unixname[ch], c4wrhook[i].u.osname);
 2935             rewrite_dir_file();
 2936             read_the_dir();
 2937         } else {
 2938             if (!overwrite) {
 2939             SetError(63, 0, 0);
 2940             return 1;
 2941             }
 2942             if ((c4dhook[findfileidx].flags & FLG_LOCK)) {
 2943             SetError(26, 0, 0); /* write protect */
 2944             return 1;
 2945             }
 2946         }
 2947         }
 2948         else
 2949 #endif
 2950         {
 2951             if (findfile(ch, nbuf))
 2952         {
 2953             if (!overwrite) {
 2954             SetError(63, 0, 0);
 2955             return 1;
 2956             }
 2957             if ((c4dhook[findfileidx].flags & FLG_LOCK)) {
 2958             SetError(26, 0, 0); /* write protect */
 2959             return 1;
 2960             }
 2961         } else
 2962             strcpy(unixname[ch], nbuf);
 2963         }
 2964     }
 2965 #ifdef ALWAYS_SAVE_P00
 2966 #ifdef DIRFILE
 2967     if (emu_mode == EMU_MODE_FILESYS)
 2968 #endif
 2969     {
 2970         if (findfileidx != -1)
 2971         unlink(unixname[ch]);
 2972         strcpy(unixname[ch], MakeP00(nbuf));
 2973     }
 2974 #endif
 2975     flags[ch] = F_WRITE;
 2976     if (overwrite)
 2977         flags[ch] |= F_OVERWRITE;
 2978     i = O_WRONLY|O_CREAT;
 2979     if (overwrite)
 2980         i |= O_TRUNC;
 2981 #ifdef __GO32__
 2982     fmd = 0666;
 2983     chfd[ch] = open(unixname[ch], i|BINARY_FILE, fmd);
 2984 #else
 2985 #ifdef DIRFILE
 2986     if (emu_mode == EMU_MODE_DIRFILE)
 2987         fmd = 0;
 2988     else
 2989 #endif
 2990 #ifdef ALWAYS_SAVE_P00
 2991         fmd = 0;
 2992 #else
 2993         fmd = mode_2_stat(ftype);
 2994     if (fmd == -1) {
 2995         SetError(28, 0, 0);
 2996         return 1;
 2997     }
 2998     if (fmd == -2) {
 2999         chfd[ch] = open(unixname[ch], i, 0666);
 3000         fmd = 0;
 3001     } else
 3002 #endif
 3003     {
 3004         fmd |= (0666 & UMask);
 3005         chfd[ch] = open(unixname[ch], i, fmd);
 3006     }
 3007 #endif        
 3008     fmod[ch] = fmd;
 3009     if (chfd[ch] != -1) {
 3010 #ifndef ALWAYS_SAVE_P00
 3011         if (findfileidx != -1 && (c4dhook[findfileidx].flags & FLG_PC64))
 3012 #endif
 3013         {
 3014             memset(&pc64header, 0, sizeof(pc64header));
 3015         strcpy(pc64header.detect, PC64ID);
 3016 #ifdef ALWAYS_SAVE_P00
 3017         if (findfileidx == -1) {
 3018             strcpy(pc64header.name, nbuf);
 3019             pc64header.recordsize = 0;
 3020         } else
 3021 #endif
 3022         {
 3023             strcpy(pc64header.name, c4dhook[findfileidx].name);
 3024             pc64header.recordsize = c4dhook[findfileidx].recordsize;
 3025         }
 3026         strasc2cbm(pc64header.name);
 3027         if (write(chfd[ch], &pc64header, sizeof(pc64header)) != sizeof(pc64header)) {
 3028             close(chfd[ch]);
 3029             chfd[ch] = -1;
 3030             chanbufp[ch] = 0;
 3031             chanpos[ch] = 0;
 3032             filelen[ch] = 0;
 3033             flags[ch] = 0;
 3034             SetError(28, 0, 0);
 3035             return 1;
 3036         }
 3037         }
 3038         filelen[ch] = 0;
 3039         filepos[ch] = 0;
 3040         chanbufp[ch] = 0;
 3041         chanpos[ch] = 0;
 3042 #ifndef __GO32__
 3043         chmod(unixname[ch], fmd);
 3044 #endif        
 3045         SetError(0, 0, 0);
 3046         return 0;
 3047     }
 3048     SetError(28, 0, 0);
 3049     return 1;
 3050     } else {
 3051     if (ftype == TYPE_L) {
 3052         /* FIXME: TYPE_L fill here: 
 3053            recordsize: openmode ( or 0 if not specified ) */
 3054         SetError(50, 0, 0);
 3055         return 1;
 3056     }
 3057     if (dir) /* open dir with chans other then 0 returns raw BAM data! */
 3058     {
 3059         SetError(3, 0, 0);
 3060         return 1;
 3061     }
 3062     /* printf("Open `%s'\n",nbuf);  * DEBUG */
 3063     switch(openmode) {
 3064         case MODE_W:
 3065         case MODE_A:
 3066 
 3067         if (!overwrite && nbuf[0] == '@') {
 3068             /* overwrite w/o ':', no longer detected by ParseFileName() to mimic 1541 behaviour */
 3069             i = 0;
 3070             if (!nbuf[1]) {
 3071             SetError(34, 0, 0);
 3072             return 1;
 3073             }
 3074             do {
 3075             nbuf[i] = nbuf[i + 1];
 3076             i++;
 3077             } while (nbuf[i]);
 3078             overwrite = 1;
 3079         }
 3080 
 3081         if (emu_mode == EMU_MODE_D64) {         /* for now! */
 3082             SetError(26, 0, 0); /* write protect */
 3083             return 1;
 3084         }
 3085 
 3086         if (strchr(nbuf, '*') || strchr(nbuf, '?'))     /* has patterns */
 3087         {
 3088             if (!findfile(ch, nbuf)) {
 3089             SetError(62, 0, 0);
 3090             return 1;
 3091             }
 3092             if (openmode != MODE_A && !overwrite) {
 3093             SetError(63, 0, 0);
 3094             return 1;
 3095             }
 3096             if (c4dhook[findfileidx].mode != ftype) {
 3097             SetError(64, 0, 0);
 3098             return 1;
 3099             }
 3100             if ((c4dhook[findfileidx].flags & FLG_LOCK)) {
 3101             SetError(26, 0, 0); /* write protect */
 3102             return 1;
 3103             }
 3104         } else {
 3105 #ifdef DIRFILE
 3106             if (emu_mode == EMU_MODE_DIRFILE) {
 3107             if (!findfile(ch, nbuf)) {
 3108                 i = MakeDirEntry(nbuf, ftype);
 3109                 if (i == -1) {
 3110                 SetError(72, 0, 0);
 3111                 return 1;
 3112                 }
 3113                 strcpy(unixname[ch], c4wrhook[i].u.osname);
 3114                 rewrite_dir_file();
 3115                 read_the_dir();
 3116             } else {
 3117                 if (openmode != MODE_A && !overwrite) {
 3118                 SetError(63, 0, 0);
 3119                 return 1;
 3120                 }
 3121                 if ((c4dhook[findfileidx].flags & FLG_LOCK)) {
 3122                 SetError(26, 0, 0); /* write protect */
 3123                 return 1;
 3124                 }
 3125             }
 3126             }
 3127             else
 3128 #endif
 3129             {
 3130             if (findfile(ch, nbuf))
 3131             {
 3132                 if (openmode != MODE_A && !overwrite) {
 3133                 SetError(63, 0, 0);
 3134                 return 1;
 3135                 }
 3136                 if ((c4dhook[findfileidx].flags & FLG_LOCK)) {
 3137                 SetError(26, 0, 0); /* write protect */
 3138                 return 1;
 3139                 }
 3140             } else
 3141                 strcpy(unixname[ch], nbuf);
 3142             }
 3143         }
 3144 #ifdef ALWAYS_SAVE_P00
 3145 #ifdef DIRFILE
 3146         if (emu_mode == EMU_MODE_FILESYS)
 3147 #endif
 3148             if (openmode != MODE_A) {
 3149             if (findfileidx != -1)
 3150                 unlink(unixname[ch]);
 3151             strcpy(unixname[ch], MakeP00(nbuf));
 3152             }
 3153 #endif
 3154         flags[ch] = F_WRITE;
 3155         if (overwrite)
 3156             flags[ch] |= F_OVERWRITE;
 3157         i = O_WRONLY|O_CREAT;
 3158         if (overwrite) i |= O_TRUNC;
 3159         if (openmode == MODE_A) i |= O_APPEND;
 3160         if ((i & (O_TRUNC|O_APPEND)) == (O_TRUNC|O_APPEND)) {
 3161             SetError(33, 0, 0);
 3162             return 1;
 3163         }
 3164 #ifdef __GO32__
 3165         fmd = 0666;
 3166         chfd[ch] = open(unixname[ch], i|BINARY_FILE, fmd);
 3167 #else
 3168 #ifdef DIRFILE
 3169         if (emu_mode == EMU_MODE_DIRFILE)
 3170             fmd = 0;
 3171         else
 3172 #endif
 3173 #ifdef ALWAYS_SAVE_P00
 3174         {
 3175             if (openmode != MODE_A && findfileidx == -1)
 3176             fmd = 0;
 3177             else
 3178             fmd = mode_2_stat(ftype);
 3179         }
 3180 #else
 3181             fmd = mode_2_stat(ftype);
 3182 #endif
 3183         if (fmd == -1) {
 3184             SetError(28, 0, 0);
 3185             return 1;
 3186         }
 3187         if (fmd == -2) {
 3188             chfd[ch] = open(unixname[ch], i, 0666);
 3189             fmd = 0;
 3190         } else {
 3191             fmd |= (0666 & UMask);
 3192             chfd[ch] = open(unixname[ch], i, fmd);
 3193         }
 3194 #endif        
 3195         fmod[ch] = fmd;
 3196         if (chfd[ch] != -1) {
 3197 #ifdef ALWAYS_SAVE_P00
 3198             if (openmode != MODE_A)
 3199 #else
 3200             if (openmode != MODE_A && findfileidx != -1 && (c4dhook[findfileidx].flags & FLG_PC64))
 3201 #endif
 3202             {
 3203             memset(&pc64header, 0, sizeof(pc64header));
 3204             strcpy(pc64header.detect, PC64ID);
 3205 #ifdef ALWAYS_SAVE_P00
 3206             if (findfileidx == -1) {
 3207                 strcpy(pc64header.name, nbuf);
 3208                 pc64header.recordsize = 0;
 3209             } else
 3210 #endif
 3211             {
 3212                 strcpy(pc64header.name, c4dhook[findfileidx].name);
 3213                 pc64header.recordsize = c4dhook[findfileidx].recordsize;
 3214             }
 3215             strasc2cbm(pc64header.name);
 3216             if (write(chfd[ch], &pc64header, sizeof(pc64header)) != sizeof(pc64header)) {
 3217                 close(chfd[ch]);
 3218                 chfd[ch] = -1;
 3219                 chanbufp[ch] = 0;
 3220                 chanpos[ch] = 0;
 3221                 filelen[ch] = 0;
 3222                 flags[ch] = 0;
 3223                 SetError(28, 0, 0);
 3224                 return 1;
 3225             }
 3226             }
 3227             filelen[ch] = 0;
 3228             filepos[ch] = 0;
 3229             chanbufp[ch] = 0;
 3230             chanpos[ch] = 0;
 3231 #ifndef __GO32__
 3232             chmod(unixname[ch], fmd);
 3233 #endif        
 3234             SetError(0, 0, 0);
 3235             return 0;
 3236         }
 3237         SetError(28, 0, 0);
 3238         return 1;
 3239         break;
 3240         case MODE_R:
 3241         case MODE_M:
 3242         default:
 3243         if (!findfile(ch, nbuf)) {
 3244             SetError(62, 0, 0);
 3245             return 1;
 3246         }
 3247         if (overwrite) {
 3248             SetError(33, 0, 0);
 3249             return 1;
 3250         }
 3251         if (c4dhook[findfileidx].mode != ftype) {
 3252             SetError(64, 0, 0);
 3253             return 1;
 3254         }
 3255         flags[ch] = F_READ;
 3256         if (emu_mode == EMU_MODE_D64) {
 3257             chfd[ch] = -5;
 3258             filepos[ch] = 0;
 3259             chanpos[ch] = 256;
 3260             chanbuf[ch][0] = c4dhook[findfileidx].u.d64.starttrack;
 3261             chanbuf[ch][1] = c4dhook[findfileidx].u.d64.startsector;
 3262             SetError(0, 0, 0);
 3263             ReadABlock(ch);
 3264             return (errorcode != 0);
 3265         }
 3266 #ifndef __GO32__
 3267         if (
 3268 #ifdef DIRFILE
 3269             emu_mode == EMU_MODE_FILESYS &&
 3270 #endif
 3271                     ftype == TYPE_D)
 3272             chmod(unixname[ch],0600);
 3273 #endif
 3274         chfd[ch] = open(unixname[ch], O_RDONLY|BINARY_FILE);
 3275 #ifndef __GO32__
 3276         if (
 3277 #ifdef DIRFILE
 3278             emu_mode == EMU_MODE_FILESYS &&
 3279 #endif
 3280                     ftype == TYPE_D)
 3281             chmod(unixname[ch],0);
 3282 #endif
 3283         if (chfd[ch] != -1)
 3284             if (fstat(chfd[ch],&st) != -1) {
 3285             filelen[ch] = st.st_size;
 3286             if ((c4dhook[findfileidx].flags & FLG_PC64)) {
 3287                 filelen[ch] -= sizeof(struct pc64entry);
 3288                 lseek(chfd[ch], sizeof(struct pc64entry), SEEK_SET);
 3289             }
 3290             filepos[ch] = 0;
 3291             ReadABlock(ch);
 3292             chanpos[ch] = 0;
 3293             SetError(0, 0, 0);
 3294             return 0;
 3295             }
 3296         SetError(62, 0, 0);
 3297         return 1;
 3298     }
 3299     }
 3300 }
 3301 
 3302 void DoCloseFile(int ch)
 3303 {
 3304     /* Write the rest of block */
 3305     
 3306     if (flags[ch] & F_WRITE)
 3307     WriteABlock(ch);
 3308     if (chfd[ch] > 0) {
 3309     close(chfd[ch]);
 3310     } else if (chfd[ch] == -2 ) {
 3311     /* command channel */ /* FIXME: close all other channels !!! */
 3312     } else if (chfd[ch] == -4 ) {
 3313     /* close a directory */
 3314     close1541dir(ch);
 3315     }
 3316     read_the_dir();
 3317 
 3318     chfd[ch] = -1;
 3319     chanbufp[ch] = 0;
 3320     chanpos[ch] = 0;
 3321     filelen[ch] = 0;
 3322     flags[ch] = 0;
 3323 }
 3324 
 3325 
 3326 void WriteToFile(int ch, int byte)
 3327 {
 3328     if (chfd[ch] == -1) {
 3329     if (errorcode == 0)
 3330         SetError(61, 0, 0);
 3331     IEC_SetStatus(0x03);
 3332     return;
 3333     }
 3334     if (chfd[ch] == -6) {
 3335     if(chanbufp[ch] == 256) {
 3336         IEC_SetStatus(0x03);
 3337         return;
 3338     }
 3339     chanbuf[ch][chanbufp[ch]++] = byte;
 3340     chanpos[ch]++;
 3341     return;
 3342     }
 3343     if (ch == CMD_CHAN)  { /* fast opened cmd channel */
 3344     if (byte == '\r') {
 3345         if (chanbufp[ch])
 3346         PerformCommand(chanbuf[ch], chanbufp[ch]);
 3347         chanpos[ch] = 0;
 3348         chanbufp[ch] = 0;
 3349         return;
 3350     }
 3351     if (chanbufp[ch] == 63) {       /* MAX CMD length */
 3352         return;
 3353     } 
 3354     }
 3355     chanbuf[ch][chanbufp[ch]++] = byte;
 3356     chanpos[ch]++;
 3357     if (chanbufp[ch] == 256) {
 3358     WriteABlock(ch);
 3359     chanbufp[ch] = 0;
 3360     }
 3361 }
 3362 
 3363 int ReadFromFile(int ch)
 3364 {
 3365     int byte;
 3366 
 3367     if (chfd[ch] == -1 ) {
 3368     if (errorcode == 0)
 3369         SetError(61, 0, 0);
 3370     IEC_SetStatus(0x02);
 3371     return '\r';
 3372     }
 3373     if (chanpos[ch] < filelen[ch]) {
 3374     byte = chanbuf[ch][chanbufp[ch]++];
 3375     chanpos[ch]++;
 3376     if (chanbufp[ch] == 256) {
 3377         if (chfd[ch] == -4 || chanpos[ch] < filelen[ch])
 3378         ReadABlock(ch);
 3379     }
 3380     } else {
 3381     IEC_SetStatus(0x02);
 3382     byte = '\r';
 3383     }
 3384     if (chanpos[ch] == filelen[ch]) {
 3385     IEC_SetStatus(0x40);
 3386     if (ch == CMD_CHAN) {
 3387         SetError(0, 0, 0);
 3388         SetCmdChannel(errorbuf, strlen(errorbuf));
 3389     }
 3390     }
 3391     return byte;
 3392 }
 3393 
 3394 #ifdef PRINTER_SUPPORT
 3395 /* The Printer Subroutines */
 3396 
 3397 void ClosePrinter(void)
 3398 {
 3399     static char prbuf[128];
 3400     close(printer_fd);
 3401     sprintf(prbuf, printer_printcmd, DEF_PRINTFILE);
 3402     system(prbuf);
 3403     printer_open = 0;
 3404     printer_cmd = 10;                           /* reset state */
 3405 }
 3406 
 3407 void OpenPrinter(void)
 3408 {
 3409     if (printer_open) 
 3410     ClosePrinter();
 3411     strcpy(DEF_PRINTFILE, SET_PRINTFILE);
 3412     mktemp(DEF_PRINTFILE);
 3413     if (printer_cmd == -1)
 3414     printer_fd = open(DEF_PRINTFILE, O_WRONLY|O_CREAT|O_APPEND, 0666);
 3415     else
 3416     printer_fd = open(DEF_PRINTFILE, O_WRONLY|O_CREAT, 0666);
 3417     printer_open = 1;
 3418 }
 3419 
 3420 void WriteToPrinter(int byte)
 3421 {
 3422     unsigned char c;
 3423 
 3424     if (printer_cmd != 0 && printer_cmd != -1 && printer_cmd != 7)
 3425     /* sa: 0:CBM-GRAPHIC charset, 7:CBM-Business charset, -1:no sa given! */
 3426     return;
 3427     c = byte & 0xff;
 3428     if (printer_cmd == 7)
 3429     c = cbmtoasc(c);
 3430     if (c == '\r')
 3431     c = '\n';
 3432     write(printer_fd, &c, 1);
 3433 }
 3434 
 3435 void FlushPrinter(void)
 3436 {
 3437     /* FIXME: add some kind of timeout here to enforce printing of opened without a secondary address */
 3438     /* this routine is called (by unlisten) every time a chunk of such data was written */
 3439 }
 3440 #endif
 3441 
 3442 /* The C64 Subroutines */
 3443 
 3444 void IEC_Listen(int iec_unit)
 3445 {
 3446     IEC_SetStatus(0);
 3447     aktunit = iec_unit;
 3448     if (aktunit != unit) {
 3449 #ifdef PRINTER_SUPPORT
 3450     if (aktunit != printer_unit)
 3451         IEC_SetStatus(0x80);
 3452     else
 3453         globflags = F_PR_LISTEN;
 3454 #else
 3455        IEC_SetStatus(0x80);
 3456 #endif
 3457     } else
 3458     globflags = F_INLISTEN;
 3459 }
 3460 
 3461 void IEC_SEC_Listen(int iec_sec)
 3462 {
 3463     int cmd;
 3464 
 3465     IEC_SetStatus(0);
 3466 #ifdef PRINTER_SUPPORT
 3467     if ((aktunit == printer_unit) && (globflags == F_PR_LISTEN)) {
 3468     printer_cmd = iec_sec & 15;
 3469     cmd = iec_sec >> 4;
 3470     switch (cmd) {
 3471         case 0xe:           /* file close */
 3472         globflags = F_PR_CLOSE;
 3473         break;
 3474         case 0x6:           /* write/open */
 3475         OpenPrinter();
 3476         globflags = F_PR_WRITE;
 3477         return;
 3478         default:
 3479         globflags = 0;
 3480         IEC_SetStatus(0);
 3481         return;
 3482     }
 3483     }
 3484 #endif
 3485     if ((aktunit != unit) || ((globflags & F_INLISTEN) == 0) )
 3486     IEC_SetStatus(0x80);
 3487     else {
 3488     channel = iec_sec & 15;
 3489     cmd = iec_sec >> 4;
 3490     switch (cmd) {
 3491         case 0xf:           /* file eroeffnen */
 3492         filenamelen[channel] = 0;
 3493         filenamebuf[channel][0] = 0;
 3494         globflags = F_INNAMELISTEN;
 3495         break;
 3496         case 0xe:           /* file schliessen */
 3497         globflags = F_INCLOSE;
 3498         break;
 3499         case 0x6:           /* write, save */
 3500         if (channel == CMD_CHAN) {
 3501             if (chfd[channel] == -1) {
 3502             chfd[channel] = -3;
 3503             flags[channel] = F_OPEN;
 3504             }
 3505             flags[channel] |= F_WRITE;
 3506             chanbufp[CMD_CHAN] = 0;
 3507             chanpos[CMD_CHAN] = 0;
 3508             filelen[CMD_CHAN] = 0;
 3509         }
 3510         globflags = F_INLISTEN;
 3511         break;
 3512         default:
 3513         break;
 3514     }
 3515     }
 3516 }
 3517 
 3518 void IEC_Write(int byte)
 3519 {
 3520     int i;
 3521 
 3522     IEC_SetStatus(0);
 3523     if (globflags & F_INNAMELISTEN)
 3524     {
 3525     if ((i = filenamelen[channel]) < 64) {
 3526         filenamebuf[channel][i] = byte;
 3527         filenamelen[channel]++;
 3528     }
 3529     /* ignore rest of name silently.. */
 3530     }
 3531     else if (globflags & F_INLISTEN)
 3532     {
 3533 
 3534     if ((flags[channel] & F_OPEN) == 0)
 3535         IEC_SetStatus(0x02);
 3536     else
 3537         WriteToFile(channel, byte);
 3538     }
 3539 #ifdef PRINTER_SUPPORT
 3540     else if ((globflags & F_PR_WRITE))
 3541     {
 3542     WriteToPrinter(byte);
 3543     }
 3544     else if ((globflags & F_PR_LISTEN))
 3545     {
 3546     if (!printer_open) {
 3547         printer_cmd = -1;           /* Open ohne secaddr */
 3548         OpenPrinter();
 3549     }
 3550     globflags = F_PR_WRITE;
 3551     WriteToPrinter(byte);
 3552     }
 3553 #endif
 3554     else
 3555     IEC_SetStatus(0x02);
 3556 }
 3557 
 3558 void IEC_Unlisten(void)
 3559 {
 3560     IEC_SetStatus(0);
 3561     if ((globflags & F_INNAMELISTEN))
 3562     {
 3563     globflags = 0;
 3564     filenamebuf[channel][filenamelen[channel]] = 0;
 3565     if (DoOpenFile(channel, filenamebuf[channel]) == 0)
 3566         flags[channel] |= F_OPEN;
 3567     }
 3568     else if ((globflags & F_INLISTEN)) {
 3569     if (chfd[channel] < -1) {   /* [fast] opened cmd channel */
 3570         if (chfd[channel] != -6)    /* chanopen */
 3571         {
 3572         if (chanbufp[channel])
 3573             PerformCommand(chanbuf[channel], chanbufp[channel]);     /* should test for length = 0 */
 3574         if (chfd[channel] == -3) {  /* fast opened */
 3575             chfd[channel] = -1;
 3576             flags[channel] = 0;
 3577         }
 3578         }
 3579     }
 3580     globflags = 0;
 3581     }
 3582     else if ((globflags & F_INCLOSE)) {
 3583     DoCloseFile(channel);
 3584     flags[channel] = 0;
 3585     globflags = 0;
 3586     }
 3587 #ifdef PRINTER_SUPPORT
 3588     else if ((globflags & F_PR_CLOSE)) {
 3589     ClosePrinter();
 3590     globflags = 0;
 3591     }
 3592     else if ((globflags & F_PR_WRITE)) {
 3593     if (printer_cmd == -1)
 3594         FlushPrinter();
 3595     globflags = 0;
 3596     }
 3597 #endif
 3598     else
 3599     IEC_SetStatus(0x02);
 3600 }
 3601 
 3602 void IEC_Talk(int iec_unit)
 3603 {
 3604     IEC_SetStatus(0);
 3605     aktunit = iec_unit;
 3606     if (aktunit != unit)
 3607     IEC_SetStatus(0x80);
 3608     else
 3609     globflags = F_INTALK;
 3610 }
 3611 
 3612 void IEC_SEC_Talk(int iec_sec)
 3613 {
 3614     IEC_SetStatus(0);
 3615     if (aktunit != unit || (globflags & F_INTALK) == 0 )
 3616     IEC_SetStatus(0x80);
 3617     else {
 3618     channel = iec_sec & 15;
 3619     if (channel != CMD_CHAN) {
 3620         if ((flags[channel] & F_OPEN) == 0) {
 3621         if (errorcode == 0)
 3622             SetError(61, 0, 0);
 3623         IEC_SetStatus(0x02);
 3624         }
 3625     } else {
 3626         if (chfd[channel] == -1) {
 3627         chfd[channel] = -3;     /* fast open */
 3628         flags[channel] = F_OPEN|F_READ;
 3629         }
 3630         SetCmdChannel(errorbuf, strlen(errorbuf));
 3631     }
 3632     }
 3633 }
 3634 
 3635 void IEC_Untalk(void)
 3636 {
 3637     IEC_SetStatus(0);
 3638     if ((globflags & F_INTALK))
 3639     globflags &= ~F_INTALK;
 3640     else
 3641     IEC_SetStatus(0x02);
 3642     if (chfd[channel] == -3) { /* fast opened cmd channel */
 3643     chfd[channel] = -1;
 3644     flags[channel] = 0;
 3645     }
 3646 }
 3647 
 3648 int IEC_Read(void)
 3649 {
 3650     IEC_SetStatus(0);
 3651     if ((globflags & F_INTALK)) {
 3652         return ReadFromFile(channel);
 3653     }
 3654     /* printf("Illegal read\n");    * DEBUG */
 3655     IEC_SetStatus(0x02);
 3656     return '\r';
 3657 }