Commit | Line | Data |
---|---|---|
79177862 WJ |
1 | /* Copyright (C) 1992 Aladdin Enterprises. All rights reserved. |
2 | Distributed by Free Software Foundation, Inc. | |
3 | ||
4 | This file is part of Ghostscript. | |
5 | ||
6 | Ghostscript is distributed in the hope that it will be useful, but | |
7 | WITHOUT ANY WARRANTY. No author or distributor accepts responsibility | |
8 | to anyone for the consequences of using it or for whether it serves any | |
9 | particular purpose or works at all, unless he says so in writing. Refer | |
10 | to the Ghostscript General Public License for full details. | |
11 | ||
12 | Everyone is granted permission to copy, modify and redistribute | |
13 | Ghostscript, but only under the conditions described in the Ghostscript | |
14 | General Public License. A copy of this license is supposed to have been | |
15 | given to you along with Ghostscript so you can know your rights and | |
16 | responsibilities. It should be in a file named COPYING. Among other | |
17 | things, the copyright notice and this notice must be preserved on all | |
18 | copies. */ | |
19 | ||
20 | /* gp_dosfb.c */ | |
21 | /* MS-DOS frame buffer swapping routines for Ghostscript */ | |
22 | #include <conio.h> | |
23 | #include "memory_.h" | |
24 | #include "gx.h" | |
25 | #include "gp.h" | |
26 | #include "gserrors.h" | |
27 | #include "gxdevice.h" | |
28 | ||
29 | /* On MS-DOS machines, we maintain a console image in memory, */ | |
30 | /* and swap screens on request. */ | |
31 | #define cw_width 80 | |
32 | #define cw_height 25 | |
33 | typedef struct text_line_s { | |
34 | int end; | |
35 | char text[cw_width + 1]; | |
36 | } text_line; | |
37 | typedef struct { | |
38 | text_line _ds *line; | |
39 | text_line lines[cw_height]; | |
40 | } ds_text_screen; | |
41 | ||
42 | private ds_text_screen console; | |
43 | ||
44 | private int console_is_current; | |
45 | ||
46 | /* Buffer one scan line of graphics. */ | |
47 | #define row_buf_size 1280 | |
48 | private char graphics_file_name[] = "_temp_.gfb"; | |
49 | ||
50 | /* Forward references */ | |
51 | private int save_graphics(P1(gx_device *)); | |
52 | private int restore_graphics(P1(gx_device *)); | |
53 | ||
54 | /* Initialize the console buffer. */ | |
55 | void | |
56 | gp_init_console() | |
57 | { memset(&console.lines, 0, sizeof(console.lines)); | |
58 | console.line = &console.lines[0]; | |
59 | console_is_current = 0; | |
60 | } | |
61 | ||
62 | /* Write a string to the console. */ | |
63 | void | |
64 | gp_console_puts(const char *str, uint size) | |
65 | { register ds_text_screen _ds *cop = &console; | |
66 | register text_line _ds *lip = cop->line; | |
67 | for ( ; size ; str++, size-- ) | |
68 | switch ( *str ) | |
69 | { | |
70 | case '\n': | |
71 | if ( lip == &cop->lines[cw_height - 1] ) | |
72 | { /* Scroll up */ | |
73 | memcpy(&cop->lines[0], &cop->lines[1], | |
74 | sizeof(text_line) * (cw_height - 1)); | |
75 | } | |
76 | else | |
77 | cop->line = ++lip; | |
78 | lip->end = 0; | |
79 | break; | |
80 | case '\t': | |
81 | gp_console_puts(" ", 8 - (lip->end & 7)); | |
82 | lip = cop->line; | |
83 | break; | |
84 | default: | |
85 | if ( lip->end == cw_width ) | |
86 | { gp_console_puts("\n", 1); | |
87 | lip = cop->line; | |
88 | } | |
89 | lip->text[lip->end++] = *str; | |
90 | } | |
91 | } | |
92 | ||
93 | /* Make the console current on the screen. */ | |
94 | int | |
95 | gp_make_console_current(gx_device *dev) | |
96 | { int code = 0; | |
97 | if ( !console_is_current ) | |
98 | code = save_graphics(dev); | |
99 | /* Transfer the console buffer to the screen. */ | |
100 | /* Unfortunately, there is no standard way to clear the screen. */ | |
101 | /* Output the ANSI sequence and hope for the best. */ | |
102 | cputs("\r\033[2J\r \r"); | |
103 | { int i; | |
104 | register text_line _ds *lip; | |
105 | for ( i = 0, lip = &console.lines[0]; i < cw_height; i++, lip++ ) | |
106 | { if ( i != 0 ) cputs("\r\n"); | |
107 | lip->text[lip->end] = 0; | |
108 | cputs(lip->text); | |
109 | } | |
110 | } | |
111 | console_is_current = 1; | |
112 | return code; | |
113 | } | |
114 | ||
115 | /* Make the graphics current on the screen. */ | |
116 | int | |
117 | gp_make_graphics_current(gx_device *dev) | |
118 | { if ( console_is_current ) | |
119 | { int code = restore_graphics(dev); | |
120 | if ( code < 0 ) return code; | |
121 | console_is_current = 0; | |
122 | } | |
123 | return 0; | |
124 | } | |
125 | ||
126 | /* ------ Internal routines ------ */ | |
127 | ||
128 | /* We compress the pixmap just a little, by noting */ | |
129 | /* replicated bytes at the beginning and end of a line. */ | |
130 | typedef struct { ushort pre, post; } row_head; | |
131 | ||
132 | /* Save the graphics screen on a file. */ | |
133 | private int | |
134 | save_graphics(gx_device *dev) | |
135 | { uint row_size = gx_device_bytes_per_scan_line(dev, 0); | |
136 | char row_buf[row_buf_size]; | |
137 | int count = row_buf_size / row_size; | |
138 | FILE *gfile; | |
139 | int y; | |
140 | if ( count == 0 ) return -1; | |
141 | gfile = fopen(graphics_file_name, "wb"); | |
142 | if ( gfile == 0 ) return gs_error_ioerror; | |
143 | for ( y = 0; y < dev->height; y += count ) | |
144 | { char _ss *row = row_buf; | |
145 | int n = count; | |
146 | (*dev->procs->get_bits)(dev, y, row, row_buf_size, 0); | |
147 | while ( n-- ) | |
148 | { row_head head; | |
149 | char _ss *beg = row, *end = row + row_size - 1; | |
150 | while ( end > beg && *end == end[-1] ) end--; | |
151 | if ( beg < end ) | |
152 | while ( *beg == beg[1] ) beg++; | |
153 | head.pre = beg - row; | |
154 | head.post = end + 1 - row; | |
155 | fwrite((char *)&head, 1, sizeof(head), gfile); | |
156 | fwrite(beg, head.post - head.pre, 1, gfile); | |
157 | row += row_size; | |
158 | } | |
159 | } | |
160 | fclose(gfile); | |
161 | return 0; | |
162 | } | |
163 | ||
164 | /* Restore the graphics screen from a file. */ | |
165 | private int | |
166 | restore_graphics(gx_device *dev) | |
167 | { FILE *gfile; | |
168 | uint row_size = gx_device_bytes_per_scan_line(dev, 0); | |
169 | char row_buf[row_buf_size]; | |
170 | int y; | |
171 | if ( row_size > row_buf_size ) return -1; | |
172 | gfile = fopen(graphics_file_name, "rb"); | |
173 | if ( gfile == 0 ) return gs_error_ioerror; | |
174 | for ( y = 0; y < dev->height; y ++ ) | |
175 | { row_head head; | |
176 | char _ss *beg, *end; | |
177 | fread((char *)&head, 1, sizeof(head), gfile); | |
178 | beg = row_buf + head.pre; | |
179 | end = row_buf + head.post; | |
180 | fread(beg, 1, end - beg, gfile); | |
181 | if ( head.pre ) | |
182 | memset(row_buf, *beg, head.pre); | |
183 | if ( head.post < row_size ) | |
184 | memset(end, end[-1], row_size - head.post); | |
185 | (*dev->procs->copy_color)(dev, row_buf, 0, row_size, gx_no_bitmap_id, 0, y, dev->width, 1); | |
186 | } | |
187 | fclose(gfile); | |
188 | return 0; | |
189 | } |