/**************************************************
 *                                                *
 *             Sage Utility Routine               *
 *                                                *
 *   Sage Utility routine supports system and     *
 *   disk parameter configuration.                *
 *                                                *
 *   The boot routine and CPM disk parameters     *
 *   can be either copied from another bootdisk   *
 *   or from a file.                              *
 *                                                *
 *   Disks can be formated using this routine     *
 *                                                *
 *   CPM system configuration can be controlled   *
 *                                                *
 *  Developement history:                         *
 *     date      modification                     *
 *   ---------   -------------------------------  *
 *   25-Feb-83   Release of version 1.0           *
 *   10-Mar-83   Add disk system reset to force   *
 *               new disk configuration           *
 *                                                *
 *                                                *
 **************************************************/

/*
 *      Include files
 */

#include <stdio.h>

/*
 *      Global program definitions
 */

#define version      1     /* version number */
#define cr        '\n'     /* carraige return */
#define true         1     /* true value */
#define false        0     /* false value */
#define online       1     /* online update of configuration */
#define infile       2     /* file update of configuration */
#define disable      0     /* parity disabled */
#define enable       1     /* parity enable */
#define odd          0     /* parity odd */
#define even         1     /* parity even */
#define termchng     0     /* terminal request */
#define remchng      1     /* remote request */
#define bell         7      /* bell */
#define device       0      /* device I/O */
#define filename     1      /* filename */
#define rsdsk        13     /* BDOS reset disk system */
#define flush        48     /* BDOS flush disk system */

/*
 *      Global variable definitions
 */

int     fd0out;             /* floppy A: updated */
int     fd1out;             /* floppy B: updated */
int     termout;            /* console updated */
int     remout;             /* remote channel updated */
int     memout;             /* ramdisk updated */
int     sysout;             /* system configuration updated */
int     prtout;             /* printer updated */
int     change;             /* modification flag */

struct cpmdef {
     unsigned fixed      : 1;
     unsigned cpmunused  : 3;
     unsigned fileoff    : 3;
     unsigned dirsize    : 6;
     unsigned blcksize   : 3;
};

struct flop {      /* standard floppy definitions */
     struct {
          unsigned   cylinders : 8;
          unsigned   sides     : 8;
     } f1;
     struct {
          unsigned   gap3      : 8;
          unsigned   sectrack  : 8;
     } f2;
     struct {
          unsigned   datalenth : 8;
          unsigned   skew      : 8;
     } f3;
     int      bytessec;
     int      motordel;
     struct {
          unsigned   headload  : 8;
          unsigned   steprate  : 8;
     } f4;
     struct {
          unsigned   IBMflag   : 1;
          unsigned   NCIflag   : 1;
          unsigned   RAWflag   : 1;
          unsigned   dummy     : 5;
          unsigned   MFMflag   : 8;
     } f5;
     struct {
          unsigned   ignorerr  : 8;
          unsigned   retries   : 8;
     } f6;
     struct {
          unsigned   doublestp : 8;
          unsigned   softerror : 8;
     } f7;
     struct {
          unsigned   gap3for   : 8;
          unsigned   patfor    : 8;
     } f8;
     struct {
          unsigned   lasterr   : 8;
          unsigned   firsterr  : 8;
     } f9;
     int      dum[4];
     struct   cpmdef dskspc;
};

struct serial  {       /* serial channel definitions */
     int       baud;
     unsigned int par;
};

struct  biosinf {          /* Bios information */
     char      name[4];
     int       biossize;
     int       biosbuffers;
     int       biosstart;
     int       biosversion;
     struct    flop flpy[2];
     struct    serial term;
     struct    serial rem;
     int       remdelay;
     int       remdsr;
     long      rambot;
     long      ramtop;
     int       ramdum;
     int       prttimeo;
     int       prtpoltim;
     struct {
          unsigned    prtopt  : 8;
          unsigned    prtmode : 8;
     } p;
     int       timecntrl;
     struct {
          unsigned     numbuf  : 8;
          unsigned     bufsize : 8;
     } cpmx;
     struct    cpmdef ramspc;
     int       dumblk[9];
} biosdata;
struct         flop ostat;
struct         flop fstat;

/*
 *      Outer level command processer
 */

main()
{
        char  command;

        printf("SAGE Computer System Utility Package ");
        printf("- Version 1.0 \n");
        do {
           printf("\n   C(onfigure, B(oot copy, F(ormat, Q(uit? ");
           command = readchr();
           switch (command) {
             case 'c' : configur(); break; 
             case 'b' : boot(); break;
             case 'f' : format(); break;
           };
        }
        while (command != 'q');
}

/***********************************************
 *                                             *
 *     Configuration routines                  *
 *                                             *
 ***********************************************/

/*
 *     Main configuration routine
 */

configur()
{
       char cngcntrl;      /* configuration command */
       int  quit;          /* quit command flag */
       char s[100];        /* file name         */
       long ioret;         /* I/O request return */
       int  accept;        /* Request completed succesfully */
       int  update;        /* Update online/infile */
       int  biosfd;        /* Bios file number */
       int  wrtret;        /* Write return */

       printf("\nBIOS Configuration Manager");
       do {
          printf("\n   O(n line or F(ile change to BIOS? ");
          cngcntrl = readchr();
          accept = false;
          quit = false;
          change = false;
          switch (cngcntrl) {
          case 'o' : accept = true; update = online; 
                     uread(128,&biosdata.flpy[0],0,0,4);
                     uread(128,&biosdata.flpy[1],0,0,5);
                     uread(128,&biosdata.term.baud,0,0,2);
                     uread(128,&biosdata.rem.baud,0,0,8);
                     uread(128,&biosdata.prttimeo,0,0,6);
                     break;
          case cr  :
          case 'q' : accept = true; quit = true; break;
          case 'f' : printf("\nEnter BIOS file? ");
                     readlin(s);
                     biosfd = openb(s,2);
                     if (biosfd > 0) 
                       {ioret = read(biosfd,&biosdata,128);};
                     if ((ioret >= 0) && (biosfd > 0)) {
                       if ((biosdata.name[0] == 'B') &&
                           (biosdata.name[1] == 'I') &&
                           (biosdata.name[2] == 'O') &&
                           (biosdata.name[3] == 'S'))   {
                         accept = true;
                         update = infile;
                       }
                       else
                         {printf("\n%s not Sage Bios file",s);};
                     }
                     else 
                       printf("\nCannot open file: %-20s",s);
                     break;
          };
        } while (accept != true);
        if (quit == false) {
          fd0out = fd1out = false;
          sysout = termout = remout = memout = prtout = false;
          bioscng(update);
          if (change) {
           if (update == online) {
            printf("\nReady to write changes to memory? ");
            cngcntrl = readchr();
            if (cngcntrl == 'y') {
              if (fd0out) uwrite(128,&biosdata.flpy[0],0,0,4);
              if (fd1out) uwrite(128,&biosdata.flpy[1],0,0,5);
              if (fd0out || fd1out)
                {bdos(flush,0l);
                 bdos(rsdsk,0l);};
              if (termout) {
                 printf("\nReady to update terminal? ");
                 cngcntrl = readchr();
                 if (cngcntrl == 'y')
                    uwrite(128,&biosdata.term.baud,0,0,2);
              };
              if (remout) uwrite(128,&biosdata.rem.baud,0,0,8);
              if (prtout) uwrite(128,&biosdata.prttimeo,0,0,6);
              printf("\nConfiguration written to memory");
            };
           }
           else {
             printf("\n\nReady to write changes to %s? ",s);
             cngcntrl = readchr();
             if (cngcntrl == 'y') {
                wrtret = -1;
                ioret = lseek(biosfd,0l,0);
                if (ioret >= 0) wrtret = write(biosfd,&biosdata,128);
                if (wrtret < 0) 
                  {printf("\nError writing new BIOS information to %s",
                         s);
                   printf("\nBIOS changes abandoned");}
                else 
                  {printf("\nBIOS data saved.");};
             };
           };
          };
          if (update == infile) close(biosfd);
        };
        return;
}

/*
 * Bios update control routine
 */

bioscng(update)
int  update;
{
        char chngreq;

        do {
           printf("\nT(erminal, R(emote, F(loppys, P(rinter,");
           printf(" M(emory-disk, S(ystem, Q(uit? ");
           chngreq = readchr();
           switch (chngreq) {
            case 't' : chngterm(); break;
            case 'r' : chngrem(); break;
            case 'f' : chngflop(); break;
            case 'p' : chngprt(); break;
            case 'm' : chngmem(update); break;
            case 's' : chngsys(update); break;
           };
        } while (chngreq != 'q');
        return;
}

/*
 *      Terminal configuration routine
 */

chngterm()
{
        extern int termout, change;
        char termreq;
        char brksel;

        printf("\nTerminal Configuration");
        do {
          printf("\nB(aud rate, P(arity, S(top-bits, ");
          printf("D(ata-bits, O(ptions, Q(uit? ");
          termreq = readchr();
          switch (termreq) {
            case 'b' : termout |=baudconv(&biosdata.term.baud,termchng);
                       break;
            case 'p' : termout |=parity(&biosdata.term.par,
                              biosdata.term.baud,
                              termchng);
                       break;
            case 's' : termout |=stopbit(&biosdata.term.par); break;
            case 'd' : termout |=databit(&biosdata.term.par); break;
            case 'o' : printf("\nTerminal options:");
                       printf("\n   B(reak key ");
                       if (biosdata.term.par & 1)
                         {printf(" enters Prom Debugger");}
                       else
                         {printf(" is ignored");};
                       printf("\nType B to change ");
                       brksel = readchr();
                       if (brksel == 'b') {
                         biosdata.term.par ^= 1;
                         termout = true;
                       };
                       break;
          };
          change |= termout;
        } while (termreq != 'q');
           return;
}

/*
 *      Remote channel configuration
 */

chngrem()
{
        char    remchr;

        printf("\nRemote channel configuration");
        do {
          printf("\nB(aud-rate, P(arity, S(top-bits, D(ata-bits, ");
          printf("O(ptions, Q(uit? ");
          remchr = readchr();
          switch (remchr) {
            case 'b' : remout |=baudconv(&biosdata.rem.baud,remchng);
                       break;
            case 'p' : remout |=parity(&biosdata.rem.par,
                                       biosdata.rem.baud,remchng);
                       break;
            case 's' : remout |=stopbit(&biosdata.rem.par); break;
            case 'd' : remout |=databit(&biosdata.rem.par); break;
            case 'o' : remout |=xonoff(&biosdata.rem.par); break;
          };
          change |= remout;
        } while (remchr != 'q');
        return;
}

/*
 *      Serial channel baudrate setup
 */

baudconv(pbaud,changtyp)
int *pbaud;
int changtyp;
{
        int  obaud;
        int  obaud1;
        int  baudsel;
        char baudchr;
        static int rate[14] = {0,19200,9600,4800,2400,2000,
               1800,1200,600,300,200,150,110,75,50};
        static int factor[14] = {0,2,4,8,16,19,21,32,64,128,
               192,256,350,512,769};

        obaud = *pbaud;
        obaud1 = *(pbaud+1);
        for ( baudsel = 0; baudsel <= 14; baudsel++) {
            if (factor[baudsel] == *pbaud) {
               printf("\nCurrently using ");
               if (rate[baudsel] != 0)
                  {printf("%2.5d baud rate",rate[baudsel]);}
               else
                  {
                   if (changtyp == termchng) 
                      {printf("using DIP switch setting");}
                   else
                      {printf(" 9600 baud rate");};
               };
           };
        };
        do {
          printf("\n A(  19200 baud  H(    600 baud");
          printf("\n B(   9600 baud  I(    300 baud");
          printf("\n C(   4800 baud  J(    200 baud");
          printf("\n D(   2400 baud  K(    150 baud");
          printf("\n E(   2000 baud  L(    110 baud");
          printf("\n F(   1800 baud  M(     75 baud");
          printf("\n G(   1200 baud  N(     50 baud");
          printf("\n");
          if (changtyp == termchng)
            printf("\n X) use DIP to specify baudrate");
          printf("\n Q(uit");
          printf("\n\nSelect baudrate from above? ");
          baudchr = readchr();
          if ((baudchr >= 'a') && (baudchr <= 'n'))
            {baudsel = baudchr - ('a'-1);};
          if ((baudchr == 'x') && (changtyp == termchng)) 
            {baudsel = 0;
             printf("\nSetting baudrate using DIP switch settings");};
          if (rate[baudsel] != 0 && baudchr != 'q')
          {printf("\nSetting baudrate to %2.5d rate",rate[baudsel]);};
        } while (baudchr != 'q');
        *pbaud = factor[baudsel];
        *(pbaud+1) = *(pbaud +1) & 0xfffc + 2;
        return (((obaud != *pbaud) || (obaud1 != *(pbaud+1))) 
                ? true : false);
}

/*
 *      Parity initialization routine
 */

parity(param,baudrate,changtyp)
int *param;
int  baudrate;
int  changtyp;
{
       int  oparam;
       int parstat;
       int parsex;
       int parsel;

       oparam = *param;
       parstat = (*param & 0x1000) >> 12;
       parsex = (*param & 0x2000) >> 13;
       do {
         printf("\n\nCurently parity is ");
         if((baudrate == 0) && (changtyp == termchng))
           {printf("selected by DIP switches");}
         else {
           if (parstat == enable) 
             {if(parsex == even) {printf("Even");} 
              else {printf("Odd");};}
           else
             {printf("Disabled");};
         };
         printf("\nD(isable\nE(ven parity\nO(dd parity\nQ(uit");
         printf("\n\nSelect parity option: ");
         parsel = readchr();
         switch (parsel) {
           case 'd' : parstat = disable; break;
           case 'e' : parstat = enable;   parsex = even; break;
           case 'o' : parstat = enable;   parsex = odd; break;
         }
       } while (parsel != 'q');
       *param = (*param & 0xcfff) + (parstat << 12) + (parsex << 13);
       return ((oparam != *param) ? true : false);
}

/*
 *     Stop-bit selection
 */

stopbit(param)
int *param;
{
       int oparam;
       int stopstat;
       int stopsel;

       oparam = *param;
       stopstat = (*param & 0xc000) >> 14;
       do {
         printf("\nCurrently ");
         switch (stopstat) {
           case 0 : printf("stop bit assignment is invalid"); break;
           case 1 : printf("1 stop bit"); break;
           case 2 : printf("1.5 stop bits"); break;
           case 3 : printf("2 stop bits"); break;
         };
         printf(" assigned");
         printf("\n A( 1 stopbit\n B( 1.5 stopbits\n C( 2 stopbits");
         printf("\n Q(uit");
         printf("\n\nSelect stop bit option: ");
         stopsel = readchr();
         switch (stopsel) {
           case 'a' : stopstat = 1; printf("\nSelected 1 stopbit");
                      break;
           case 'b' : stopstat = 2; printf("\nSelected 1.5 stopbits");
                      break;
           case 'c' : stopstat = 3; printf("\nSelected 2 stopbits");
                      break;
         }
       } while (stopsel != 'q');
       *param = (*param & 0x3fff) + (stopstat << 14);
       return ((oparam != *param) ? true : false);
}

/*
 *      Data-bit selection
 */

databit(param)
int *param;
{
        int oparam;
        int datastat;
        int datasel;

        oparam = *param;
        datastat = (*param & 0xc00) >> 10;
        do {
          printf("\n\nCurrently using %1.1d data bits",5+datastat);
          printf("\n A( 5 data bits\n B( 6 data bits");
          printf("\n C( 7 data bits\n D( 8 data bits");
          printf("\n Q(uit");
          printf("\n\n Select data size option: ");
          datasel = readchr();
          switch (datasel) {
            case 'a' : datastat = 0; printf("\n Selected 5 databits");
                       break;
            case 'b' : datastat = 1; printf("\n Selected 6 databits");
                       break;
            case 'c' : datastat = 2; printf("\n Selected 7 databits");
                       break;
            case 'd' : datastat = 3; printf("\n Selected 8 databits");
                       break;
          };
        } while (datasel != 'q');
          *param = (*param & 0xf3ff) + (datastat << 10);
          return ((oparam != *param) ? true : false);
}

/*
 *     Xon & Xoff enable/disable routine
 */

xonoff(param)
int *param;
{
       int  oparam;
       int  oparam1;
       char selxon;
       int  xonin;
       int  xonout;
       int  dsr;
       int  delay;

       oparam = *param;
       oparam1 = *(param+1);
       xonin = (*param & 1);
       xonout = (*param & 2) >> 1;
       dsr = (*param & 4) >> 2;
       delay = *(param+1);
       do {
         printf("\n I - Xon/Xoff for input is ");
         if (xonin == 1) {printf("enabled");} 
         else {printf("disabled");};
         printf("\n O - Xon/Xoff for output is ");
         if (xonout == 1) {printf("enabled");} 
         else {printf("disabled");};
         printf("\n D - Data set ready is ");
         if (dsr == 0)
           {printf("ignored");}
         else {
           printf("checked before transmitting");
           printf("\n P - Polling interval (in 1/64000 second) ");
           printf("%1.5d",delay);
         };
         printf("\n\nSelect option to change (<cr> for none)? ");
         selxon = readchr();
         switch (selxon) {
           case 'i' : xonin ^= 1; break;
           case 'o' : xonout ^= 1; break;
           case 'd' : dsr ^= 1; break;
           case 'p' : printf("\n Polling Interval? ");
                      getint(&delay);
                      break;
         };
       } while (selxon != cr);
       *param = (*param & 0xff00) + xonin + (xonout << 1) + (dsr << 2);
       *(param+1) = delay;
       return (((oparam != *param) || (oparam1 != *(param+1)))
              ? true : false);
}

/*
 *     Floppy configuration routine
 */

chngflop()
{
        int drv;
        int standard;
        int tmp, tmp1;
        char ch, ch1;

        printf("\nFloppy Parameter Maintance");
        standard = true;
        if((drv = mainflop()) >= 0) {
        do {
          descflop(drv,standard);
          if (standard == true) {
            printf("\nSelect floppy option (CR to quit)? ");
            ch = readchr();
            switch (ch) {
              case 'a' : sf(drv,64,2,80,8,0,0,512,42,255,80,229,0);
                         break;
              case 'b' : sf(drv,64,2,40,8,0,0,512,42,255,80,229,0);
                         break;
              case 'c' : sf(drv,64,1,40,8,1,0,512,42,255,80,229,0);
                         break;
              case 'd' : sf(drv,64,2,40,8,1,0,512,42,255,80,229,0);
                         break;
              case 'e' : sf(drv,64,1,40,10,1,1,512,24,255,32,229,2);
                         break;
              case 'f' : sf(drv,64,2,40,10,1,1,512,24,255,32,229,2);
                         break;
              case 'g' : sf(drv,64,2,80,10,1,1,512,24,255,32,229,2);
                         break;
              case 'h' : sf(drv,64,1,35,8,1,0,512,42,255,80,229,0);
                         break;
              case 'i' : sf(drv,64,0);
                         break;
              case 'z' : standard = false;
                         break;
              default  : if (ch != 'q' && ch != cr) putchar(bell);
                         break;
            };
          }
          else {
            printf("\nSelect item to change (CR to quit)? ");
            ch = readchr();
            switch (ch) {
              case 'a' : printf("\nNumber of sides (0, 1, 2)? ");
                         getint(&tmp);
                         if((tmp >= 0) && (tmp < 3))
                           {biosdata.flpy[drv].f1.sides = tmp;}
                         else
                           {putchar(bell);};
                         break;
              case 'b' : printf("\nNumber of Cylinders (40, 80)? ");
                         getint(&tmp);
                         if ((tmp == 40) || (tmp == 80))
                           {biosdata.flpy[drv].f1.cylinders = tmp;}
                         else
                           {putchar(bell);};
                         break;
              case 'c' : printf("\nNumber of Sectors per Track");
                         printf(" (8, 10, 16) ");
                         getint(&tmp);
                         switch (tmp) {
                           case  8 : setflop(tmp,512,42,255,drv);
                                     break;
                           case 10 : setflop(tmp,512,24,255,drv);
                                     break;
                           case 16 : setflop(tmp,256,10,255,drv);
                                     break;
                           default : if (tmp != 0) {putchar(bell);};
                         };
                         break;
              case 'd' : printf("IBM track format: ");
                         if ((biosdata.flpy[drv].f5.IBMflag ^= 1) == 1) 
                           {printf("Yes");}
                         else
                           {printf("No");};
                         break;
              case 'e' : printf("\nDensity - S(ingle or D(ouble? ");
                         ch1 = readchr();
                         if (ch1 == 's')
                           {biosdata.flpy[drv].f5.MFMflag = 0;}
                         else if (ch1 == 'd')
                           {biosdata.flpy[drv].f5.MFMflag = 64;}
                         else 
                           {putchar(bell);};
                         break;
              case 'f' : printf("Retries? ");
                         getint(&tmp);
                         if ((tmp > 0) && (tmp < 20))
                           {biosdata.flpy[drv].f6.retries = tmp;}
                         else
                           {putchar(bell);};
                         break;
              case 'g' : printf("\nIgnore errors: ");
                         if((biosdata.flpy[drv].f6.ignorerr ^= 1)
                               == 1)
                           {printf("Yes");}
                         else
                           {printf("No");};
                         break;
              case 'h' : printf("\nH - Read 48 or 96 TPI: ");
                         if((biosdata.flpy[drv].f7.doublestp ^= 1)
                               == 1)
                           {printf("Yes"); 
                            biosdata.flpy[drv].f1.cylinders = 40;}
                         else
                           {printf("No");
                            biosdata.flpy[drv].f1.cylinders = 80;};
                         break;
              case 'i' : printf("\nNCI 10 sectors/track: ");
                         if((biosdata.flpy[drv].f5.NCIflag ^= 1) == 1)
                           {printf("Yes");}
                         else
                           {printf("No");};
                         break;
              case 'j' : printf("\nRead after write: ");
                         if((biosdata.flpy[drv].f5.RAWflag ^= 1) == 1)
                           {printf("Yes");}
                         else
                           {printf("No");};
                         break;
              case 'k' : printf("\nNumber of bytes per Sector: ");
                         getint(&biosdata.flpy[drv].bytessec);
                         break;
              case 'l' : printf("\nGap 3 parameter? ");
                         getint(&tmp);
                         if (tmp > 0 && tmp < 256)
                           {biosdata.flpy[drv].f2.gap3 = tmp;}
                         else
                           {if(tmp != 0) putchar(bell);};
                         break;
              case 'm' : printf("\nData length? ");
                         getint(&tmp);
                         if (tmp > 0 && tmp < 256)
                           {biosdata.flpy[drv].f2.datalenth = tmp;}
                         else
                           {if (tmp != 0) putchar(bell);};
                         break;
              case 'n' : printf("\nStep rate? ");
                         getint(&tmp);
                         if (tmp > 0 && tmp <= 32) {
                           tmp1 = biosdata.flpy[drv].f4.steprate;
                           tmp = (tmp1 % 16)+(16*(16-((tmp+1) / 2)));
                           biosdata.flpy[drv].f4.steprate = tmp;}
                         else
                           {if (tmp != 0) putchar(bell);};
                         break;
              case 'o' : printf("\nGap 3 for formatting? ");
                         getint(&tmp);
                         if (tmp > 0 && tmp < 256)
                           {biosdata.flpy[drv].f8.gap3for = tmp;}
                         else
                           {if (tmp != 0) putchar(bell);};
                         break;
              case 'p' : printf("\nData pattern for formatting? ");
                         getint(&tmp);
                         if (tmp > 0 && tmp < 256)
                           {biosdata.flpy[drv].f8.patfor = tmp;}
                         else
                           {if (tmp != 0) putchar(bell);};
                         break;
              case 'r' : printf("\nSkew for formatting? ");
                         getint(&tmp);
                         if (tmp >= 0 && tmp < 256)
                           {biosdata.flpy[drv].f3.skew = tmp;}
                         else
                           {putchar(bell);};
                         break;
              case 'z' : standard = true; break;
              default  : if (ch != cr) {putchar(bell);};
                         break;
            };
            if ((ch >= 'a') && (ch <= 'r')) { 
              change = true;
              if (drv == 0) 
                {fd0out = true;}
              else
                {fd1out = true;};
            };
          };
        } while (ch != cr);
        };
}
          
/*
 *      Set floppy sector parameters
 */

setflop(setsec,setbyt,setgap,setlen,drive)
int setsec,setbyt,setgap,setlen, drive;
{
        biosdata.flpy[drive].bytessec = setbyt;
        biosdata.flpy[drive].f2.gap3 = setgap;
        biosdata.flpy[drive].f3.datalenth = setlen;
        biosdata.flpy[drive].f2.sectrack = setsec;
}

/*
 *      Set standard floppy parameters
 */

sf(drv,mfm,sid,cyl,sec,ibm,nci,byt,gap3,datal,gap3f,patfor,skw)
int drv,mfm,sid,cyl,sec,ibm,nci,byt,gap3,datal,gap3f,patfor,skw;
{
        if (sid != 0) {
          biosdata.flpy[drv].f5.MFMflag   = mfm;
          biosdata.flpy[drv].f1.sides     = sid;
          biosdata.flpy[drv].f1.cylinders = cyl;
          biosdata.flpy[drv].f2.sectrack  = sec;
          biosdata.flpy[drv].f5.IBMflag   = ibm;
          biosdata.flpy[drv].f5.NCIflag   = nci;
          biosdata.flpy[drv].bytessec     = byt;
          biosdata.flpy[drv].f2.gap3      = gap3;
          biosdata.flpy[drv].f3.datalenth = datal;
          biosdata.flpy[drv].f8.gap3for   = gap3f;
          biosdata.flpy[drv].f8.patfor    = patfor;
          biosdata.flpy[drv].f3.skew      = skw;
        }
        else
          {biosdata.flpy[drv].f1.sides = sid;};
        if (drv == 0) fd0out = change = true;
        if (drv == 1) fd1out = change = true;
        return;
}

/*
 *      Describe floppy parameters
 */

descflop(drive,stand)
int drive;
int stand;
{
        int temp;
        char tempc;

        tempc = 'A' + drive;
        printf("\n\nCurrent drive %c:  setup:\n",tempc);
        if (stand == true) {
          temp = whatflop(drive);
          writestd(temp);
          if (biosdata.flpy[drive].doublestp == 1)
             {printf("\nOnly read allowed on 80 track drive");};
          tempc = 'A';
          for (temp = 1; temp <= 9; temp++) {
            printf("\n%c - ",tempc);
            writestd(temp);
            tempc += 1;
          };
          printf("\nZ - ");
          writestd(0);
        }
        else {
          temp = biosdata.flpy[drive].f1.sides;
          printf("\nA - Number of Sides:   %3.3d",temp);
          printf("     K - Bytes per sector   %4.4d",
                 biosdata.flpy[drive].bytessec);
  
          temp = biosdata.flpy[drive].f1.cylinders;
          printf("\nB - Cylinders:         %3.3d",temp);
          temp = biosdata.flpy[drive].f2.gap3;
          printf("     L - Gap 3 parameter:   %4.4d",temp);
  
          temp = biosdata.flpy[drive].f2.sectrack;
          printf("\nC - Sectors per Track: %3.3d",temp);
          temp = biosdata.flpy[drive].f3.datalenth;
          printf("     M - Data length:       %4.4d",temp);
  
          printf("\nD - IBM track format:  ");
          if (biosdata.flpy[drive].f5.IBMflag == 1)
            {printf("Yes");}
          else
            {printf(" No");};
          temp = biosdata.flpy[drive].f4.steprate;
          temp = (16-(temp / 16))*2;
          printf("     N - Step rate:         %4.4d",temp);
  
          printf("\nE - Density:           ");
          if (biosdata.flpy[drive].f5.MFMflag == 0)
            {printf("Sgl");}
          else
            {printf("Dbl");};
          temp = biosdata.flpy[drive].f8.gap3for;
          printf("     O - Gap 3 for format:  %4.4d",temp);
  
          temp = biosdata.flpy[drive].f6.retries;
          printf("\nF - Retries:           %3.3d",temp);
          temp = biosdata.flpy[drive].f8.patfor;
          printf("     P - Pattern for format: %3.3d",temp);
  
          printf("\nG - Ignore errors:     ");
          if (biosdata.flpy[drive].f6.ignorerr == 1)
            {printf("Yes");}
          else
            {printf(" No");};
          temp = biosdata.flpy[drive].f3.skew;
          printf("     R - Skew for format:  %5.5d",temp);
  
          printf("\nH - Read 48 on 96 TPI: ");
          if (biosdata.flpy[drive].f7.doublestp == 1)
            {printf("Yes");}
          else
            {printf(" No");};
          printf("     Z - Standard options");
  
          printf("\nI - NCI 10 sects/trk:  ");
          if (biosdata.flpy[drive].f5.NCIflag == 1)
            {printf("Yes");}
          else
            {printf(" No");};
          
          printf("\nJ - Read after write:  ");
          if (biosdata.flpy[drive].f5.RAWflag == 1)
            {printf("Yes");}
          else
            {printf(" No");};
        };

        printf("\n");
        return;
}

/*
 *      Write floppy standards
 */

writestd(standard)
int standard;
{
        switch (standard) {
          case 0 : printf("Non standard type");
                   break;
          case 1 : printf("SAGE double side, 80 track (1280 blocks)");
                   break;
          case 2 : printf("SAGE double side, 40 track ( 640 blocks)");
                   break;
          case 3 : printf("IBM single side, 40 track (320 blocks)");
                   break;
          case 4 : printf("IBM double side, 40 track (640 blocks)");
                   break;
          case 5 : printf("Network Consulting single side, 40 track");
                   printf(" (400 blocks)");
                   break;
          case 6 : printf("Network Consulting double side, 40 track");
                   printf(" (800 blocks)");
                   break;
          case 7 : printf("Network Consulting double side, 80 track");
                   printf(" (1600 blocks)");
                   break;
          case 8 : printf("Softech Universal Medium, single side, ");
                   printf("35 track (280 blocks)");
                   break;
          case 9 : printf("No drive equipped");
                   break;
        };
        return;
}

/*
 *      Establish floppy type if standard
 */

whatflop (drive)
int drive;
{
        static int side[8] = { 2, 2, 1, 2, 1, 2, 2, 1};
        static int cyl[8]  = {80,40,40,40,40,40,80,35};
        static int sec[8]  = { 8, 8, 8, 8,10,10,10, 8};
        static int ibm[8]  = { 0, 0, 1, 1, 1, 1, 1, 1};
        static int nci[8]  = { 0, 0, 0, 0, 1, 1, 1, 0};

        int temp1;
        int stat;
        int flg;

        if (biosdata.flpy[drive].f1.sides != 0) {
          temp1 = 0;
          do { 
            stat = (biosdata.flpy[drive].f1.sides != side[temp1]);
            stat |= (biosdata.flpy[drive].f1.cylinders != cyl[temp1]);
            stat |= (biosdata.flpy[drive].f2.sectrack != sec[temp1]);
            flg = biosdata.flpy[drive].f5.IBMflag;
            stat |= (flg != ibm[temp1]);
            flg = biosdata.flpy[drive].f5.NCIflag;
            stat |= (flg != nci[temp1]);
          } while ((stat) && ( ++temp1 <= 7));
          if (temp1 > 7) temp1 = -1;
        }
        else
          {temp1 = 8;};
        return (++temp1);
}

/*
 *      Floppy select
 */

mainflop()
{
        char ch2;
        while (true) {
          printf("\nSelect drive (A or B, CR to quit? ");
          ch2 = readchr();
          if (ch2 == 'a') {return (0);};
          if (ch2 == 'b') {return (1);};
          if (ch2 == cr ) {return (-1);};
        };
}

/*
 *      Printer configuration
 */

chngprt()
{
          int temp;
          char pc;
        printf("Printer Configuration");
        do {
          temp = biosdata.p.prtmode;
          switch (temp) {
            case 0 : printf("\nPrinter is disabled"); break;
            case 1 : printf("\nPrinter is using (Remote) serial");
                     printf(" Channel"); break;
            case 2 : printf("\nPrinter on parallel (Centronics)");
                     printf(" port with interupts"); break;
            case 3 : printf("\nPrinter is on parallel port with ");
                     printf("scheduled polling");
                     printf("\n Polling attempts befor schedule ");
                     printf("delay: %d",biosdata.prttimeo);
                     printf("\n Delay is 1/64000's second before ");
                     printf("re-polling %d",biosdata.prtpoltim);
                     break;
            default: printf("\nUnknown printer mode");
                     break;
          };
          printf("\n\nModes:");
          printf("\nA( printer on Remote Channel");
          printf("   (set up using Remote serial channel parameters");
          printf("\nB( printer on parallel port with interupts");
          printf("\nC( printer on parallel port with scheduled ");
          printf("polling");
          printf("\nD( printer is disabled\n");
          printf("\nQ(uit\n");
          printf("\nSelect printer mode? ");
          pc = readchr();
          switch (pc) {
            case 'a' : change = prtout = true;
                       biosdata.p.prtmode = 1;
                       break;
            case 'b' : change = prtout = true;
                       biosdata.p.prtmode = 2;
                       break;
            case 'c' : change = prtout = true;
                       biosdata.p.prtmode = 3;
                       pollprt();
                       break;
            case 'd' : change = prtout = true;
                       biosdata.p.prtmode = 0;
                       break;
            default  : if (pc != 'q') {putchar(bell);};
          };
        } while (pc != 'q');
        return;
}

pollprt()
{
        char pollc;
        int temp2;

      do {
        printf("\n\nPrinting with Scheduled Polling selected");
        printf("\n P(olling attemps befor scheduled delay:");
        printf("      %d",biosdata.prttimeo);
        printf("\n D(elay in 1/64000's second before ");
        printf("re-polling:  %d",biosdata.prtpoltim);
        printf("\n\nSelect P(olling, D(elay, Q(uit: ");
        pollc = readchr();
        switch (pollc) {
          case 'p' : printf("\nPolling attempts (236 = 1 ");
                     printf("millisecond)? ");
                     getint(&temp2);
                     if (temp2 != 0) {biosdata.prttimeo = temp2;};
                     break;
          case 'd' : printf("\nDelay in 1/64000's second before ");
                     printf("re-polling? ");
                     getint(&temp2);
                     if (temp2 != 0) {biosdata.prtpoltim = temp2;};
                     break;
          default  : if (pollc != 'q') {putchar(bell);};
        };
      } while (pollc != 'q');
      return;
}

/*
 *      Ram disk configuration routine
 */

chngmem(update)
int update;
{
        long tpasize;
        int  tpak;
        char cmnd;

        printf("\nRam Disk Configuration");
        do {
          if (update == online)
            {printf("\nUpdate to Online bios not allowed");
             return;};
          printf("\n");
          if (biosdata.rambot == 0l)
            {printf("\nRam disk is disabled ");
             printf("(TPA fills available memory)");}
          else
            {printf("\nTPA is %ld K",((biosdata.rambot-1024)/1024));
             printf(" (Ram disk fills remaining available memory)");};
          printf("\n\nE(nable / D(isable ram disk, Q(uit? ");
          cmnd = readchr();
          switch (cmnd) {
            case 'e' : printf("\nEnter TPA size in kilobytes ?");
                       getint(&tpak);
                       tpasize = tpak;
                       if (tpasize > 30l)
                         {biosdata.rambot = (tpasize + 1l) * 1024l;
                          memout = change = true;};
                       break;
            case 'd' : biosdata.rambot = 0;
                       memout = change = true;
                       break;
            default  : if (cmnd != 'q') putchar(bell);
                       break;
          };
        } while (cmnd != 'q');
        biosdata.ramdum = biosdata.ramtop = 0;
        return;
}

/*
 *      CPM system configuration routine
 */

chngsys(update)
int  update;
{
        int temp;
        char cmnd;

        printf("\nCPM system configuration");
        do {
          if (biosdata.flpy[0].f1.sides != 0)
            prtcpmb('A',&biosdata.flpy[0].dskspc);
          if (biosdata.flpy[1].f1.sides != 0)
            prtcpmb('B',&biosdata.flpy[1].dskspc);
          if ((biosdata.rambot != 0l) && (update != online))
             prtcpmb('E',&biosdata.ramspc);
          temp = biosdata.cpmx.bufsize;
          temp = (temp & 31) * 512;
          printf("\n\nF( Disk I/O buffer size:      %5d",temp);
          temp = biosdata.cpmx.numbuf;
          temp = (temp & 15) + 1;
          printf("\nG( Number of disk I/O buffers: %4d",temp);
          printf("\n\nQ(uit");
          printf("\n\nEnter Selection (A - Q)? ");
          cmnd = readchr();
          switch (cmnd) {
          case 'a' : chgcpmb('A',&biosdata.flpy[0].dskspc);
                     break;
          case 'b' : chgcpmb('B',&biosdata.flpy[1].dskspc);
                     break;
          case 'e' : if (update == online)
                      {printf("\nUpdate to Online bios not allowed");}
                     else
                      {chgcpmb('E',&biosdata.ramspc);};
                     break;
          case 'f' : printf("\nEnter buffer size in bytes");
                     printf(" (it will be rounded to 512 bytes)? ");
                     getint(&temp);
                     temp = temp / 512;
                     if ((temp > 0) && (temp < 32))
                       {biosdata.cpmx.bufsize = temp;
                        change = sysout = true;}
                     else
                       {putchar(bell);};
                     break;
          case 'g' : printf("\nEnter number of I/O buffers (1-16)? ");
                     getint(&temp);
                     if ((temp > 0) && (temp < 17))
                       {biosdata.cpmx.numbuf = temp - 1;
                        change = sysout = true;}
                     else
                       {putchar(bell);};
                     break;
          default  : if (cmnd != 'q') putchar(bell);
                     break;
        };
      } while (cmnd != 'q');
      return;
}

/*
 *      Print CPM disk configuration data
 */

prtcpmb(drv,config)
char drv;
struct cpmdef *config;
{
        int temp, temp1, temp2;

        printf("\n\n%c( Drive configuration:",drv);
        if (drv == 'E') printf(" (Ram disk)");
        if ((*config).blcksize < 5)
          {temp = 1024 << (*config).blcksize;
           printf("\n  1( Logical block size:      %5d",temp);}
        else
          {printf("\n  1( Logical block size:  Undefined");};
        temp = 32 * (*config).dirsize;
        printf("    3( Number of directory entires:  %5d",temp);
        printf("\n  2( Directory track offset:  %5d",
               (*config).fileoff);
        if ((*config).fixed == 0)
          {printf("    4( Disk media:                   Fixed");}
        else
          {printf("    4( Disk media:               Removable");};
        return;
}

/*
 *      Alter CPM disk configuration data
 */

chgcpmb(drv,config)
char drv;
struct cpmdef *config;
{
        int temp, temp1;

        printf("\nSelect Subgroup for drive %c: (1 - 4, Q)? ",drv);
        temp = readchr();
        switch (temp) {
        case '1' : printf("\n Block size (1024,2048,4096,8192,16384)");
                   getint(&temp1);
                   if ((temp1 == 1024) || (temp1 == 2048) ||
                       (temp1 == 4096) || (temp1 == 8192) ||
                       (temp1 == 16384)) 
                        change = sysout = true;
                   switch (temp1) {
                     case  1024 : (*config).blcksize = 0; break;
                     case  2048 : (*config).blcksize = 1; break;
                     case  4096 : (*config).blcksize = 2; break;
                     case  8192 : (*config).blcksize = 3; break;
                     case 16384 : (*config).blcksize = 4; break;
                     default    : putchar(bell);
                   };
                   break;
        case '2' : if (drv == 'E') {
                     printf("\nTrack offset allways 0 for ram disk");
                     (*config).fileoff = 0;
                   }
                   else {
                     printf("\nDirectory offset (0 - 7) tracks ?");
                     getint(&temp1);
                     if ((temp1 >= 0) && (temp1 < 8))
                       {(*config).fileoff = temp1;
                        change = sysout = true;}
                     else
                       {putchar(bell);};
                   };
                   break;
        case '3' : printf("\nNumber of directory entries? ");
                   getint(&temp1);
                   temp1 = temp1 / 32;
                   if ((temp1 >= 0) && (temp1 < 64))
                     {(*config).dirsize = temp1;
                      change = sysout = true;}
                   else
                     {putchar(bell);};
                   break;
        case '4' : (*config).fixed ^= 1;
                   change = sysout = true;
                   if (drv == 'E') (*config).fixed = 0;
                   break;
        case 'q' : break;
        default  : putchar(bell);
                   break;
        };
        return;
};

/***********************************************
 *                                             *
 *         Boot transfer routine               *
 *                                             *
 ***********************************************/

boot()
{
        char s[100];
        int  typ;
        long ioret;
        int  ibootfd,obootfd;
        char ch;
        int  drive,i;
        int  accept;
        struct {
            int   header;      /* file type */
            long  text;        /* bytes of text */
            long  data;        /* bytes of data */
            long  bss;         /* bytes of bss */
            long  symbol;      /* bytes of symbol table */
            long  reserved;    /* reserved area */
            long  start;       /* load address */
            int   reloc;       /* relocation flag */
            char  prog[2048];  /* program area */
            int   dirsize;     /* number entries in directory */
            int   dirpos;      /* directory starting track */
            char  dummy[508];  /* unused area */
        } bootfile;

        printf("\n\nBootstrap Copy Utility");
        do {
          accept = false;
          printf("\n\nSource file or device <just CR quits> ? ");
          readlin(s);
          if (s[0] == '\0') return;
          if ( (typ = checkname(s)) >= 0) {
             printf("\nReady to load bootstrap from ");
             if (typ == device) 
               {printf("volumn");}
             else
               {printf("file");};
             printf(" %s ? ",s);
             ch = readchr();
             if (ch == 'q') return;
             if (typ == device) {
               drive = s[0] - 'a' + 4;
               i = uread(drive,&bootfile.prog[0],2560,0,0);
               if ( i == 0) {
                 bootfile.header = 0x601a;
                 bootfile.text   = 2048;
                 bootfile.data   = 0;
                 bootfile.bss    = 0;
                 bootfile.symbol = 0;
                 bootfile.start  = 0x400;
                 bootfile.reloc  = 0xffff;
                 accept = true;
               }
               else {
                 printf("\nError reading %s",s);
               };
             }
             else {
               ibootfd = openb(s,0);
               lseek(ibootfd,0l,0);
               if (ibootfd > 0) {
                 ioret = read(ibootfd,&bootfile,2076);
                 if (ioret > 0) {
                   printf("\nEnter starting track ? ");
                   getint(&bootfile.dirpos);
                   printf("\nEnter number of directory entries? ");
                   getint(&bootfile.dirsize);
                   accept = true;
                 }
                 else
                   {printf("\nError reading %s",s);};
                 close(ibootfd);
               }
               else
                 {printf("\nCannot find file %s",s);};
             };
             if (accept) {
               accept = false;
               if (bootfile.header != 0x601a) 
                 {printf("\nText, Data, BSS areas not contiguous");}
               else if (bootfile.text + bootfile.data > 2048)
                 {printf("\nCode file too long");}
               else if (bootfile.start != 0x400)
                 {printf("\nStarting address not at 400");}
               else if (bootfile.prog[0] != 'B' ||
                        bootfile.prog[1] != 'O' ||
                        bootfile.prog[2] != 'O' ||
                        bootfile.prog[3] != 'T')
                 {printf("\nFile not boot file");}
               else 
                 {accept = true;};
            };
          };
        } while (accept == false);
        if (accept) {
          do {
            printf("\nDestination file or device <just CR quits> ? ");
            readlin(s);
            if (s[0] == '\0') return;
            if ((typ = checkname(s)) >= 0) {
              accept = true;
              printf("\nReady to store bootstrap ");
              if (typ == device) 
                {printf("on volumn");}
              else
                {printf("in file");};
              printf(" %s ? ",s);
              ch = readchr();
              if (ch == 'q' || ch != 'y') return;
              if (typ == device) {
                drive = s[0] - 'a' + 4;
                ioret = uwrite(drive,&bootfile.prog[0],2560,0,0);
                if (ioret < 0) 
                  {printf("\nError writing %s",s);}
                else
                  {printf("\nBootstrap data written successfully");};
              }
              else {
                obootfd = creatb(s,1);
                if (obootfd > 0) {
                  ioret = write(obootfd,&bootfile,2586);
                  if (ioret < 0)
                    {printf("\nError writing %s",s);}
                  else
                    {printf("\nBootstrap file created successfully");};
                  close(obootfd);
                }
                else
                  {printf("\nCannot open output file");};
              };
            }
            else
              {printf("\nIllegal file or device %s",s);
               accept = false;};
          } while (accept == false);
        };
        return;
}

/*
 *      Check file name for type
 */

checkname(s)
char s[];
{
        if (s[1] == ':') {
          if(s[0] < 'a' || s[0] > 'b') return (-1);
          if(s[2] == '\0') 
            {return (device);}
          else
            {return (filename);};
        }
        else
          {return (filename);};
}

/***********************************************
 *                                             *
 *       Floppy format routine                 *
 *                                             *
 ***********************************************/

format()
{
        int  drive;
        int  accept;
        char ch;
        
        accept = false;
        printf("\n\nFloppy Diskette Formatter");
        do {
          printf("\n\nDrive to be formatted (A or B) ? ");
          ch = readchr();
          if (ch >= 'a' && ch <= 'b') {
            drive = ch - 'a' + 4;
            uread(128,&ostat,0,0,drive);
            uread(128,&biosdata.flpy[drive-4],0,0,drive);
            if (ostat.f1.sides == 0) 
              {printf("\n\nDrive not equipped");}
            else
              {accept = true;};
          }
          else
            {if (ch != 'q') putchar(bell);};
          while (accept) {
            genformat(drive);
            printf("\nMore diskettes to format? ");
            ch = readchr();
            if (ch != 'y') {
              accept = false;
              ch = 'q';
            };
          };
        } while (ch != 'q');
        return;
}

/*
 *     Generate format on floppy
 */

genformat(drive)
int drive;
{
       int drv;
       int c,h,s;
       int i,n;
       int gap3r, olddtr;
       int ferrors;
       int blk, skew, stemp, try, done, blktrk, temp;
       char ch;
       struct {
           struct {
               unsigned head     : 8;
               unsigned cyl      : 8;
           } g1;
           struct {
               unsigned bspcode  : 8;
               unsigned sector   : 8;
           } g2;
       } formdata[20];
       int  dumbuf[2561];

       drv = drive - 4;
       n = whatflop(drv);
       writestd(n);
       printf("\nIs diskette ready for formatting in drive");
       ch = 'A' + drive - 4;
       printf(" %c: ?",ch);
       ch = readchr();
       if (ch != 'y')
         {printf("\nFormat aborted");
          return;};
       gap3r = ostat.f2.gap3;
       i = ostat.f8.gap3for;
       ostat.f2.gap3 = i;
       olddtr = ostat.f3.datalenth;
       i = ostat.f8.patfor;
       ostat.f3.datalenth = i;
       if ((uwrite(128,&ostat,0,0,drive)) != 0)
         {printf("\n\nError writing drive status with format ");
          printf("parameters");
          return;};
       printf("\nFormatting");
       skew = 0;
       blktrk = ostat.bytessec * ostat.f2.sectrack / 512;
       ferrors = 0;
       for (c = 0; c < ostat.f1.cylinders; c++) {
         for (h = 0; h < ostat.f1.sides; h++) {
           for (s = 1; s <= ostat.f2.sectrack; s++) {
             formdata[s].g1.cyl = c;
             formdata[s].g1.head = h;
             if (ostat.f5.IBMflag == 1 && h == 1) {
               stemp = s + ostat.f3.skew;
               if (stemp > ostat.f2.sectrack)
                 stemp -= ostat.f2.sectrack;
             }
             else {
               stemp = s - ostat.f3.skew;
               if (stemp <= 0) 
                 stemp += ostat.f2.sectrack;
             };
             if (ostat.f5.NCIflag == 1) {
               if (c != 0 || h != 0 || stemp != 1) stemp += 8;
             };
             formdata[s].g2.sector = stemp;
             if (ostat.bytessec == 512)
               {formdata[s].g2.bspcode = 2;}
             else
               {formdata[s].g2.bspcode = 1;};
           };
           if ((c % 20) == 0 && h == 0) printf("\n");
           printf(".");
           try = 0;
           done = false;
           do {
             i = uwrite(drive,&formdata[1],ostat.f2.sectrack*4,
                       (c*256)+h,8192);
             if (i != 0) {
               ferrors += 1;
               if (++try >= 3) {
                 printf("\nError %d while formating ",i);
                 printf("Cylinder %d  Head %d",c,h);
                 uwrite(128,&biosdata.flpy[drv],0,0,drive);
                 return;
               };
             }
             else {
               if (ostat.f5.IBMflag == 1) {
                 if (h == 0)
                   {blk = c * blktrk;}
                 else
                   {blk = ((ostat.f1.cylinders * c) + h) * blktrk;};
               }
               else
                 {blk = ((ostat.f1.sides * c) + h) *blktrk;};
               i = uread(drive,&dumbuf,ostat.f2.sectrack 
                         * ostat.f2.sectrack,blk);
               if (i != 0) {
                 ferrors += 1;
                 if (try >= 3) {
                   printf("\n\nError %d while checking ",i);
                   printf("Cylinder %d   Head %d",c,h);
                   uwrite(128,&biosdata.flpy[drv],0,0,drive);
                   return;
                 };
               }
               else
                 {done = true;};
             };
           } while (done == false);
         };
         skew += ostat.skew;
         if( skew > ostat.f2.sectrack) skew -= ostat.f2.sectrack;
       };
       ostat.f2.gap3 = gap3r;
       ostat.f6.retries = 1;
       ostat.f3.datalenth = olddtr;
       i = uwrite(128,&ostat,0,0,drive);
       if (i != 0) 
         {printf("\n\nError writting drive status with ");
          printf("parameters");
          return;};
       verifydisk(drive);
       return;
}

/*
 *    Verify format
 */

verifydisk(drive)
int drive;
{
        int blk,drv;
        int c,h,i;
        int dumbuf[2561];

        printf("\nVerification");
        drv = drive - 4;
        blk = 0;
        for (c = 0; c < ostat.f1.cylinders; c++) {
          for (h = 0; h < ostat.f1.sides; h++) {
            if ((c % 20) == 0 && h == 0) printf("\n");
            printf(".");
            i = uread(drive,&dumbuf,ostat.f2.sectrack * ostat.bytessec,
                      blk,0);
            if(i != 0) {
              printf("\n\nError while verifying Cylinder %d   Head %d",
                     c,h);
              uwrite(128,&biosdata.flpy[drv],0,0,drive);
              return;
            };
            blk += (ostat.f2.sectrack * ostat.bytessec) / 512;
          };
        };
        uwrite(128,&biosdata.flpy[drv],0,0,drive);
        printf("\n\nFormat Complete");
        return;
}

/***********************************************
 *                                             *
 *    Support routines for Sage Utilitys       *
 *                                             *
 ***********************************************/

/*
 *      Read character and force to lower case
 */

char readchr()
{
       char i;

       i = fgetc(stdin);
       if ((i >= 'A') && (i <= 'Z')) i += 32;
       if (i != cr) do { ;} while (fgetc(stdin) != cr);
       return (i);
}

/*
 *     Read a line of characters converted to lower case
 */

readlin(s)
char s[];
{
       int i;
       char c;

       i = 0;
       do {
         c = fgetc(stdin);
         if ((c >= 'A') && (c <= 'Z')) c += 32;
         if( c != cr) 
           {s[i++] = c;}
         else
           {s[i] = 0;};
       } while (c != cr);
       return;
}
