Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 446 lines (393 sloc) 10.309 kb
cf92e3b @mbert Import Elvis 2.0 (written by Steve Kirkendall)
authored
1 /* lp.c */
2 /* Copyright 1995 by Steve Kirkendall */
3
4
5 /* This file contains generic printing code. */
6
7 #include "elvis.h"
9f1c6f0 @mbert Import Elvis 2.2_0 (written by Steve Kirkendall)
authored
8 #ifdef FEATURE_RCSID
9 char id_lp[] = "$Id: lp.c,v 2.39 2003/10/17 17:41:23 steve Exp $";
10 #endif
8d1ac0c @mbert Import Elvis 2.1 (written by Steve Kirkendall)
authored
11 #ifdef FEATURE_LPR
cf92e3b @mbert Import Elvis 2.0 (written by Steve Kirkendall)
authored
12
13 #if USE_PROTOTYPES
14 static LPTYPE *findtype(char *name);
9f1c6f0 @mbert Import Elvis 2.2_0 (written by Steve Kirkendall)
authored
15 # if defined (GUI_WIN32)
cf92e3b @mbert Import Elvis 2.0 (written by Steve Kirkendall)
authored
16 static void dummyprt(_CHAR_ ch);
9f1c6f0 @mbert Import Elvis 2.2_0 (written by Steve Kirkendall)
authored
17 # endif
cf92e3b @mbert Import Elvis 2.0 (written by Steve Kirkendall)
authored
18 static void prtchar(_CHAR_ ch);
19 static void draw(CHAR *p, long qty, _char_ font, long offset);
20 #endif
21
22
23 /* This is a list of all known printer types. The first one is the default. */
9f1c6f0 @mbert Import Elvis 2.2_0 (written by Steve Kirkendall)
authored
24 static LPTYPE *alltypes[] = { &lpdumb, &lpepson, &lppana, &lpibm, &lphp,
25 &lpcr, &lpbs, &lpansi, &lphtml, &lpps, &lpps2,
cf92e3b @mbert Import Elvis 2.0 (written by Steve Kirkendall)
authored
26 #if defined (GUI_WIN32)
9f1c6f0 @mbert Import Elvis 2.2_0 (written by Steve Kirkendall)
authored
27 &lpwindows,
cf92e3b @mbert Import Elvis 2.0 (written by Steve Kirkendall)
authored
28 #endif
29 };
30 static LPTYPE *type; /* type of printer being used at the moment */
31
32 /* Page formatting variables */
33 static int pagenum; /* page number withing this printing */
34 static int linesleft; /* number of usable lines left on this page */
35 static int column; /* column number, used to implement wrapping */
36 static WINDOW prwin; /* window doing the printing */
9f1c6f0 @mbert Import Elvis 2.2_0 (written by Steve Kirkendall)
authored
37 static ELVBOOL anytext; /* ElvFalse if blank page, ElvTrue if any text */
8d1ac0c @mbert Import Elvis 2.1 (written by Steve Kirkendall)
authored
38 static long lnum; /* line number of current line */
cf92e3b @mbert Import Elvis 2.0 (written by Steve Kirkendall)
authored
39
40 /* Output buffering variables */
41 static CHAR *iobuf; /* pointer to the I/O buffer */
42 static int iomax; /* number of CHARS that the iobuf can hold */
43 static int ionext; /* number of CHARS currently in iobuf */
44
9f1c6f0 @mbert Import Elvis 2.2_0 (written by Steve Kirkendall)
authored
45 /* Return the value of a field from lpoptions, as a string */
46 char *lpoptfield(field, dflt)
47 char *field; /* name of the field to retrieve */
48 char *dflt; /* default value, if not in lpoptions */
49 {
50 int len;
51 static char buf[50];
52 char *scan;
53
54 /* if no options, then return "" */
55 if (!o_lpoptions || !*o_lpoptions)
56 return dflt;
57
58 /* look for the requested field */
59 len = strlen(field);
60 for (scan = tochar8(o_lpoptions); scan && *scan;)
61 {
62 /* is this it? */
63 if (!strncmp(scan, field, len) && scan[len] == ':')
64 {
65 /* found! copy the value into buf */
66 for (len = 0;
67 len < QTY(buf)-1 && scan[len] && scan[len] != '\0';
68 len++)
69 {
70 buf[len] = scan[len];
71 }
72 buf[len] = '\0';
73
74 /* if default is Boolean then force Boolean values */
75 if (!strcmp(dflt, "false") || !strcmp(dflt, "true"))
76 {
77 if (strchr("nNfF0", buf[0]))
78 strcpy(buf, "false");
79 else
80 strcpy(buf, "true");
81 }
82
83 /* return it */
84 return buf;
85 }
86
87 /* scan for the next field */
88 scan = strchr(scan, ',');
89 if (scan)
90 {
91 scan++;
92 while (elvspace(*scan))
93 scan++;
94 }
95 }
96
97 /*not found -- return the default */
98 return dflt;
99 }
100
101
cf92e3b @mbert Import Elvis 2.0 (written by Steve Kirkendall)
authored
102 /* This function converts a type name to an LPTYPE pointer. Returns NULL if
103 * unsuccessful. If the name is NULL, it returns the default LPTYPE.
104 */
105 static LPTYPE *findtype(name)
106 char *name; /* name of printer type */
107 {
108 int i;
109
110 /* if name is NULL, return the default type */
111 if (name == NULL)
112 {
113 return alltypes[0];
114 }
115
116 /* search for the name in the list */
117 for (i = 0; i < QTY(alltypes); i++)
118 {
119 if (!strcmp(name, alltypes[i]->name))
120 {
121 return alltypes[i];
122 }
123 }
124
125 /* failed */
126 return NULL;
127 }
128
9f1c6f0 @mbert Import Elvis 2.2_0 (written by Steve Kirkendall)
authored
129 /* return the RGB value for the foreground of a given font. This takes into
130 * consideration the "lpcolor" and "lpcontrast" options.
131 */
132 unsigned char *lpfg(fontcode)
133 _char_ fontcode;
134 {
135 static unsigned char rgb[3];
136 int i, j;
137
138 if (o_lpcolor)
139 {
140 /* fetch the RGB value from colorinfo[] */
141 memcpy(rgb, colorinfo[fontcode].lpfg_rgb, 3);
142
143 /* if the color is too pale, then darken it */
144 i = rgb[0] + rgb[1] + rgb[2];
145 j = 3 * (255 - (o_lpcontrast * 255 / 100));
146 if (i > j)
147 {
148 rgb[0] = (unsigned char)(rgb[0] * j / i);
149 rgb[1] = (unsigned char)(rgb[1] * j / i);
150 rgb[2] = (unsigned char)(rgb[2] * j / i);
151 }
152 }
153 else
154 {
155 /* nolpcolor, always use black */
156 memset(rgb, 0, 3);
157 }
158
159 return rgb;
160 }
161
cf92e3b @mbert Import Elvis 2.0 (written by Steve Kirkendall)
authored
162 #if defined (GUI_WIN32)
163 static void dummyprt(ch)
164 _CHAR_ ch; /* character to be sent to printer */
165 {
166 }
167 #endif
168 /* This function copies a single character to the printer (or file).
169 * Internally, is uses a large I/O buffer for the sake of efficiency.
170 */
171 static void prtchar(ch)
172 _CHAR_ ch; /* character to be sent to printer */
173 {
174 assert(ionext >= 0 && ionext < iomax);
175 iobuf[ionext++] = ch;
176 if (ionext == iomax)
177 {
178 iowrite(iobuf, ionext);
179 ionext = 0;
180 }
181 }
182
183 /* This function takes a single character from the mode's image() function
184 * and passes it to the LP driver. This function also performs newline
185 * conversion, line wrapping/clipping, and page breaks.
186 */
187 static void draw(p, qty, font, offset)
188 CHAR *p; /* character to be output */
189 long qty; /* number of characters to be output */
190 _char_ font; /* font of character */
191 long offset; /* buffer offset of ch, or -1 if not from buffer */
192 {
193 WINDOW win;
194 long delta;
195 CHAR ch;
8d1ac0c @mbert Import Elvis 2.1 (written by Steve Kirkendall)
authored
196 char lnumstr[20];
cf92e3b @mbert Import Elvis 2.0 (written by Steve Kirkendall)
authored
197
198 /* A negative qty indicates that the character *p is to be repeated.
199 */
200 if (qty < 0)
201 {
202 delta = 0;
203 qty = -qty;
204 }
205 else
206 {
207 delta = 1;
208 }
209
210 for ( ; qty > 0; qty--, p += delta)
211 {
212 ch = *p;
213
214 /* VTAB is treated either as a '\f', or as two '\n's */
215 if (ch == '\013' || (o_lplines == 0 && ch == '\f'))
216 {
217 if (o_lplines == 0 || linesleft >= 5)
218 {
219 ch = '\n';
220 draw(&ch, 1L, font, offset);
221 }
222 else
223 {
224 ch = '\f';
225 }
226 }
227
8d1ac0c @mbert Import Elvis 2.1 (written by Steve Kirkendall)
authored
228 /* maybe output a line number */
229 if (column == 0 /* at start of line */
230 && o_lpnumber /* "lpnumber" option is set */
231 && offset >= -1 /* not doing header or line number */
232 && ch != '\f') /* character isn't formfeed */
233 {
234 /* output a line number */
235 sprintf(lnumstr, "%6ld ", lnum);
236 draw(toCHAR(lnumstr), 8, 'n', -2L);
237 }
238
cf92e3b @mbert Import Elvis 2.0 (written by Steve Kirkendall)
authored
239 /* if line is too long, then wrap it or clip it */
240 if (o_lpcolumns > 0 && column >= o_lpcolumns && ch != '\f' && ch != '\n')
241 {
242 /* if we're supposed to clip, then just ignore this char */
243 if (!o_lpwrap)
244 {
245 continue;
246 }
247
248 /* else insert a newline */
249 if (o_lpcrlf)
250 {
251 (*type->fontch)(font, '\r');
252 }
253 (*type->fontch)(font, '\n');
254
255 /* that newline has the side-effects of incrementing the line
256 * number and resetting the column number.
257 */
258 linesleft--;
259 column = 0;
260 }
261
262 /* FF is treated specially, below */
263 if (ch != '\f')
264 {
265 /* maybe convert newline to CR-LF */
266 if (ch == '\n' && o_lpcrlf)
267 {
268 (*type->fontch)(font, '\r');
269 }
270
271 /* pass the character to the LP driver */
272 (*type->fontch)(font, ch);
273
9f1c6f0 @mbert Import Elvis 2.2_0 (written by Steve Kirkendall)
authored
274 /* if the character was newline, then decrement the
275 * number of lines left on this page, and reset the
276 * column to 0.
cf92e3b @mbert Import Elvis 2.0 (written by Steve Kirkendall)
authored
277 */
278 if (ch == '\n')
279 {
280 linesleft--;
281 column = 0;
282 }
283 else /* must have been a normal printable character */
284 {
285 column++;
9f1c6f0 @mbert Import Elvis 2.2_0 (written by Steve Kirkendall)
authored
286 anytext = ElvTrue;
cf92e3b @mbert Import Elvis 2.0 (written by Steve Kirkendall)
authored
287 }
288 }
289
290 if ((ch == '\f' && anytext) || (o_lplines > 0 && linesleft <= 1))
291 {
292 /* End the line, if it has any characters in it */
293 if (column > 0)
294 {
295 (*type->fontch)('n', '\n');
296 column = 0;
297 linesleft--;
298 }
299
300 /* End this page */
301 (*type->page)(linesleft);
302 linesleft = o_lplines;
303
304 /* Start the next page by calling the mode's header() function.
305 * This can cause this draw() function to be called recursively.
306 * If the header is larger than the page size, we could
307 * potentially get stuck in a loop. To avoid this, we will
308 * temporarily set prwin to NULL.
309 */
310 pagenum++;
311 if (prwin && prwin->md->header)
312 {
313 win = prwin;
314 prwin = NULL;
315 (*win->md->header)(win, pagenum, win->mi, draw);
316 prwin = win;
317 }
9f1c6f0 @mbert Import Elvis 2.2_0 (written by Steve Kirkendall)
authored
318 anytext = ElvFalse;
cf92e3b @mbert Import Elvis 2.0 (written by Steve Kirkendall)
authored
319 }
320 }
321 }
322
323 /* This function performs printing. */
324 RESULT lp(win, top, bottom, force)
325 WINDOW win; /* window where print request was generated */
326 MARK top; /* start of text to be printed */
327 MARK bottom; /* end of text to be printed */
9f1c6f0 @mbert Import Elvis 2.2_0 (written by Steve Kirkendall)
authored
328 ELVBOOL force; /* allow an existing file to be clobbered? */
cf92e3b @mbert Import Elvis 2.0 (written by Steve Kirkendall)
authored
329 {
330 long oldcurs;
331 MARK next;
8d1ac0c @mbert Import Elvis 2.1 (written by Steve Kirkendall)
authored
332 CHAR *origdisplay = NULL;
333 char *out;
334 char rwa;
cf92e3b @mbert Import Elvis 2.0 (written by Steve Kirkendall)
authored
335
336 /* convert the value of o_lptype to an LPTYPE pointer */
337 type = findtype(tochar8(o_lptype));
338 if (!type)
339 {
340 msg(MSG_ERROR, "bad lptype");
341 return RESULT_ERROR;
342 }
343
8d1ac0c @mbert Import Elvis 2.1 (written by Steve Kirkendall)
authored
344 /* Switch to the bufdisplay display mode, if not that way already */
345 if (CHARcmp(o_display(win), o_bufdisplay(markbuffer(top))))
346 {
347 origdisplay = CHARdup(o_display(win));
348 if (!dispset(win, tochar8(o_bufdisplay(markbuffer(top)))))
349 {
350 safefree(origdisplay);
351 return RESULT_ERROR;
352 }
353 }
354
cf92e3b @mbert Import Elvis 2.0 (written by Steve Kirkendall)
authored
355 /* Call the mode's setup function. Pretend the cursor is at the
356 * top of the print region, so setup() doesn't try to scroll.
357 */
8d1ac0c @mbert Import Elvis 2.1 (written by Steve Kirkendall)
authored
358 next = (*win->md->setup)(win, top, markoffset(top), bottom, win->mi);
cf92e3b @mbert Import Elvis 2.0 (written by Steve Kirkendall)
authored
359
360 /* open file or filter program */
361 if (type->spooled)
362 {
8d1ac0c @mbert Import Elvis 2.1 (written by Steve Kirkendall)
authored
363 rwa = 'w';
364 out = tochar8(o_lpout);
365 if (!out || !*out)
cf92e3b @mbert Import Elvis 2.0 (written by Steve Kirkendall)
authored
366 {
367 msg(MSG_ERROR, "must set lpout");
8d1ac0c @mbert Import Elvis 2.1 (written by Steve Kirkendall)
authored
368 goto Error;
cf92e3b @mbert Import Elvis 2.0 (written by Steve Kirkendall)
authored
369 }
8d1ac0c @mbert Import Elvis 2.1 (written by Steve Kirkendall)
authored
370 if (out[0] == '>' && out[1] == '>')
371 out += 2, rwa = 'a';
9f1c6f0 @mbert Import Elvis 2.2_0 (written by Steve Kirkendall)
authored
372 if (!ioopen(out, rwa, ElvTrue, force, 'b'))
cf92e3b @mbert Import Elvis 2.0 (written by Steve Kirkendall)
authored
373 {
8d1ac0c @mbert Import Elvis 2.1 (written by Steve Kirkendall)
authored
374 goto Error;
cf92e3b @mbert Import Elvis 2.0 (written by Steve Kirkendall)
authored
375 }
376 }
377
378 /* allocate the I/O buffer */
379 iomax = 1024;
380 iobuf = (CHAR *)safealloc(iomax, sizeof(CHAR));
381 ionext = 0;
382
383 /* initialize the LP driver */
384 #if defined (GUI_WIN32)
385 if (strcmp (o_lptype, "windows") == 0)
9f1c6f0 @mbert Import Elvis 2.2_0 (written by Steve Kirkendall)
authored
386 (*type->before)(type->minorno, dummyprt);
cf92e3b @mbert Import Elvis 2.0 (written by Steve Kirkendall)
authored
387 else
388 #endif
389 (*type->before)(type->minorno, prtchar);
390
391 /* start the first page */
392 pagenum = 1;
393 linesleft = o_lplines;
394 column = 0;
395 prwin = win;
396 if (win->md->header)
397 {
398 (*win->md->header)(win, pagenum, win->mi, draw);
399 }
9f1c6f0 @mbert Import Elvis 2.2_0 (written by Steve Kirkendall)
authored
400 anytext = ElvFalse;
cf92e3b @mbert Import Elvis 2.0 (written by Steve Kirkendall)
authored
401
402 /* generate image lines, and send them to the printer. Temporarily
403 * move the cursor to the end of the buffer so it doesn't affect
404 * the appearance of the text.
405 */
406 oldcurs = markoffset(win->cursor);
407 marksetoffset(win->cursor, o_bufchars(markbuffer(win->cursor)));
408 while (markoffset(next) < markoffset(bottom))
409 {
8d1ac0c @mbert Import Elvis 2.1 (written by Steve Kirkendall)
authored
410 lnum = markline(next);
cf92e3b @mbert Import Elvis 2.0 (written by Steve Kirkendall)
authored
411 next = (*win->md->image)(win, next, win->mi, draw);
412 }
413 marksetoffset(win->cursor, oldcurs);
414
415 /* end the printout */
416 (*type->after)(linesleft);
417
418 /* end the I/O */
419 if (ionext > 0)
420 {
421 iowrite(iobuf, ionext);
422 }
423 safefree(iobuf);
9f1c6f0 @mbert Import Elvis 2.2_0 (written by Steve Kirkendall)
authored
424 if (type->spooled && !ioclose())
8d1ac0c @mbert Import Elvis 2.1 (written by Steve Kirkendall)
authored
425 goto Error;
426
427 /* clean up and return success */
428 if (origdisplay)
cf92e3b @mbert Import Elvis 2.0 (written by Steve Kirkendall)
authored
429 {
8d1ac0c @mbert Import Elvis 2.1 (written by Steve Kirkendall)
authored
430 (void)dispset(win, tochar8(origdisplay));
431 safefree(origdisplay);
cf92e3b @mbert Import Elvis 2.0 (written by Steve Kirkendall)
authored
432 }
9f1c6f0 @mbert Import Elvis 2.2_0 (written by Steve Kirkendall)
authored
433 msg(MSG_STATUS, "[d]$1 pages", (long)pagenum);
8d1ac0c @mbert Import Elvis 2.1 (written by Steve Kirkendall)
authored
434 return RESULT_COMPLETE;
435
436 Error:
437 /* clean up and return failure */
438 if (origdisplay)
cf92e3b @mbert Import Elvis 2.0 (written by Steve Kirkendall)
authored
439 {
8d1ac0c @mbert Import Elvis 2.1 (written by Steve Kirkendall)
authored
440 (void)dispset(win, tochar8(origdisplay));
441 safefree(origdisplay);
cf92e3b @mbert Import Elvis 2.0 (written by Steve Kirkendall)
authored
442 }
8d1ac0c @mbert Import Elvis 2.1 (written by Steve Kirkendall)
authored
443 return RESULT_ERROR;
cf92e3b @mbert Import Elvis 2.0 (written by Steve Kirkendall)
authored
444 }
8d1ac0c @mbert Import Elvis 2.1 (written by Steve Kirkendall)
authored
445 #endif /* FEATURE_LPR */
Something went wrong with that request. Please try again.