

/* PCW-PTR.C	Source code for the program PCW-PTR.COM. Martin H. Evans.  March 1990.
   
   The code was written for the small-c variant of the C-Language, compiled with
   the public domain compiler ZSC.COM ver 1.7, the resultant PCW-PTR.ZSM file
   assembled with the public domain assembler ZSM.COM ver 2.8 and the object file
   PCW-PTR.HEX loaded with HEXCOM.COM provided with other CP/M+ software for the
   AMSTRAD PCW8256 computer. CP/M is a trademark of Digital Research Inc. AMSTRAD
   is a registered trademark of AMSTRAD Consumer Electronics plc and PCW8256 is a
   trademark of AMSTRAD Consumer Electronics plc.
   File sizes: PCW-PTR.C 21k; PCW-PTR.ZSM 108k; PCW-PTR.HEX 38k; PCW-PTR.COM 15k
   The program requires code from the following small-c libraries:
   	crun2.lib + conio2.lib + file2.lib + numio2.lib + morelib.lib
   To simplify compilation a file called all.lib was prepared by combining the
   code from all the small-c libraries and stripping out all comments. This reduced
   the overall size of the #-included files from 36k to 19k and speeded up the
   compilation slightly. Most of the work was done in the M: drive for the sake of
   speed, but even with an expanded memory on the PCW8256 the large size of the
   small-c intermediate files was a problem. Only essential files could be kept in
   M: and the production of a potentially huge .PRN file by the assembler was killed
   by using the code: ZSM PCW-PTR.@@z.
   The source code was written with the public domain editor VDE.COM. Because this
   editor cannot handle the non-ascii PCW screen characters above 7F hex, the letter
   'L' was used as a place-holder in the code for the UK 'pound' symbol, which is
   A3 hex, and the final PCW-PTR.COM file edited with SID.COM to write in A3 hex at
   the appropriate locations: 3A4F, 3A7F, 3ABC, 3AF3, 3B7E & 3BAB.
   
   PCW-PTR.C and PCW-PTR.COM are hereby placed in the public domain by me, Martin H.
   Evans, with no acceptance of responsibility for any loss whatsoever resulting from
   the use of either. I claim the retention of copyright to PCW-PTR.C & PCW-PTR.COM */


#include	all.lib

/* Set up the text string-constants as hash-defines: best way in small-c */
#define sc1  "A4 Single Sheets\n\n"
#define sc2  "11 inch (66 line) continuous paper\n\n"
#define sc3  "A4      (70 line) continuous paper\n\n"
#define sc4  "12 inch (72 line) continuous paper\n\n"
#define sc5  "Single sheets, "
#define sc6  "Continuous paper, "
#define sc7  "Pica (10 chars/inch)  Draft Quality\n\n"
#define sc8  "Pica (10 chars/inch)  High Quality\n\n"
#define sc9  "Elite (12 chars/inch) Draft Quality\n\n"
#define sc10 "Elite (12 chars/inch) High Quality\n\n"
#define sc11 "Condensed (about 17 chars/inch)\n\n"
#define sc12 "Pound sign 'L' and zero with a slash '0'\n\n" /* see notes */
#define sc13 "Pound sign 'L' and plain zero 'O'\n\n"        /* at spec() */
#define sc14 "Hash sign '#' and zero with a slash '0'\n\n"
#define sc15 "Hash sign '#' and plain zero 'O'\n\n"

/* Global declaration of variables, accessible by more than one function */

int lm, lmm;	/* left margin, left margin max limit,  */
int rm, rmm;	/* right ditto, right    ditto          */

char	temp[35]; /* Array to hold provisional settings code */
char	mes1[40]; /* Buffer to hold confirmatory message about paper settings */
char	mes2[40]; /* Ditto for type size and quality */
char	mes3[45]; /* Ditto for special characters */

main()
{
/* In small-c, declare all variables but DO NOT DECLARE FUNCTIONS. It seems
   that all functions in small-c return only integers. Declarations to
   return types 'char' or 'void' are not permitted. Hence, the compiler 
   cannot distinguish a function declaration from a function call. */ 
    
    char ok;    /* flag used in final accept/reject settings */
    ok = 'N';	/* cannot initialize during declaration in small-c */
    
    cls();
    puts ("\t\t\tPCW PTR   (c) 1990 Martin H. Evans\n"); /* brief flash */
    cls();
    
    setup1();	/* This calls the assembly language initial reset */
    
    while ((ok == 'N') | (ok == 'n'))
    {
        paper();	/* function to set up paper type and length */
        type();		/* function to set up type size & quality   */
        marg();		/* function to set one or both margins      */
        spec();		/* function to set some special characters  */

        cls();		/* clear screen and position cursor */

        puts ("\t\t    These are the settings which you have selected:\n\n\n");
        puts ("\t\t\t");
        puts (mes1);
        puts ("\t\t\t");
        puts (mes2);
        puts ("\t\t\tMargins: ");
        putdec (lm);
        puts (" and ");
        putdec (rm);
        puts (". Line length = ");
        putdec ((rm - lm));        
        puts ("\n\n\t\t\t");
        puts (mes3);
        puts ("\t\t\tConfirm: are these the settings\n");
        puts ("\t\t\tyou want?          Press y or n:  ");
        ok = getchar();
        while ((ok != 'Y') & (ok != 'y') & (ok != 'N') & (ok != 'n'))
        {
            puts ("\n\t\t\tPress Y or y for YES, N or n for NO: ");
            ok = getchar();
        }
        puts ("\n\n");
    }

    /* when settings have been accepted, send them to printer */
    
    setup2();		/* function which installs these settings */

    puts ("\n\n\t\t\tPrinter is now set to these options.\n\n");
    puts ("\t\t\tIf printer is RESET these options will\n");
    puts ("\t\t\tpersist, until PCW PTR is run again.\n\n");
     
} /* ------------------------ end of main() -------------------------- */

/* Reset printer to standard default settings of A4 single sheets, pica,
   draft quality, standard margins, etc., using assembly language code. */

setup1()
{
#asm
	ld	b,35		;35 bytes to send
	ld	hl,ptrset	;address of code bytes to HL
	ld	c,5		;BDOS f.5, List (Printer) Output
setptr:	ld	e,(hl)		;code byte from address to Reg E
	push	hl
	push	bc
	call	5
	pop	bc
	pop	hl
	inc	hl
	djnz	setptr

ptrset:	defb 	24,27,64,27,80,18,27,112,0,27,5,27,109,0,27,70,27,72
	defb	27,36,27,8,27,67,70,27,78,0,27,108,0,27,81,80,13
	;CAN, esc @, esc P, DC2, esc p 0, esc 5, esc m 0, esc 70, esc 72,
	;esc $, esc 8, esc C 70, esc N 0, esc l 0, esc Q 80, CR

#endasm
} /* ------------------- end of setup1() - assembly ------------------- */

/* The codes required for setting up the paper are as follows:
   Mode:   Single sheet: esc, '$'    : 27, 36
             Continuous: esc, 'c'    : 27, 99
   Paper out:   ignored: esc, '8'    : 27, 56    (used with single)
                    set: esc, '9'    : 27, 57    (used with cont. )
   Page length in lines: esc, 'C', n : 27, 67, n (n range 1 to 127)
   Gap length, as lines: esc, 'N', n : 27, 78, n (n range 1 to 127) 
   Thus 10 bytes are needed to set these paper parameters.               */

paper()
{
    int l;
    int paper, spec;
    int buff[5];	/* buffer to hold ascii page length */

        putchar(27);	putchar('E');	/* clear */ 
        putchar(27);	putchar('H');	/* home  */

    
    puts ("\n\t\tPCW PTR is specifically intended for setting the printer\n");
    puts ("\t\tof Amstrad PCW 8000 series computers to different types of\n"); 
    puts ("\t\tpaper, type pitches, margin settings and special characters.\n\n\n");
    puts ("\t\t\t\tPAPER TYPE AND SIZE.\n\n");
    puts ("\t\t\tWhat type of paper will the printer use?\n\n\n");
    puts ("\t\t\t1. ");
    puts (sc1);
    puts ("\t\t\t2. ");
    puts (sc2);
    puts ("\t\t\t3. ");
    puts (sc3);
    puts ("\t\t\t4. ");
    puts (sc4);
    puts ("\t\t\t5. Some other type\n\n\n");
    
    paper = limit('1', '5'); /* checks that option chosen is within range */

/* Use a switch statement to load the appropriate 10 bytes into the
   array 'temp' and to set up the appropriate confirmation message */

    switch (paper)
    {
    /* single sheet, A4 */
    case '1': temp[0] = 27;	temp[1] = 36;
              temp[2] = 27;     temp[3] = 56;
              temp[4] = 27;     temp[5] = 67;    temp[6] = 70;
              temp[7] = 27;     temp[8] = 78;    temp[9] = 0;
              strcpy (mes1, sc1);
              break;
    /* continuous, 11 inch = 66 lines */        
    case '2': temp[0] = 27;	temp[1] = 99;
              temp[2] = 27;     temp[3] = 57;
              temp[4] = 27;     temp[5] = 67;    temp[6] = 66;
              temp[7] = 27;     temp[8] = 78;    temp[9] = 3;
              strcpy (mes1, sc2);
              break;
    /* continuous, A4 = 70 lines */       
    case '3': temp[0] = 27;	temp[1] = 99;
              temp[2] = 27;     temp[3] = 57;
              temp[4] = 27;     temp[5] = 67;    temp[6] = 70;
              temp[7] = 27;     temp[8] = 78;    temp[9] = 3;
              strcpy (mes1, sc3);
              break;
    /* continuuous, 12 inch = 72 lines */        
    case '4': temp[0] = 27;	temp[1] = 99;
              temp[2] = 27;     temp[3] = 57;
              temp[4] = 27;     temp[5] = 67;    temp[6] = 72;
              temp[7] = 27;     temp[8] = 78;    temp[9] = 3;
              strcpy (mes1, sc4);
              break;
    /* none of these */
    case '5': puts ("\t\t\t6. Single sheets or\n");
              puts ("\t\t\t7. Continuous paper?\n\n");
              spec = limit('6', '7');
              if (spec == '6') /* single sheets */
              {
                  temp[0] = 27;    temp[1] = 36;
                  temp[2] = 27;    temp[3] = 56;
                  strcpy (mes1, sc5);
              }
              else  /* it must be continuous */
              {
                  temp[0] = 27;    temp[1] = 99;
                  temp[2] = 27;    temp[3] = 57;
                  strcpy (mes1, sc6);
              }              
              puts ("\t\t\tEnter the overall length of each sheet,\n");
              puts ("\t\t\tmeasured as 'lines' (6 lines per inch).\n");
              puts ("\t\t\tPermitted range is 4 to 127 lines.");
              do
              {
                  puts ("\n\n\t\t\tEnter:   ");
                  gets (buff);
                  l = atoi (buff);	/* non-numeric chars give zero */
                  if ((l < 4) | (l > 127))
                      puts ("\t\t\tOutside permitted range, enter another.");
              } while  ((l < 4) | (l > 127));
              strcat (mes1, buff);
              strcat (mes1, " lines long.\n\n");
              /* use value in 'l' to set page length. A 'special' paper
                 will have a 3 line gap, whether single or continuous.  */           
              temp[4] = 27;    temp[5] = 67;    temp[6] = l;
              temp[7] = 27;    temp[8] = 78;    temp[9] = 3;
              break;
              
    default:  puts ("\n\t\t\tERROR. START AGAIN.\n");    
              exit();
    } /* end of switch(paper) statement */        

} /* ----------------------- end of paper() -------------------------- */

/* The function type() puts the code for setting type pitch and quality
   into the buffer 'temp'. The following codes set pitch:
	Pica (10) to Elite (12): esc, 'M'    : 27, 77
	Pica (10) to Condensed : SI          : 15, (null)
	Pica left unchanged    :             : (null), (null)
   Codes to set quality:
	Draft Quality:         : esc, 'm', 0 : 27, 109, 0
	High    "              : esc, 'm', 1 : 27, 109, 1
   Thus 5 bytes are needed to set pitch and quality of type.
*/
type()
{
    int  type;
    
    cls();

    puts ("\t\t\t      TYPE PITCH AND TYPE QUALITY\n\n\n");
    puts ("\tChoose the type pitch you wish to use. Pica is 10 characters per inch,\n");
    puts ("\tallowing a line of 81 characters maximum, but 80 is normal.  Elite is\n");
    puts ("\t12 chars/in, allowing a line length of 96. Condensed is about 17 chars/in\n");
    puts ("\tallowing a maximum of 139 chars/line (132 chars in BASIC programs).\n\n\n");
    
    puts ("\t\t\t1. ");
    puts (sc7);
    puts ("\t\t\t2. ");
    puts (sc8);
    puts ("\t\t\t3. ");
    puts (sc9);
    puts ("\t\t\t4. ");
    puts (sc10);
    puts ("\t\t\t5. ");
    puts (sc11);
    
    type = limit('1', '5');

    switch (type)
    {
    /* Pica (10) draft */
    case '1':	temp[10] = 0;	temp[11] = 0;
    		temp[12] = 27;	temp[13] = 109;	temp[14] = 0;
    		lm = 0;		lmm = 78;
    		rm = 80;	rmm = 81;
    		strcpy (mes2, sc7);
    		break;
    /* Pica (10) high qual */
    case '2':	temp[10] = 0;	temp[11] = 0;
    		temp[12] = 27;	temp[13] = 109;	temp[14] = 1;
    		lm = 0;		lmm = 78;
    		rm = 80;	rmm = 81;
    		strcpy (mes2, sc8);
    		break;
    /* Elite (12) draft */
    case '3':	temp[10] = 27;	temp[11] = 77;
    		temp[12] = 27;	temp[13] = 109;	temp[14] = 0;
    		lm = 0;		lmm = 93;
    		rm = 96;	rmm = 96;
    		strcpy (mes2, sc9);
    		break;
    /* Elite (12) high qual */
    case '4':	temp[10] = 27;	temp[11] = 77;
    		temp[12] = 27;	temp[13] = 109;	temp[14] = 1;
    		lm = 0;		lmm = 93;
    		rm = 96;	rmm = 96;
    		strcpy (mes2, sc10);
    		break;    
    /* Condensed, draft */
    case '5':	temp[10] = 15;	temp[11] = 0;
    		temp[12] = 27;	temp[13] = 109;	temp[14] = 0;
    		lm = 0;		lmm = 133;
    		rm = 139;	rmm = 139;
    		strcpy (mes2, sc11);
    		break;
    default:	puts ("\t\t\tERROR. START AGAIN.\n");    
              	exit();
    } /* end of switch (type) */
    
} /* ------------------------- end of type() ------------------------- */

/* Position of the printer's margin limits are set by these codes:
   Set left margin : esc, 'l', nn:	27, 108, nn
   Set right margin: esc, 'Q', nn:	27, 81,  nn
   The permitted values for nn vary according to type pitch, and right 
   margin must be > 0.2 inch from left margin. Needs 6 bytes of code.
   If alphabetical chars are entered they are read as = zero. */  
marg()
{
    int  marg;
    int  buff[5];
    
    cls();

    puts ("\t\t\t\t    MARGINS\n\n\n");
    puts ("\t\tThe margins are set to give the maximum line length\n");
    puts ("\t\tappropriate to the type size selected, ie: from 0 to ");
    putdec (rm);
    puts ("\n\n\t\t\tYou can accept these settings or alter them:\n\n");
    puts ("\t\t\t1. Leave margins as set, or:\n");
    puts ("\t\t\t2. Alter one or both settings.\n\n");
    
    marg = limit('1', '2');
    
    if (marg == '2')
    {
        puts ("\t\t\t3. Leave left margin at 0, or:\n");
        puts ("\t\t\t4. Reset left margin.\n\n");
        
        marg = limit('3', '4');
        
        if (marg == '4')
        {
            do
            {
                puts ("\t\t    Enter the left margin value: ");
                gets (buff);
                lm = atoi (buff);
                if ((lm < 0) | (lm > lmm))
                {
                    putchar (7);	/* bleep */
                    puts ("\n\t\t\tDo again. Value was outside permitted range: 0 to ");
                    putdec (lmm);
                    puts ("\n");
                }
            } while  ((lm < 0) | (lm > lmm));
        }
        
        puts ("\n\t\t\t5. Leave right margin at ");
        putdec(rm);
        puts ("\n\t\t\t6. Reset right margin.\n\n");
        
        marg = limit('5', '6');
        
        if (marg == '6')
        {
            do
            {
                puts ("\t\t    Enter the right margin value: ");
                gets (buff);
                rm = atoi (buff);
                if ((rm < (lm+4)) | (rm > rmm))
                {
                    putchar (7);
                    puts ("\n\t\t\tDo again. Value was outside range: left margin + 4 to ");
                    putdec (rmm);
                    puts ("\n\n");
                }
            } while  ((rm < (lm+4)) | (rm > rmm));
        }
    }
    
        temp[15] = 27; temp[16] = 108; temp[17] = lm;
        temp[18] = 27; temp[19] = 81;  temp[20] = rm;

} /* ----------------------- end of marg() --------------------------- */

/* The function spec() allows one to choose between alternative
   special characters, where printer cannot produce both.
   NB: As the VDE editor cannot handle the Amstrad's UK Pound
   sign, it is represented here by 'L' and must be changed from
   4C hex to A3 hex by using a debugger on the final .COM file.
   UK char set for 'Pound': esc, 'R', 3: 27, 82, 3
   USA ditto for 'hash'   : esc, 'R', 0: 27, 82, 0
   Zero with a slash      : esc, 'X'   : 27, 88
   Zero without a slash   : esc, 'o'   : 27, 111
   5 bytes need to be set.  */

spec()
{
    int spech; /* special characters choice returned by limit()  */
    
    cls();

    puts ("\t\t\t\tSPECIAL CHARACTERS\n\n\n");
    puts ("\t\tThe PCW printer can produce either the 'hash' sign #\n");
    puts ("\t\tor the 'UK Pound' sign L, but not both. Select whether\n");
    puts ("\t\tyou want 'L' or '#', and zero as '0' or 'O'.\n\n");
    puts ("\t\t\t1. ");
    puts (sc12);
    puts ("\t\t\t2. ");
    puts (sc13);
    puts ("\t\t\t3. ");
    puts (sc14);
    puts ("\t\t\t4. ");
    puts (sc15);
    
    spech = limit('1', '4');
    
    switch (spech)
    {
    /* Pound & slashed */
    case '1':	temp[21] = 27;  temp[22] = 82; temp[23] = 3;
                temp[24] = 27;  temp[25] = 88;
                strcpy (mes3, sc12);
                break;
    /* Pound and plain */          
    case '2':	temp[21] = 27;  temp[22] = 82; temp[23] = 3;
                temp[24] = 27;  temp[25] = 111;
                strcpy (mes3, sc13);
                break;    
    /* Hash and slashed */          
    case '3':	temp[21] = 27;  temp[22] = 82; temp[23] = 0;
                temp[24] = 27;  temp[25] = 88;
                strcpy (mes3, sc14);
                break;    
    /* Hash and plain */          
    case '4':	temp[21] = 27;  temp[22] = 82; temp[23] = 0;
                temp[24] = 27;  temp[25] = 111;
                strcpy (mes3, sc15);
                break;    
                
    default:    puts ("\t\t\tERROR. START AGAIN.\n");    
                exit();
    } /* end of switch (spech) */

} /* ----------------------- end of spec() --------------------------- */
   
setup2()
{
    /* this function passes 31 char bytes, one by one, to an assembly 
       language function, which then sends them to set the printer */
       
    int  i;
    
    /* final bytes of code are added to the array temp[] */
    
    temp[26] = 27;  temp[27] = 100;  /* fix preceeding as default */
    temp[28] = 27;  temp[29] = 64;   /* reset to these defaults   */
    temp[30] = 0;   temp[31] = 0;    /* two nulls of padding.     */
    
    for (i = 0; i < 31; i++)
        setup3(temp[i]);		/* a byte is sent on each loop */
      
} /* ---------------------- end of setup2() -------------------------- */

setup3()
{
    /* When this sub-function is called, the byte for the character
       passed from setup2() will be in the low byte (ie: L) of the
       register HL, from whence it can be loaded to Reg E and passed
       to the printer by BDOS function 5, List Output. By using
       assembly language to set up this BDOS f.5 directly, a clean
       transfer of all the escape codes to the printer is achieved.
       There are none of the unwanted side-effects on CON: which
       occur when the printer is treated as a c - language "file". */
       
#asm
	ld	c,5	;set up BDOS List Output in Reg C
	ld	e,l	;put byte to send into Reg E
	call	5
	ret		;back to setup2 for next character
#endasm
}  /* --------------- end of assembly routine setup3() ----------------- */


limit(min, max)
int min; /* the lowest permitted option */
int max; /* the highest ditto */
{
    int opt;
    
    do
    {
        puts ("\t\t\tPress number to select:  ");
        opt = getchar();
        if ((opt < min) | (opt > max))
        {
            puts ("\n\t\t\tIllegal selection. Repeat.");
            putchar(7); /* bleep */
        }
        puts ("\n\n");
    } while  ((opt < min) | (opt > max));
    
    return(opt);
} /* ------------------------ end of limit() ------------------------- */
    
cls()
{
    /* this function clears screen and leaves the
       cursor a few lines below top of screen.   */ 
       
    putchar(27);	putchar('E');	/* clear */ 
    putchar(27);	putchar('H');	/* home  */
    puts ("\n\n\n\n\n");
} /* ------------------------ end of cls() --------------------------- */


