home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / gnu / gscript / gs261s.zoo / atari / gp_atari.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-06  |  70.1 KB  |  3,161 lines

  1. /* Copyright (C) 1989, 1992, 1993 Aladdin Enterprises.  All rights reserved.
  2.  
  3. This file is part of Ghostscript.
  4.  
  5. Ghostscript is distributed in the hope that it will be useful, but
  6. WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  7. to anyone for the consequences of using it or for whether it serves any
  8. particular purpose or works at all, unless he says so in writing.  Refer
  9. to the Ghostscript General Public License for full details.
  10.  
  11. Everyone is granted permission to copy, modify and redistribute
  12. Ghostscript, but only under the conditions described in the Ghostscript
  13. General Public License.  A copy of this license is supposed to have been
  14. given to you along with Ghostscript so you can know your rights and
  15. responsibilities.  It should be in a file named COPYING.  Among other
  16. things, the copyright notice and this notice must be preserved on all
  17. copies.  */
  18.  
  19. /* gp_atari.c */
  20.  
  21. /* Atari-specific routines for Ghostscript */
  22.  
  23. #include "gp_atari.h"
  24.  
  25. /* popen isn't POSIX-standard, so we declare it here. */
  26.  
  27. extern FILE *popen();
  28. extern int pclose();
  29. extern char *getenv(P1(const char *));
  30.  
  31. extern void gs_exit(P1(int exit_status));    /* from gsmain.c */
  32. extern stream *gs_stream_stdin;            /* from zfiledev.c */
  33. extern stream *gs_stream_stdout;        /* from zfiledev.c */
  34. extern stream *gs_stream_stderr;        /* from zfiledev.c */
  35.  
  36. extern int plot_x, plot_y, step_dx, step_dy;    /* from gdevvdi.c */
  37. extern int width, height;            /* from gdevvdi.c */
  38.  
  39. /* Use a pseudo file device to get win_stdio_init called at the right time. */
  40. /* This is bad architecture; we'll fix it later. */
  41.  
  42. private fdev_proc_init(win_std_init);
  43. private int win_std_read_buf();
  44. private int win_std_write_buf();
  45. private int cons_redraw(int, TEXTWIN *);
  46. private int objw_redraw(int, OBJECT *, WINDOW *);
  47. private int form_redraw(int, WINDOW *);
  48.  
  49. const file_device gs_fdev_wstdio = {
  50.     "wstdio", {
  51.     win_std_init, fdev_no_open_device,
  52.     fdev_no_open_file, fdev_no_fopen, fdev_no_fclose,
  53.     fdev_no_delete_file, fdev_no_rename_file,
  54.     fdev_no_enumerate_files }
  55. };
  56.  
  57. WINDOW twin = {
  58.     0,
  59.     T_GADGETS,
  60.     0,
  61.     T_TITL,
  62.     {0, 0, 0, 0},
  63.     {0, 0, 0, 0},
  64.     {0, 0, 0, 0},
  65.     {0, 0, 0, 0},
  66.     cons_redraw
  67. };
  68.  
  69. TEXTWIN cons = {
  70.     &twin,
  71.     {},
  72.     0,
  73.     0,
  74.     0, 0,
  75.     0, 0,
  76.     0,
  77.     0, 0,
  78.     0, 0,
  79.     0, 0,
  80.     0, LINES-1,
  81.     0, INITLINES-1,
  82.     0, 0,
  83.     0
  84. };
  85.  
  86. WINDOW icon = {
  87.     0,
  88.     I_GADGETS,
  89.     0,
  90.     I_TITL,
  91.     {0, 0, 0, 0},
  92.     {0, 0, 0, 0},
  93.     {0, 0, 0, 0},
  94.     {0, 0, 0, 0},
  95.     objw_redraw
  96. };
  97.  
  98. WINDOW dial = {
  99.     0,
  100.     D_GADGETS,
  101.     0,
  102.     D_TITL,
  103.     {0, 0, 0, 0},
  104.     {0, 0, 0, 0},
  105.     {0, 0, 0, 0},
  106.     {0, 0, 0, 0},
  107.     objw_redraw
  108. };
  109.  
  110. WINDOW imag = {
  111.     0,
  112.     W_GADGETS,
  113.     0,
  114.     W_TITL,
  115.     {0, 0, 0, 0},
  116.     {0, 0, 0, 0},
  117.     {0, 0, 0, 0},
  118.     {0, 0, 0, 0},
  119.     form_redraw
  120. };
  121.  
  122. void GetPalette(), SetPalette();
  123.  
  124. short GSPalette=0;
  125. uint PaletteSize=0;
  126. int *Palette, *OldPalette;
  127. int *ColorReg;
  128.  
  129. char command[MAXLEN]="";            /* GS command string      */
  130. char infile[MAXLEN]="";                /* input file          */
  131. char current_dir[MAXLEN]="";            /* current directory      */
  132. char dir_spec[MAXLEN]="";            /* used for file selector */
  133. char file_sel[MAXLEN]="";            /* selected file      */
  134. char *sptr;                    /* generic string pointer */
  135.  
  136. gx_color_value MaxRGB;
  137. int ChangeX, ChangeY;
  138.  
  139. /* GEM variables. */
  140.  
  141. short TrueColor=0;
  142. short Chunky8=0;
  143. short Gdebug=0, Debug8=0, Debug16=0;
  144.  
  145. ushort SendMsg[8];
  146.  
  147. int ApId, ExitButton;
  148. int XRes, YRes, ColorBits;
  149. int msgbuff[8], pxy[8];
  150. int GemHandle, VdiHandle;
  151. int window=1;
  152.  
  153. char    prgname[] = "  ST-GS";                    /* CF */
  154. int    MultiTOS = 0;                /* true : AES-Version >=0x400 */
  155. #ifdef USE_RSC                    /* use resource-file */
  156. OBJECT    *menu, *about, *noghost;
  157. #endif
  158.  
  159. float AspectRatio;
  160.  
  161. GRECT full;
  162.  
  163. MFDB plane_image, image, screen;
  164.  
  165. /* Do platform-dependent initialization. */
  166.  
  167. void
  168. gp_init(void)
  169. {
  170.     char *env;
  171.  
  172.     int i, j;
  173.     int wchar, hchar, wbox, hbox;
  174.     int work_out[57], rgb[3];
  175.     int work_in[11] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2};
  176.  
  177.     /* Check the GS_WIN environment variable to decide what to
  178.      * do about windows. Windows are used unless GS_WIN contains
  179.      * the string "off".
  180.      */
  181.  
  182.     if ((env = getenv("GS_WIN")) != NULL) {
  183.     if (!strcmp(env, "off") || !strcmp(env, "OFF")) {
  184.         window = 0;        
  185.         }
  186.     }
  187.  
  188.     /* Check the GS_DISPLAY environment variable. Chunky8/16
  189.      * tell the screen driver that the screen hardware uses chunky
  190.      * pixel format (each pixel is one byte or one word). This
  191.      *  knowledge allows some image transformations to be skipped.
  192.      */
  193.  
  194.     if ((env = getenv("GS_DISPLAY")) != NULL) {
  195.     if (!strcmp(env, "chunky8") || !strcmp(env, "CHUNKY8")) {
  196.         Chunky8 = 1;
  197.     }
  198.     }
  199.  
  200.     if ((env = getenv("GS_DEBUG")) != NULL) {
  201.     if (!strcmp(env, "gdebug")) {
  202.         Gdebug = 1;
  203.     }
  204.     else if (!strcmp(env, "debug8")) {
  205.         Debug8 = 1;
  206.     }
  207.     else if (!strcmp(env, "debug16")) {
  208.         Debug16 = 1;
  209.     }
  210.     }
  211.  
  212.     /* Find the current directory. */
  213.  
  214.     getcwd(current_dir, MAXLEN);
  215.     while ((sptr = strchr(current_dir, '/')) != NULL) {
  216.        *sptr = '\\';    /* change forward to backward slashes */
  217.     }
  218.     strcat(current_dir, "\\");
  219.  
  220.     /* Call appl_init() to initialize the aes before using any aes
  221.      * functions.
  222.      */
  223.  
  224.     if ((ApId = appl_init()) == -1) {
  225.     eprintf("stvdi_open: appl_init() failed!\n");
  226.     gs_exit(-1);
  227.     }
  228.  
  229.     MultiTOS = (gl_ap_version >= 0x400);            /* CF */
  230.     
  231.     /* Open a virtual workstation and get the screen resolution. */
  232.  
  233.     GemHandle = graf_handle(&wchar, &hchar, &wbox, &hbox);
  234.     VdiHandle = GemHandle;
  235.     v_opnvwk(work_in, &VdiHandle, work_out);
  236.  
  237.     if (VdiHandle == 0) {
  238.     eprintf("stvdi_open: Could not open virtual screen workstation");
  239.     gs_exit(-1);
  240.     }
  241.  
  242.     /* Get the character size, screen resolution, aspect ratio, and
  243.      * palette size.
  244.      */
  245.  
  246.     cons.wc = wchar;
  247.     cons.hc = hchar;
  248.  
  249.     XRes = work_out[0];
  250.     YRes = work_out[1];
  251.  
  252.     AspectRatio = (float)(work_out[3])/(float)(work_out[4]);
  253.  
  254.     /* Get the number of color planes. */
  255.  
  256.     vq_extnd(VdiHandle, 1, work_out);
  257.  
  258.     if (Debug8) {
  259.     ColorBits = 8;
  260.     }
  261.     else if (Debug16) {
  262.     ColorBits = 16;
  263.     }
  264.     else {
  265.     ColorBits = work_out[4];
  266.     }
  267.  
  268.     TrueColor = (!work_out[5] || (ColorBits >= 16));
  269.  
  270.     if ((env = getenv("GS_DISPLAY")) != NULL) {
  271.     if (!strcmp(env, "truecolor")) {
  272.         TrueColor = 1;        
  273.         }
  274.     }
  275.  
  276.     if (ColorBits != 1 && ColorBits != 2 &&
  277.     ColorBits != 4 && ColorBits != 8 && ColorBits != 16) {
  278.     eprintf1("stvdi_open: %d bit color is not supported.\n", ColorBits);
  279.     gs_exit(-1);
  280.     }
  281.  
  282.     MaxRGB = DITH_RGB(ColorBits) - 1;
  283.     
  284.     if ((ColorBits > 1) && !TrueColor) {
  285.  
  286.     int psize;
  287.  
  288.     psize = (int)(pow(2, ColorBits) + .5);
  289.     PaletteSize = 3 * psize;
  290.  
  291.     /* Set up the palette--a sequence of rgb values. */
  292.  
  293.     if ((Palette = (int *)gs_malloc((uint)PaletteSize,
  294.         sizeof(int), "Palette")) == NULL) {
  295.         eprintf("stvdi_open: No memory for color palette!\n");
  296.         gs_exit(-1);
  297.     }
  298.  
  299.     if ((OldPalette = (int *)gs_malloc((uint)PaletteSize,
  300.         sizeof(int), "OldPalette")) == NULL) {
  301.         eprintf("stvdi_open: No memory for color palette!\n");
  302.         gs_exit(-1);
  303.     }
  304.  
  305.     if ((ColorReg = (int *)gs_malloc((uint)psize,
  306.         sizeof(int), "ColorReg")) == NULL) {
  307.         eprintf("stvdi_open: No memory for color map array!\n");
  308.         gs_exit(-1);
  309.     }
  310.  
  311.     if (Debug8) {
  312.  
  313.         Palette[0] = 0;
  314.         Palette[1] = 0;
  315.         Palette[2] = 0;
  316.  
  317.         for (i=3; i<PaletteSize; i++) {
  318.         Palette[i] = 1;
  319.         }
  320.  
  321.     }
  322.     else {
  323.  
  324.         /* Fill the array ColorReg. The value of ColorReg[i]
  325.          * will be the hardware color register which corresponds
  326.          * to the ith vdi color index.
  327.          */
  328.  
  329.         reg_to_index(ColorReg, ColorBits, psize);
  330.  
  331.         GetPalette(psize, Palette);        /* Get the current palette. */
  332.         GetPalette(psize, OldPalette);    /* Save it for restoration. */
  333.         GSPalette = 1;
  334.  
  335.     }
  336.  
  337.     }
  338.  
  339.     if (Gdebug) {
  340.     eprintf1("Color Bits   = %ld\n", ColorBits);
  341.     eprintf1("True Color   = %ld\n", TrueColor);
  342.     eprintf1("Max RGB      = %ld\n", MaxRGB);
  343.     eprintf1("Palette Size = %ld\n", PaletteSize);
  344.     }
  345.  
  346.     /* Window initialization. */
  347.  
  348.     if (window) {
  349.  
  350.     wind_get(0, WF_WORKXYWH,
  351.         &full.g_x, &full.g_y,
  352.         &full.g_w, &full.g_h);
  353.  
  354.     /* Set up the image window. */
  355.  
  356.     imag.handle = wind_create(imag.gadgets + (MultiTOS ? SMALLER : 0),
  357.         full.g_x, full.g_y,
  358.         full.g_w, full.g_h);
  359.  
  360.     if (imag.handle == -1) {
  361.         form_alert(1,
  362.         "[3][Fatal Error !|Window not available.][Abort]");
  363.         gs_exit(-1);
  364.     }
  365.  
  366.     wind_set(imag.handle, WF_NAME, imag.title, imag.title, 0, 0);
  367.  
  368.     wind_set(imag.handle, WF_CURRXYWH,             /* CF */
  369.         5, 25, 100, 60);        /* initial window-size !!*/
  370.         
  371.     wind_get(imag.handle, WF_WORKXYWH,
  372.         &imag.canvas.g_x, &imag.canvas.g_y,
  373.         &imag.canvas.g_w, &imag.canvas.g_h);
  374.  
  375.     /* Set up the console window. */
  376.  
  377.     wind_calc(0, cons.win->gadgets, full.g_x, full.g_y,
  378.         (COLUMNS + 4)*cons.wc, (LINES + 1)*cons.hc,
  379.         &cons.win->mframe.g_x, &cons.win->mframe.g_y,
  380.         &cons.win->mframe.g_w, &cons.win->mframe.g_h);
  381.  
  382.     cons.win->handle = wind_create(
  383.         cons.win->gadgets + (MultiTOS ? SMALLER : 0),
  384.         cons.win->mframe.g_x, cons.win->mframe.g_y,
  385.         MIN(cons.win->mframe.g_w, full.g_w),
  386.         MIN(cons.win->mframe.g_h, full.g_h));
  387.  
  388.     if (cons.win->handle == -1) {
  389.         form_alert(1,
  390.         "[3][Fatal Error !|Window not available.][Abort]");
  391.         gs_exit(-1);
  392.     }
  393.  
  394.     wind_set(cons.win->handle, WF_NAME, cons.win->title,
  395.          cons.win->title, 0, 0);
  396.  
  397.     /* Set up the icon window. */
  398.  
  399.     icon.handle = wind_create(icon.gadgets,
  400.         full.g_x, full.g_y,
  401.         full.g_w, full.g_h);
  402.  
  403.     if (icon.handle == -1) {
  404.         form_alert(1,
  405.         "[3][Fatal Error !|Window not available.][Abort]");
  406.         gs_exit(-1);
  407.     }
  408.  
  409.     wind_set(icon.handle, WF_NAME, icon.title, icon.title, 0, 0);
  410.  
  411.  
  412. #ifdef USE_RSC                            /* CF */
  413.     {
  414.         char    name[255];
  415.         
  416.         (void) strcpy(name, current_dir);
  417.         (void) strcat(name, rscname);
  418.         if (rsrc_load(name))
  419.         {
  420.             rsrc_gaddr(R_TREE, MENUBAR, &menu);
  421.             rsrc_gaddr(R_TREE, ABOUTBOX, &about);
  422.             rsrc_gaddr(R_TREE, ICONBOX, &noghost);
  423.         }
  424.         else
  425.         {
  426.                   (void) form_alert(1,
  427.                 "[3][Fatal Error !|Can't load resource.][Abort]");
  428.             gs_exit(-1);
  429.         }
  430.     }
  431. #else
  432.     /* Fix object sizes for current resolution. */
  433.  
  434.     objc_fix(menu);
  435.     objc_fix(about);
  436.     for(i=0; i<2; i++) rsrc_obfix(noghost, i);
  437. #endif
  438.  
  439.     icon.canvas.g_x = noghost[0].ob_x = full.g_w / 2;
  440.     icon.canvas.g_y = noghost[0].ob_y = full.g_h / 2;
  441.     icon.canvas.g_w = noghost[0].ob_width;
  442.     icon.canvas.g_h = noghost[0].ob_height;
  443.  
  444.     wind_calc(0, icon.gadgets,
  445.         icon.canvas.g_x, icon.canvas.g_y,
  446.         icon.canvas.g_w, icon.canvas.g_h,
  447.         &icon.frame.g_x, &icon.frame.g_y,
  448.         &icon.frame.g_w, &icon.frame.g_h);
  449.  
  450.     icon.frame.g_x = full.g_w - icon.frame.g_w - 5;
  451.     icon.frame.g_y = full.g_y + 5;
  452.  
  453.     wind_calc(1, icon.gadgets,
  454.         icon.frame.g_x, icon.frame.g_y,
  455.         icon.frame.g_w, icon.frame.g_h,
  456.         &icon.canvas.g_x, &icon.canvas.g_y,
  457.         &icon.canvas.g_w, &icon.canvas.g_h);
  458.  
  459.     noghost[0].ob_x = icon.canvas.g_x;
  460.     noghost[0].ob_y = icon.canvas.g_y;
  461.  
  462.     /* Set up the dialog window. */
  463.  
  464.     dial.handle = wind_create(dial.gadgets,
  465.         full.g_x, full.g_y,
  466.         full.g_w, full.g_h);
  467.  
  468.     if (dial.handle == -1) {
  469.         form_alert(1,
  470.         "[3][Fatal Error !|Window not available.][Abort]");
  471.         gs_exit(-1);
  472.     }
  473.  
  474.     wind_set(dial.handle, WF_NAME, dial.title, dial.title, 0, 0);
  475.  
  476.     }
  477.  
  478.     /* Display the menu and open the console window. */
  479.  
  480.     if (window && !cons.win->opened) {
  481.  
  482.     int dummy;
  483.  
  484.     restore_bg();
  485.     graf_mouse(M_OFF, 0L );
  486.  
  487.     menu_bar(menu, 1);
  488.  
  489.     if (MultiTOS)                        /* CF */
  490.     {
  491.         menu_register(gl_apid, prgname);
  492.         menu_ienable(menu, ICON, 0);        /* use iconifier! */
  493.     }    
  494.     
  495.     wind_calc(0, cons.win->gadgets, full.g_x, full.g_y,
  496.         (COLUMNS + 4)*cons.wc, (INITLINES + 1)*cons.hc,
  497.         &cons.win->frame.g_x, &cons.win->frame.g_y,
  498.         &cons.win->frame.g_w, &cons.win->frame.g_h);
  499.  
  500.     cons.win->frame.g_x = full.g_x;
  501.     cons.win->frame.g_y = full.g_y;
  502.  
  503.     wind_open(cons.win->handle,
  504.         cons.win->frame.g_x, cons.win->frame.g_y,
  505.         MIN(cons.win->frame.g_w, full.g_w),
  506.         MIN(cons.win->frame.g_h, full.g_h));
  507.     cons.win->opened = 1;
  508.  
  509.     wind_get(cons.win->handle, WF_CURRXYWH,
  510.         &cons.win->oframe.g_x, &cons.win->oframe.g_y,
  511.         &cons.win->oframe.g_w, &cons.win->oframe.g_h);
  512.  
  513.     wind_get(cons.win->handle, WF_WORKXYWH,
  514.         &cons.win->canvas.g_x, &cons.win->canvas.g_y,
  515.         &cons.win->canvas.g_w, &cons.win->canvas.g_h);
  516.  
  517.     cons.edge = cons.win->canvas.g_x;
  518.     cons.top = cons.win->canvas.g_y;
  519.  
  520.     cons.xoff = cons.wc/2;
  521.     cons.yoff = cons.hc/2;
  522.  
  523.     cons.lins = visible_lines();
  524.     cons.cols = visible_cols();
  525.     cons.ldl = cons.fdl + cons.lins - 1;
  526.  
  527.     cons.cx = align(cons.edge + cons.xoff);
  528.     cons.cy = cons.top + cons.yoff;
  529.  
  530.     vst_alignment(VdiHandle, 0, 5, &dummy, &dummy);
  531.  
  532.     clear_win(&cons.win->canvas);
  533.     update_scroll(cons.win->handle);
  534.  
  535.     graf_mouse(BUSY_BEE, 0L);
  536.     graf_mouse(M_ON, 0L);
  537.  
  538.     }
  539.  
  540. }
  541.  
  542. void GetPalette(int DefinedColors, int *Palette)
  543. {
  544.     int ColorIndex;
  545.     int ColorEntry[3];
  546.  
  547.     for (ColorIndex = 0; ColorIndex < DefinedColors; ColorIndex++) {
  548.     vq_color(VdiHandle, ColorIndex, DEFINED_INTENSITY, ColorEntry);
  549.  
  550.     Palette[3*ColorIndex]   = ColorEntry[0];
  551.     Palette[3*ColorIndex+1] = ColorEntry[1];
  552.     Palette[3*ColorIndex+2] = ColorEntry[2];
  553.       
  554.     }
  555. }
  556.  
  557. void SetPalette(int DefinedColors, int *Palette)
  558.   
  559.     int ColorIndex;
  560.     int ColorEntry[3];
  561.  
  562.     for (ColorIndex = 0; ColorIndex < DefinedColors; ColorIndex++) {
  563.     ColorEntry[0] = Palette[3*ColorIndex];
  564.     ColorEntry[1] = Palette[3*ColorIndex+1];
  565.     ColorEntry[2] = Palette[3*ColorIndex+2];
  566.   
  567.     vs_color(VdiHandle, ColorIndex, ColorEntry);
  568.     }
  569. }
  570.  
  571. /* Do platform-dependent cleanup */
  572.  
  573. void
  574. gp_exit(int exit_status, int code)
  575. {
  576.     graf_mouse(ARROW, 0L);
  577.  
  578.     /* Restore the palette and free the allocated memory. */
  579.  
  580.     if (ColorBits > 1 && !TrueColor) {
  581.     int psize = PaletteSize/3;
  582.  
  583.     if (GSPalette) {
  584.         SetPalette(psize, OldPalette);
  585.         GSPalette = 0;
  586.     }
  587.  
  588.     gs_free((char *)Palette, PaletteSize, sizeof(int), "Palette");
  589.     gs_free((char *)OldPalette, PaletteSize, sizeof(int), "OldPalette");
  590.  
  591.     }
  592.  
  593.     /* Free the resources used by the aes. */
  594.  
  595.     if (window) {
  596.         menu_bar(menu, 0);
  597.  
  598.     if (imag.opened) wind_close(imag.handle);
  599.     if (icon.opened) wind_close(icon.handle);
  600.     if (dial.opened) wind_close(dial.handle);
  601.     if (cons.win->opened) wind_close(cons.win->handle);
  602.  
  603.     wind_delete(imag.handle);
  604.     wind_delete(icon.handle);
  605.     wind_delete(dial.handle);
  606.     wind_delete(cons.win->handle);
  607.     }
  608.  
  609.     v_clsvwk(VdiHandle);
  610.  
  611. #ifdef USE_RSC                            /* CF */
  612.     rsrc_free();
  613. #endif
  614.  
  615.     if (appl_exit() == 0) {
  616.     eprintf("stvdi_close: appl_exit() failed!\n");
  617.     exit_status = -1;
  618.     }
  619.  
  620. }
  621.  
  622. /* ------ Date and time ------ */
  623.  
  624. /* Read the current date (in days since Jan. 1, 1980) */
  625. /* and time (in milliseconds since midnight). */
  626.  
  627. void
  628. gp_get_clock(long *pdt)
  629. {    long secs_since_1970, secs_since_1980;
  630.     struct tm *tm, *localtime();
  631.  
  632.     if ( (secs_since_1970 = time(NULL)) == 0 )
  633.        {    perror("Ghostscript: gettimeofday failed:");
  634.         exit(-1);
  635.        }
  636.  
  637.     /* secs_since_1970 is #secs since Jan 1, 1970 */
  638.  
  639.     /* subtract off number of seconds in 10 years */
  640.     /* leap seconds are not accounted for */
  641.     secs_since_1980 = secs_since_1970 - (long)(60 * 60 * 24 * 365.25 * 10);
  642.  
  643.     /* there is no time zone adjustment for the atari st */
  644.  
  645.     /* adjust for daylight savings time - assume dst offset is 1 hour */
  646.     tm = localtime(&(secs_since_1970));
  647.     if ( tm->tm_isdst )
  648.         secs_since_1980 += (60 * 60);
  649.  
  650.     /* divide secs by #secs/day to get #days (integer division truncates) */
  651.     pdt[0] = secs_since_1980 / (60 * 60 * 24);
  652.     /* modulo * 1000 gives number of millisecs since midnight */
  653.     pdt[1] = (secs_since_1980 % (60 * 60 * 24)) * 1000;
  654. #ifdef DEBUG_CLOCK
  655.     printf("secs_since_1970 = %d  usecs_since_1970 = %d  pdt[0] = %ld\
  656.   pdt[1] = %ld\n", secs_since_1970, pdt[1], pdt[0], pdt[1]);
  657. #endif
  658. }
  659.  
  660. /* ------ Screen management ------ */
  661.  
  662. /* Write a string to the console. */
  663.  
  664. void
  665. gp_console_puts(const char *str, uint size)
  666. {
  667.     fwrite(str, 1, size, stdout);
  668. }
  669.  
  670. /* Check whether a file is the console. */
  671.  
  672. int
  673. gp_file_is_console(FILE *f)
  674. {
  675.     if (!f) return 0;
  676.     if (fileno(f) >= 0 && fileno(f) <= 2) return 1;
  677.  
  678.     return 0;
  679. }
  680.  
  681. /* Make the console current on the screen. */
  682.  
  683. int
  684. gp_make_console_current(struct gx_device_s *dev)
  685. {
  686.     return 0;
  687. }
  688.  
  689. /* Make the graphics current on the screen. */
  690.  
  691. int
  692. gp_make_graphics_current(struct gx_device_s *dev)
  693. {
  694.     return 0;
  695. }
  696.  
  697. /* ====== Substitute for stdio ====== */
  698.  
  699. /* This method for redirecting stdio to a window was stolen from the
  700.  * Microsoft Windows driver.
  701.  */
  702.  
  703. /* reinitialize stdin/out/err to use windows */
  704. /* assume stream has already been initialized for the real stdin */
  705.  
  706. #define win_stdin_buf_size 160
  707.  
  708. int
  709. win_std_init(file_device *fdev)
  710. {
  711.  
  712.     if (window) {
  713.  
  714.     if ( gp_file_is_console(gs_stream_stdin->file) ) {
  715.  
  716.         /* Allocate a real buffer for stdin. */
  717.         /* The size must not exceed the size of the */
  718.         /* lineedit buffer.  (This is a hack.) */
  719.     
  720.         static const stream_procs pin = {
  721.         s_std_noavailable, s_std_noseek,
  722.         s_std_read_flush, s_std_close,
  723.         win_std_read_buf, NULL
  724.         };
  725.  
  726.         byte *buf = (byte *)gs_malloc(win_stdin_buf_size, 1,
  727.         "win_stdin_init");
  728.  
  729.         s_std_init(gs_stream_stdin, buf, win_stdin_buf_size,
  730.         &pin, s_mode_read);
  731.  
  732.         gs_stream_stdin->file = NULL;
  733.  
  734.     }
  735.  
  736.     {
  737.         static const stream_procs pout = {
  738.         s_std_noavailable, s_std_noseek,
  739.         s_std_write_flush, s_std_close,
  740.         NULL, win_std_write_buf 
  741.         };
  742.  
  743.         if ( gp_file_is_console(gs_stream_stdout->file) ) {
  744.         gs_stream_stdout->procs = pout;
  745.         gs_stream_stdout->file = NULL;
  746.         }
  747.  
  748.         if ( gp_file_is_console(gs_stream_stderr->file) ) {
  749.         gs_stream_stderr->procs = pout;
  750.         gs_stream_stderr->file = NULL;
  751.         }
  752.     }
  753.     }
  754. }
  755.  
  756. #define ERASELINE 21        /* ^U */
  757. #define ERASECHAR1 8        /* ^H */
  758. #define ERASECHAR2 127        /* DEL */
  759.  
  760. /* Handle all user input. This contains the main event loop for
  761.  * Atari windows.
  762.  */
  763.  
  764. private int
  765. win_std_read_buf(register stream *s)
  766. {
  767.  
  768.     byte *buf = s->cbuf;
  769.  
  770.     byte *dest = buf - 1;
  771.     byte *limit = dest + s->bsize - 1;  /* always leave room for \n */
  772.  
  773.     uint ch;
  774.  
  775.     int ret;
  776.     int psize = PaletteSize/3;
  777.     int event, obj_ind, loop_end=0, menuitem=0, scrollitem=-1;
  778.     int wait_event, button_state, mx, my, mb, mk, key, clicks;
  779.  
  780.     TEXTWIN *cw = &cons;
  781.  
  782.     char *inf = infile, *curd = current_dir, *dspec = dir_spec;
  783.     char *fs  = file_sel;
  784.  
  785.     /* Copy the appropriate portion of the image to the screen. */
  786.  
  787.     if (window) {
  788.         wait_event = MU_MESAG | MU_KEYBD | MU_BUTTON;
  789.         button_state = 1;
  790.     }
  791.  
  792.     while (!loop_end && window) {
  793.  
  794.         graf_mouse(ARROW, 0L);
  795.  
  796.         step_dx = .9 * imag.canvas.g_w;
  797.         step_dy = .9 * imag.canvas.g_h;
  798.  
  799.         if (menuitem) {        /* fake menu events for hot keys */
  800.  
  801.         event = MU_MESAG;
  802.         msgbuff[0] = MN_SELECTED;
  803.         msgbuff[3] = -1;
  804.         msgbuff[4] = menuitem;
  805.         menuitem = 0;
  806.  
  807.         }
  808.         else if (scrollitem >= 0) {
  809.  
  810.         event = MU_MESAG;
  811.         msgbuff[0] = WM_ARROWED;
  812.         msgbuff[3] = imag.handle;
  813.         msgbuff[4] = scrollitem;
  814.         scrollitem = -1;
  815.  
  816.         }
  817.         else {
  818.  
  819.         event = evnt_multi(wait_event, 2, 1, button_state,
  820.             1, mx, my, 1, 1, 0, 0, 0, 0, 0,
  821.             msgbuff, 0L, &mx, &my, &mb, &mk,
  822.             &key, &clicks);
  823.  
  824.         }
  825.  
  826.         if (event & MU_BUTTON) {        /* button events */
  827.  
  828.         if ((obj_ind = objc_find(about, OK, 0, mx, my)) >= 0) {
  829.  
  830.             objc_change(about, OK, 0,
  831.             dial.canvas.g_x, dial.canvas.g_y,
  832.             dial.canvas.g_w, dial.canvas.g_h, 1, 1);
  833.  
  834.             wind_close(dial.handle);
  835.  
  836.             objc_change(about, OK, 0,
  837.             dial.canvas.g_x, dial.canvas.g_y,
  838.             dial.canvas.g_w, dial.canvas.g_h, 0, 0);
  839.  
  840.             dial.opened = 0;
  841.  
  842.         }
  843.         }
  844.  
  845.         if (event & MU_KEYBD) {        /* keyboard input */
  846.  
  847.         ch = (uint)( key & 255 );
  848.  
  849.         switch (key) {
  850.  
  851.         case 0x1300:            /* alt-r */
  852.             menuitem = RUN;
  853.             break;
  854.  
  855.         case 0x3100:            /* alt-n */
  856.             menuitem = NEXT;
  857.             break;
  858.  
  859.         case 0x1000:            /* alt-q */
  860.             menuitem = QUIT;
  861.             break;
  862.  
  863.         case 0x1700:            /* alt-i */
  864.             menuitem = ICON;
  865.             break;
  866.  
  867.         case 0x1400:            /* alt-t */
  868.             menuitem = TOGTOP;
  869.             break;
  870.  
  871.         case 0x4800:            /* up arrow */
  872.             scrollitem = WA_UPPAGE;
  873.             break;
  874.  
  875.         case 0x5000:            /* down arrow */
  876.             scrollitem = WA_DNPAGE;
  877.             break;
  878.  
  879.         case 0x4b00:            /* left arrow */
  880.             scrollitem = WA_LFPAGE;
  881.             break;
  882.  
  883.         case 0x4d00:            /* right arrow */
  884.             scrollitem = WA_RTPAGE;
  885.             break;
  886.  
  887.         case 0x1c0d:            /* return */
  888.  
  889.             /* Close dialog if opened. Otherwise exit
  890.              * the event loop so the interpreter can
  891.              * read the input buffer.
  892.              */
  893.  
  894.             if (dial.opened) {
  895.  
  896.             objc_change(about, OK, 0,
  897.                 dial.canvas.g_x, dial.canvas.g_y,
  898.                 dial.canvas.g_w, dial.canvas.g_h, 1, 1);
  899.  
  900.             wind_close(dial.handle);
  901.  
  902.             objc_change(about, OK, 0,
  903.                 dial.canvas.g_x, dial.canvas.g_y,
  904.                 dial.canvas.g_w, dial.canvas.g_h, 0, 0);
  905.  
  906.             dial.opened = 0;
  907.  
  908.             }
  909.             else {
  910.  
  911.             /* If return is pressed after a showpage,
  912.              * send a message to redraw the image window.
  913.              */
  914.  
  915.             int prevline = (cons.ln > 0) ? cons.ln-1 : LINES-1;
  916.  
  917.             if ((sptr = strstr(cons.text[prevline], ">>"))
  918.                 != NULL) {
  919.  
  920.                 SendMsg[0] = WM_REDRAW;
  921.                 SendMsg[3] = imag.handle;
  922.                 SendMsg[4] = imag.canvas.g_x;
  923.                 SendMsg[5] = imag.canvas.g_y;
  924.                 SendMsg[6] = imag.canvas.g_w;
  925.                 SendMsg[7] = imag.canvas.g_h;
  926.                 appl_write(ApId, 16, SendMsg);
  927.  
  928.             }
  929.         
  930.             *++dest = '\n';
  931.             gemputc(ch);
  932.             s->cptr = buf - 1;
  933.             s->end_status = 0;
  934.             s->endptr = dest;
  935.  
  936.             graf_mouse(BUSY_BEE, 0L);
  937.             loop_end = 1;
  938.  
  939.             }
  940.             break;
  941.  
  942.         default:    /* handle the input character. */
  943.  
  944.             switch (ch) {
  945.  
  946.             default:        /* put char in the input buffer. */
  947.             if ( dest == limit ) {
  948.                 ; /* MessageBeep(-1); */
  949.             }
  950.             else {
  951.                 *++dest = ch;
  952.                 gemputc(ch);
  953.             }
  954.             break;
  955.  
  956.             case ERASELINE:
  957.             clear_line(dest - buf + 1);
  958.             dest = buf - 1;
  959.             break;
  960.  
  961.             case ERASECHAR1:
  962.             case ERASECHAR2:
  963.             if ( dest >= buf ) {
  964.                 gemputc('\b');
  965.                 gemputc(' ');
  966.                 gemputc('\b');
  967.                 dest--;
  968.             }
  969.             break;
  970.  
  971.             }
  972.  
  973.         }
  974.  
  975.         }
  976.  
  977.         if (event & MU_MESAG) {    /* message events */
  978.  
  979.             switch (msgbuff[0]) {
  980.  
  981.             case MN_SELECTED:
  982.  
  983.             if (msgbuff[3] != -1) {
  984.             menu_tnormal(menu, msgbuff[3], 1);
  985.             }
  986.  
  987.             switch (msgbuff[4]) {
  988.  
  989.             case ABOUT:
  990.  
  991.             if (!dial.opened) {
  992.  
  993.                 form_center(about,
  994.                 &dial.canvas.g_x, &dial.canvas.g_y,
  995.                 &dial.canvas.g_w, &dial.canvas.g_h);
  996.  
  997.                 wind_calc(0, dial.gadgets,
  998.                 dial.canvas.g_x, dial.canvas.g_y,
  999.                 dial.canvas.g_w, dial.canvas.g_h,
  1000.                 &dial.frame.g_x, &dial.frame.g_y,
  1001.                 &dial.frame.g_w, &dial.frame.g_h);
  1002.  
  1003.                 wind_open(dial.handle,
  1004.                 dial.frame.g_x, dial.frame.g_y,
  1005.                 dial.frame.g_w, dial.frame.g_h);
  1006.  
  1007.                 dial.opened = 1;
  1008.             }
  1009.  
  1010.             break;
  1011.  
  1012.             case RUN:
  1013.  
  1014.             {
  1015.  
  1016.             /* If return was not pressed after a showpage,
  1017.              * then enter a return and send a message to
  1018.              * redraw the image window and run a new program
  1019.              * the next time through the event loop.
  1020.              */
  1021.  
  1022.             int prevline = (cons.ln > 0) ? cons.ln-1 : LINES-1;
  1023.  
  1024.             if ((sptr = strstr(cons.text[prevline], ">>"))
  1025.                 != NULL) {
  1026.  
  1027.                 *++dest = '\n';
  1028.                 gemputc('\n');
  1029.                 graf_mouse(BUSY_BEE, 0L);
  1030.                 loop_end = 1;
  1031.  
  1032.                 SendMsg[0] = WM_REDRAW;
  1033.                 SendMsg[3] = imag.handle;
  1034.                 SendMsg[4] = imag.canvas.g_x;
  1035.                 SendMsg[5] = imag.canvas.g_y;
  1036.                 SendMsg[6] = imag.canvas.g_w;
  1037.                 SendMsg[7] = imag.canvas.g_h;
  1038.                 appl_write(ApId, 16, SendMsg);
  1039.  
  1040.                 SendMsg[0] = MN_SELECTED;
  1041.                 SendMsg[3] = -1;
  1042.                 SendMsg[4] = RUN;
  1043.                 appl_write(ApId, 16, SendMsg);
  1044.  
  1045.                 break;
  1046.             }
  1047.  
  1048.             sprintf(dir_spec, "%s%s", current_dir, "*.PS");
  1049.  
  1050.             /* If a single input file has been specified,
  1051.              * make it the default selection. If more than
  1052.              * one input file exists, or no input is selected,
  1053.              * use no default.
  1054.              */
  1055.  
  1056.             if (strlen(infile)) {
  1057.                 strcpy(file_sel, infile);
  1058.             }
  1059.             else {
  1060.                 strcpy(file_sel, "");
  1061.             }
  1062.  
  1063.                 ret = fsel_input(dir_spec, file_sel, &ExitButton);
  1064.  
  1065.             if (ExitButton && strlen(file_sel)) {
  1066.  
  1067.                 sptr = strrchr(dir_spec, '\\');
  1068.                 *++sptr = '\0';
  1069.  
  1070.                 strcpy(current_dir, dir_spec);
  1071.                 strcpy(infile, file_sel);
  1072.  
  1073.                 sprintf(command, "(%s%s) run\n",
  1074.                 dir_spec, file_sel);
  1075.  
  1076.                 /* change back slashes to forward */
  1077.  
  1078.                 while ((sptr = strchr(command, '\\')) != NULL) {
  1079.                 *sptr = '/';
  1080.                 }
  1081.  
  1082.                 for (sptr = command; *sptr; sptr++) {
  1083.                 *++dest = *sptr;
  1084.                 }
  1085.  
  1086.                 s->cptr = buf - 1;
  1087.                 s->end_status = 0;
  1088.                 s->endptr = dest;
  1089.  
  1090.                 /* Send a message to output the command after
  1091.                  * all pending events have been dispatched.
  1092.                  */
  1093.  
  1094.                 SendMsg[0] = COMMAND;
  1095.                 appl_write(ApId, 16, SendMsg);
  1096.  
  1097.             }
  1098.             }
  1099.  
  1100.             break;
  1101.  
  1102.             case NEXT:
  1103.             if (imag.opened) {
  1104.                 wind_get(imag.handle, WF_CURRXYWH,
  1105.                 &imag.oframe.g_x, &imag.oframe.g_y,
  1106.                 &imag.oframe.g_w, &imag.oframe.g_h);
  1107.             }
  1108.  
  1109.             if (icon.opened) {
  1110.                 wind_close(icon.handle);
  1111.                 icon.opened = 0;
  1112.             }
  1113.  
  1114.             if (dial.opened) {
  1115.                 wind_close(dial.handle);
  1116.                 dial.opened = 0;
  1117.             }
  1118.  
  1119.             graf_mouse(BUSY_BEE, 0L);
  1120.  
  1121.             loop_end = 1;
  1122.             break;
  1123.  
  1124.             case QUIT:
  1125.             gs_exit(0);
  1126.             break;
  1127.  
  1128.             case ICON:
  1129.                 if (!MultiTOS)                /* CF */
  1130.             if (icon.opened) {
  1131.  
  1132.                 wind_get(icon.handle, WF_CURRXYWH,
  1133.                 &icon.frame.g_x, &icon.frame.g_y,
  1134.                 &icon.frame.g_w, &icon.frame.g_h);
  1135.  
  1136.                 wind_close(icon.handle);
  1137.  
  1138.                     wind_open(imag.handle,
  1139.                 imag.oframe.g_x, imag.oframe.g_y,
  1140.                 imag.oframe.g_w, imag.oframe.g_h);
  1141.  
  1142.                     wind_open(cons.win->handle,
  1143.                 cons.win->frame.g_x, cons.win->frame.g_y,
  1144.                 cons.win->frame.g_w, cons.win->frame.g_h);
  1145.  
  1146.                 menu[ICON].ob_spec = UL"  Iconify    ❎i ";
  1147.                 
  1148.                     icon.opened = 0;
  1149.                     imag.opened = 1;
  1150.                 cons.win->opened = 1;
  1151.  
  1152.             }
  1153.             else {
  1154.  
  1155.                 if (imag.opened) {
  1156.                 wind_get(imag.handle, WF_CURRXYWH,
  1157.                     &imag.oframe.g_x, &imag.oframe.g_y,
  1158.                     &imag.oframe.g_w, &imag.oframe.g_h);
  1159.  
  1160.                 wind_close(imag.handle);
  1161.                 imag.opened = 0;
  1162.                 }
  1163.  
  1164.                 if (cons.win->opened) {
  1165.                 wind_get(cons.win->handle, WF_CURRXYWH,
  1166.                     &cons.win->frame.g_x, &cons.win->frame.g_y,
  1167.                     &cons.win->frame.g_w, &cons.win->frame.g_h);
  1168.  
  1169.                 wind_close(cons.win->handle);
  1170.                 cons.win->opened = 0;
  1171.                 }
  1172.  
  1173.                     wind_open(icon.handle,
  1174.                 icon.frame.g_x, icon.frame.g_y,
  1175.                 icon.frame.g_w, icon.frame.g_h);
  1176.  
  1177.                 menu[ICON].ob_spec = UL"  DeIconify  ❎i ";
  1178.  
  1179.                 icon.opened = 1;
  1180.             }
  1181.             break;
  1182.  
  1183.             case TOGTOP:
  1184.             {
  1185.                 int topwin, empty;
  1186.  
  1187.                 wind_get(0, WF_TOP, &topwin, &empty,
  1188.                     &empty, &empty);
  1189.  
  1190.                 if (topwin == cons.win->handle && imag.opened) {
  1191.                 wind_set(imag.handle, WF_TOP, 0, 0, 0, 0);
  1192.                 }
  1193.                 else if (cons.win->opened) {
  1194.                 wind_set(cons.win->handle, WF_TOP, 0, 0, 0, 0);
  1195.                 }
  1196.             }
  1197.  
  1198.             break;
  1199.  
  1200.             }
  1201.  
  1202.             break;
  1203.  
  1204.             case WM_REDRAW:
  1205.             cursor(OFF);
  1206.             gp_win_redraw(DIRT_RECT);
  1207.             cursor(ON);
  1208.             break;
  1209.  
  1210.             case WM_ARROWED:
  1211.  
  1212.             switch (msgbuff[4]) {
  1213.  
  1214.             case WA_UPLINE:    /* up line or top of page */
  1215.             if (msgbuff[3] == imag.handle) {
  1216.                 plot_y = 0;
  1217.             }
  1218.             else if (msgbuff[3] == cons.win->handle) {
  1219.                 if (cons.fdl != cons.fl) {
  1220.                 cons.top += cons.hc;
  1221.                 cons.cy += cons.hc;
  1222.                 if (--cons.fdl < 0) cons.fdl += LINES;
  1223.                 if (--cons.ldl < 0) cons.fdl += LINES;
  1224.                 }
  1225.             }
  1226.             break;
  1227.  
  1228.             case WA_DNLINE:    /* down line or bottom of page */
  1229.             if (msgbuff[3] == imag.handle) {
  1230.                 plot_y = (height-1) - imag.canvas.g_h;
  1231.             }
  1232.             else if (msgbuff[3] == cons.win->handle) {
  1233.                 if (cons.ldl != cons.ll) {
  1234.                 cons.top -= cons.hc;
  1235.                 cons.cy  -= cons.hc;
  1236.                 if (++cons.fdl >= LINES) cons.fdl = 0;
  1237.                 if (++cons.ldl >= LINES) cons.ldl = 0;
  1238.                 }
  1239.             }
  1240.             break;
  1241.  
  1242.             case WA_LFLINE:
  1243.             if (msgbuff[3] == imag.handle) {
  1244.                 plot_x = 0;
  1245.             }
  1246.             else if (msgbuff[3] == cons.win->handle) {
  1247.                 if (cons.fdc > 0) {
  1248.                 cons.edge += cons.wc;
  1249.                 cons.cx  += cons.wc;
  1250.                 cons.fdc--;
  1251.                 }
  1252.             }
  1253.             break;
  1254.  
  1255.             case WA_RTLINE:
  1256.             if (msgbuff[3] == imag.handle) {
  1257.                 plot_x = (width-1) - imag.canvas.g_w;
  1258.             }
  1259.             else if (msgbuff[3] == cons.win->handle) {
  1260.                 if ((cons.fdc + cons.cols) < CLIMIT) {
  1261.                 cons.edge -= cons.wc;
  1262.                 cons.cx  -= cons.wc;
  1263.                 cons.fdc++;
  1264.                 }
  1265.             }
  1266.             break;
  1267.  
  1268.             case WA_UPPAGE:
  1269.             if (msgbuff[3] == imag.handle) {
  1270.                 plot_y = MAX(plot_y - step_dy, 0);
  1271.             }
  1272.             else if (msgbuff[3] == cons.win->handle) {
  1273.                 int to_top = cons.fdl - cons.fl;
  1274.                 to_top = (to_top >= 0) ? to_top : to_top + LINES;
  1275.  
  1276.                 if (to_top >= (cons.lins - 1)) {
  1277.                 cons.top += (cons.lins - 1) * cons.hc;
  1278.                 cons.cy  += (cons.lins - 1) * cons.hc;
  1279.                 cons.fdl -= (cons.lins - 1);
  1280.                 cons.ldl  -= (cons.lins - 1);
  1281.                 if (cons.fdl < 0) cons.fdl += LINES;
  1282.                 if (cons.ldl < 0) cons.ldl += LINES;
  1283.                 }
  1284.                 else {
  1285.                 ChangeY = cons.win->canvas.g_y - cons.top;
  1286.                 cons.top += ChangeY;
  1287.                 cons.cy  += ChangeY;
  1288.                 cons.fdl = cons.fl;
  1289.                 cons.ldl = cons.fl + cons.lins - 1;
  1290.                 if (cons.ldl >= LINES) cons.ldl -= LINES;
  1291.                 }
  1292.             }
  1293.             break;
  1294.  
  1295.             case WA_DNPAGE:
  1296.             if (msgbuff[3] == imag.handle) {
  1297.                 plot_y = plot_y + step_dy;
  1298.             }
  1299.             else if (msgbuff[3] == cons.win->handle) {
  1300.                 int to_bot = cons.ll - cons.ldl;
  1301.                 to_bot = (to_bot >= 0) ? to_bot : to_bot + LINES;
  1302.  
  1303.                 if (to_bot >= (cons.lins - 1)) {
  1304.                 cons.top -= (cons.lins - 1) * cons.hc;
  1305.                 cons.cy  -= (cons.lins - 1) * cons.hc;
  1306.                 cons.fdl += (cons.lins - 1);
  1307.                 cons.ldl += (cons.lins - 1);
  1308.                 if (cons.fdl >= LINES) cons.fdl -= LINES;
  1309.                 if (cons.ldl >= LINES) cons.ldl -= LINES;
  1310.                 }
  1311.                 else {
  1312.                 ChangeY = cons.win->canvas.g_y
  1313.                     - (LINES - cons.lins) * cons.hc
  1314.                     - cons.top;
  1315.                 cons.top += ChangeY;
  1316.                 cons.cy  += ChangeY;
  1317.                 cons.fdl = cons.ll - cons.lins + 1;
  1318.                 cons.ldl = cons.ll;
  1319.                 if (cons.fdl < 0) cons.fdl += LINES;
  1320.                 }
  1321.             }
  1322.             break;
  1323.  
  1324.             case WA_LFPAGE:
  1325.             if (msgbuff[3] == imag.handle) {
  1326.                 plot_x = MAX(plot_x - step_dx, 0);
  1327.             }
  1328.             else if (msgbuff[3] == cons.win->handle) {
  1329.                 if (cons.fdc  >= (cons.cols - 1)) {
  1330.                 cons.edge += (cons.cols - 1) * cons.wc;
  1331.                 cons.cx   += (cons.cols - 1) * cons.wc;
  1332.                 cons.fdc  -= (cons.cols - 1);
  1333.                 }
  1334.                 else {
  1335.                 ChangeX = cons.win->canvas.g_x - cons.edge;
  1336.                 cons.edge += ChangeX;
  1337.                 cons.cx   += ChangeX;
  1338.                 cons.fdc = 0;
  1339.                 }
  1340.             }
  1341.             break;
  1342.  
  1343.             case WA_RTPAGE:
  1344.             if (msgbuff[3] == imag.handle) {
  1345.                 plot_x = plot_x + step_dx;
  1346.             }
  1347.             else if (msgbuff[3] == cons.win->handle) {
  1348.                 if (cons.fdc <= (CLIMIT - 2*cons.cols + 1)) {
  1349.                 cons.edge -= (cons.cols - 1) * cons.wc;
  1350.                 cons.cx  -= (cons.cols - 1) * cons.wc;
  1351.                 cons.fdc += (cons.cols - 1);
  1352.                 }
  1353.                 else {
  1354.                 ChangeX = cons.win->canvas.g_x
  1355.                     - (CLIMIT - cons.cols) * cons.wc
  1356.                     - cons.edge;
  1357.                 cons.edge += ChangeX;
  1358.                 cons.cx   += ChangeX;
  1359.                 cons.fdc = (CLIMIT - cons.cols);
  1360.                 }
  1361.             }
  1362.             break;
  1363.  
  1364.             }
  1365.             update_scroll(msgbuff[3]);
  1366.             cursor(OFF);
  1367.             gp_win_redraw(FULL_WIN);
  1368.             cursor(ON);
  1369.             break;
  1370.  
  1371.         case WM_HSLID:
  1372.             if (msgbuff[3] == imag.handle) {
  1373.             plot_x = (width - imag.canvas.g_w) * msgbuff[4]/1000;
  1374.             }
  1375.             else if (msgbuff[3] == cons.win->handle) {
  1376.             cons.fdc =
  1377.                 (CLIMIT - cons.cols) * msgbuff[4]/1000;
  1378.             ChangeX = cons.win->canvas.g_x
  1379.                 - cons.fdc * cons.wc
  1380.                 - cons.edge;
  1381.             cons.edge += ChangeX;
  1382.             cons.cx   += ChangeX;
  1383.  
  1384.             }
  1385.             update_scroll(msgbuff[3]);
  1386.             cursor(OFF);
  1387.             gp_win_redraw(FULL_WIN);
  1388.             cursor(ON);
  1389.             break;
  1390.  
  1391.         case WM_VSLID:
  1392.             if (msgbuff[3] == imag.handle) {
  1393.             plot_y = (height - imag.canvas.g_h) * msgbuff[4]/1000;
  1394.             }
  1395.             else if (msgbuff[3] == cons.win->handle) {
  1396.             int OldOffset = cons.fdl - cons.fl;
  1397.             int NewOffset = (LINES - cons.lins) * msgbuff[4]/1000;
  1398.  
  1399.             if (OldOffset < 0) OldOffset += LINES;
  1400.  
  1401.             cons.fdl = cons.fl + NewOffset;
  1402.             if (cons.fdl >= LINES) cons.fdl -= LINES;
  1403.  
  1404.             cons.ldl = cons.fdl + cons.lins - 1;
  1405.             if (cons.ldl >= LINES) cons.ldl -= LINES;
  1406.  
  1407.             ChangeY = (OldOffset - NewOffset) * cons.hc;
  1408.             cons.top += ChangeY;
  1409.             cons.cy  += ChangeY;
  1410.             }
  1411.             update_scroll(msgbuff[3]);
  1412.             cursor(OFF);
  1413.             gp_win_redraw(FULL_WIN);
  1414.             cursor(ON);
  1415.             break;
  1416.  
  1417.             case WM_TOPPED:
  1418.             wind_set(msgbuff[3], WF_TOP, 0, 0, 0, 0);
  1419.             /* intentional fall-through */
  1420.  
  1421.         case WM_ONTOP:
  1422.             if (ColorBits > 1 && !GSPalette && !TrueColor) {
  1423.             SetPalette(psize, Palette);  /* Restore GS palette. */
  1424.             GSPalette = 1;
  1425.             }
  1426.             break;
  1427.  
  1428.         case WM_UNTOPPED:
  1429.             {
  1430.             int topwin, empty;
  1431.  
  1432.             wind_get(0, WF_TOP, &topwin, &empty,
  1433.                     &empty, &empty);
  1434.  
  1435.             if (GSPalette &&        /* Release palette. */
  1436.                 topwin != cons.win->handle &&
  1437.                 topwin != imag.handle &&
  1438.                 topwin != icon.handle &&
  1439.                 topwin != dial.handle) {
  1440.  
  1441.                 SetPalette(psize, OldPalette);
  1442.                 GSPalette = 0;
  1443.             }
  1444.  
  1445.             }
  1446.             break;
  1447.  
  1448.             case WM_CLOSED:
  1449.             if (msgbuff[3] == dial.handle) {
  1450.             dial.opened = 0;
  1451.             wind_close(msgbuff[3]);
  1452.             }
  1453.             else if (msgbuff[3] == imag.handle) {
  1454.             int prevline = (cons.ln > 0) ? cons.ln-1 : LINES-1;
  1455.  
  1456.             wind_get(imag.handle, WF_CURRXYWH,
  1457.                 &imag.oframe.g_x, &imag.oframe.g_y,
  1458.                 &imag.oframe.g_w, &imag.oframe.g_h);
  1459.             imag.opened = 0;
  1460.  
  1461.             wind_close(msgbuff[3]);
  1462.  
  1463.             /* If a return has not been entered after a
  1464.              * showpage, then enter one.
  1465.              */
  1466.  
  1467.             if ((sptr = strstr(cons.text[prevline], ">>"))
  1468.                 != NULL) {
  1469.  
  1470.                 *++dest = '\n';
  1471.                 gemputc('\n');
  1472.                 loop_end = 1;
  1473.             }
  1474.  
  1475.             }
  1476.             else {
  1477.             gs_exit(0);
  1478.             }
  1479.  
  1480.             break;
  1481.  
  1482.             case WM_FULLED:
  1483.             if (msgbuff[3] == icon.handle) {
  1484.             menuitem = ICON;
  1485.             }
  1486.             else {
  1487.  
  1488.             WINDOW *win;
  1489.  
  1490.             if (msgbuff[3] == imag.handle) {
  1491.                 win = &imag;
  1492.             }
  1493.             else if (msgbuff[3] == cons.win->handle) {
  1494.                 win = cons.win;
  1495.             }
  1496.  
  1497.             SendMsg[0] = WM_SIZED;
  1498.             SendMsg[3] = win->handle;
  1499.  
  1500.             wind_get(win->handle, WF_CURRXYWH,
  1501.                 &win->frame.g_x, &win->frame.g_y,
  1502.                 &win->frame.g_w, &win->frame.g_h);
  1503.  
  1504.             if (win->frame.g_x == full.g_x &&
  1505.                 win->frame.g_y == full.g_y &&
  1506.                     win->frame.g_w == MIN(win->mframe.g_w, full.g_w) &&
  1507.                 win->frame.g_h == MIN(win->mframe.g_h, full.g_h)) {
  1508.  
  1509.                 SendMsg[4] = win->oframe.g_x;
  1510.                 SendMsg[5] = win->oframe.g_y;
  1511.                 SendMsg[6] = win->oframe.g_w;
  1512.                 SendMsg[7] = win->oframe.g_h;
  1513.  
  1514.             }
  1515.             else {
  1516.                 win->oframe.g_x = win->frame.g_x;
  1517.                 win->oframe.g_y = win->frame.g_y;
  1518.                 win->oframe.g_w = win->frame.g_w;
  1519.                 win->oframe.g_h = win->frame.g_h;
  1520.  
  1521.                 SendMsg[4] = full.g_x;
  1522.                 SendMsg[5] = full.g_y;
  1523.                 SendMsg[6] = MIN(win->mframe.g_w, full.g_w);
  1524.                 SendMsg[7] = MIN(win->mframe.g_h, full.g_h);
  1525.  
  1526.             }
  1527.  
  1528.             /* Send a message to handle the window resizing. */
  1529.  
  1530.             appl_write(ApId, 16, SendMsg);
  1531.  
  1532.             }
  1533.  
  1534.             break;
  1535.  
  1536.             case WM_MOVED:
  1537.  
  1538.             if (msgbuff[3] == icon.handle) {
  1539.  
  1540.             wind_set(icon.handle, WF_CURRXYWH,
  1541.                 msgbuff[4], msgbuff[5],
  1542.                 msgbuff[6], msgbuff[7]);
  1543.  
  1544.             wind_get(icon.handle, WF_WORKXYWH,
  1545.                 &icon.canvas.g_x, &icon.canvas.g_y,
  1546.                 &icon.canvas.g_w, &icon.canvas.g_h);
  1547.  
  1548.             noghost[0].ob_x = icon.canvas.g_x;
  1549.             noghost[0].ob_y = icon.canvas.g_y;
  1550.  
  1551.             }
  1552.             else if (msgbuff[3] == dial.handle) {
  1553.  
  1554.             wind_set(dial.handle, WF_CURRXYWH,
  1555.                 msgbuff[4], msgbuff[5],
  1556.                 msgbuff[6], msgbuff[7]);
  1557.  
  1558.             ChangeX = msgbuff[4] - dial.frame.g_x;
  1559.             ChangeY = msgbuff[5] - dial.frame.g_y;
  1560.  
  1561.             dial.canvas.g_x += ChangeX;
  1562.             dial.canvas.g_y += ChangeY;
  1563.  
  1564.             about[0].ob_x += ChangeX;
  1565.             about[0].ob_y += ChangeY;
  1566.  
  1567.             wind_get(dial.handle, WF_CURRXYWH,
  1568.                 &dial.frame.g_x, &dial.frame.g_y,
  1569.                 &dial.frame.g_w, &dial.frame.g_h);
  1570.             }
  1571.             else if (msgbuff[3] == imag.handle) {
  1572.  
  1573.             wind_set(imag.handle, WF_CURRXYWH,
  1574.                 msgbuff[4], msgbuff[5],
  1575.                 MIN(imag.mframe.g_w, msgbuff[6]),
  1576.                 MIN(imag.mframe.g_h, msgbuff[7]));
  1577.  
  1578.             wind_get(imag.handle, WF_WORKXYWH,
  1579.                 &imag.canvas.g_x, &imag.canvas.g_y,
  1580.                 &imag.canvas.g_w, &imag.canvas.g_h);
  1581.  
  1582.             }
  1583.             else {
  1584.  
  1585.             int oldterm_x = cons.win->canvas.g_x;
  1586.             int oldterm_y = cons.win->canvas.g_y;
  1587.  
  1588.             wind_set(cons.win->handle, WF_CURRXYWH,
  1589.                 align(msgbuff[4]), msgbuff[5],
  1590.                 MIN(cons.win->mframe.g_w, msgbuff[6]),
  1591.                 MIN(cons.win->mframe.g_w, msgbuff[7]));
  1592.  
  1593.             wind_get(cons.win->handle, WF_WORKXYWH,
  1594.                 &cons.win->canvas.g_x, &cons.win->canvas.g_y,
  1595.                 &cons.win->canvas.g_w, &cons.win->canvas.g_h);
  1596.  
  1597.             ChangeX = cons.win->canvas.g_x - oldterm_x;
  1598.             ChangeY = cons.win->canvas.g_y - oldterm_y;
  1599.  
  1600.             cons.edge += ChangeX;
  1601.             cons.top  += ChangeY;
  1602.  
  1603.             cons.cx += ChangeX;
  1604.             cons.cy += ChangeY;
  1605.  
  1606.             }
  1607.  
  1608.             break;
  1609.  
  1610.             case WM_SIZED:
  1611.  
  1612.             if (msgbuff[3] == imag.handle) {
  1613.  
  1614.             wind_set(imag.handle, WF_CURRXYWH,
  1615.                 msgbuff[4], msgbuff[5],
  1616.                 MIN(imag.mframe.g_w, msgbuff[6]),
  1617.                 MIN(imag.mframe.g_h, msgbuff[7]));
  1618.  
  1619.             wind_get(imag.handle, WF_WORKXYWH,
  1620.                 &imag.canvas.g_x, &imag.canvas.g_y,
  1621.                 &imag.canvas.g_w, &imag.canvas.g_h);
  1622.  
  1623.             }
  1624.             else if (msgbuff[3] == cons.win->handle) {
  1625.             int offset;
  1626.             int old_x = cons.win->canvas.g_x;
  1627.             int old_y = cons.win->canvas.g_y;
  1628.             int old_w = cons.win->canvas.g_w;
  1629.             int old_h = cons.win->canvas.g_h;
  1630.  
  1631.             wind_set(cons.win->handle, WF_CURRXYWH,
  1632.                 msgbuff[4], msgbuff[5],
  1633.                 MIN(cons.win->mframe.g_w, msgbuff[6]),
  1634.                 MIN(cons.win->mframe.g_h, msgbuff[7]));
  1635.  
  1636.             wind_get(cons.win->handle, WF_WORKXYWH,
  1637.                 &cons.win->canvas.g_x, &cons.win->canvas.g_y,
  1638.                 &cons.win->canvas.g_w, &cons.win->canvas.g_h);
  1639.  
  1640.             cons.lins = visible_lines();
  1641.             cons.cols = visible_cols();
  1642.  
  1643.             cons.fdl = cons.ln - cons.lins + 1;
  1644.  
  1645.             if (cons.fdl > LINES) {
  1646.                 cons.fdl -= LINES;
  1647.             }
  1648.             else if (cons.fdl < 0 && !cons.scrolled) {
  1649.                 cons.fdl = 0;
  1650.             }
  1651.             else if (cons.fdl < 0 && cons.scrolled) {
  1652.                 cons.fdl += LINES;
  1653.             }
  1654.  
  1655.             cons.ldl = cons.fdl + cons.lins - 1;
  1656.             if (cons.ldl >= LINES) cons.ldl -= LINES;
  1657.  
  1658.             offset = cons.ln - cons.fdl;
  1659.             if (offset < 0) offset += LINES;
  1660.             if (offset >= LINES) offset -= LINES;
  1661.             cons.cy = cons.win->canvas.g_y
  1662.                 + cons.yoff + offset * cons.hc;
  1663.  
  1664.             offset = cons.fdl - cons.fl;
  1665.             if (offset < 0) offset += LINES;
  1666.             if (offset >= LINES) offset -= LINES;
  1667.             cons.top = cons.win->canvas.g_y - offset * cons.hc;
  1668.  
  1669.             /* Redraw the window if the OS won't. */
  1670.  
  1671.             if (old_x <= cons.win->canvas.g_x &&
  1672.                 old_y <= cons.win->canvas.g_y &&
  1673.                 old_w >= cons.win->canvas.g_w &&
  1674.                 old_h >= cons.win->canvas.g_h) {
  1675.  
  1676.                 cursor(OFF);
  1677.                 gp_win_redraw(FULL_WIN);
  1678.                 cursor(ON);
  1679.             }
  1680.             }
  1681.  
  1682.             update_scroll(msgbuff[3]);
  1683.             break;
  1684.         
  1685.         case WM_BOTTOM:                    /* CF */
  1686.             wind_set(msgbuff[3], WF_BOTTOM, 0, 0, 0, 0);
  1687.             break;
  1688.         
  1689.         case WM_ICONIFY:
  1690.         case WM_ALLICONIFY:                /* CF */
  1691.             if (imag.opened) 
  1692.             {
  1693.                 wind_get(imag.handle, WF_CURRXYWH,
  1694.                         &imag.oframe.g_x, &imag.oframe.g_y,
  1695.                         &imag.oframe.g_w, &imag.oframe.g_h);
  1696.                 wind_close(imag.handle);
  1697.                 imag.opened = 0;
  1698.             }
  1699.  
  1700.             if (cons.win->opened) 
  1701.             {
  1702.                 wind_get(cons.win->handle, WF_CURRXYWH,
  1703.                         &cons.win->frame.g_x, &cons.win->frame.g_y,
  1704.                         &cons.win->frame.g_w, &cons.win->frame.g_h);
  1705.                 wind_close(cons.win->handle);
  1706.                 cons.win->opened = 0;
  1707.             }
  1708.  
  1709.             wind_set(icon.handle, WF_ICONIFY,
  1710.                 msgbuff[4], msgbuff[5], msgbuff[6], msgbuff[7]);
  1711.  
  1712.             wind_get(icon.handle, WF_CURRXYWH,
  1713.                 &icon.frame.g_x, &icon.frame.g_y,
  1714.                 &icon.frame.g_w, &icon.frame.g_h);
  1715.                 
  1716.                 wind_open(icon.handle, icon.frame.g_x, icon.frame.g_y,
  1717.                     icon.frame.g_w, icon.frame.g_h);
  1718.  
  1719.             wind_get(icon.handle, WF_WORKXYWH,
  1720.                     &icon.canvas.g_x, &icon.canvas.g_y,
  1721.                     &icon.canvas.g_w, &icon.canvas.g_h);
  1722.  
  1723.             noghost[0].ob_x = icon.canvas.g_x;
  1724.             noghost[0].ob_y = icon.canvas.g_y;
  1725.             icon.opened = 1;
  1726.             break;
  1727.             
  1728.         case WM_UNICONIFY:                /* CF */
  1729.             wind_set(icon.handle, WF_UNICONIFY,
  1730.                 icon.frame.g_x, icon.frame.g_y,
  1731.                 icon.frame.g_w, icon.frame.g_h);
  1732.                 
  1733.             wind_get(icon.handle, WF_CURRXYWH,
  1734.                 &icon.frame.g_x, &icon.frame.g_y,
  1735.                 &icon.frame.g_w, &icon.frame.g_h);
  1736.             wind_close(icon.handle);
  1737.  
  1738.             wind_open(imag.handle, imag.oframe.g_x, 
  1739.                        imag.oframe.g_y, imag.oframe.g_w, imag.oframe.g_h);
  1740.                         
  1741.                 wind_open(cons.win->handle, cons.win->frame.g_x, cons.win->frame.g_y,
  1742.                     cons.win->frame.g_w, cons.win->frame.g_h);
  1743.  
  1744.             icon.opened = 0;
  1745.             imag.opened = 1;
  1746.             cons.win->opened = 1;
  1747.             break;
  1748.                         
  1749.         case COMMAND:
  1750.             dprintf1("%s", command);
  1751.             graf_mouse(BUSY_BEE, 0L);
  1752.             loop_end = 1;
  1753.             break;
  1754.  
  1755.         }
  1756.  
  1757.         }
  1758.  
  1759.     }
  1760.  
  1761.     return 0;
  1762. }
  1763.  
  1764. private int
  1765. win_std_write_buf(register stream *s)
  1766. {
  1767.  
  1768.     char string[COLUMNS+1];
  1769.  
  1770.     char *ptr = s->cbuf;
  1771.  
  1772.     int i, j, tempcol;
  1773.  
  1774.     uint count = s->cptr + 1 - s->cbuf;
  1775.         
  1776.     cursor(OFF);
  1777.     msgbuff[3] = cons.win->handle;
  1778.  
  1779.     for (i=0, tempcol=0; i<count; i++) {
  1780.  
  1781.         switch(*ptr) {
  1782.  
  1783.         case '\r':
  1784.         case '\n':
  1785.         newline:
  1786.  
  1787.         string[tempcol] = '\0';
  1788.         strcat(cons.text[cons.ln], string);
  1789.         next_line();
  1790.  
  1791.         tempcol = 0;
  1792.  
  1793.         ptr++;
  1794.         break;
  1795.  
  1796.         case '\t':
  1797.  
  1798.         for(j=0; j<8; j++) {        
  1799.             string[tempcol++] = ' ';
  1800.             cons.cn++;
  1801.         }
  1802.         
  1803.         ptr++;
  1804.         break;
  1805.  
  1806.         case '\b':
  1807.         --tempcol;
  1808.         if (--cons.cn < 0) cons.cn = 0;
  1809.         else --ptr;
  1810.         break;
  1811.  
  1812.         default:
  1813.  
  1814.         string[tempcol++] = *ptr;
  1815.         if (++cons.cn >= COLUMNS) goto newline;
  1816.  
  1817.         ptr++;
  1818.         break;
  1819.  
  1820.         }
  1821.  
  1822.     }
  1823.  
  1824.     if (tempcol) {
  1825.         int dirtw;
  1826.  
  1827.         string[tempcol] = '\0';
  1828.         strcat(cons.text[cons.ln], string);
  1829.  
  1830.         dirtw = strlen(string) * cons.wc;
  1831.         msgbuff[4] = cons.cx;
  1832.         msgbuff[5] = cons.cy;
  1833.         msgbuff[6] = dirtw;
  1834.         msgbuff[7] = cons.hc;
  1835.  
  1836.         gp_win_redraw(DIRT_RECT);
  1837.  
  1838.         cons.cx += dirtw;
  1839.  
  1840.     }
  1841.  
  1842.     cursor(ON);
  1843.     s->cptr = s->cbuf - 1;
  1844.     s->endptr = s->cptr + s->bsize;
  1845.  
  1846.     return 0;
  1847. }
  1848.  
  1849. int
  1850. gemputc(uint ch)
  1851. {
  1852.     char c[2];
  1853.  
  1854.     cursor(OFF);
  1855.     msgbuff[3] = cons.win->handle;
  1856.  
  1857.     switch (ch) {
  1858.  
  1859.     default:
  1860.  
  1861.     c[0] = ch;
  1862.     c[1] = '\0';
  1863.  
  1864.     strcat(cons.text[cons.ln], c);
  1865.  
  1866.     msgbuff[4] = cons.cx;
  1867.     msgbuff[5] = cons.cy;
  1868.     msgbuff[6] = cons.wc;
  1869.     msgbuff[7] = cons.hc;
  1870.  
  1871.     gp_win_redraw(DIRT_RECT);
  1872.  
  1873.     if (++cons.cn >= COLUMNS) goto newline;
  1874.     cons.cx += cons.wc;
  1875.     break;
  1876.  
  1877.     case '\r':
  1878.     case '\n':
  1879.     newline:
  1880.  
  1881.     cons.text[cons.ln][cons.cn] = '\0';
  1882.  
  1883.     if (++cons.ln >= LINES) {
  1884.         cons.ln = 0;
  1885.         cons.scrolled = 1;
  1886.     }
  1887.  
  1888.     *cons.text[cons.ln] = '\0';
  1889.  
  1890.     if (cons.scrolled) {
  1891.         if (++cons.fl >= LINES) cons.fl = 0;
  1892.         if (++cons.fdl >= LINES) cons.fdl = 0;
  1893.         if (++cons.ll >= LINES) cons.ll = 0;
  1894.         if (++cons.ldl >= LINES) cons.ldl = 0;
  1895.         gp_win_redraw(FULL_WIN);
  1896.     }
  1897.     else if (cons.ln == (cons.ldl + 1)) {
  1898.         cons.top -= cons.hc;
  1899.         cons.fdl++;
  1900.         cons.ldl++;
  1901.         gp_win_redraw(FULL_WIN);
  1902.         update_scroll(cons.win->handle);
  1903.     }
  1904.     else {
  1905.         cons.cy += cons.hc;
  1906.     }
  1907.  
  1908.     cons.cx = align(cons.edge + cons.xoff);
  1909.     cons.cn = 0;
  1910.  
  1911.     break;
  1912.  
  1913.     case '\b':
  1914.     cons.text[cons.ln][--cons.cn] = '\0';
  1915.     cons.cx -= cons.wc;
  1916.     break;
  1917.  
  1918.     }
  1919.  
  1920.     cursor(ON);
  1921. }
  1922.  
  1923. int clear_line(int cnt)
  1924. {
  1925.     int x, w;
  1926.  
  1927.     cursor(OFF);
  1928.     msgbuff[3] = cons.win->handle;
  1929.  
  1930.     if (cnt < 0) {
  1931.         *cons.text[cons.ln] = '\0';
  1932.     x = cons.win->canvas.g_x;
  1933.     w = cons.win->canvas.g_w;
  1934.     cons.cx = align(cons.edge + cons.xoff);
  1935.     cons.cn = 0;
  1936.     }
  1937.     else {
  1938.     cons.cn = MAX(cons.cn - cnt, 0);
  1939.     cons.cx -= cnt * cons.wc;
  1940.     cons.text[cons.ln][cons.cn] = '\0';
  1941.     x = MAX(cons.cx, cons.win->canvas.g_x);
  1942.     w = MIN(cnt * cons.wc, cons.win->canvas.g_w);
  1943.     }
  1944.  
  1945.     msgbuff[4] = x;
  1946.     msgbuff[5] = cons.cy;
  1947.     msgbuff[6] = w;
  1948.     msgbuff[7] = cons.hc;
  1949.  
  1950.     gp_win_redraw(DIRT_RECT);
  1951.  
  1952.     cursor(ON);
  1953.  
  1954. }
  1955.  
  1956. int next_line(void)
  1957. {
  1958.  
  1959.     if (++cons.ln >= LINES) {
  1960.     cons.ln = 0;
  1961.     cons.scrolled = 1;
  1962.     }
  1963.  
  1964.     *cons.text[cons.ln] = '\0';
  1965.  
  1966.     if (cons.scrolled) {
  1967.     if (++cons.fl  >= LINES) cons.fl  = 0;
  1968.     if (++cons.fdl >= LINES) cons.fdl = 0;
  1969.     if (++cons.ll  >= LINES) cons.ll  = 0;
  1970.     if (++cons.ldl >= LINES) cons.ldl = 0;
  1971.     gp_win_redraw(FULL_WIN);
  1972.     }
  1973.     else if (cons.ln == (cons.ldl + 1)) {
  1974.     cons.top -= cons.hc;
  1975.     cons.fdl++;
  1976.     cons.ldl++;
  1977.     gp_win_redraw(FULL_WIN);
  1978.     update_scroll(cons.win->handle);
  1979.     }
  1980.     else {
  1981.     msgbuff[4] = cons.cx;
  1982.     msgbuff[5] = cons.cy;
  1983.     msgbuff[6] = cons.win->canvas.g_x + cons.win->canvas.g_w - cons.cx;
  1984.     msgbuff[7] = cons.hc;
  1985.     gp_win_redraw(DIRT_RECT);
  1986.  
  1987.     cons.cy += cons.hc;
  1988.     }
  1989.  
  1990.     cons.cx = align(cons.edge + cons.xoff);
  1991.     cons.cn = 0;
  1992.  
  1993. }
  1994.  
  1995. /* ------ Printer accessing ------ */
  1996.  
  1997. /* Open a file or a printing device. A null file name will cause
  1998.  * output to be sent to "PRN:". If gp_open_printer returns
  1999.  * a NULL, the file will be sent directly to the centronics port.
  2000.  * This happens if fname = "CEN:" or if gp_open_scratch_file()
  2001.  * fails. Usually, GS wants to interpret a NULL return value as
  2002.  * an error, so this is slightly incompatible.
  2003.  * "|command" opens an output pipe.
  2004.  */
  2005.  
  2006. FILE *
  2007. gp_open_printer(char *fname, int binary_mode)
  2008. {
  2009.     if (!strcmp(fname, "CEN:")) {    /* Direct Centronics printing. */
  2010.        return NULL;
  2011.     }
  2012.     else {
  2013.        return
  2014.          (strlen(fname) == 0 ?
  2015.           gp_open_scratch_file(gp_scratch_file_name_prefix, fname, "wb") :
  2016.           fname[0] == '|' ?
  2017.           popen(fname + 1, "wb") :
  2018.           fopen(fname, "wb"));
  2019.     }
  2020. }
  2021.  
  2022. /* Close the connection to the printer. */
  2023. void
  2024. gp_close_printer(FILE *pfile, const char *fname)
  2025. {    if ( fname[0] == '|' )
  2026.         pclose(pfile);
  2027.     else
  2028.         fclose(pfile);
  2029. }
  2030.  
  2031. /* ------ File name syntax ------ */
  2032.  
  2033. /* Define the character used for separating file names in a list. */
  2034. char gp_file_name_list_separator = ',';
  2035.  
  2036. /* Define the default scratch file name prefix. */
  2037. const char gp_scratch_file_name_prefix[] = "gs_pr.";
  2038.  
  2039. /* Define the string to be concatenated with the file mode */
  2040. /* for opening files without end-of-line conversion. */
  2041. const char gp_fmode_binary_suffix[] = "b";
  2042.  
  2043. /* Define the file modes for binary reading or writing. */
  2044. const char gp_fmode_rb[] = "rb";
  2045. const char gp_fmode_wb[] = "wb";
  2046.  
  2047. /* Define whether case is insignificant in file names. */
  2048. const int gp_file_names_ignore_case = 1;
  2049.  
  2050. /* Create and open a scratch file with a given name prefix. */
  2051. /* Write the actual file name at fname. */
  2052.  
  2053. #if 0
  2054.  
  2055. FILE *
  2056. gp_open_scratch_file(const char *prefix, char *fname, const char *mode)
  2057. {
  2058.     strcpy(fname, prefix);
  2059.     strcat(fname, "XXX");
  2060.     mktemp(fname);
  2061.     return fopen(fname, mode);
  2062. }
  2063.  
  2064. #endif
  2065.  
  2066. FILE *
  2067. gp_open_scratch_file(const char *prefix, char *fname, const char *mode)
  2068. {    char *temp;
  2069.  
  2070.     if ( (temp = getenv("TEMP")) != NULL )
  2071.         strcpy(fname, temp);
  2072.     else
  2073.         strcpy(fname, "");
  2074.  
  2075.     strcat(fname, prefix);
  2076.  
  2077.     /* Prevent trailing X's in path from being converted by mktemp. */
  2078.     if ( *fname != 0 && fname[strlen(fname) - 1] == 'X' )
  2079.         strcat(fname, "-");
  2080.  
  2081.     strcat(fname, "XXX");
  2082.     mktemp(fname);
  2083.     return fopen(fname, mode);
  2084. }
  2085.  
  2086. /* Answer whether a file name contains a directory/device specification, */
  2087. /* i.e. is absolute (not directory- or device-relative). */
  2088. int
  2089. gp_file_name_is_absolute(const char *fname, uint len)
  2090. {    /* A file name is absolute if it contains a drive specification */
  2091.     /* (second character is a :) or if it start with / or \. */
  2092.     return ( len >= 1 && (*fname == '/' || *fname == '\\' ||
  2093.         (len >= 2 && fname[1] == ':')) );
  2094. }
  2095.  
  2096. /* Answer the string to be used for combining a directory/device prefix */
  2097. /* with a base file name.  The file name is known to not be absolute. */
  2098. const char *
  2099. gp_file_name_concat_string(const char *prefix, uint plen,
  2100.                const char *fname, uint len)
  2101. {    if ( plen > 0 )
  2102.       switch ( prefix[plen - 1] )
  2103.        {    case ':': case '/': case '\\': return "";
  2104.        };
  2105.     return "\\";
  2106. }
  2107.  
  2108. /* ------ File operations ------ */
  2109.  
  2110. /* If the file given by fname exists, fill in its status and return 1; */
  2111. /* otherwise return 0. */
  2112. int
  2113. gp_file_status(const char *fname, file_status *pstatus)
  2114. {    struct stat sbuf;
  2115.     /* The RS/6000 prototype for stat doesn't include const, */
  2116.     /* so we have to explicitly remove the const modifier. */
  2117.     if ( stat((char *)fname, &sbuf) < 0 ) return 0;
  2118.     pstatus->size_pages = stat_blocks(&sbuf);    /* st_blocks is */
  2119.                     /* missing on some systems, */
  2120.                     /* see stat_.h */
  2121.     pstatus->size_bytes = sbuf.st_size;
  2122.     pstatus->time_referenced = sbuf.st_mtime;
  2123.     pstatus->time_created = sbuf.st_ctime;
  2124.     return 1;
  2125. }
  2126.  
  2127. /* ------ File enumeration ------ */
  2128.  
  2129. /****** THIS IS NOT SUPPORTED ON UNIX SYSTEMS. ******/
  2130. /* Amazingly enough, there is no standard Unix library routine */
  2131. /* for enumerating the files matching a pattern, */
  2132. /* or even for enumerating (conveniently) the files in a directory. */
  2133.  
  2134. struct file_enum_s {
  2135.     char *pattern;
  2136.     int first_time;
  2137.     const gs_memory_procs *mprocs;
  2138. };
  2139.  
  2140. /* Initialize an enumeration.  NEEDS WORK ON HANDLING * ? \. */
  2141.  
  2142. file_enum *
  2143. gp_enumerate_files_init(const char *pat, uint patlen,
  2144.   const gs_memory_procs *mprocs)
  2145. {    file_enum *pfen = (file_enum *)(*mprocs->alloc)(1, sizeof(file_enum), "gp_enumerate_files");
  2146.     char *pattern;
  2147.     if ( pfen == 0 ) return 0;
  2148.     pattern = (*mprocs->alloc)(patlen + 1, 1,
  2149.                 "gp_enumerate_files(pattern)");
  2150.     if ( pattern == 0 ) return 0;
  2151.     memcpy(pattern, pat, patlen);
  2152.     pattern[patlen] = 0;
  2153.     pfen->pattern = pattern;
  2154.     pfen->mprocs = mprocs;
  2155.     pfen->first_time = 1;
  2156.     return pfen;
  2157. }
  2158.  
  2159. /* Enumerate the next file. */
  2160. /* PUNT: JUST RETURN THE PATTERN. */
  2161.  
  2162. uint
  2163. gp_enumerate_files_next(file_enum *pfen, char *ptr, uint maxlen)
  2164. {    if ( pfen->first_time )
  2165.     {    char *pattern = pfen->pattern;
  2166.         uint len = strlen(pattern);
  2167.         pfen->first_time = 0;
  2168.         if ( len > maxlen )
  2169.             return maxlen + 1;
  2170.         strcpy(ptr, pattern);
  2171.         return len;
  2172.     }
  2173.     return -1;
  2174. }
  2175.  
  2176. /* Clean up the file enumeration. */
  2177.  
  2178. void
  2179. gp_enumerate_files_close(file_enum *pfen)
  2180. {    const gs_memory_procs *mprocs = pfen->mprocs;
  2181.     (*mprocs->free)(pfen->pattern, strlen(pfen->pattern) + 1, 1,
  2182.             "gp_enumerate_files_close(pattern)");
  2183.     (*mprocs->free)((char *)pfen, 1, sizeof(file_enum),
  2184.             "gp_enumerate_files_close");
  2185. }
  2186.  
  2187.  
  2188. int
  2189. gp_win_redraw(int flag)
  2190. {
  2191.  
  2192.     wind_update(BEG_UPDATE);    /* lock the screen */
  2193.  
  2194.     if (msgbuff[3] == icon.handle) {
  2195.     (icon.redraw)(flag, noghost, &icon);
  2196.     }
  2197.     else if (msgbuff[3] == dial.handle) {
  2198.     (dial.redraw)(flag, about, &dial);
  2199.     }
  2200.     else if (msgbuff[3] == cons.win->handle) {
  2201.     (cons.win->redraw)(flag, &cons);
  2202.     }
  2203.     else {
  2204.     (imag.redraw)(flag, &imag);
  2205.     }
  2206.  
  2207.     wind_update(END_UPDATE);    /* release screen */
  2208.  
  2209. }
  2210.  
  2211. int
  2212. cons_redraw(int full_win, TEXTWIN *tw)
  2213. {
  2214.  
  2215.     int i, cnt;
  2216.     int x = align(tw->win->canvas.g_x + tw->xoff);
  2217.     int fcol = tw->fdc;
  2218.     int y, ln, *tpxy = pxy;
  2219.  
  2220.     GRECT redraw, rect;
  2221.  
  2222.     graf_mouse(M_OFF, 0L );
  2223.  
  2224.     if (full_win) {
  2225.     redraw.g_x = tw->win->canvas.g_x;
  2226.     redraw.g_y = tw->win->canvas.g_y;
  2227.     redraw.g_w = tw->win->canvas.g_w;
  2228.     redraw.g_h = tw->win->canvas.g_h;
  2229.     }
  2230.     else {
  2231.     redraw.g_x = msgbuff[4];
  2232.     redraw.g_y = msgbuff[5];
  2233.     redraw.g_w = msgbuff[6];
  2234.     redraw.g_h = msgbuff[7];
  2235.     }
  2236.  
  2237.     cnt = tw->ln - tw->fdl + 1;
  2238.     cnt = (cnt > 0) ? cnt : cnt + LINES;
  2239.     cnt = MIN(cnt, tw->lins);
  2240.  
  2241.     wind_get(tw->win->handle, WF_FIRSTXYWH,
  2242.     &rect.g_x, &rect.g_y,
  2243.     &rect.g_w, &rect.g_h);
  2244.  
  2245.     while (rect.g_w && rect.g_h) {
  2246.  
  2247.     if (intersect(&redraw, &rect)) {
  2248.         if (intersect(&tw->win->canvas, &rect)) {
  2249.         
  2250.         grect_to_array(&rect, pxy);
  2251.         vs_clip(VdiHandle, 1, pxy);
  2252.         
  2253.         clear_win(&rect);
  2254.  
  2255.         y = tw->win->canvas.g_y + tw->yoff;
  2256.  
  2257.         for (ln=tw->fdl, i=cnt; i; i--, ln++, y+=cons.hc) {
  2258.             if (ln >= LINES) ln -= LINES;
  2259.             if (strlen(cons.text[ln]) > fcol)
  2260.             v_gtext(VdiHandle, x, y, cons.text[ln]+fcol);
  2261.         }
  2262.  
  2263.         vs_clip(VdiHandle, 0, pxy);
  2264.  
  2265.         }
  2266.     }
  2267.  
  2268.     wind_get(tw->win->handle, WF_NEXTXYWH,
  2269.         &rect.g_x, &rect.g_y,
  2270.         &rect.g_w, &rect.g_h);
  2271.     }
  2272.  
  2273.     graf_mouse(M_ON, 0L );
  2274.  
  2275. }
  2276.  
  2277. int
  2278. objw_redraw(int full_win, OBJECT *object, WINDOW *w)
  2279. {
  2280.  
  2281.     GRECT redraw, rect;
  2282.  
  2283.     graf_mouse(M_OFF, 0L );
  2284.  
  2285.     if (full_win) {
  2286.     redraw.g_x = w->canvas.g_x;
  2287.     redraw.g_y = w->canvas.g_y;
  2288.     redraw.g_w = w->canvas.g_w;
  2289.     redraw.g_h = w->canvas.g_h;
  2290.     }
  2291.     else {
  2292.     redraw.g_x = msgbuff[4];
  2293.     redraw.g_y = msgbuff[5];
  2294.     redraw.g_w = msgbuff[6];
  2295.     redraw.g_h = msgbuff[7];
  2296.     }
  2297.  
  2298.     wind_get(msgbuff[3], WF_FIRSTXYWH,
  2299.     &rect.g_x, &rect.g_y,
  2300.     &rect.g_w, &rect.g_h);
  2301.  
  2302.     while (rect.g_w && rect.g_h) {
  2303.  
  2304.     if (intersect(&redraw, &rect)) {
  2305.         if (intersect(&w->canvas, &rect)) {
  2306.         objc_draw(object, 0, 1,
  2307.             rect.g_x, rect.g_y,
  2308.             rect.g_w, rect.g_h);
  2309.         }
  2310.     }
  2311.  
  2312.     wind_get(msgbuff[3], WF_NEXTXYWH,
  2313.         &rect.g_x, &rect.g_y,
  2314.         &rect.g_w, &rect.g_h);
  2315.  
  2316.     }
  2317.  
  2318.     graf_mouse(M_ON, 0L );
  2319.  
  2320. }
  2321.  
  2322. int
  2323. form_redraw(int full_win, WINDOW *w)
  2324. {
  2325.  
  2326.     int tpxy[4];
  2327.  
  2328.     GRECT redraw, rect;
  2329.  
  2330.     graf_mouse(M_OFF, 0L );
  2331.  
  2332.     if (full_win) {
  2333.     redraw.g_x = w->canvas.g_x;
  2334.     redraw.g_y = w->canvas.g_y;
  2335.     redraw.g_w = w->canvas.g_w;
  2336.     redraw.g_h = w->canvas.g_h;
  2337.     }
  2338.     else {
  2339.     redraw.g_x = msgbuff[4];
  2340.     redraw.g_y = msgbuff[5];
  2341.     redraw.g_w = msgbuff[6];
  2342.     redraw.g_h = msgbuff[7];
  2343.     }
  2344.  
  2345.     if (plot_x >= width - w->canvas.g_w)
  2346.     plot_x = (width - 1) - w->canvas.g_w;
  2347.     if (plot_x < 0) plot_x = 0;
  2348.  
  2349.     if (plot_y >= height - w->canvas.g_h)
  2350.     plot_y = (height - 1) - w->canvas.g_h;
  2351.     if (plot_y < 0) plot_y = 0;
  2352.  
  2353.     wind_get(msgbuff[3], WF_FIRSTXYWH,
  2354.     &rect.g_x, &rect.g_y,
  2355.     &rect.g_w, &rect.g_h);
  2356.  
  2357.     while (rect.g_w && rect.g_h) {
  2358.     if (intersect(&redraw, &rect)) {
  2359.         if (intersect(&w->canvas, &rect)) {
  2360.         
  2361.         pxy[0] = plot_x + (rect.g_x - w->canvas.g_x);
  2362.         pxy[1] = plot_y + (rect.g_y - w->canvas.g_y);
  2363.         pxy[2] = pxy[0] + rect.g_w - 1;
  2364.         pxy[3] = pxy[1] + rect.g_h - 1;
  2365.  
  2366.         grect_to_array(&rect, &pxy[4]);
  2367.  
  2368.         vs_clip(VdiHandle, 1, &pxy[4]);
  2369.         vro_cpyfm(VdiHandle, 3, pxy, &image, &screen);
  2370.         vs_clip(VdiHandle, 0, &pxy[4]);
  2371.  
  2372.         }
  2373.     }
  2374.  
  2375.     wind_get(w->handle, WF_NEXTXYWH,
  2376.         &rect.g_x, &rect.g_y,
  2377.         &rect.g_w, &rect.g_h);
  2378.     }
  2379.  
  2380.     graf_mouse(M_ON, 0L );
  2381.  
  2382. }
  2383.  
  2384. int align(int x)
  2385. {
  2386.     return ((x & 0xfffffff0) + ((x & 0xf) ? 0x10 : 0));
  2387. /*    return ((x & 0xfffffff8) + ((x & 0x07) ? 0x08 : 0)); */
  2388. }
  2389.  
  2390. int visible_lines(void)
  2391. {
  2392.     return ((cons.win->canvas.g_h - cons.yoff) / cons.hc);
  2393. }
  2394.  
  2395. int visible_cols(void)
  2396. {
  2397.     return ((cons.win->canvas.g_w - align(cons.xoff)) / cons.wc);
  2398. }
  2399.  
  2400. int cursor(int state)
  2401. {
  2402.     int xy[4], txy[4];
  2403.     GRECT rect;
  2404.  
  2405.     if ((state == OFF && cons.cstate == ON) ||
  2406.     (state == ON  && cons.cstate == OFF)) {
  2407.  
  2408.     vsf_interior(VdiHandle, 1);    /* set fill mode to solid */
  2409.     vswr_mode(VdiHandle, 3);    /* set write mode to XOR */
  2410.  
  2411.     xy[0] = cons.cx;
  2412.     xy[1] = cons.cy;
  2413.     xy[2] = xy[0] + cons.wc - 1;
  2414.     xy[3] = xy[1] + cons.hc - 1;
  2415.  
  2416.     wind_get(cons.win->handle, WF_FIRSTXYWH,
  2417.         &rect.g_x, &rect.g_y,
  2418.         &rect.g_w, &rect.g_h);
  2419.  
  2420.     while (rect.g_w && rect.g_h) {
  2421.  
  2422.         if (intersect(&cons.win->canvas, &rect)) {
  2423.  
  2424.         grect_to_array(&rect, txy);
  2425.         vs_clip(VdiHandle, 1, txy);
  2426.  
  2427.         vr_recfl(VdiHandle, xy);    /* draw the cursor */
  2428.  
  2429.         vs_clip(VdiHandle, 0, txy);
  2430.  
  2431.         }
  2432.  
  2433.         wind_get(cons.win->handle, WF_NEXTXYWH,
  2434.         &rect.g_x, &rect.g_y,
  2435.         &rect.g_w, &rect.g_h);
  2436.  
  2437.     }
  2438.  
  2439.     vs_clip(VdiHandle, 0, xy);
  2440.     vswr_mode(VdiHandle, 1);        /* restore replace mode */
  2441.     cons.cstate = !cons.cstate;        /* toggle cursor state  */
  2442.  
  2443.     }
  2444. }
  2445.  
  2446. int update_scroll(int handle)
  2447. {
  2448.  
  2449.     int hslide_pos, hslide_siz, vslide_pos, vslide_siz;
  2450.  
  2451.     if (handle == imag.handle) {
  2452.  
  2453.     if (width != imag.canvas.g_w) {
  2454.         hslide_pos = 1000 * plot_x/(width - imag.canvas.g_w);
  2455.     }
  2456.     else {
  2457.         hslide_pos = 0;
  2458.     }
  2459.  
  2460.     if (height != imag.canvas.g_h) {
  2461.         vslide_pos = 1000 * plot_y/(height - imag.canvas.g_h);
  2462.     }
  2463.     else {
  2464.         vslide_pos = 0;
  2465.     }
  2466.  
  2467.     hslide_siz = 1000 * imag.canvas.g_w/width;
  2468.     vslide_siz = 1000 * imag.canvas.g_h/height;
  2469.  
  2470.  
  2471.     }
  2472.     else if (handle == cons.win->handle) {
  2473.     int offset = cons.fdl - cons.fl;
  2474.  
  2475.     if (offset < 0) offset += LINES;
  2476.  
  2477.     if (cons.cols != CLIMIT) {
  2478.         hslide_pos = 1000 * cons.fdc/(CLIMIT - cons.cols);
  2479.     }
  2480.     else {
  2481.         hslide_pos = 0;
  2482.     }
  2483.  
  2484.     if (cons.lins < LINES) {
  2485.         vslide_pos = 1000 * offset/(LINES - cons.lins);
  2486.     }
  2487.     else {
  2488.         vslide_pos = 0;
  2489.     }
  2490.  
  2491.     hslide_siz = 1000 * cons.cols/CLIMIT;
  2492.     vslide_siz = 1000 * cons.lins/LINES;
  2493.  
  2494.     }
  2495.  
  2496.     wind_set(handle, WF_HSLIDE,  hslide_pos);
  2497.     wind_set(handle, WF_VSLIDE,  vslide_pos);
  2498.     wind_set(handle, WF_HSLSIZE, hslide_siz);
  2499.     wind_set(handle, WF_VSLSIZE, vslide_siz);
  2500.  
  2501. }
  2502.  
  2503.  
  2504. int intersect(GRECT *rec1, GRECT *rec2)
  2505. {
  2506.     GRECT temp;
  2507.  
  2508.     temp.g_x = MAX(rec1->g_x, rec2->g_x);
  2509.     temp.g_y = MAX(rec1->g_y, rec2->g_y);
  2510.     temp.g_w = MIN(rec1->g_x + rec1->g_w, rec2->g_x + rec2->g_w);
  2511.     temp.g_h = MIN(rec1->g_y + rec1->g_h, rec2->g_y + rec2->g_h);
  2512.  
  2513.     rec2->g_x = temp.g_x;
  2514.     rec2->g_y = temp.g_y;
  2515.     rec2->g_w = temp.g_w - temp.g_x;
  2516.     rec2->g_h = temp.g_h - temp.g_y;
  2517.  
  2518.     return ((temp.g_w > temp.g_x) && (temp.g_h > temp.g_y));
  2519. }
  2520.  
  2521. /* Adjust the size of an object for the current screen resolution. */
  2522.  
  2523. int objc_fix(OBJECT *object)
  2524. {
  2525.     int i=-1;
  2526.  
  2527.     do {
  2528.     i++;
  2529.  
  2530.     if      (object[i].ob_x == 769) object[i].ob_x = full.g_y;
  2531.     else if (object[i].ob_x == 513) object[i].ob_x = full.g_y;
  2532.     else                object[i].ob_x *= cons.wc;
  2533.  
  2534.     if      (object[i].ob_y == 769) object[i].ob_y = full.g_y;
  2535.     else if (object[i].ob_y == 513) object[i].ob_y = full.g_y;
  2536.     else                object[i].ob_y *= cons.hc;
  2537.  
  2538.     if      (object[i].ob_width == 769) object[i].ob_width = full.g_y;
  2539.     else if (object[i].ob_width == 513) object[i].ob_width = full.g_y;
  2540.     else if (object[i].ob_width == 80)  object[i].ob_width = full.g_w;
  2541.     else                    object[i].ob_width *= cons.wc;
  2542.  
  2543.     if      (object[i].ob_height == 769) object[i].ob_height = full.g_y;
  2544.     else if (object[i].ob_height == 513) object[i].ob_height = full.g_y;
  2545.     else                     object[i].ob_height *= cons.hc;
  2546.  
  2547.     }
  2548.     while (!(object[i].ob_flags & LASTOB));
  2549.  
  2550. }
  2551.  
  2552. int clear_win(GRECT *area)
  2553. {
  2554.     int xy[4];
  2555.  
  2556.     xy[0] = area->g_x;
  2557.     xy[1] = area->g_y;
  2558.     xy[2] = xy[0] + area->g_w - 1;
  2559.     xy[3] = xy[1] + area->g_h - 1;
  2560.  
  2561.     vsf_interior(VdiHandle, 0);    /* set fill mode to hollow */
  2562.     vr_recfl(VdiHandle, xy);        /* clear the window */
  2563. }
  2564.  
  2565. /*
  2566.  * The remainder of this file contains printer output routines, most of
  2567.  * which were contributed by Chris Strunk (some of them were written by me).
  2568.  * I made some modifications to the following code (with permission), and
  2569.  * may have introduced errors not in the original code.
  2570.  * Tim Gallivan, 3/92.
  2571.  */
  2572.  
  2573. /*
  2574.  * This file is Copyright (C) 1990 Christoph Strunk.
  2575.  *
  2576.  * You are not allowed to copy or modify it.
  2577.  */
  2578.  
  2579. #define ATARI_TOS    (1)
  2580. #define MAKE_VOID    (void *)
  2581. #define MAXLEN        (256)
  2582.  
  2583. void con_flush();
  2584. int OutputIsAscii = 0, RTX_Found = 0;
  2585. long *old_ssp = NULL;
  2586. FILE *OutFile = NULL;
  2587.  
  2588. #if PC_DOS || ATARI_TOS
  2589. #  define DIRECT    1    /* 1 = Direct Centronics port programming */
  2590. #endif
  2591.  
  2592. #if ATARI_TOS || ( PC_DOS && DIRECT )
  2593. static short prn_out ( int );
  2594. #endif
  2595.  
  2596. #if ATARI_TOS && LATTICE
  2597. #include <dos.h>
  2598. #endif
  2599.  
  2600. #ifdef __GNUC__
  2601. #include <osbind.h>
  2602. #endif
  2603.  
  2604. #if PC_DOS && DIRECT
  2605. #include <bios.h>
  2606. #endif
  2607.  
  2608. /* output one character */
  2609.  
  2610. static int fatal_output_error = 0;
  2611.  
  2612. void
  2613. lputc(c)
  2614. int c;
  2615. {
  2616.     static short rc;
  2617.     static unsigned char global_count = 0; /* other processes every 256 chars */
  2618.     void l_stop(), fatal();
  2619.  
  2620.     if ( fatal_output_error ) return;
  2621.  
  2622.     global_count += 1;
  2623.  
  2624.     c &= 255;            /* New in 2.9.44: avoid signed char problems */
  2625.  
  2626. #if ATARI_TOS || PC_DOS
  2627.     if ( ( c == '\n' ) && OutputIsAscii ) {
  2628.       lputc ( '\r' );    /* recursion */
  2629.     }
  2630. #endif
  2631.  
  2632.     if ( OutFile ) {
  2633.        rc = ( fputc ( c, OutFile ) == EOF );
  2634.     } else {
  2635. #if ATARI_TOS || ( PC_DOS && DIRECT )
  2636.                    rc = prn_out ( c );
  2637. #else
  2638.                    rc = -1;
  2639. #endif
  2640.     }
  2641.  
  2642.     if ( rc ) {
  2643.         if ( OutFile ) {
  2644.             perror ( "\nlputc" );
  2645.             fprintf ( stderr, "\nOutput error -- %s ?\n",
  2646.                       "Disk full or printer not ready" );
  2647.             fclose ( OutFile );
  2648.             OutFile = NULL;
  2649.         } else {
  2650.             fprintf ( stderr, "\nOutput error -- Printer not ready ?\n" );
  2651.         }
  2652.         l_stop();
  2653.         fatal_output_error = 1;
  2654.         fatal ( "Output error" );
  2655.     }
  2656.  
  2657. #if ATARI_TOS
  2658.     if ( RTX_Found && ! global_count ) call_yield(); /* allow other processes */
  2659. #endif
  2660. }
  2661.  
  2662. /* output a string */
  2663.  
  2664. void
  2665. lputs ( s )
  2666. char *s;
  2667. {
  2668.     while ( *s ) lputc ( *s++ );
  2669. }
  2670.  
  2671. void
  2672. lflush()
  2673. {
  2674.    if ( OutFile ) fflush ( OutFile );
  2675. }
  2676.  
  2677. /* start/stop lputc device */
  2678.  
  2679. void
  2680. l_start()
  2681. {
  2682.   void l_stop(), fatal();
  2683.  
  2684. #if ATARI_TOS && DIRECT
  2685.   volatile char *gpip = (char *) 0xFFFFFA01L;
  2686.   int cnt;
  2687.  
  2688.   if ( OutFile == NULL && old_ssp == NULL ) {
  2689.     old_ssp = (void *) call_super ( NULL );
  2690.     cnt = 0;
  2691. /*    for ( cnt=0; ( *gpip & 1 ) && ( ++cnt <= 10 ); ) {
  2692.      printf("cnt = %d\n", cnt); */
  2693.      Ongibit(0x20);                                        /* set strobe bit */
  2694. /*    } */
  2695.     if ( cnt > 10 ) {
  2696.       l_stop();
  2697.       puts ( "\n" );
  2698.       fatal_output_error = 1;
  2699.       fatal ( "Printer not ready" );
  2700.     }
  2701.   }
  2702. #endif
  2703. #if ATARI_TOS && ! DIRECT
  2704.   int cnt;
  2705.  
  2706.   if ( OutFile == NULL && old_ssp == NULL ) {
  2707.     old_ssp = (void *) call_super ( NULL );
  2708.  
  2709.     for ( cnt=0; ( ! prt_ready(0) ) && ( ++cnt <= 10 ); ) {
  2710.      Ongibit(0x20);                                        /* set strobe bit */
  2711.     }
  2712.     if ( cnt > 10 ) {
  2713.       l_stop();
  2714.       puts ( "\n" );
  2715.       fatal_output_error = 1;
  2716.       fatal ( "Printer not ready" );
  2717.     }
  2718.   }
  2719. #endif
  2720. #if PC_DOS && DIRECT
  2721.   if ( OutFile == NULL && ( biosprint ( 2, 0, BiosChannel ) & 0x29 ) ) {
  2722.     l_stop();
  2723.     puts ( "\n" );
  2724.     fatal_output_error = 1;
  2725.     fatal ( "Printer not ready" );
  2726.   }
  2727. #endif
  2728. }
  2729.  
  2730. void l_stop()
  2731. {
  2732.     lflush();
  2733. #if ATARI_TOS
  2734.     if ( old_ssp != NULL ) {
  2735.         MAKE_VOID call_super ( old_ssp );
  2736.         old_ssp = NULL;
  2737.     }
  2738. #endif
  2739. }
  2740.  
  2741. #if ATARI_TOS && DIRECT
  2742.  
  2743. extern void int_off __PROTO( ( void ) );
  2744.  
  2745. /* int_off:  ori.w  #$0700,sr
  2746.  *           ret
  2747.  */
  2748.  
  2749. extern void int_on __PROTO( ( void ) );
  2750.  
  2751. /* int_on:   andi.w #$F8FF,sr
  2752.  *           ret
  2753.  */
  2754.  
  2755. static short prn_out ( c )
  2756. int c;
  2757. {
  2758.   volatile unsigned long *hz_200;
  2759.   register unsigned long end_time;
  2760.   volatile char *gpip = (char *) 0xFFFFFA01L;
  2761.   register char g;
  2762.  
  2763. #if OLD
  2764.   unsigned char loop_count = 0;
  2765. #endif
  2766.  
  2767.   if ( old_ssp == NULL ) l_start();
  2768.  
  2769.   hz_200 = (unsigned long *) 0x04BAL;
  2770. #if OLD
  2771.   end_time = *hz_200 + 200;        /* check once per second */
  2772. #else
  2773.   end_time = *hz_200 + 2;          /* check 100 times per second */
  2774. #endif
  2775.  
  2776.   while ( *gpip & 1 ) {  /* wait */
  2777. #if OLD
  2778.     /* Printer 1 sec. or more not ready ? */
  2779.     if ( ( end_time < *hz_200 ) ||
  2780.          ( ( ( ++loop_count & 7 ) == 0 ) && ( BatchMode || RTX_Found ) ) ) {
  2781.         con_flush();         /* allow Control_C, other Processes etc. */
  2782.         end_time = *hz_200 + 2;          /* check 100 times per second */
  2783.     }
  2784. #else
  2785.     if ( end_time <= *hz_200 ) {
  2786.         con_flush();               /* allow Control_C, other Processes etc. */
  2787.         end_time = *hz_200 + 1;              /* check 200 times per second */
  2788.     }
  2789. #endif
  2790.   }
  2791.  
  2792.   int_off();                   /* disable interrupts */
  2793.  
  2794.   gpip = (char *) 0xFFFF8800L; /* load sound chip adress now */
  2795.  
  2796.   *gpip = 15;                  /* select port B */
  2797.   gpip[2] = (char) c;          /* write out char */
  2798.   *gpip = 14;                  /* select port A */
  2799.   g = *gpip;                   /* get old value */
  2800. #if OLD
  2801.   g &= 0xDF;                   /* clear strobe bit */
  2802. #else
  2803.   g &= ~0x20;                  /* clear strobe bit */
  2804. #endif
  2805.   gpip[2] = g;
  2806.   g |= 0x20;                   /* set strobe bit */
  2807.   g |= 0x20;                   /* short delay */
  2808.   gpip[2] = g;
  2809.  
  2810.   int_on();                    /* enable interrupts */
  2811.  
  2812.   return 0;
  2813. }
  2814. #endif
  2815.  
  2816. #if ATARI_TOS && ! DIRECT
  2817. static short prn_out ( c )
  2818. int c;
  2819. {
  2820.   volatile unsigned long *hz_200 = (unsigned long *) 0x04BAL;
  2821.   register unsigned long end_time;
  2822.  
  2823.   if ( old_ssp == NULL ) l_start();
  2824.  
  2825.   end_time = *hz_200 + 2;          /* check 200 times per second */
  2826.  
  2827.   while ( ! prt_ready(0) ) {  /* wait */
  2828.     if ( end_time <= *hz_200 ) {
  2829.         con_flush();               /* allow Control_C, other Processes etc. */
  2830.         end_time = *hz_200 + 1;              /* check 200 times per second */
  2831.     }
  2832.   }
  2833.  
  2834.   prt_out ( 0, c );
  2835.  
  2836.   return 0;
  2837. }
  2838. #endif
  2839.  
  2840. #if PC_DOS && DIRECT
  2841.  
  2842. static short prn_out ( c )
  2843. int c;
  2844. {
  2845.   while ( biosprint ( 0, c, BiosChannel ) & 0x29 ) {
  2846.     /* wait until Ok or Control-C pressed */
  2847.     con_flush();
  2848.   }
  2849.  
  2850.   return 0;
  2851. }
  2852.  
  2853. #endif
  2854.  
  2855. void
  2856. con_flush()
  2857. {
  2858.     int chin;
  2859.     void fatal();
  2860.  
  2861.     chin = Crawio(0xFF);
  2862.     if ((chin & 0xFF) == 3) fatal("Keyboard Interrupt");
  2863. }
  2864.  
  2865. void
  2866. fatal(char *message)
  2867. {
  2868.     fprintf(stderr, "%s\n", message);
  2869.     l_stop();
  2870.     exit(-1);
  2871. }
  2872.  
  2873. /* The following routines are generic interfaces to Chris Strunk's
  2874.  * fast printing routines. Tim Gallivan 3/92.
  2875.  */
  2876.  
  2877. int
  2878. csputc(int c, FILE *stream)
  2879. {
  2880.     if (gp_file_is_console(stream) && window) {    /* console I/O to a window */
  2881.     gemputc(c);
  2882.     }
  2883.     else {
  2884.     OutFile = stream;
  2885.     l_start();
  2886.     lputc(c);
  2887.     l_stop();
  2888.     }
  2889.  
  2890.     return c;
  2891. }
  2892.  
  2893. int
  2894. csputs(const char *s, FILE *stream)
  2895. {
  2896.     if (gp_file_is_console(stream) && window) {    /* console I/O to a window */
  2897.     gemprintf(stream, s);
  2898.     }
  2899.     else {
  2900.     OutFile = stream;
  2901.     l_start();
  2902.     lputs(s);
  2903.     l_stop();
  2904.     }
  2905.  
  2906.     return 1;
  2907. }
  2908.  
  2909. size_t
  2910. cswrite(const void *ptr, size_t size, size_t nobj, FILE *stream)
  2911. {
  2912.     int count;
  2913.  
  2914.     if (stream == NULL) {
  2915.         OutFile = stream;
  2916.         l_start();
  2917.         for (count=0; count < size*nobj; count++) {
  2918.             lputc(*(char *)(ptr++));       /* send the data */
  2919.         }
  2920.         l_stop();
  2921.         return count;
  2922.     }
  2923.     else {
  2924.         int ret;
  2925.         ret = fwrite(ptr, size, nobj, stream);
  2926.         con_flush();
  2927.         return ret;
  2928.     }
  2929.         
  2930. }
  2931.  
  2932. #if 0
  2933. int
  2934. csprintf(FILE *stream, char *format, ...)
  2935. {
  2936.     va_list args;
  2937.     char line[MAXLEN];
  2938.  
  2939.     va_start(args, format);
  2940.  
  2941.     if (stream == NULL) {
  2942.         OutFile = stream;
  2943.         vsprintf(line, format, args);
  2944.         l_start();
  2945.         lputs(line);
  2946.         l_stop();
  2947.         va_end(args);
  2948.         return 0;
  2949.     }
  2950.     else {
  2951.         vfprintf(stream, format, args);
  2952.         va_end(args);
  2953.         con_flush();
  2954.         return 0;
  2955.     }
  2956.  
  2957. }
  2958. #endif
  2959.  
  2960. int
  2961. gemprintf(FILE *stream, const char *format, ...)
  2962. {
  2963.     va_list args;
  2964.  
  2965.     char c, *lptr, *bptr;
  2966.     char buffer[1024], line[COLUMNS+1];
  2967.     
  2968.     int i, count;
  2969.  
  2970.     va_start(args, format);
  2971.  
  2972.     lptr = line;
  2973.     bptr = buffer;
  2974.  
  2975.     if (gp_file_is_console(stream) && window) {    /* console I/O to a window */
  2976.  
  2977.     msgbuff[3] = cons.win->handle;
  2978.     cursor(OFF);
  2979.  
  2980.     count = vsprintf(buffer, format, args);
  2981.  
  2982.     for (; (c = *bptr) != '\0'; bptr++) {
  2983.       switch (c) {
  2984.  
  2985.         case '\r':
  2986.         case '\n':
  2987.         newline:
  2988.         *lptr = '\0';
  2989.         strcat(cons.text[cons.ln], line);
  2990.         next_line();
  2991.  
  2992.         lptr = line;
  2993.         break;
  2994.  
  2995.         default:
  2996.         *lptr++ = c;
  2997.         if (++cons.cn >= COLUMNS) goto newline;
  2998.  
  2999.       }
  3000.  
  3001.     }
  3002.  
  3003.     if (lptr != line) {
  3004.         int dirtw;
  3005.  
  3006.         *lptr = '\0';
  3007.         strcat(cons.text[cons.ln], line);
  3008.  
  3009.         dirtw = strlen(line) * cons.wc;
  3010.         msgbuff[4] = cons.cx;
  3011.         msgbuff[5] = cons.cy;
  3012.         msgbuff[6] = dirtw;
  3013.         msgbuff[7] = cons.hc;
  3014.  
  3015.         gp_win_redraw(DIRT_RECT);
  3016.  
  3017.         cons.cx += dirtw;
  3018.  
  3019.     }
  3020.  
  3021.     cursor(ON);
  3022.  
  3023.     }
  3024.     else if (stream == NULL) {        /* output for the centronics port */
  3025.     OutFile = stream;
  3026.     count = vsprintf(buffer, format, args);
  3027.     l_start();
  3028.     lputs(buffer);
  3029.     l_stop();
  3030.     }
  3031.     else {                /* print to other streams normally */
  3032.     count = vfprintf(stream, format, args);
  3033.     con_flush();
  3034.     }
  3035.  
  3036.     va_end(args);
  3037.     return count;
  3038.  
  3039. }
  3040.  
  3041. /* Restore the usual desktop background. */
  3042.  
  3043. #undef puts
  3044.  
  3045. int restore_bg()
  3046. {
  3047.     puts("\033f");
  3048.     v_hide_c(VdiHandle);
  3049.     form_dial(FMD_FINISH, 0, 0, 8, 16, 0, 0, XRes, YRes);
  3050.     v_show_c(VdiHandle, 0);
  3051. }
  3052.  
  3053. /*
  3054. #-----------------------------------------------------------------------------#
  3055. #:    Simple support routines for LATTICE C 5.04.01 and other C compilers
  3056. #
  3057. #:    Lattice C Assembler
  3058. #
  3059. #:    The parameter comes on the stack for functions starting with '_'.
  3060. #
  3061. #:    void *call_super ( void * );  supervisor mode on/off
  3062. #
  3063. #:    Original code by Chris Strunk. Modified for use with gcc in
  3064. #:    Ghostscript by Tim Gallivan, 3/92.
  3065. #-----------------------------------------------------------------------------#
  3066. */
  3067.     asm("\
  3068.  
  3069.     .text 0
  3070.  
  3071.     .globl _int_off
  3072.     .globl _int_on
  3073.     .globl _call_super
  3074.     .globl _call_yield
  3075.     .globl _call_nice
  3076.     .globl _user_trace
  3077.     .globl _prt_ready
  3078.     .globl _prt_out
  3079.  
  3080. _get_la:
  3081.     moveml   d2/a2,sp@- 
  3082.     .byte    0xA0,0x00            | Adresse Line-A-Var nach A0 & D0
  3083.     moveml   sp@+,d2/a2
  3084.     rts
  3085.  
  3086. _int_off:
  3087.     oriw     #0x0700,sr
  3088.     rts
  3089.  
  3090. _int_on:
  3091.     andiw    #0xF8FF,sr
  3092.     rts
  3093.  
  3094. _call_super:
  3095.     movel    a7@(4),a0
  3096.     moveml   d2/a2-a3,sp@-
  3097.     movel    a0,sp@-
  3098.     movew    #0x20,sp@-
  3099.     movel    a7,a3     | save current stack pointer
  3100.     trap      #1
  3101.     movel    a3,a7     | make bad stack pointer good again !!!!!!!
  3102.     addql    #6,sp
  3103.     movel    d0,a0     | return value in both: d0 and a0
  3104.     moveml   sp@+,d2/a2-a3
  3105.     rts
  3106.  
  3107. _call_yield:
  3108.     moveml   d2/a2,sp@-
  3109.     movew    #0x00ff,sp@-   | MiNT Syield()  --  TOS illegal (rc -32)
  3110.     trap      #1
  3111.     addql    #2,sp
  3112.     moveml   sp@+,d2/a2
  3113.     rts
  3114.  
  3115. _call_nice:
  3116.     movel    a7@(4),d0
  3117.     moveml   d2/a2,sp@-
  3118.     movew    d0,sp@-
  3119.     movew    #0x10A,sp@-
  3120.     trap      #1
  3121.     addql    #4,sp
  3122.     moveml   sp@+,d2/a2
  3123.     rts
  3124.  
  3125. _user_trace:
  3126.     moveml   d1-d7/a0-a6,sp@-
  3127.     moveql   #0,d0
  3128.     movel    0x3F0,a1     | TEMPLMON user trace vector
  3129.     cmpal    #0,a1       | not installed ?
  3130.     beqs     end_trace
  3131.     jsr      a1@        | execute it !
  3132.     extl     d0
  3133.  
  3134. end_trace:
  3135.     moveml   sp@+,d1-d7/a0-a6
  3136.     rts
  3137.  
  3138. _prt_ready:
  3139.     moveml    d3/a3/a5,a7@-
  3140.     subl    a5,a5
  3141.     movew    d0,a7@-
  3142.     movel    0x506,a0
  3143.     jsr    a0@
  3144.     addql    #2,a7
  3145.     moveml    a7@+,d3/a3/a5
  3146.     rts
  3147.  
  3148. _prt_out:
  3149.     moveml    d3/a3/a5,a7@-
  3150.     subl    a5,a5
  3151.     movew    d1,a7@-
  3152.     movew    d0,a7@-
  3153.     movel    0x50A,a0
  3154.     jsr    a0@
  3155.     addql    #4,a7
  3156.     moveml    a7@+,d3/a3/a5
  3157.     rts
  3158.  
  3159.     ");
  3160.