
/***********************************************************************
*                                                                      *
*                                                                      *
*                         GST COMPILE PROGRAM                          *
*                         ===================                          *
*                                                                      *
*                                                                      *
*    This program is a menu driven QC "shell" that is provided to      *
*    drive the QC Compiler and associated utility programs.  The       *
*    COMPILE program makes extensive use of tagged windows for:        *
*                                                                      *
*    (a)  console dialogue                                             *
*                                                                      *
*    (b)  display of contents of program and data directories          *
*                                                                      *
*    (c)  display of a menu for the following options:                 *
*                                                                      *
*         Compile, Assemble and Link a QC program                      *
*         Run an arbitrary program                                     *
*         Run the Window Manager                                       *
*         Run the Backup program                                       *
*         Run the QED Screen Editor                                    *
*         Return to SuperBASIC                                         *
*                                                                      *
*    It is not necessary to use the COMPILE program for compiling QC   *
*    programs or running the utilities, these can be invoked in the    *
*    usual way from SuperBASIC using either:                           *
*                                                                      *
*         EXEC_W <device>_<program>                                    *
*                                                                      *
*    or, if you posess the QL Toolkit:                                 *
*                                                                      *
*         EW <device>_<program>;"<options>"                            *
*                                                                      *
*    Note that it is not possible to run both the COMPILE program and  *
*    the QC Compiler together with the Toolkit on a standard QL.       *
*                                                                      *
*                                                                      *
*    REVISION HISTORY                                                  *
*    ================                                                  *
*                                                                      *
*    2.10      New version for release with QED                        *
*    2.09      Output directory data in tag                            *
*    2.08      Better handling of directories                          *
*    2.07      Introduce default 2nd directory                         *
*    2.06      Use FLP1_default and GST editor                         *
*    2.05      QC release 1.00 version                                 *
*    2.04      Call WINDOW_MGR differently                             *
*    2.03      Changes to windows                                      *
*    2.02      More bug fixes                                          *
*    2.01      Fix assorted bugs                                       *
*    2.00      Rewritten in C                                          *
*    1.00      Beta test version in SuperBASIC                         *
*                                                                      *
***********************************************************************/
#page 

/* --- Define version number --- */


#define   VERSION   "QC Shell 2.10"


/* --- Read standard I/O header --- */


#include  "stdio.h"                /* Read standard I/O header */

/* --- Define the colours --- */


#define   BLACK     0
#define   RED       2
#define   GREEN     4
#define   WHITE     7
#define   STIPPLE   255            /* Black and white check stipple */


/* --- Define special keys --- */


#define   F1        232
#define   F2        236
#define   F3        240
#define   F4        244
#define   F5        248
#define   ESC       27


/* --- Define globals --- */


int       *winblank,               /* Stippled background window */
          *winmenu,                /* Menu window */
          *winprog,                /* Program directory window */
          *windata;                /* Data directory window */
 
char      *progdefault,            /* Default program directory */
          *datadefault;            /* Default data directory */

#page

/* --- MAIN program --- */
 
main ()

     {

     unsigned char  key;      /* Keystroke */
     int            status;   /* Status returned from program */
 
     /* --- Set up windows, display directories and menu --- */

     initialise ();
 
     /* --- Main polling loop --- */

     while ( 1 )

          {

          key = poll ( 0 );

          if ( key == 0 ) continue;
 
          /* --- Select option by keystroke value --- */

          switch ( key )

               {

               case F1:

                    /* --- Run compiler, assembler and linker --- */

                    status = compile ();
                    break;

               case F2:

                    /* --- Run an arbitrary program --- */

                    status = execute ();
                    break;
 
               case F3:

                    /* --- Run the window manager --- */

                    status = windows ();
                    reinit ();
                    continue;

               case F4:

                    /* --- Run the backup program --- */

                    status = backup ();
                    break;
 
               case F5:

                    /* --- Run the editor --- */

                    status = edit ();
                    break;

               case ESC:

                    /* --- Fake a NEW and return to SuperBASIC --- */

                    newwin ( 512, 256, 0, 0, BLACK, GREEN, BLACK );
                    newwin ( 256, 202, 0, 0, WHITE, RED, STIPPLE );
                    newwin ( 256, 202, 256, 0, RED, WHITE, STIPPLE );
                    exit ( 0 );
 
               default:

                    /* --- Ignore spurious keystrokes --- */

                    continue;
 
               }

          /* --- Report error status if any --- */

          if ( status )

               {
               saystatus ( status );
               }

          else

               {
               printf ( "Finished" );
               }

          /* --- Wait for keystroke, then repaint windows --- */

          printf ( " - press any key to continue" );
          fflush ( stdout );
          while ( poll ( 0 ) == 0 );
          reinit ();

          }

     }

/* --- End of MAIN program --- */
#page 

/* --- INITIALISE - create windows, test for floppy disks --- */

initialise ()

     {

     int  chan1,
          chan2;

     /* --- Open channels to SCR_ of arbitrary size --- */

     winblank = fopen ( "scr_10x10", "w" );
     winmenu  = fopen ( "scr_10x10", "w" );
     winprog  = fopen ( "scr_10x10", "w" );
     windata  = fopen ( "scr_10x10", "w" );

     blankscreen ( YES );

     /* --- See if disks are present, set appropriate defaults --- */
 
     chan1 = fopen ( "flp1_", "d" ); if ( chan1 ) fclose ( chan1 );
     chan2 = fopen ( "flp2_", "d" ); if ( chan2 ) fclose ( chan2 );

     if ( chan1 && chan2 )
          {
          progdefault = "flp1_";
          datadefault = "flp2_";
          }
     else if ( chan1 ) 
          {
          progdefault = "flp1_";
          datadefault = progdefault;
          }
     else if ( chan2 )
          {
          progdefault = "flp2_";
          datadefault = progdefault;
          }
     else
          {
          progdefault = "mdv1_";
          datadefault = "mdv2_";
          }

     /* --- Now paint the windows --- */

     reinit ();

     }

/* --- End of INITIALISE --- */
#page
 
/* --- REINIT - paint windows and update directories --- */

reinit ()

     {

     char progtag[41],   /* tag buffer for program directory */
          datatag[41];   /* tag buffer for data directory */

     /* --- Stipple the entire screen then paint windows --- */

     blankscreen ( YES );

     tagwin ( stdout, 496, 43, 8, 207, RED, BLACK, "Console" );
     tagwin ( winmenu, 243, 193, 8, 6, WHITE, BLACK, VERSION );

     /* --- Display 1 or 2 directories as appropriate --- */

     if ( progdefault == datadefault )

          {
          dirinfo ( progdefault, progtag, 41 );
          tagwin ( winprog, 248, 193, 257, 6, GREEN, BLACK, progtag );
          directory ( winprog, progdefault );
          }

     else

          {
          dirinfo ( progdefault, progtag, 19 );
          dirinfo ( datadefault, datatag, 19 );
          tagwin ( winprog, 122, 193, 257, 6, GREEN, BLACK, progtag );
          tagwin ( windata, 121, 193, 384, 6, GREEN, BLACK, datatag );
          directory ( winprog, progdefault );
          directory ( windata, datadefault );
          }

     /* --- Write logo, update directory listings and write menu --- */

     shadow ( stdout, 160, 4, BLACK, WHITE, "GST QC Compiler" );

     printmenu ();

     }
 
/* --- End of REINIT --- */
#page
/* --- COMPILE - compile assemble and link a program --- */
 
compile ()

     {

     char fname[40], optbuff[80], linebuff[80], *p;
     int  channel, status;
 
     /* --- Read <device>_<file> from console --- */

     blankconsole ();
     printf ( "Name of file to compile ? " );
     fflush ( stdout );
     fgets ( linebuff, 40, stdin );
 
     /* --- Strip off leading spaces & trailing newline --- */
 
     left ( linebuff );
     if ( *linebuff == '\n' ) return ( 0 );
     p = strchr ( linebuff, '\n' );
     if ( p ) *p = 0;
 
     /* --- Check that file exists --- */
 
     strcpy ( fname, linebuff );
     strcpy ( optbuff, linebuff );
     strcat ( linebuff, "_c" );
     channel = fopen ( linebuff, "r" );

     /* --- Complain if file not found --- */

     if ( channel == 0 )

          {
          printf ( "Unable to find file %s\n", linebuff );
          return ( ferror ( 0 ) );
          }

     else

          {
          fclose ( channel );
          } 
 
     /* --- Construct rest of compiler command line --- */
 
     strcat ( optbuff, " -d " );
     strcat ( optbuff, progdefault );
     strcat ( optbuff, " " );
 
     /* --- Read options and append to command line --- */

     printf ( "Extra compiler options  ? " );
     fflush ( stdout );
     fgets ( linebuff, 40, stdin );
     strcat ( optbuff, linebuff );
     p=strchr ( optbuff,'\n' );
     if ( p ) *p = 0;

     /* --- Stipple top half of screen then run compiler --- */

     blankscreen ( NO );
     printf ( "Compiling:  %s\n", optbuff );
     status = progexec ( progdefault, "qc", optbuff );
     if ( status ) return ( status );
 
     /* --- Now run the assembler --- */

     strcpy ( optbuff, fname );
     strcat ( optbuff, " -nolist" );
     printf ( "Assembling: %s\n", optbuff );
     status = progexec ( progdefault, "qcasm", optbuff );
     if ( status ) return ( status );
 
     /* --- Finally, run the linker --- */

     strcpy ( optbuff, fname );
     strcat ( optbuff, " -nolist -with " );
     strcat ( optbuff, progdefault );
     strcat ( optbuff, "qc_link" );
     printf ( "Linking:    %s\n", optbuff );
     status = progexec ( progdefault, "link", optbuff );              
     return ( status );

     }
 
/* --- End of COMPILE --- */
#page

/* --- EXECUTE - run an arbitrary program --- */
 
execute ()

     {

     char linebuff[128];
     char *p, *progname, *options;
     int  status;

     /* --- Fetch program name and options --- */

     blankconsole ();
     printf ( "Program name and options ? " );
     fflush ( stdout );
     fgets ( linebuff, 128, stdin );
     p = strchr ( linebuff,'\n' );
     if ( p ) *p = 0;

     /* --- Find program name, return if none --- */
 
     for ( p = linebuff; *p == ' '; ++p );
     if ( *p == 0 ) return(0);
     progname = p;

     /* --- Scan to end of program name --- */

     while ( *p && *p!=' ' ) ++p;
 
     /* --- If options exist, terminate program name with null --- */

     if ( *p )

          {
          *p++ = 0;
          while ( *p == ' ' ) ++p;
          }

     options = p;

     /* --- Call program, return status when finished --- */

     blankscreen(NO);
     status = exec ( progname, options, YES );
     return ( status );

     }
 
/* --- End of EXECUTE --- */
#page
 
/* --- WINDOWS - call window manager to adjust windows --- */

windows ()

     {

     int  status;

     /* --- Run window manager from default data device --- */

     status = progexec ( datadefault, "window_mgr", "" );
     return ( status );

     }

/* --- End of WINDOWS --- */
#page
 
/* --- BACKUP - Run backup program --- */

backup ()

     {

     /* --- Run backup from default program device --- */

     blankscreen ( NO );
     blankconsole ();
     return progexec ( progdefault, "backup", "" );

     }
 
/* --- End of BACKUP --- */
#page

/* --- EDIT - Run the editor --- */

edit ()

     {

     /* --- Run the editor from default program device --- */

     blankscreen ( NO );
     blankconsole ();
     return progexec ( progdefault, "qed", "" );

     }

/* --- End of EDIT --- */
#page

/* --- NEWWIN - define and clear new window --- */

newwin ( w, h, x, y, p, i, b )

     int  w,   /* Width */
          h,   /* Height */
          x,   /* X-coordinate */
          y,   /* Y-coordinate */
          p,   /* Paper colour */
          i,   /* Ink colour */
          b;   /* Border colour */

     {

     /* --- Create and clear window --- */

     window ( w, h, x, y );
     paper ( p );
     ink ( i );
     border ( 1, b );
     cls ( 0 );

     }

/* --- End of WINDOW --- */
#page

/* --- PROGEXEC - start program from QC --- */

progexec ( def, prog, parms )

     char *def,   /* Default device string */
          *prog,  /* Program name string */
          *parms; /* Program parameters string */

     {

     char progbuff[80];  /* Work buffer for string handling */
 
     /* --- Copy device into buffer and append program name --- */

     strcpy ( progbuff, def );
     strcat ( progbuff, prog );
 
     /* --- Run program and return status when completed --- */

     return exec ( progbuff, parms , YES );

     }

/* --- End of PROGEXEC --- */ 
#page 
 
/* --- TAGWIN - create and display tagged window --- */

tagwin ( chan, horiz, vert, x, y, p, i, tag )

     int  *chan,    /* Channel */
          horiz,    /* Width */
          vert,     /* Height */
          x,        /* X-coordinate */
          y,        /* Y-coordinate */
          p,        /* Paper colour */
          i;        /* Ink colour */

     char *tag;     /* Tag string */

     {

     selwindow ( chan );
 
     /* --- Create tag and write tag string --- */

     newwin ( horiz, 12, x, y , BLACK, WHITE, BLACK );
     fputs ( tag, chan );
     fflush ( chan );

     /* --- Create main window --- */
 
     newwin ( horiz, vert-11, x, y+11, p, i, BLACK );

     }
     
/* --- End of TAGWIN --- */
#page

/* --- BLANKSCREEN - clear whole or top of screen with stipple --- */

blankscreen ( flag )

     int  flag;     /* Whole or top flag */

     {

     int  y;        /* Y-dimension */

     /* --- Determine area to blank --- */

     if ( flag )
          {
          y = 256;
          }
     else
          {
          y = 202;
          }

     /* --- Select blanking window and clear required area --- */

     selwindow ( winblank );
     window ( 512, y, 0, 0 );
     paper ( STIPPLE );
     cls ( 0 );

     }

/* --- End of BLANKSCREEN --- */
#page

/* --- BLANKCONSOLE - clear stdout window --- */

blankconsole ()

     {

     selwindow ( stdout );
     cls ( 0 );

     }
 
/* --- End of BLANKCONSOLE --- */
#page

/* --- SHADOW - write text in shadow writing --- */

shadow ( chan, x, y, ink1, ink2, text )

     int  *chan,    /* Channel */
          x,        /* X-coordinate */
          y,        /* Y-coordinate */
          ink1,     /* Background ink */
          ink2;     /* Foreground ink */

     char *text;    /* Text string */

     {

     selwindow ( chan );
 
     /* --- Print background in double height and width --- */

     cursor ( x+1, y+1 );
     ink ( ink1 );
     csize ( 2, 1 );
     fputs ( text, chan );
     fflush ( chan );
 
     /* --- Print foreground with transparent background --- */

     cursor ( x, y );
     ink ( ink2 );
     over ( 1 );
     fputs ( text, chan );
     fflush ( chan );
 
     /* --- Reset character attributes --- */
 
     over ( 0 );
     csize ( 0, 0 );

     }
 
/* --- End of SHADOW --- */
#page

/* --- PRINTMENU - output menu to screen window --- */

printmenu ()

     {

     selwindow ( winmenu );
 
     at ( 5, 7 ); fputs ( "F1  - Compile QC Program\n", winmenu );
     at ( 6, 7 ); fputs ( "F2  - Execute a Program\n", winmenu );
     at ( 7, 7 ); fputs ( "F3  - Adjust Windows\n", winmenu );
     at ( 8, 7 ); fputs ( "F4  - Make a Backup Copy\n", winmenu );
     at ( 9, 7 ); fputs ( "F5  - Run GST Text Editor\n", winmenu );
     at (10, 7 ); fputs ( "ESC - Return to SuperBASIC\n", winmenu );
 
     }
 
/* --- End of PRINTMENU --- */
#page
 
/* --- DIRECTORY - print directory list in a window --- */

directory ( channel, drivename )

     int  *channel;      /* Window channel */
     char *drivename;    /* Device to read */

     {

     int  *dirchan,      /* Channel for device */
          dirinfo[8];    /* Buffer for directory entry */

     char filename[40];  /* Filename buffer */
 
     /* --- Open channel to directory, return if error --- */

     dirchan = fopen ( drivename, "d" );

     if ( dirchan == 0 ) return;
 
     /* --- Print each file in directory --- */

     while ( readdir ( dirchan, filename, dirinfo ) == 0 )

          {

          if ( progdefault == datadefault )

               {
               fprintf ( channel, "%-32s%8d\n", filename, dirinfo[0] );
               }

          else

               {
               fprintf ( channel, "%s\n", filename );
               }

          }

     fclose ( dirchan );

     }

/* --- End of DIRECTORY --- */
#page

/* --- SAYSTATUS - print error message in console window --- */

saystatus ( status )

     int  status;

     {

     char *m;

     switch ( status )

          {

          case -1 : m = "not complete";   break;
          case -3 : m = "out of memory";  break;
          case -7 : m = "not found";      break;
          case -8 : m = "already exists"; break;
          case -9 : m = "in use";         break;
          case -10: m = "end of file";    break;
          case -11: m = "disk full";      break;
          case -15: m = "bad parameter";  break;
          default : m = "status = %d";    break;

          }

     printf ( m, status );

     }

/* --- End of SAYSTATUS --- */
#page

/* --- DIRINFO - write directory data to tag buffer --- */

dirinfo ( device, tagbuff, length )

     char *device,       /* Device name */
          *tagbuff;      /* Tag buffer */

     int  length;        /* Buffer length */

     {

     int  regs[8],
          count,
          *chan;

     char *ptr;

     /* --- Fill buffer with spaces and copy in device name --- */

     ptr = tagbuff;
     count = length;
     while ( count-- ) *ptr++ = ' ';
     strcpy ( tagbuff, device );
     ptr = tagbuff + strlen ( tagbuff );

     /* --- Read directory data --- */

     chan = fopen ( device, "d");
     regs[0] = 0x45;
     regs[3] = -1;
     regs[4] = *chan;
     regs[5] = ptr;
     trap3 ( regs );

     /* --- If wide tag, write free/total sectors --- */

     if ( length >= 24 )
          {
          ptr = tagbuff + length;
          itod ( regs[1]>>16, ptr-10, -4 );
          *( ptr-6 ) = '/';
          itod ( regs[1]&0xFFFF, ptr-5, 5 );
          }
     else
          {
          *( regs[5] ) = 0;
          }

     fclose ( chan );

     }

/* --- End of DIRINFO --- */
#page

