home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / utility / fastdump / fastdump.src next >
C/C++ Source or Header  |  1989-03-29  |  14KB  |  341 lines

  1. /*
  2.  ******************************************************************************
  3.  *                                                                            *
  4.  *    fastdump.c  version 1.1 of 19 June 1988    (C) L.J.M. de Wit 1988       *
  5.  *                                                                            *
  6.  * This software may be used and distributed freely if not used commercially  *
  7.  * and the originator (me) is mentioned.                                      *
  8.  *                                                                            *
  9.  ******************************************************************************
  10.  *
  11.  * NAME
  12.  *    fastdump - fast ascii screen dump
  13.  *
  14.  * SYNTAX
  15.  *    fastdump.prg
  16.  *
  17.  * DESCRIPTION
  18.  *    Fastdump does a fast screen dump whenever the Alt Help key is pressed.
  19.  *    It reads the screen memory to match on font characters; matched
  20.  *    characters are printed as-is, non-matched characters as spaces.
  21.  *    It has some intelligence as to avoid printing trailing spaces.
  22.  *    It is very useful as afterwards printer, e.g. after a compilation with
  23.  *    error messages, or a program that exits with failure messages, and also
  24.  *    for printing source/text from within an editor, or for programs that do
  25.  *    not provide for hardcopy output.
  26.  *
  27.  *    Fastdump should be in the AUTO folder as FASTDUMP.PRG so that it is
  28.  *    installed memory resident when the system is loaded. It then overrides
  29.  *    the standard screen dump routine.
  30.  *
  31.  * BUGS
  32.  *    The program does not provide for RS232 printing yet. The Centronics port
  33.  *    is used.
  34.  *
  35.  *    The routine is not used when it is called from the XBIOS. This is because
  36.  *    of old disk-based TOS versions that had the dump vector hardcoded. A
  37.  *    future release of this program (if there will be any &-) will use the
  38.  *    screen dump vector at address 0x502.
  39.  *
  40.  *    Characters in reverse video are not matched yet with their reverse images
  41.  *    so that reverse video now results in spaces. Also something for the next
  42.  *    release.
  43.  *
  44.  * DECISIONS
  45.  *    The current version is compiled with a Lattice C compiler; people using
  46.  *    other compilers should be aware of the fact that on entrance of do_dump()
  47.  *    the contents of A4/A5 will be different from what it was when the
  48.  *    program was started (being an interrupt-routine) so that register
  49.  *    relative addressing cannot be used in this case (or A4 should be loaded
  50.  *    when the routine is entered). For Lattice C absolute addressing is the
  51.  *    default so that there was no problem in this case.
  52.  *    After compilation the module should be linked only with the standard
  53.  *    library (for the gemdos function). So the link file should contain:
  54.  *            INPUT fastdump.bin
  55.  *            LIBRARY clib.bin
  56.  *    startup.bin is not used, and the function startup() is used as entry point.
  57.  *    The size of the resulting code is much smaller now (not using stdio etc).
  58.  *
  59.  */
  60.  
  61. #include <osbind.h>
  62. #include <portab.h>
  63.  
  64. #define DUMPFLG  (*(WORD *)0x4EE)            /* Alt Help pressed flag       */
  65. #define SSHIFTMD (*(BYTE *)0x44C)            /* Screen Shift Mode           */
  66. #define V_BAS_AD (*(LONG *)0x44E)            /* logical screen base address */
  67. #define NVBLS    (*(WORD *)0x454)            /* length of this array        */
  68. #define VBLQUEUE (*(que_ptr *)0x456)         /* array of VBL vectors        */
  69. #define HZ_200   (*(LONG *)0x4BA)            /* 200 Hz system clock         */
  70. #define CENTRONICS_BUSY (1 & *(BYTE *)0xFFFFFA01)
  71. #define GI       ((BYTE *)0xFFFF8800)        /* I/O locations for sound chip*/
  72.  
  73. /* font definitions */
  74. typedef struct font_header {
  75.    WORD f_id;       /* font identifier; system font = 1 */
  76.    WORD f_point;    /* font size in points */
  77.    char f_name[32]; /* font name */
  78.    WORD f_low;      /* lowest ascii code in font */
  79.    WORD f_high;     /* highest ascii code in font */
  80.    WORD f_top;      /* relative distance of top to base line */
  81.    WORD f_ascent;   /* relative distance of ascent to base line */
  82.    WORD f_half;     /* relative distance of half to base line */
  83.    WORD f_descent;  /* relative distance of descent to base line */
  84.    WORD f_bottom;   /* relative distance of bottom to base line */
  85.    WORD f_maxcharw; /* maximal character width in font */
  86.    WORD f_maxcellw; /* maximal cell width in font */
  87.    WORD f_loffset;  /* left offset */
  88.    WORD f_roffset;  /* right offset */
  89.    WORD f_fatsiz;   /* degree of fattening */
  90.    WORD f_ulsiz;    /* underline degree */
  91.    WORD f_normask;  /* normal cancelled mask */
  92.    WORD f_skewmask; /* skewing cancelled mask */
  93.    WORD f_flag;     /* flag:
  94.                      *  bit 0: system font;
  95.                      *  bit 1: hor. offset;
  96.                      *  bit 2: byte swap;
  97.                      *  bit 3: non proportional font
  98.                      */
  99.    WORD *f_horoff;  /* pointer to horizontal offsets table */
  100.    WORD *f_charoff; /* pointer to character offsets table */
  101.    char *f_data;    /* pointer to font data table */
  102.    WORD f_fontw;    /* total width of all chars in font */
  103.    WORD f_fonth;    /* height of font (# scanlines) */
  104.    struct font_header
  105.           *f_next;  /* pointer to next font header */
  106. } font_header;
  107.  
  108. static UWORD g_fheader[] = {  0xA000,        /* LineA exception 0   */
  109.                               0x222F,0x0004, /* MOVE.L  4(SP),D1    */
  110.                               0xE581,        /* ASL.L   #2,D1       */
  111.                               0x2031,0x1800, /* MOVE.L  0(A1,D1),D0 */
  112.                               0x4E75 };      /* RTS                 */
  113.  
  114. static UWORD get_sr[]    = {  0x7000,        /* MOVEQ.L #0,D0       */
  115.                               0x40C0,        /* MOVE.W  SR,D0       */
  116.                               0x007C,0x0700, /* OR.W    #$700,SR    */
  117.                               0x4E75 };      /* RTS                 */
  118.  
  119. static UWORD set_sr[]    = {  0x46EF,0x0006, /* MOVE.W 6(SP),SR     */
  120.                               0x4E75 };      /* RTS                 */
  121.  
  122. WORD planes;
  123. font_header *fhp;
  124.  
  125. static void do_dump(), startup();
  126. static BYTE lstout(),  get_schar(),
  127.             read_gi(), write_gi(), dummy();
  128.  
  129. typedef void (**que_ptr)();  /* que_ptr points to an array of pointers
  130.                               *    to functions returning void
  131.                               */
  132.  
  133. static void startup(base)
  134. LONG *base;
  135. {
  136.    LONG memneed;
  137.    extern LONG _mneed;
  138.    WORD i, nvbls;
  139.    LONG ssp;
  140.  
  141.    memneed = 0x100   +                    /* base page   */
  142.              base[3] +                    /* text length */
  143.              base[5] +                    /* data length */
  144.              base[7] +                    /* bss  length */
  145.              0x800   +                    /* workspace   */
  146.              0x900;                       /* for stack   */
  147.  
  148.    ssp = Super(0);                        /* Supervisor mode             */
  149.    nvbls = NVBLS;                         /* length of VBLQUEUE array    */
  150.  
  151.    for (i = 0; i < nvbls; i++) {
  152.       if (VBLQUEUE[i] == (void (*)())0) {/* If empty slot found          */
  153.          VBLQUEUE[i] = do_dump;          /* set vector for new routine   */
  154.          break;
  155.       }
  156.    }
  157.  
  158.    Super(ssp);                            /* Back to User mode again     */
  159.  
  160.    if (i < nvbls) {                       /* If empty slot was found     */
  161.       Ptermres(memneed,0);                /* make resident & terminate   */
  162.    } else {                               /* else report the problem &   */
  163.       Cconws("Cannot bind new VBL routine\r\n");
  164.       Pterm(1);                           /* terminate with error status */
  165.    }
  166. }
  167.  
  168. static void do_dump()                     /* The interrupt routine       */
  169. {
  170.    WORD i, j;
  171.    char *s, *t;
  172.    WORD rows, cols;                       /* Rows & columns of screen    */
  173.    char line[81];                         /* Holds a line to be printed  */
  174.    BYTE status;                           /* Printer ready status        */
  175.    BYTE rez;                              /* resolution 2 high 1 med 0 low*/
  176.  
  177.    if (DUMPFLG != 0) {                    /* Alt Help not pressed?       */
  178.       return;
  179.    }
  180.  
  181.    if ((rez = SSHIFTMD & 3) == 3) {
  182.       rez = 2;
  183.    }
  184.    fhp = (*(font_header *(*)())g_fheader)
  185.          ((rez == 2) ? 2 : 1);            /* pointer to standard font    */
  186.    planes = 4 >> rez;                     /* # of bit planes: 4, 2 or 1  */
  187.    rows = 25;
  188.    cols = (rez == 0) ? 40 : 80;
  189.  
  190.    for (i = 0; i < rows; i++) {           /* Handle each screen row ...  */
  191.       s = line; t = line;
  192.       for (j = 0; j < cols; j++, s++) {   /* Handle each column per row  */
  193.          *s = get_schar(i,j);             /* Get ASCII value at this pos.*/
  194.          if ((*s != ' ') || (*t != ' ')) {/* t: last nonsp. or first sp. */
  195.             t = s;
  196.          }
  197.       }
  198.       *s = '\0';                          /* null-terminate line         */
  199.       if (*t == ' ') {
  200.          *t = '\0';                       /* discards trailing spaces    */
  201.       }
  202.  
  203.       status = 0;
  204.       for (s = line; *s != '\0'; s++) {   /* print each char/test status */
  205.          status = lstout(*s);
  206.          if (status != 0) break;          /* printer not ready; abort    */
  207.       }
  208.  
  209.       if (status != 0) break;             /*        abort                */
  210.  
  211.       lstout('\r'); lstout('\n');         /* terminate line with CR/LF   */
  212.  
  213.       if (DUMPFLG != 0) {                 /* Alt Help pressed again?     */
  214.          break;
  215.       }
  216.    }
  217.  
  218.    DUMPFLG = -1;                          /* No Hardcopy                 */
  219. }
  220.  
  221. static BYTE lstout(c)                     /* Send one character          */
  222. char c;                                   /* to Centronics port          */
  223. {
  224.    LONG start;
  225.    BYTE not_ready;
  226.  
  227.    start = HZ_200;
  228.    do {                                   /* poll the status             */
  229.       not_ready = CENTRONICS_BUSY;
  230.       dummy();                            /* to prevent erroneous optim. */
  231.    } while (not_ready &&
  232.                 (HZ_200 - start < 6000)); /* 30 sec. timeout             */
  233.  
  234.    if (!not_ready) {                      /* The actual printing         */
  235.       BYTE val;
  236.       LONG istatus;
  237.  
  238.       istatus = (*(LONG (*)())get_sr)();  /* Save SR                     */
  239.       val = read_gi(7);
  240.       write_gi(7,val | 0x80);
  241.       (*(LONG (*)())set_sr)(istatus);     /* Restore SR                  */
  242.       write_gi(15,c);
  243.  
  244.       val = read_gi(14);
  245.       write_gi(14,val & 0xDF);
  246.       val = read_gi(14);
  247.       write_gi(14,val | 0x20);
  248.    }
  249.  
  250.    return not_ready;                      /* return 0 for OK             */
  251. }
  252.  
  253. static BYTE read_gi(reg)                  /* Read from G.I. sound chip   */
  254. BYTE reg;
  255. {
  256.    LONG istatus;
  257.  
  258.    istatus = (*(LONG (*)())get_sr)();     /* Save SR                     */
  259.    GI[0] = reg;
  260.    reg = dummy();                         /* prevents optimizing away .. */
  261.    reg = GI[0];                           /* ... this statement          */
  262.    (*(LONG (*)())set_sr)(istatus);        /* Restore SR                  */
  263.  
  264.    return reg;
  265. }
  266.  
  267. static BYTE dummy()                       /* This function is used to    */
  268. {                                         /* fool the compiler so that   */
  269.    return 0;                              /* no statement is optimized   */
  270. }                                         /* away (volatile variables)   */
  271.  
  272. static BYTE write_gi(reg,val)             /* Write to G.I. sound chip    */
  273. BYTE reg,val;
  274. {
  275.    LONG istatus;
  276.  
  277.    istatus = (*(LONG (*)())get_sr)();     /* Save SR                     */
  278.    GI[0] = reg;
  279.    GI[2] = val;
  280.    reg = dummy();                         /* prevents optimizing away .. */
  281.    reg = GI[0];                           /* ... this statement          */
  282.    (*(LONG (*)())set_sr)(istatus);        /* Restore SR                  */
  283.  
  284.    return reg;
  285. }
  286.  
  287. static BYTE get_schar(i,j)                /* Find match in a font for    */
  288. WORD i,j;                                 /* the character bit image at  */
  289. {                                         /* position (row,col)          */
  290.    register WORD l;                       /* line counter                */
  291.    register BYTE *cpd,                    /* char ptr into font_data     */
  292.                  *cps;                    /* char ptr into ch_img[]      */
  293.    register WORD p, c;
  294.    WORD *curadd,                          /* screen address of top word  */
  295.         sval;                             /* will hold a word of image   */
  296.    BYTE ch_img[16],                       /* will hold image as bytes    */
  297.         or_all;                           /* OR of all bytes of image    */
  298.    UWORD w_p_l,                           /* # words per line            */
  299.          maxl;                            /* height of a char in lines   */
  300.  
  301.    w_p_l = (planes == 1) ? 40 : 80;
  302.    maxl = (planes == 1) ? 16 : 8;
  303.    curadd = (WORD *)(V_BAS_AD + i * 1280 + (j & ~1) * planes);
  304.  
  305.    /* prepare ch_img[] to hold a adjusted copy of the bit image */
  306.    or_all = 0;
  307.    for (l = 0; l < maxl; l++) {
  308.       sval = 0;
  309.       for (p = 0; p < planes; p++) {      /* OR in all colour bit planes */
  310.          sval |= curadd[l * w_p_l + p];
  311.       }
  312.  
  313.       ch_img[l] = (j & 1) ? sval & 0xff   /* Take lower or upper byte    */
  314.                    : (sval >> 8) & 0xff;  /* as appropriate              */
  315.       or_all |= ch_img[l];                /* Keeps inclusive Or of all   */
  316.    }
  317.  
  318.    /* search */
  319.    if (or_all == 0) {                     /* Not a pixel set             */
  320.       c = ' ';                            /* then space will be printed  */
  321.    } else {                               /* else for each char in font  */
  322.       for (c = fhp->f_low; c <= fhp->f_high; c++) {
  323.          cpd = fhp->f_data + (fhp->f_charoff[c] >> 3);
  324.          cps = ch_img;
  325.          for (l = 0; l < maxl; l++) {     /* Compare each line (byte)    */
  326.             if (*cps++ != *cpd) break;    /* Match failed at this line   */
  327.             cpd += fhp->f_fontw;
  328.          }
  329.          if (l >= maxl) break;            /* All lines matched           */
  330.       }
  331.  
  332.       if ((c == '\0') || (c > fhp->f_high)) { /* If no match             */
  333.          c = ' ';                         /* use space instead           */
  334.       }
  335.    }
  336.  
  337.    return (BYTE)c;                        /* Return matched char or space*/
  338. }
  339.  
  340.  
  341.