/* setdru -- install setdru1 or setdru2                                     */
/* copyright 1983-84  Michael M Rubenstein                                  */

/* version 1.3   9 Feb 84  -- eliminated Z80 code                           */
/*                            change in run time library only, but version  */
/*                            changed to avoid confusion.                   */

/* version 1.2   2 Feb 84  -- code modified for distribution                */

/* version 1.1  26 Nov 83  -- allowed user numbers up thru 31 for           */
/*                            compatibility with zcpr                       */

#define NULL    0
#define TRUE    1
#define FALSE   0

/* declaration of structure for fcb            */
struct fcb_ {
            struct {
                   char drive;        /* drive number */
                   char fname[8];     /* file name */
                   char ftype[3];     /* file type */
                   char fext;         /* file extent */
                   char filler[3];
                   } name1, name2;
            char crec;                /* current record */
            int rrec;                 /* random record */
            char rovf;                /* random record overflow */
            };

#define FCB struct fcb_

#define CTLC            '\003'

#define BUFSIZE         (16*1024)

struct sdr {            char        s_fil1[3];      /* jp instruction */
                        int         s_len;          /* length of module */
                        unsigned    s_plen;         /* length of pgm */
                        struct {    char    s_drive, s_user;
                                    char    s_fname[8];
                                    char    s_ftype[3];
                               }    s_file[9];
           };

extern FCB              dfcb_;
extern char             dbuff_[];
extern struct sdr       sdru1, sdru2;

struct {                char    maxin;
                        char    insize;
                        char    inline[33];
       }                inbuf = { 32 };


main()
{
  static struct sdr     *sdru;
  static int            integr;
  static int            i, j;
  static char           *s, *t;
  FCB                   infcb, outfcb, holdfcb;
  char                  buffer[BUFSIZE];

  signon();
  integr = ask("\nDo you want SETDRU integrated with the program (y or n)? ");
  sdru = integr ? &sdru2 : &sdru1;
  for (;;)
  {
    if (!askfn("\nTo which program do you want to apply SETDRU? ",
               &infcb))
      return;
    strncpy(sdru->s_file[0].s_fname, infcb.name1.fname, 11);
    sdru->s_file[0].s_drive = dfcb_.name1.drive
                            ? dfcb_.name1.drive : (curdsk() + 1);
    sdru->s_file[0].s_user = '\0';
    if (integr)
    {
      if (open(&infcb) != 0xff)
      {
        filsiz(&infcb);
        sdru->s_plen = 128 * infcb.rrec;
        break;
      }
      ps("Cannot open\n");
    }
    else
    {
      sdru->s_file[0].s_user = askuser();
      break;
    }
  }

  if (!askfn("What is the name of the program to be created? ",
             &outfcb))
      return;
  strncpy(&holdfcb, &outfcb, sizeof(FCB));
  strncpy(outfcb.name1.ftype, "$$$", 3);
  delete(&outfcb);
  if (make(&outfcb) == 0xff)
    error("Cannot create file");

  for (i = 1; i < 9; ++i)
  { 
    ps("\nFile ");
    pn(i);
    if (!askfn("? ", &dfcb_))
      if (i > 1)
        break;
      else
      {
        i = 0;
        continue;
      }
    strncpy(sdru->s_file[i].s_fname, dfcb_.name1.fname, 11);
    sdru->s_file[i].s_drive = dfcb_.name1.drive
                            ? dfcb_.name1.drive : (curdsk() + 1);
    sdru->s_file[i].s_user = askuser();
  }

  for (s = (char *) sdru, i = sdru->s_len; i > 0; s += 128, i -=128)
  {
    setdma(s);
    if (wrseq(&outfcb))
      error("Error writing file.");
  }
  if (integr)
  {
    do
    {
      for (s = buffer, i = BUFSIZE; i > 0; s += 128, i -= 128)
      {
        setdma(s);
        if (j = rdseq(&infcb))
          break;
      }
      for (t = buffer; t < s; t += 128)
      {
        setdma(t);
        if (wrseq(t, &outfcb))
          error("Error writing file.");
      }
    } while(!j);
  }

  close(&outfcb);
  delete(&holdfcb);
  strncpy(&outfcb.name2, &holdfcb.name1, sizeof(outfcb.name1));
  outfcb.name2.drive = '\0';
  if (rename(&outfcb) == 0xff)
    error("Cannot rename output file.");
  ps("\nInstallation successful.\n");
}

signon()
{
  static char           *msg[] = {
  "Copyright 1983-4  Michael M Rubenstein\n",
  "SETDRU 1.3 -- set drive and user for specified files in a program\n\n",
  "Up to 8 (ambiguous) file names may be specified.\n\n",
  "An input file will match the first matching file name.  If it is\n",
  "ambiguous, the redirection (drive and user) will be used only if the\n",
  "file cannot be found on the drive specified by the program.  If\n",
  "unambiguous, the file will always be redirected.\n\n",
  "An output file will match the first unambiguous (only) matching file\n",
  "name.  It will always be redirected.\n\n",
  "Nonmatching files will not be affected\n\n",
  "May be installed as a separate program which loads the desired program\n",
  "or as a modification to the desired program.\n\n",
  "See SETDRU.DOC for more information.\n\n",
  "Specify drive letters in the normal manner (B:FILE.TYP).  You will be\n",
  "prompted for user number.\n",
  NULL
                                 };
  char                  **s;

  for (s = msg; *s != NULL; ++s)
    ps(*s);
}

/* ask yes or no                                                            */
ask(s)
  char                  *s;
{
  for (;;)
  {
    ps(s);
    rdbuf(&inbuf);
    wrcon('\n');
    switch (toupper(inbuf.inline[0]))
    {
      case '\r':
      case '\n':
      case 'Y':     return TRUE;

      case 'N':     return FALSE;

      case CTLC:    exit();

    }
  }
}

askfn(s, f)
  char                  *s;
  FCB                   *f;
{
  for (;;)
  {
    ps(s);
    rdbuf(&inbuf);
    wrcon('\n');
    if (inbuf.insize == '\0')
      return FALSE;
    inbuf.inline[inbuf.insize] = '\0';
    setfcb(inbuf.inline, f);
    if (f->name1.drive == '\0')
      f->name1.drive = curdsk() + 1;
    if (f->name1.fname[0] != ' ')
      return(TRUE);
  }
}

askuser()
{
  static int            n;

  for (;;)
  {
    ps("User number? ");
    rdbuf(&inbuf);
    wrcon('\n');
    if (inbuf.insize == 0)
      return getusr();
    inbuf.inline[inbuf.insize] = '\0';
    if ((n = atoi(inbuf.inline)) >=0 && n <= 31)
      return n;
  }
}

pn(n)
  int                   n;
{
  if (n > 9)
    pn(n / 10);
  wrcon(n % 10 + '0');
}

ps(s)
  char                  *s;
{
  while (*s)
  {
    if (*s == '\n')
      wrcon('\r');
    wrcon(*(s++));
  }
}
   return TRUE;

      case '