/* 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() --------------------------- */