koreth@ssyx.ucsc.edu (Steven Grimm) (06/21/88)
Submitted-by: uunet!mcvax!philmds!leo (Leo de Wit) Posting-number: Volume 1, Issue 58 Archive-name: fastdump another submission for the ST. It runs in any case on a color monitor (med and high res); I have no chance of testing it on a monochrome monitor. The following program (FASTDUMP.PRG) should be placed in the AUTO folder, so that it is made resident at startup time. After pressing Alternate-Help the screen is dumped to the printer (at least, a copy of the graphic image 8-). It is much faster than the standard routine but only suitable for text screens. The program was compiled and linked with the compiler and linker that come with the Lattice-C compiler, as follows: Click on LC.TTP, then enter: fastdump Create a file fastdump.lnk with contents (2 lines): INPUT fastdump.bin LIBRARY clib.bin Click on LINK.TTP, then enter: -with fastdump The resulting code was 1924 bytes in size. L.J.M. de Wit Nachtegaallaan 7 5731XP Mierlo Holland --------------------- H E R E I T A L L S T A R T S ------------------- /* ****************************************************************************** * * * fastdump.c version 1.1 of 19 June 1988 (C) L.J.M. de Wit 1988 * * * * This software may be used and distributed freely if not used commercially * * and the originator (me) is mentioned. * * * ****************************************************************************** * * NAME * fastdump - fast ascii screen dump * * SYNTAX * fastdump.prg * * DESCRIPTION * Fastdump does a fast screen dump whenever the Alt Help key is pressed. * It reads the screen memory to match on font characters; matched * characters are printed as-is, non-matched characters as spaces. * It has some intelligence as to avoid printing trailing spaces. * It is very useful as afterwards printer, e.g. after a compilation with * error messages, or a program that exits with failure messages, and also * for printing source/text from within an editor, or for programs that do * not provide for hardcopy output. * * Fastdump should be in the AUTO folder as FASTDUMP.PRG so that it is * installed memory resident when the system is loaded. It then overrides * the standard screen dump routine. * * BUGS * The program does not provide for RS232 printing yet. The Centronics port * is used. * * The routine is not used when it is called from the XBIOS. This is because * of old disk-based TOS versions that had the dump vector hardcoded. A * future release of this program (if there will be any &-) will use the * screen dump vector at address 0x502. * * Characters in reverse video are not matched yet with their reverse images * so that reverse video now results in spaces. Also something for the next * release. * * DECISIONS * The current version is compiled with a Lattice C compiler; people using * other compilers should be aware of the fact that on entrance of do_dump() * the contents of A4/A5 will be different from what it was when the * program was started (being an interrupt-routine) so that register * relative addressing cannot be used in this case (or A4 should be loaded * when the routine is entered). For Lattice C absolute addressing is the * default so that there was no problem in this case. * After compilation the module should be linked only with the standard * library (for the gemdos function). So the link file should contain: * INPUT fastdump.bin * LIBRARY clib.bin * startup.bin is not used, and the function startup() is used as entry point. * The size of the resulting code is much smaller now (not using stdio etc). * */ #include <osbind.h> #include <portab.h> #define DUMPFLG (*(WORD *)0x4EE) /* Alt Help pressed flag */ #define SSHIFTMD (*(BYTE *)0x44C) /* Screen Shift Mode */ #define V_BAS_AD (*(LONG *)0x44E) /* logical screen base address */ #define NVBLS (*(WORD *)0x454) /* length of this array */ #define VBLQUEUE (*(que_ptr *)0x456) /* array of VBL vectors */ #define HZ_200 (*(LONG *)0x4BA) /* 200 Hz system clock */ #define CENTRONICS_BUSY (1 & *(BYTE *)0xFFFFFA01) #define GI ((BYTE *)0xFFFF8800) /* I/O locations for sound chip*/ /* font definitions */ typedef struct font_header { WORD f_id; /* font identifier; system font = 1 */ WORD f_point; /* font size in points */ char f_name[32]; /* font name */ WORD f_low; /* lowest ascii code in font */ WORD f_high; /* highest ascii code in font */ WORD f_top; /* relative distance of top to base line */ WORD f_ascent; /* relative distance of ascent to base line */ WORD f_half; /* relative distance of half to base line */ WORD f_descent; /* relative distance of descent to base line */ WORD f_bottom; /* relative distance of bottom to base line */ WORD f_maxcharw; /* maximal character width in font */ WORD f_maxcellw; /* maximal cell width in font */ WORD f_loffset; /* left offset */ WORD f_roffset; /* right offset */ WORD f_fatsiz; /* degree of fattening */ WORD f_ulsiz; /* underline degree */ WORD f_normask; /* normal cancelled mask */ WORD f_skewmask; /* skewing cancelled mask */ WORD f_flag; /* flag: * bit 0: system font; * bit 1: hor. offset; * bit 2: byte swap; * bit 3: non proportional font */ WORD *f_horoff; /* pointer to horizontal offsets table */ WORD *f_charoff; /* pointer to character offsets table */ char *f_data; /* pointer to font data table */ WORD f_fontw; /* total width of all chars in font */ WORD f_fonth; /* height of font (# scanlines) */ struct font_header *f_next; /* pointer to next font header */ } font_header; static UWORD g_fheader[] = { 0xA000, /* LineA exception 0 */ 0x222F,0x0004, /* MOVE.L 4(SP),D1 */ 0xE581, /* ASL.L #2,D1 */ 0x2031,0x1800, /* MOVE.L 0(A1,D1),D0 */ 0x4E75 }; /* RTS */ static UWORD get_sr[] = { 0x7000, /* MOVEQ.L #0,D0 */ 0x40C0, /* MOVE.W SR,D0 */ 0x007C,0x0700, /* OR.W #$700,SR */ 0x4E75 }; /* RTS */ static UWORD set_sr[] = { 0x46EF,0x0006, /* MOVE.W 6(SP),SR */ 0x4E75 }; /* RTS */ WORD planes; font_header *fhp; static void do_dump(), startup(); static BYTE lstout(), get_schar(), read_gi(), write_gi(), dummy(); typedef void (**que_ptr)(); /* que_ptr points to an array of pointers * to functions returning void */ static void startup(base) LONG *base; { LONG memneed; extern LONG _mneed; WORD i, nvbls; LONG ssp; memneed = 0x100 + /* base page */ base[3] + /* text length */ base[5] + /* data length */ base[7] + /* bss length */ 0x800 + /* workspace */ 0x900; /* for stack */ ssp = Super(0); /* Supervisor mode */ nvbls = NVBLS; /* length of VBLQUEUE array */ for (i = 0; i < nvbls; i++) { if (VBLQUEUE[i] == (void (*)())0) {/* If empty slot found */ VBLQUEUE[i] = do_dump; /* set vector for new routine */ break; } } Super(ssp); /* Back to User mode again */ if (i < nvbls) { /* If empty slot was found */ Ptermres(memneed,0); /* make resident & terminate */ } else { /* else report the problem & */ Cconws("Cannot bind new VBL routine\r\n"); Pterm(1); /* terminate with error status */ } } static void do_dump() /* The interrupt routine */ { WORD i, j; char *s, *t; WORD rows, cols; /* Rows & columns of screen */ char line[81]; /* Holds a line to be printed */ BYTE status; /* Printer ready status */ BYTE rez; /* resolution 2 high 1 med 0 low*/ if (DUMPFLG != 0) { /* Alt Help not pressed? */ return; } if ((rez = SSHIFTMD & 3) == 3) { rez = 2; } fhp = (*(font_header *(*)())g_fheader) ((rez == 2) ? 2 : 1); /* pointer to standard font */ planes = 4 >> rez; /* # of bit planes: 4, 2 or 1 */ rows = 25; cols = (rez == 0) ? 40 : 80; for (i = 0; i < rows; i++) { /* Handle each screen row ... */ s = line; t = line; for (j = 0; j < cols; j++, s++) { /* Handle each column per row */ *s = get_schar(i,j); /* Get ASCII value at this pos.*/ if ((*s != ' ') || (*t != ' ')) {/* t: last nonsp. or first sp. */ t = s; } } *s = '\0'; /* null-terminate line */ if (*t == ' ') { *t = '\0'; /* discards trailing spaces */ } status = 0; for (s = line; *s != '\0'; s++) { /* print each char/test status */ status = lstout(*s); if (status != 0) break; /* printer not ready; abort */ } if (status != 0) break; /* abort */ lstout('\r'); lstout('\n'); /* terminate line with CR/LF */ if (DUMPFLG != 0) { /* Alt Help pressed again? */ break; } } DUMPFLG = -1; /* No Hardcopy */ } static BYTE lstout(c) /* Send one character */ char c; /* to Centronics port */ { LONG start; BYTE not_ready; start = HZ_200; do { /* poll the status */ not_ready = CENTRONICS_BUSY; dummy(); /* to prevent erroneous optim. */ } while (not_ready && (HZ_200 - start < 6000)); /* 30 sec. timeout */ if (!not_ready) { /* The actual printing */ BYTE val; LONG istatus; istatus = (*(LONG (*)())get_sr)(); /* Save SR */ val = read_gi(7); write_gi(7,val | 0x80); (*(LONG (*)())set_sr)(istatus); /* Restore SR */ write_gi(15,c); val = read_gi(14); write_gi(14,val & 0xDF); val = read_gi(14); write_gi(14,val | 0x20); } return not_ready; /* return 0 for OK */ } static BYTE read_gi(reg) /* Read from G.I. sound chip */ BYTE reg; { LONG istatus; istatus = (*(LONG (*)())get_sr)(); /* Save SR */ GI[0] = reg; reg = dummy(); /* prevents optimizing away .. */ reg = GI[0]; /* ... this statement */ (*(LONG (*)())set_sr)(istatus); /* Restore SR */ return reg; } static BYTE dummy() /* This function is used to */ { /* fool the compiler so that */ return 0; /* no statement is optimized */ } /* away (volatile variables) */ static BYTE write_gi(reg,val) /* Write to G.I. sound chip */ BYTE reg,val; { LONG istatus; istatus = (*(LONG (*)())get_sr)(); /* Save SR */ GI[0] = reg; GI[2] = val; reg = dummy(); /* prevents optimizing away .. */ reg = GI[0]; /* ... this statement */ (*(LONG (*)())set_sr)(istatus); /* Restore SR */ return reg; } static BYTE get_schar(i,j) /* Find match in a font for */ WORD i,j; /* the character bit image at */ { /* position (row,col) */ register WORD l; /* line counter */ register BYTE *cpd, /* char ptr into font_data */ *cps; /* char ptr into ch_img[] */ register WORD p, c; WORD *curadd, /* screen address of top word */ sval; /* will hold a word of image */ BYTE ch_img[16], /* will hold image as bytes */ or_all; /* OR of all bytes of image */ UWORD w_p_l, /* # words per line */ maxl; /* height of a char in lines */ w_p_l = (planes == 1) ? 40 : 80; maxl = (planes == 1) ? 16 : 8; curadd = (WORD *)(V_BAS_AD + i * 1280 + (j & ~1) * planes); /* prepare ch_img[] to hold a adjusted copy of the bit image */ or_all = 0; for (l = 0; l < maxl; l++) { sval = 0; for (p = 0; p < planes; p++) { /* OR in all colour bit planes */ sval |= curadd[l * w_p_l + p]; } ch_img[l] = (j & 1) ? sval & 0xff /* Take lower or upper byte */ : (sval >> 8) & 0xff; /* as appropriate */ or_all |= ch_img[l]; /* Keeps inclusive Or of all */ } /* search */ if (or_all == 0) { /* Not a pixel set */ c = ' '; /* then space will be printed */ } else { /* else for each char in font */ for (c = fhp->f_low; c <= fhp->f_high; c++) { cpd = fhp->f_data + (fhp->f_charoff[c] >> 3); cps = ch_img; for (l = 0; l < maxl; l++) { /* Compare each line (byte) */ if (*cps++ != *cpd) break; /* Match failed at this line */ cpd += fhp->f_fontw; } if (l >= maxl) break; /* All lines matched */ } if ((c == '\0') || (c > fhp->f_high)) { /* If no match */ c = ' '; /* use space instead */ } } return (BYTE)c; /* Return matched char or space*/ }