home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / g / gs252src.zip / GS252 / GDEV3B1.C < prev    next >
C/C++ Source or Header  |  1992-09-11  |  15KB  |  610 lines

  1. /* Copyright (C) 1992 Aladdin Enterprises.  All rights reserved.
  2.    Distributed by Free Software Foundation, Inc.
  3.  
  4. This file is part of Ghostscript.
  5.  
  6. Ghostscript is distributed in the hope that it will be useful, but
  7. WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  8. to anyone for the consequences of using it or for whether it serves any
  9. particular purpose or works at all, unless he says so in writing.  Refer
  10. to the Ghostscript General Public License for full details.
  11.  
  12. Everyone is granted permission to copy, modify and redistribute
  13. Ghostscript, but only under the conditions described in the Ghostscript
  14. General Public License.  A copy of this license is supposed to have been
  15. given to you along with Ghostscript so you can know your rights and
  16. responsibilities.  It should be in a file named COPYING.  Among other
  17. things, the copyright notice and this notice must be preserved on all
  18. copies.  */
  19.  
  20. /*
  21.  * gdev3b1.c
  22.  *
  23.  * This is a driver for the AT&T 3b1/7300/UnixPC console display.
  24.  *
  25.  * The image is built in a buffer the size of the page.  Once complete,
  26.  * a screen-sized subset is copied to the screen, and one can scroll
  27.  * through the entire image (move with "vi" or arrow keys).
  28.  *
  29.  * Written by Andy Fyfe, andy@cs.caltech.edu.
  30.  */
  31.  
  32. #include "gx.h"
  33. #include "gxdevice.h"
  34. #include "gserrors.h"
  35.  
  36. #include <errno.h>
  37. #include <sys/window.h>
  38. #include <sys/termio.h>
  39.  
  40. typedef struct gx_device_att3b1_s {
  41.     gx_device_common;
  42.     int fd;            /* window file descriptor */
  43.     uchar *screen;        /* pointer to screen image */
  44.     ushort line_size;        /* size of single screen line in bytes */
  45.     ulong screen_size;        /* size of screen image in bytes */
  46.     int screen_width, screen_height; /* size of screen used */
  47.     int page;            /* page number */
  48. #ifdef ATT3B1_PERF
  49.     char *no_output, *no_fill, *no_copy;
  50. #endif
  51. } gx_device_att3b1;
  52. #define att3b1dev ((gx_device_att3b1 *)dev)
  53.  
  54. #define XDPI    100        /* to get a more-or-less square aspect ratio */
  55. #define YDPI    72
  56. #define XSIZE (8.5 * XDPI)    /* 8.5 x 11 inch page, by default */
  57. #define YSIZE (11 * YDPI)
  58.  
  59. static const ushort masks[] = { 0,
  60.     0x0001, 0x0003, 0x0007, 0x000f,
  61.     0x001f, 0x003f, 0x007f, 0x00ff,
  62.     0x01ff, 0x03ff, 0x07ff, 0x0fff,
  63.     0x1fff, 0x3fff, 0x7fff, 0xffff,
  64. };
  65. static uchar reverse_bits[256] = {
  66.   0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240,
  67.   8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248,
  68.   4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244,
  69.   12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252,
  70.   2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242,
  71.   10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250,
  72.   6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246,
  73.   14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254,
  74.   1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241,
  75.   9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249,
  76.   5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245,
  77.   13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253,
  78.   3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243,
  79.   11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251,
  80.   7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247,
  81.   15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255
  82. };
  83.  
  84. dev_proc_open_device(att3b1_open);
  85. dev_proc_close_device(att3b1_close);
  86. dev_proc_fill_rectangle(att3b1_fill_rectangle);
  87. dev_proc_copy_mono(att3b1_copy_mono);
  88. dev_proc_output_page(att3b1_output_page);
  89.  
  90. private gx_device_procs att3b1_procs = {
  91.     att3b1_open,
  92.     gx_default_get_initial_matrix,
  93.     gx_default_sync_output,
  94.     att3b1_output_page,
  95.     att3b1_close,
  96.     gx_default_map_rgb_color,
  97.     gx_default_map_color_rgb,
  98.     att3b1_fill_rectangle,
  99.     gx_default_tile_rectangle,
  100.     att3b1_copy_mono,
  101.     gx_default_copy_color,
  102.     gx_default_draw_line,
  103.     gx_default_get_bits,
  104.     gx_default_get_props,
  105.     gx_default_put_props
  106. };
  107.  
  108. gx_device_att3b1 gs_att3b1_device = {
  109.     sizeof(gx_device_att3b1),
  110.     &att3b1_procs,
  111.     "att3b1",
  112.     XSIZE, YSIZE,
  113.     XDPI, YDPI,
  114.     no_margins,
  115.     dci_black_and_white,
  116.     0,
  117.     -1, 0, 0,            /* fd, screen, line_size, */
  118.     0, 0, 0, 0,            /* screen size width and height, page */
  119. #ifdef ATT3B1_PERF
  120.     0, 0, 0,            /* no_output, no_fill, no_copy */
  121. #endif
  122. };
  123.  
  124. int
  125. att3b1_open(gx_device *dev)
  126. {
  127.     struct uwdata uw;
  128. #ifdef ATT3B1_PERF
  129.     char *getenv(const char *);
  130. #endif
  131.  
  132.     if (att3b1dev->fd >= 0) {
  133.     close(att3b1dev->fd);
  134.     att3b1dev->fd = -1;
  135.     }
  136.  
  137.     if (att3b1dev->screen != NULL) {
  138.     gs_free((char *)att3b1dev->screen,
  139.         att3b1dev->screen_size, 1, "att3b1_open");
  140.     att3b1dev->screen = 0;
  141.     att3b1dev->screen_size = 0;
  142.     }
  143.  
  144.     att3b1dev->fd = open("/dev/tty", 2);
  145.     if (att3b1dev->fd < 0) {
  146.     lprintf1("att3b1_open: open /dev/tty failed [%d]\n", errno);
  147.     return_error(gs_error_ioerror);
  148.     }
  149.  
  150.     if (ioctl(att3b1dev->fd, WIOCGETD, &uw) < 0) {
  151.     lprintf1("att3b1_open: window WIOCGETD ioctl failed [%d]\n", errno);
  152.     att3b1_close(dev);
  153.     return_error(gs_error_ioerror);
  154.     }
  155.  
  156.     /* we need an even number of bytes per line */
  157.     att3b1dev->line_size = ((att3b1dev->width + 15) / 16) * 2;
  158.     att3b1dev->screen_size = att3b1dev->line_size * att3b1dev->height;
  159.  
  160.     att3b1dev->screen =
  161.     (uchar *)gs_malloc(att3b1dev->screen_size, 1, "att3b1_open");
  162.     if (att3b1dev->screen == NULL) {
  163.     att3b1_close(dev);
  164.     return_error(gs_error_VMerror);
  165.     }
  166.  
  167.     att3b1dev->screen_width = (uw.uw_width < att3b1dev->width) ? uw.uw_width
  168.                 : att3b1dev->width;
  169.     att3b1dev->screen_height = (uw.uw_height < att3b1dev->width) ? uw.uw_height
  170.                 : att3b1dev->height;
  171.     att3b1dev->page = 1;
  172.  
  173. #ifdef ATT3B1_PERF
  174.     att3b1dev->no_output = getenv("GS_NOOUTPUT");
  175.     att3b1dev->no_fill = getenv("GS_NOFILL");
  176.     att3b1dev->no_copy = getenv("GS_NOCOPY");
  177. #endif
  178.  
  179.     return 0;
  180. }
  181.  
  182. int
  183. att3b1_close(gx_device *dev)
  184. {
  185.     if (att3b1dev->fd >= 0) {
  186.     close(att3b1dev->fd);
  187.     att3b1dev->fd = -1;
  188.     }
  189.  
  190.     if (att3b1dev->screen != NULL) {
  191.     gs_free((char *)att3b1dev->screen,
  192.         att3b1dev->screen_size, 1, "att3b1_close");
  193.     att3b1dev->screen = 0;
  194.     att3b1dev->screen_size = 0;
  195.     }
  196.  
  197.     return 0;
  198. }
  199.  
  200. int
  201. att3b1_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
  202.                       gx_color_index colour)
  203. {
  204.     int o, b, wl, wr, w2;
  205.     ushort *p, *q, maskl, maskr;
  206.  
  207. #ifdef ATT3B1_PERF
  208.     if (att3b1dev->no_fill) return 0;
  209. #endif
  210.  
  211.     fit_fill(dev, x, y, w, h);
  212.  
  213.     p = (ushort *)&att3b1dev->screen[(ushort)y*att3b1dev->line_size] + x/16;
  214.     o = x % 16;
  215.     b = 16 - o;
  216.     wl = (w < b) ? w : b;
  217.     maskl = masks[wl] << o;
  218.     w -= wl;
  219.     wr = w % 16;
  220.     maskr = masks[wr];
  221.  
  222.     if (colour == 0) {
  223.     maskl = ~maskl;
  224.     maskr = ~maskr;
  225.     while (h-- > 0) {
  226.         q = p;
  227.         w2 = w;
  228.         *q++ &= maskl;
  229.         while (w2 >= 16) {
  230.         *q++ = 0;
  231.         w2 -= 16;
  232.         }
  233.         *q &= maskr;
  234.         p += (att3b1dev->line_size / 2);
  235.     }
  236.     }
  237.     else {
  238.     while (h-- > 0) {
  239.         q = p;
  240.         w2 = w;
  241.         *q++ |= maskl;
  242.         while (w2 >= 16) {
  243.         *q++ = 0xffff;
  244.         w2 -= 16;
  245.         }
  246.         *q |= maskr;
  247.         p += (att3b1dev->line_size / 2);
  248.     }
  249.     }
  250.  
  251.     return 0;
  252. }
  253.  
  254. #ifdef __GNUC__
  255. #define rotate(value, count) \
  256.     asm("ror%.l    %2,%0" : "=d" (value) : "0" (value), "d" (count))
  257. #else
  258. #define rotate(value, count) \
  259.     value = (value >> count) | (value << (32-count))
  260. #endif
  261.  
  262. int
  263. att3b1_copy_mono(gx_device *dev, const uchar *data,
  264.          int data_x, int raster, gx_bitmap_id id,
  265.          int x, int y, int width, int height, 
  266.          gx_color_index colour0, gx_color_index colour1)
  267. {
  268.     const ushort *src_p, *src_q;
  269.     ushort *dst_p, *dst_q;
  270.     ulong bits, mask, *p;
  271.     int src_o, src_b, dst_o, dst_b, op;
  272.     int w1, w2;
  273.  
  274. #ifdef ATT3B1_PERF
  275.     if (att3b1dev->no_copy) return 0;
  276. #endif
  277.  
  278.     fit_copy(dev, data, data_x, raster, id, x, y, width, height);
  279.     if (colour1 == colour0)        /* vacuous case */
  280.     return att3b1_fill_rectangle(dev, x, y, width, height, colour0);
  281.  
  282.     /*
  283.      * In what follows, we're assuming that each row of the input bitmap
  284.      * is short-aligned, that is, that both "data" and "raster" are even.
  285.      */
  286.     src_p = ((const ushort *)data) + data_x/16;
  287.     src_o = data_x % 16;
  288.     src_b = 16 - src_o;
  289.  
  290.     dst_p = (ushort *)&att3b1dev->screen[(ushort)y*att3b1dev->line_size] + x/16;
  291.     dst_o = x % 16;
  292.     dst_b = 16 - dst_o;
  293.  
  294.     op = (int)colour0 * 3 + (int)colour1 + 4;
  295.  
  296.     while (height-- > 0) {
  297.     w2 = width;
  298.     src_q = src_p;
  299.     dst_q = dst_p;
  300.  
  301.     while (w2 > 0) {
  302.         w1 = (w2 < 16) ? w2 : 16;
  303.         mask = masks[w1];
  304.         /*
  305.          * We are assuming that the bitmap "data" is typically aligned.
  306.          * Thus the test for this special case is typically a win over
  307.          * a 16-bit shift.
  308.          */
  309.         if (src_o == 0)
  310.         bits = *src_q++;
  311.         else {
  312.         bits = *((ulong *)src_q) >> src_b;
  313.         bits &= 0xffff;
  314.         src_q++;
  315.         }
  316.         if (w1 <= 8)
  317.         bits = reverse_bits[bits>>8];
  318.         else
  319.         bits = (reverse_bits[bits&0xff] << 8) | reverse_bits[bits>>8];
  320.         /*
  321.          * While the input bit map is assumed to be typically aligned, we
  322.          * assume that the place in the image is not.  Thus we don't
  323.          * separate out the aligned case.  Doing so would cost a test,
  324.          * and only reduce the average shift by about 1.
  325.          */
  326.         p = (ulong *)dst_q;
  327.         switch(op) {
  328.         case 1:    /* not src and dst */
  329.         bits = ~(bits & mask);
  330.         rotate(bits,dst_b);
  331.         *p &= bits;
  332.         break;
  333.         case 2:    /* src or dst */
  334.         bits = bits & mask;
  335.         rotate(bits,dst_b);
  336.         *p |= bits;
  337.         break;
  338.         case 3:    /* src and dst */
  339.         bits = bits | ~mask;
  340.         rotate(bits,dst_b);
  341.         *p &= bits;
  342.         break;
  343.         case 5:    /* src */
  344.         rotate(bits,dst_b);
  345.         rotate(mask,dst_b);
  346.         *p = (*p & ~mask) | (bits & mask);
  347.         break;
  348.         case 6:    /* not src or dst */
  349.         bits = ~bits & mask;
  350.         rotate(bits,dst_b);
  351.         *p |= bits;
  352.         break;
  353.         case 7:    /* not src */
  354.         rotate(bits,dst_b);
  355.         rotate(mask,dst_b);
  356.         *p = (*p & ~mask) | (~bits & mask);
  357.         break;
  358.         }
  359.         dst_q++;
  360.         w2 -= w1;
  361.     }
  362.  
  363.     src_p += (raster / 2);
  364.     dst_p += (att3b1dev->line_size / 2);
  365.     }
  366.  
  367.     return 0;
  368. }
  369.  
  370. int
  371. att3b1_output_page(gx_device *dev, int num_copies, int flush)
  372. {
  373.     struct urdata ur;
  374.     struct utdata ut, ut_orig;
  375.     struct termio old, new;
  376.     int xorigin = 0;
  377.     int yorigin = 0;
  378.     int inverted = 0;
  379.     int ch;
  380.     ushort *p;
  381.     ushort save_image[WINWIDTH * WINHEIGHT / 16];
  382.     static int getKeyboard(gx_device *);
  383.  
  384. #ifdef ATT3B1_PERF
  385.     if (att3b1dev->no_output) return 0;
  386. #endif
  387.  
  388.     /*
  389.      * save screen state
  390.      */
  391.  
  392.     ioctl(att3b1dev->fd, TCGETA, &old);
  393.     new = old;
  394.     new.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
  395.     new.c_cc[VMIN] = 1;
  396.     ioctl(att3b1dev->fd, TCSETAF, &new);
  397.  
  398.     ut_orig.ut_num = WTXTSLK1;
  399.     ioctl(att3b1dev->fd, WIOCGETTEXT, &ut_orig);
  400.  
  401.     ur.ur_srcbase = 0;
  402.     ur.ur_srcwidth = 0;
  403.     ur.ur_srcx = 0;
  404.     ur.ur_srcy = 0;
  405.     ur.ur_dstbase = save_image;
  406.     ur.ur_dstwidth = WINWIDTH / 8;
  407.     ur.ur_dstx = 0;
  408.     ur.ur_dsty = 0;
  409.     ur.ur_width = att3b1dev->screen_width;
  410.     ur.ur_height = att3b1dev->screen_height;
  411.     ur.ur_srcop = SRCSRC;
  412.     ur.ur_dstop = DSTSRC;
  413.     ur.ur_pattern = 0;
  414.     ioctl(att3b1dev->fd, WIOCRASTOP, &ur);
  415.  
  416.     /*
  417.      * initialize
  418.      */
  419.  
  420.     write(att3b1dev->fd, "\a\033[=1C", 6);
  421.  
  422.     ur.ur_srcbase = (ushort *)att3b1dev->screen;
  423.     ur.ur_srcwidth = att3b1dev->line_size;
  424.     ur.ur_dstbase = 0;
  425.     ur.ur_dstwidth = 0;
  426.  
  427.     /*
  428.      * allow one to move the screen window through the entire image
  429.      */
  430.  
  431.     while (1) {
  432.     ur.ur_srcx = xorigin;
  433.     ur.ur_srcy = yorigin;
  434.  
  435.     if (ioctl(att3b1dev->fd, WIOCRASTOP, &ur) < 0) {
  436.         lprintf1(
  437.         "att3b1_output_page: window WIOCRASTOP ioctl failed [%d]\n",
  438.         errno);
  439.         return_error(gs_error_ioerror);
  440.     }
  441.  
  442.     ut.ut_num = WTXTSLK1;
  443.     sprintf(ut.ut_text,
  444.         "%s %d, top right (%d,%d), size (%d,%d), press <space> when done.",
  445.         flush ? "Showpage" : "Copypage", att3b1dev->page, xorigin, yorigin,
  446.         att3b1dev->width, att3b1dev->height);
  447.     ioctl(att3b1dev->fd, WIOCSETTEXT, &ut);
  448.  
  449.     ch = getKeyboard(dev);
  450.  
  451.     switch(ch) {
  452.     case 'h':
  453.         xorigin -= att3b1dev->x_pixels_per_inch/4;
  454.         break;
  455.  
  456.     case 'k':
  457.         yorigin -= att3b1dev->y_pixels_per_inch/2;
  458.         break;
  459.  
  460.     case 'l':
  461.         xorigin += att3b1dev->x_pixels_per_inch/4;
  462.         break;
  463.  
  464.     case 'j':
  465.         yorigin += att3b1dev->y_pixels_per_inch/2;
  466.         break;
  467.  
  468.     case 'H':
  469.         xorigin = 0;
  470.         break;
  471.  
  472.     case 'K':
  473.         yorigin = 0;
  474.         break;
  475.  
  476.     case 'L':
  477.         xorigin = att3b1dev->width - att3b1dev->screen_width;
  478.         break;
  479.  
  480.     case 'J':
  481.         yorigin = att3b1dev->height - att3b1dev->screen_height;
  482.         break;
  483.         
  484.     case '\f':
  485.     case 'r' :
  486.         xorigin = 0;
  487.         yorigin = 0;
  488.         break;
  489.  
  490.     case 'I':
  491.         for (p = (ushort *)att3b1dev->screen;
  492.           p < (ushort *)&att3b1dev->screen[att3b1dev->screen_size]; ++p)
  493.         *p = ~ *p;
  494.         inverted = !inverted;
  495.         break;
  496.  
  497.     case 'q':
  498.     case 'x':
  499.     case '\003':    /* control-C */
  500.     case '\004':    /* control-D */
  501.     case 'n':
  502.     case 'f':
  503.     case ' ':
  504.     case '\n':
  505.     case '\r':
  506.         if (flush)
  507.         att3b1dev->page++;
  508.         else if (inverted)    /* restore inverted image for copypage */
  509.         for (p = (ushort *)att3b1dev->screen;
  510.           p < (ushort *)&att3b1dev->screen[att3b1dev->screen_size]; ++p)
  511.             *p = ~ *p;
  512.         ur.ur_srcbase = save_image;
  513.         ur.ur_srcwidth = WINWIDTH / 8;
  514.         ur.ur_srcx = 0;
  515.         ur.ur_srcy = 0;
  516.         ioctl(att3b1dev->fd, WIOCRASTOP, &ur);
  517.         ioctl(att3b1dev->fd, WIOCSETTEXT, &ut_orig);
  518.         ioctl(att3b1dev->fd, TCSETAF, &old);
  519.         write(att3b1dev->fd, "\033[=0C", 5);
  520.         return 0;
  521.     
  522.     case -1:
  523.         return_error(gs_error_ioerror);
  524.     }
  525.  
  526.     if (xorigin >= att3b1dev->width - att3b1dev->screen_width)
  527.         xorigin = att3b1dev->width - att3b1dev->screen_width;
  528.     if (xorigin < 0)
  529.         xorigin = 0;
  530.     if (yorigin >= att3b1dev->height - att3b1dev->screen_height)
  531.         yorigin = att3b1dev->height - att3b1dev->screen_height;
  532.     if (yorigin < 0)
  533.         yorigin = 0;
  534.     }
  535. }
  536.  
  537. static int
  538. get_char(gx_device *dev)
  539. {
  540.     char ch;
  541.     int count;
  542.  
  543.     count = read(att3b1dev->fd, &ch, 1);
  544.     if (count == 0)
  545.     return 'q';
  546.     else if (count < 0)
  547.     return -1;
  548.     else
  549.     return ch;
  550. }
  551.  
  552. static int
  553. getKeyboard(gx_device *dev)
  554. {
  555.     char ch;
  556.  
  557.     ch = get_char(dev);
  558.  
  559.     if (ch != '\033')
  560.     return ch;
  561.  
  562.     /*
  563.      * If the char is escape, try and interpret escape sequences and return
  564.      * an equivalent single character.
  565.      */
  566.  
  567.     switch (get_char(dev)) {
  568.     case '[':
  569.     switch(get_char(dev)) {
  570.     case 'A':    /* up arrow */
  571.     case 'T':    /* shift up arrow */
  572.         return 'k';
  573.     case 'B':    /* down arrow */
  574.     case 'S':    /* shift down arrow */
  575.         return 'j';
  576.     case 'C':    /* right arrow */
  577.         return 'l';
  578.     case 'D':    /* left arrow */
  579.         return 'h';
  580.     case 'H':    /* home */
  581.         return 'r';
  582.     case 'U':    /* page down */
  583.         return 'J';
  584.     case 'V':    /* page up */
  585.         return 'K';
  586.     }
  587.     break;
  588.     case 'O':
  589.     switch(get_char(dev)) {
  590.     case 'k':    /* exit */
  591.     case 'K':    /* shift exit */
  592.     case 'w':    /* cancl */
  593.     case 'W':    /* shift cancl */
  594.         return 'q';
  595.     }
  596.     break;
  597.     case 'N':
  598.     switch(get_char(dev)) {
  599.     case 'h':    /* next */
  600.         return 'f';
  601.     case 'L':    /* shift right arrow */
  602.         return 'l';
  603.     case 'K':    /* shift left arrow */
  604.         return 'h';
  605.     }
  606.     break;
  607.     }
  608.     return '\0';
  609. }
  610.