1 /*
2  * Copyright (c) 1993-2014, 2019 Paul Mattes.
3  * Copyright (c) 1990, Jeff Sparkes.
4  * Copyright (c) 1989, Georgia Tech Research Corporation (GTRC), Atlanta, GA
5  *  30332.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  *     * Redistributions of source code must retain the above copyright
11  *       notice, this list of conditions and the following disclaimer.
12  *     * Redistributions in binary form must reproduce the above copyright
13  *       notice, this list of conditions and the following disclaimer in the
14  *       documentation and/or other materials provided with the distribution.
15  *     * Neither the names of Paul Mattes, Jeff Sparkes, GTRC nor the names of
16  *       their contributors may be used to endorse or promote products derived
17  *       from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY PAUL MATTES, JEFF SPARKES AND GTRC "AS IS" AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL PAUL MATTES, JEFF SPARKES OR GTRC BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  *	ctlr.c
34  *		This module handles interpretation of the 3270 data stream and
35  *		maintenance of the 3270 device state.
36  *
37  */
38 
39 #include <stdio.h>
40 #include <errno.h>
41 #include <string.h>
42 #if !defined(_MSC_VER) /*[*/
43 #include <unistd.h>
44 #endif /*]*/
45 #include <stdlib.h>
46 #include <sys/types.h>
47 #if !defined(_WIN32) /*[*/
48 #include <sys/wait.h>
49 #endif /*]*/
50 #include <signal.h>
51 #include "globals.h"
52 #include "pr3287.h"
53 #include "3270ds.h"
54 #include "codepage.h"
55 #include "ctlrc.h"
56 #include "trace.h"
57 #include "sf.h"
58 #include "tables.h"
59 #include "unicodec.h"
60 #include "xtablec.h"
61 #if defined(_WIN32) /*[*/
62 #include "wsc.h"
63 #include <windows.h>
64 #endif /*]*/
65 
66 #define CS_GE 0x04	/* hack */
67 
68 #define WCC_LINE_LENGTH(c)		((c) & 0x30)
69 #define WCC_132				0x00
70 #define WCC_40				0x10
71 #define WCC_64				0x20
72 #define WCC_80				0x30
73 
74 #define MAX_BUF				(MAX_UNF_MPP * MAX_UNF_MPP) /* swag */
75 
76 #define VISIBLE		0x01	/* visible field */
77 #define INVISIBLE	0x02	/* invisible field */
78 
79 #define BUFSZ		4096
80 
81 #define FCORDER_NOP	0x0001	/* dummy filler for DBCS right half */
82 
83 static const char *ll_name[] = { "unformatted132", "formatted40", "formatted64", "formatted80" };
84 static int ll_len[] = { 132, 40, 64, 80 };
85 
86 /* 3270 (formatted mode) data */
87 static unsigned char default_gr;
88 static unsigned char default_cs;
89 static int line_length;
90 static ucs4_t page_buf[MAX_BUF];
91 static unsigned char *xlate_buf[MAX_BUF];
92 int xlate_len[MAX_BUF];
93 static int baddr = 0;
94 static bool page_buf_initted = false;
95 static bool any_3270_printable = false;
96 static int any_3270_output = 0;
97 #if !defined(_WIN32) /*[*/
98 static FILE *prfile = NULL;
99 static int prpid = -1;
100 #else /*][*/
101 static int ws_initted = 0;
102 static int ws_needpre = 1;
103 #endif /*]*/
104 static unsigned char wcc_line_length;
105 
106 static int ctlr_erase(void);
107 static int dump_formatted(void);
108 static int dump_unformatted(void);
109 static int stash(unsigned char c);
110 static int prflush(void);
111 static int copyfile(const char *filename);
112 
113 #define DECODE_BADDR(c1, c2) \
114     ((((c1) & 0xC0) == 0x00) ? \
115     (((c1) & 0x3F) << 8) | (c2) : \
116     (((c1) & 0x3F) << 6) | ((c2) & 0x3F))
117 
118 /* SCS constants and data. */
119 #define MAX_MPP	132
120 #define MAX_MPL	108
121 
122 static ucs4_t linebuf[MAX_MPP+1];
123 static struct {
124     unsigned malloc_len;
125     unsigned data_len;
126     char *buf;
127 } trnbuf[MAX_MPP+1];
128 static char htabs[MAX_MPP+1];
129 static char vtabs[MAX_MPL+1];
130 static int lm, tm, bm, mpp, mpl, scs_any;
131 static int pp;
132 static int line;
133 static bool scs_initted = false;
134 static bool any_scs_output = false;
135 static size_t scs_leftover_len = 0;
136 static int scs_leftover_buf[256];
137 static int scs_dbcs_subfield = 0;
138 static unsigned char scs_dbcs_c1 = 0;
139 static unsigned scs_cs = 0;
140 static bool ffeoj_last = false;
141 
142 /*
143 * Interpret an incoming 3270 command.
144 */
145 enum pds
process_ds(unsigned char * buf,size_t buflen)146 process_ds(unsigned char *buf, size_t buflen)
147 {
148     if (!buflen) {
149 	return PDS_OKAY_NO_OUTPUT;
150     }
151 
152     trace_ds("< ");
153 
154     switch (buf[0]) {	/* 3270 command */
155     case CMD_EAU:	/* erase all unprotected */
156     case SNA_CMD_EAU:
157 	trace_ds("EraseAllUnprotected\n");
158 	if (ctlr_erase() < 0 || prflush() < 0) {
159 	    return PDS_FAILED;
160 	}
161 	return PDS_OKAY_NO_OUTPUT;
162     case CMD_EWA:	/* erase/write alternate */
163     case SNA_CMD_EWA:
164 	trace_ds("EraseWriteAlternate");
165 	if (ctlr_erase() < 0 || prflush() < 0) {
166 	    return PDS_FAILED;
167 	}
168 	baddr = 0;
169 	ctlr_write(buf, buflen, true);
170 	return PDS_OKAY_NO_OUTPUT;
171     case CMD_EW:	/* erase/write */
172     case SNA_CMD_EW:
173 	trace_ds("EraseWrite");
174 	if (ctlr_erase() < 0 || prflush() < 0) {
175 	    return PDS_FAILED;
176 	}
177 	baddr = 0;
178 	ctlr_write(buf, buflen, true);
179 	return PDS_OKAY_NO_OUTPUT;
180     case CMD_W:	/* write */
181     case SNA_CMD_W:
182 	trace_ds("Write");
183 	ctlr_write(buf, buflen, false);
184 	return PDS_OKAY_NO_OUTPUT;
185     case CMD_RB:	/* read buffer */
186     case SNA_CMD_RB:
187 	trace_ds("ReadBuffer\n");
188 	return PDS_BAD_CMD;
189     case CMD_RM:	/* read modifed */
190     case SNA_CMD_RM:
191 	trace_ds("ReadModified\n");
192 	return PDS_BAD_CMD;
193     case CMD_RMA:	/* read modifed all */
194     case SNA_CMD_RMA:
195 	trace_ds("ReadModifiedAll\n");
196 	return PDS_BAD_CMD;
197     case CMD_WSF:	/* write structured field */
198     case SNA_CMD_WSF:
199 	trace_ds("WriteStructuredField");
200 	return write_structured_field(buf, buflen);
201     case CMD_NOP:	/* no-op */
202 	trace_ds("NoOp\n");
203 	return PDS_OKAY_NO_OUTPUT;
204     default:
205 	/* unknown 3270 command */
206 	errmsg("Unknown 3270 Data Stream command: 0x%X", buf[0]);
207 	return PDS_BAD_CMD;
208     }
209 }
210 
211 /*
212  * Process a 3270 Write command.
213  */
214 void
ctlr_write(unsigned char buf[],size_t buflen,bool erase)215 ctlr_write(unsigned char buf[], size_t buflen, bool erase)
216 {
217     unsigned char *cp;
218     bool wcc_keyboard_restore, wcc_sound_alarm;
219     bool wcc_start_printer;
220     bool ra_ge;
221     int i;
222     unsigned char na;
223     int any_fa;
224     ucs4_t ra_xlate = 0;
225     const char *paren = "(";
226     int xbaddr;
227     enum { NONE, ORDER, SBA, TEXT, NULLCH } previous = NONE;
228 
229 #define END_TEXT0	{ if (previous == TEXT) trace_ds("'"); }
230 #define END_TEXT(cmd)	{ END_TEXT0; trace_ds(" %s", cmd); }
231 
232 #define START_FIELD(fa) { \
233 	    ctlr_add(0, FA_IS_ZERO(fa)?INVISIBLE:VISIBLE, 0, default_gr); \
234 	    trace_ds(see_attr(fa)); \
235 	}
236 
237     if (buflen < 2) {
238 	return;
239     }
240 
241     if (!page_buf_initted) {
242 	memset(page_buf, '\0', MAX_BUF * sizeof(ucs4_t));
243 	memset(xlate_buf, '\0', MAX_BUF * sizeof(unsigned char *));
244 	memset(xlate_len, '\0', MAX_BUF * sizeof(int));
245 	page_buf_initted = true;
246 	baddr = 0;
247     }
248 
249     default_gr = 0;
250     default_cs = 0;
251 
252     if (WCC_RESET(buf[1])) {
253 	trace_ds("%sreset", paren);
254 	paren = ",";
255     }
256     wcc_line_length = WCC_LINE_LENGTH(buf[1]);
257     if (wcc_line_length) {
258 	trace_ds("%s%s", paren, ll_name[wcc_line_length >> 4]);
259 	paren = ",";
260     } else {
261 	trace_ds("%sunformatted", paren);
262 	paren = ",";
263     }
264     line_length = ll_len[wcc_line_length >> 4];
265     wcc_sound_alarm = WCC_SOUND_ALARM(buf[1]);
266     if (wcc_sound_alarm) {
267 	trace_ds("%salarm", paren);
268 	paren = ",";
269     }
270     wcc_keyboard_restore = WCC_KEYBOARD_RESTORE(buf[1]);
271     if (wcc_keyboard_restore) {
272 	trace_ds("%srestore", paren);
273 	paren = ",";
274     }
275 
276     if (WCC_RESET_MDT(buf[1])) {
277 	trace_ds("%sresetMDT", paren);
278 	paren = ",";
279     }
280     wcc_start_printer = WCC_START_PRINTER(buf[1]);
281     if (wcc_start_printer) {
282 	trace_ds("%sstartprinter", paren);
283 	paren = ",";
284     }
285     if (strcmp(paren, "(")) {
286 	trace_ds(")");
287     }
288 
289     for (cp = &buf[2]; cp < (buf + buflen); cp++) {
290 	switch (*cp) {
291 	case ORDER_SF:	/* start field */
292 	    END_TEXT("StartField");
293 	    previous = ORDER;
294 	    cp++;		/* skip field attribute */
295 	    START_FIELD(*cp);
296 	    break;
297 	case ORDER_SBA:	/* set buffer address */
298 	    cp += 2;	/* skip buffer address */
299 	    xbaddr = DECODE_BADDR(*(cp - 1), *cp);
300 	    END_TEXT("SetBufferAddress");
301 	    if (wcc_line_length) {
302 		trace_ds("(%d,%d)", 1 + (xbaddr / line_length),
303 			1 + (xbaddr % line_length));
304 	    } else {
305 		    trace_ds("(%d[%+d])", xbaddr, xbaddr - baddr);
306 	    }
307 	    if (xbaddr >= MAX_BUF) {
308 		/* Error! */
309 		baddr = 0;
310 		return;
311 	    }
312 	    if (wcc_line_length) {
313 		/* Formatted. */
314 		baddr = xbaddr;
315 	    } else if (xbaddr > baddr) {
316 		/* Unformatted. */
317 		while (baddr < xbaddr) {
318 		    ctlr_add(0, ' ', default_cs, default_gr);
319 		}
320 	    }
321 	    previous = SBA;
322 	    break;
323 	case ORDER_IC:	/* insert cursor */
324 	    END_TEXT("InsertCursor");
325 	    previous = ORDER;
326 	    break;
327 	case ORDER_PT:	/* program tab */
328 	    END_TEXT("ProgramTab");
329 	    previous = ORDER;
330 	    break;
331 	case ORDER_RA:	/* repeat to address */
332 	    cp += 2;	/* skip buffer address */
333 	    xbaddr = DECODE_BADDR(*(cp-1), *cp);
334 	    END_TEXT("RepeatToAddress");
335 	    if (wcc_line_length) {
336 		trace_ds("(%d,%d)", 1 + (xbaddr / line_length),
337 			1 + (xbaddr % line_length));
338 	    } else {
339 		trace_ds("(%d[%+d])", xbaddr, xbaddr - baddr);
340 	    }
341 	    cp++;		/* skip char to repeat */
342 	    if (*cp == ORDER_GE){
343 		ra_ge = true;
344 		trace_ds("GraphicEscape");
345 		cp++;
346 	    } else {
347 		ra_ge = false;
348 	    }
349 	    trace_ds("'%s'", see_ebc(*cp));
350 	    previous = ORDER;
351 	    if (xbaddr > MAX_BUF || xbaddr < baddr) {
352 		baddr = 0;
353 		return;
354 	    }
355 	    /* Translate '*cp' once. */
356 	    switch (*cp) {
357 	    case FCORDER_FF:
358 	    case FCORDER_CR:
359 	    case FCORDER_NL:
360 	    case FCORDER_EM:
361 		ra_xlate = *cp;
362 		break;
363 	    default:
364 		if (*cp <= 0x3F) {
365 		    ra_xlate = '\0';
366 		} else {
367 		    ra_xlate = ebcdic_to_unicode(*cp, ra_ge? CS_GE: CS_BASE,
368 			    EUO_NONE);
369 		}
370 		break;
371 	    }
372 	    while (baddr < xbaddr) {
373 		ctlr_add(ra_ge? 0: *cp, ra_xlate, ra_ge? CS_GE: default_cs,
374 			default_gr);
375 	    }
376 	    break;
377 	case ORDER_EUA:	/* erase unprotected to address */
378 	    cp += 2;	/* skip buffer address */
379 	    xbaddr = DECODE_BADDR(*(cp-1), *cp);
380 	    END_TEXT("EraseUnprotectedAll");
381 	    previous = ORDER;
382 	    break;
383 	case ORDER_GE:	/* graphic escape */
384 	    END_TEXT("GraphicEscape ");
385 	    cp++;		/* skip char */
386 	    previous = ORDER;
387 	    if (*cp) {
388 		trace_ds("'");
389 	    }
390 	    trace_ds("%s", see_ebc(*cp));
391 	    if (*cp) {
392 		trace_ds("'");
393 	    }
394 	    ctlr_add(0, ebcdic_to_unicode(*cp, CS_GE, EUO_NONE), CS_GE,
395 		    default_gr);
396 	    break;
397 	case ORDER_MF:	/* modify field */
398 	    END_TEXT("ModifyField");
399 	    previous = ORDER;
400 	    cp++;
401 	    na = *cp;
402 	    cp += na * 2;
403 	    break;
404 	case ORDER_SFE:	/* start field extended */
405 	    END_TEXT("StartFieldExtended");
406 	    previous = ORDER;
407 	    cp++;	/* skip order */
408 	    na = *cp;
409 	    any_fa = 0;
410 
411 	    for (i = 0; i < (int)na; i++) {
412 		cp++;
413 		if (*cp == XA_3270) {
414 		    trace_ds(" 3270");
415 		    cp++;
416 		    START_FIELD(*cp);
417 		    any_fa++;
418 		} else if (*cp == XA_FOREGROUND) {
419 		    trace_ds("%s", see_efa(*cp, *(cp + 1)));
420 		    cp++;
421 		} else if (*cp == XA_HIGHLIGHTING) {
422 		    trace_ds("%s", see_efa(*cp, *(cp + 1)));
423 		    cp++;
424 		} else if (*cp == XA_CHARSET) {
425 		    trace_ds("%s", see_efa(*cp, *(cp + 1)));
426 		    cp++;
427 		} else if (*cp == XA_ALL) {
428 		    trace_ds("%s", see_efa(*cp, *(cp + 1)));
429 		    cp++;
430 		} else {
431 		    trace_ds("%s[unsupported]", see_efa(*cp, *(cp + 1)));
432 		    cp++;
433 		}
434 	    }
435 	    if (!any_fa) {
436 		START_FIELD(0);
437 	    }
438 	    ctlr_add(0, '\0', 0, default_gr);
439 	    break;
440 	case ORDER_SA:	/* set attribute */
441 	    END_TEXT("SetAttribtue");
442 	    previous = ORDER;
443 	    cp++;
444 	    if (*cp == XA_FOREGROUND)  {
445 		trace_ds("%s", see_efa(*cp, *(cp + 1)));
446 	    } else if (*cp == XA_HIGHLIGHTING)  {
447 		trace_ds("%s", see_efa(*cp, *(cp + 1)));
448 		default_gr = *(cp + 1) & 0x07;
449 	    } else if (*cp == XA_ALL)  {
450 		trace_ds("%s", see_efa(*cp, *(cp + 1)));
451 		default_gr = 0;
452 		default_cs = 0;
453 	    } else if (*cp == XA_CHARSET) {
454 		trace_ds("%s", see_efa(*cp, *(cp + 1)));
455 		default_cs = (*(cp + 1) == 0xf1) ? 1 : 0;
456 	    } else {
457 		trace_ds("%s[unsupported]", see_efa(*cp, *(cp + 1)));
458 	    }
459 	    cp++;
460 	    break;
461 	case FCORDER_FF:	/* Form Feed */
462 	    END_TEXT("FF");
463 	    previous = ORDER;
464 	    ctlr_add(0, FCORDER_FF, default_cs, default_gr);
465 	    break;
466 	case FCORDER_CR:	/* Carriage Return */
467 	    END_TEXT("CR");
468 	    previous = ORDER;
469 	    ctlr_add(0, FCORDER_CR, default_cs, default_gr);
470 	    break;
471 	case FCORDER_NL:	/* New Line */
472 	    END_TEXT("NL");
473 	    previous = ORDER;
474 	    ctlr_add(0, FCORDER_NL, default_cs, default_gr);
475 	    break;
476 	case FCORDER_EM:	/* End of Media */
477 	    END_TEXT("EM");
478 	    previous = ORDER;
479 	    ctlr_add(0, FCORDER_EM, default_cs, default_gr);
480 	    break;
481 	case FCORDER_DUP:	/* Visible control characters */
482 	case FCORDER_FM:
483 	    END_TEXT(see_ebc(*cp));
484 	    previous = ORDER;
485 	    ctlr_add(0, ebc2asc0[*cp], default_cs, default_gr);
486 	    break;
487 	case FCORDER_SUB:	/* misc format control orders */
488 	case FCORDER_EO:
489 	    END_TEXT(see_ebc(*cp));
490 	    previous = ORDER;
491 	    ctlr_add(0, '\0', default_cs, default_gr);
492 	    break;
493 	case FCORDER_NULL:
494 	    END_TEXT("NULL");
495 	    previous = NULLCH;
496 	    ctlr_add(0, '\0', default_cs, default_gr);
497 	    break;
498 	default:	/* enter character */
499 	    if (*cp <= 0x3F) {
500 		END_TEXT("ILLEGAL-ORDER ");
501 		previous = ORDER;
502 		ctlr_add(0, '\0', default_cs, default_gr);
503 		trace_ds("%s", see_ebc(*cp));
504 		break;
505 	    }
506 	    if (previous != TEXT) {
507 		trace_ds(" '");
508 	    }
509 	    previous = TEXT;
510 	    trace_ds("%s", see_ebc(*cp));
511 	    ctlr_add(*cp, ebcdic_to_unicode(*cp, default_cs, EUO_NONE),
512 		    default_cs, default_gr);
513 	    break;
514 	}
515     }
516 
517     trace_ds("\n");
518 }
519 
520 #undef START_FIELDx
521 #undef START_FIELD0
522 #undef START_FIELD
523 #undef END_TEXT0
524 #undef END_TEXT
525 
526 /*
527  * Process SCS (SNA Character Stream) data.
528  */
529 
530 /* Reinitialize the SCS virtual 3287. */
531 static void
init_scs_horiz(void)532 init_scs_horiz(void)
533 {
534     int i;
535 
536     mpp = MAX_MPP;
537     lm = 1;
538     htabs[1] = 1;
539     for (i = 2; i <= MAX_MPP; i++) {
540 	htabs[i] = 0;
541     }
542 }
543 
544 static void
init_scs_vert(void)545 init_scs_vert(void)
546 {
547     int i;
548 
549     mpl = 1;
550     tm = 1;
551     bm = mpl;
552     vtabs[1] = 1;
553     for (i = 0; i <= MAX_MPL; i++) {
554 	vtabs[i] = 0;
555     }
556 }
557 
558 static void
init_scs(void)559 init_scs(void)
560 {
561     int i;
562 
563     if (scs_initted) {
564 	return;
565     }
566 
567     trace_ds("Initializing SCS virtual 3287.\n");
568     init_scs_horiz();
569     init_scs_vert();
570     pp = 1;
571     line = 1;
572     scs_any = 0;
573     for (i = 0; i < MAX_MPP+1; i++) {
574 	linebuf[i] = ' ';
575     }
576     for (i = 0; i < MAX_MPP+1; i++) {
577 	if (trnbuf[i].malloc_len != 0) {
578 	    Free(trnbuf[i].buf);
579 	    trnbuf[i].buf = NULL;
580 	    trnbuf[i].malloc_len = 0;
581 	}
582 	trnbuf[i].data_len = 0;
583     }
584     scs_leftover_len = 0;
585     scs_dbcs_subfield = 0;
586     scs_dbcs_c1 = 0;
587     scs_cs = 0;
588 
589     scs_initted = true;
590 }
591 
592 #if defined(_WIN32) /*[*/
593 static int
unicode_to_printer(ucs4_t u,char mb[],int mb_len)594 unicode_to_printer(ucs4_t u, char mb[], int mb_len)
595 {
596     int nc;
597     wchar_t wuc = u;
598 
599     nc = WideCharToMultiByte(options.printercp, 0, &wuc, 1, mb, mb_len, NULL,
600 	    NULL);
601     if (nc > 0) {
602 	mb[nc++] = '\0';
603     }
604     return nc;
605 }
606 #endif /*[*/
607 
608 /*
609  * Our philosophy for automatic newlines and formfeeds is that we generate them
610  * only if the user attempts to put data outside the MPP/MPL-defined area.
611  * Therefore, the user can put a byte on the last column of each line, and on
612  * the last column of the last line of the page, and not need to worry about
613  * suppressing their own NL or FF.
614  */
615 
616 /*
617  * Dump and reset the current line.
618  * This will always result in at least one byte of output to the printer (a
619  * newline).  The 'line' variable is always incremented, and may end up
620  * pointing past the bottom margin.  The 'pp' variable is set to the left
621  * margin.
622  *
623  * We do not observe the -skipcc option with SCS data.
624  */
625 static int
dump_scs_line(bool reset_pp,bool always_nl)626 dump_scs_line(bool reset_pp, bool always_nl)
627 {
628     int i;
629     bool any_data = false;
630 
631     /* Find the last non-space character in the line buffer. */
632     for (i = mpp; i >= 1; i--) {
633 	if (trnbuf[i].data_len != 0 || linebuf[i] != ' ') {
634 	    break;
635 	}
636     }
637 
638     /*
639      * If there is data there, print it with a trailing newline and
640      * clear out the line buffer for next time.  If not, just print the
641      * newline.
642      */
643     if (i >= 1) {
644 	int j;
645 	int n_data = 0;
646 	int n_trn = 0;
647 	int k;
648 
649 	for (j = 1; j <= i; j++) {
650 	    /*
651 	     * Dump and transparent data that precedes this
652 	     * character.
653 	     */
654 	    if (trnbuf[j].data_len) {
655 		unsigned k;
656 
657 		n_trn += trnbuf[j].data_len;
658 		for (k = 0; k < trnbuf[j].data_len; k++) {
659 		    if (stash(trnbuf[j].buf[k]) < 0) {
660 			return -1;
661 		    }
662 		}
663 		trnbuf[j].data_len = 0;
664 	    }
665 	    if (j < i || linebuf[j] != ' ') {
666 		char mb[16];
667 		int len;
668 
669 		if (linebuf[j] == FCORDER_NOP) {
670 		    continue;
671 		}
672 		n_data++;
673 		any_data = true;
674 		scs_any = true;
675 #if !defined(_WIN32) /*[*/
676 		len = unicode_to_multibyte(linebuf[j], mb, sizeof(mb));
677 #else /*][*/
678 		len = unicode_to_printer(linebuf[j], mb, sizeof(mb));
679 #endif /*]*/
680 		if (len == 0) {
681 		    mb[0] = ' ';
682 		    len = 1;
683 		} else {
684 		    len--;
685 		}
686 		for (k = 0; k < len; k++) {
687 		    if (stash(mb[k]) < 0) {
688 			return -1;
689 		    }
690 		}
691 	    }
692 	}
693 #if defined(DEBUG_FF) /*[*/
694 	trace_ds(" [dumping %d+%dt]", n_data, n_trn);
695 #endif /*]*/
696 	for (k = 0; k < MAX_MPP+1; k++) {
697 	    linebuf[k] = ' ';
698 	}
699     }
700     if (any_data || always_nl) {
701 	if (options.crlf) {
702 	    if (stash('\r') < 0) {
703 		return -1;
704 	    }
705 	}
706 	if (stash('\n') < 0)
707 	return -1;
708 	line++;
709     }
710 #if defined(DEBUG_FF) /*[*/
711     trace_ds(" [line=%d]", line);
712 #endif /*]*/
713     if (reset_pp) {
714 	pp = lm;
715     }
716     any_scs_output = false;
717     return 0;
718 }
719 
720 /* SCS formfeed. */
721 static int
scs_formfeed(bool explicit)722 scs_formfeed(bool explicit)
723 {
724     int nls = 0;
725 
726     /*
727      * In ffskip mode, if it's an explicit formfeed, and we haven't
728      * printed any non-transparent data, do nothing.
729      */
730     if (options.ffskip && explicit && !scs_any) {
731 	return 0;
732     }
733 
734     /*
735      * In ffthru mode, pass through a \f, but only if it's explicit.
736      */
737     if (options.ffthru) {
738 	if (explicit) {
739 	    if (stash('\f') < 0) {
740 		return -1;
741 	    }
742 	    scs_any = 0;
743 	}
744 	line = 1;
745 	return 0;
746     }
747 
748     if (explicit) {
749 	scs_any = 0;
750     }
751 
752     if (mpl > 1) {
753 	/* Skip to the end of the physical page. */
754 	while (line <= mpl) {
755 	    if (options.crlf) {
756 		if (stash('\r') < 0) {
757 		    return -1;
758 		}
759 	    }
760 	    if (stash('\n') < 0) {
761 		return -1;
762 	    }
763 	    nls++;
764 	    line++;
765 	}
766 	line = 1;
767 
768 	/* Skip the top margin. */
769 	while (line < tm) {
770 	    if (options.crlf) {
771 		if (stash('\r') < 0) {
772 		    return -1;
773 		}
774 	    }
775 	    if (stash('\n') < 0) {
776 		return -1;
777 	    }
778 	    nls++;
779 	    line++;
780 	}
781 #if defined(DEBUG_FF) /*[*/
782 	if (nls) {
783 	    trace_ds(" [formfeed %s %d]", explicit?  "explicit": "implicit",
784 		    nls);
785 	}
786 #endif /*]*/
787     } else {
788 	line = 1;
789     }
790     return 0;
791 }
792 
793 /*
794  * Add a printable character to the SCS virtual 3287.
795  * If the line position is past the bottom margin, we will skip to the top of
796  * the next page.  If the character position is past the MPP, we will skip to
797  * the left margin of the next line.
798  */
799 static int
add_scs(ucs4_t c)800 add_scs(ucs4_t c)
801 {
802     /*
803      * They're about to print something.
804      * If the line is past the bottom margin, we need to skip to the
805      * MPL, and then past the top margin.
806      */
807     if (line > bm) {
808 	if (scs_formfeed(false) < 0) {
809 	    return -1;
810 	}
811     }
812 
813     /*
814      * If this character would overflow the line, then dump the current
815      * line and start over at the left margin.
816      */
817     if (pp > mpp) {
818 	if (dump_scs_line(true, true) < 0) {
819 	    return -1;
820 	}
821     }
822 
823     /*
824      * Store this character in the line buffer and advance the print
825      * position.
826      */
827     if (c != ' ') {
828 	linebuf[pp++] = c;
829     } else {
830 	pp++;
831     }
832     any_scs_output = true;
833     ffeoj_last = false;
834     return 0;
835 }
836 
837 /*
838  * Add a string of transparent data to the SCS virtual 3287.
839  * Transparent data lives between the 'counted' 3287 characters.  Really.
840  */
841 static void
add_scs_trn(unsigned char * cp,int cnt)842 add_scs_trn(unsigned char *cp, int cnt)
843 {
844     int i;
845     unsigned new_malloc_len;
846 
847     for (i = 0; i < cnt; i++) {
848 	trace_ds(" %02x", cp[i]);
849     }
850 
851     new_malloc_len = trnbuf[pp].data_len + cnt;
852     while (trnbuf[pp].malloc_len < new_malloc_len) {
853 	trnbuf[pp].malloc_len += BUFSZ;
854 	trnbuf[pp].buf = Realloc(trnbuf[pp].buf, trnbuf[pp].malloc_len);
855     }
856     memcpy(trnbuf[pp].buf + trnbuf[pp].data_len, cp, cnt);
857     trnbuf[pp].data_len += cnt;
858     any_scs_output = true;
859     ffeoj_last = true;
860 }
861 
862 /*
863  * Process a bufferful of SCS data.
864  *
865  * Note that unlike a 3270 Write command, even though the record is bounded
866  * by an EOR, the SCS data are not guaranteed to be complete.
867  *
868  * Rather than have a full FSM for every byte of every SCS order, we resort
869  * to the rather inefficient method of concatenating the previous, incomplete
870  * record with a copy of the new record, processing it as a contiguous
871  * buffer, and saving any incomplete order for next time.
872  */
873 
874 /*
875  * 'Internal' SCS function, called by process_scs() below with the previous
876  * leftover data plus the current buffer.
877  *
878  * If an incomplete order is detected, saves it in scs_leftover_buf for
879  * next time.
880  */
881 static enum pds
process_scs_contig(unsigned char * buf,size_t buflen)882 process_scs_contig(unsigned char *buf, size_t buflen)
883 {
884     unsigned char *cp;
885     int i;
886     int cnt;
887     int tab;
888     ucs4_t uc;
889     enum { NONE, DATA, ORDER } last = NONE;
890 #   define END_TEXT(s) { \
891 	    if (last == DATA) { \
892 		    trace_ds("'"); \
893 	    } \
894 	    trace_ds(" " s); \
895 	    last = ORDER; \
896     }
897 #   define LEFTOVER { \
898 	    trace_ds(" [pending]"); \
899 	    scs_leftover_len = buflen - (cp - buf); \
900 	    memcpy(scs_leftover_buf, cp, scs_leftover_len); \
901 	    cp = buf + buflen; \
902     }
903 
904     trace_ds("< ");
905 
906     init_scs();
907 
908     for (cp = &buf[0]; cp < (buf + buflen); cp++) {
909 	switch (*cp) {
910 	case SCS_BS:	/* back space */
911 	    END_TEXT("BS");
912 	    if (pp != 1) {
913 		pp--;
914 	    }
915 	    if (scs_dbcs_subfield && pp != 1) {
916 		pp--;
917 	    }
918 	    break;
919 	case SCS_CR:	/* carriage return */
920 	    END_TEXT("CR");
921 	    pp = lm;
922 	    break;
923 	case SCS_ENP:	/* enable presentation */
924 	    END_TEXT("ENP");
925 	    /* No-op. */
926 	    break;
927 	case SCS_FF:	/* form feed */
928 	    END_TEXT("FF");
929 	    /* Dump any pending data, and go to the next line. */
930 	    if (dump_scs_line(true, false) < 0) {
931 		return PDS_FAILED;
932 	    }
933 	    /*
934 	     * If there is a max page length, skip to the next
935 	     * page.
936 	     */
937 	    if (scs_formfeed(true) < 0) {
938 		return PDS_FAILED;
939 	    }
940 	    break;
941 	case SCS_HT:	/* horizontal tab */
942 	    END_TEXT("HT");
943 	    for (i = pp + 1; i <= mpp; i++) {
944 		if (htabs[i]) {
945 		    break;
946 		}
947 	    }
948 	    if (i <= mpp) {
949 		pp = i;
950 	    } else {
951 		if (add_scs(' ') < 0) {
952 		    return PDS_FAILED;
953 		}
954 	    }
955 	    break;
956 	case SCS_INP:	/* inhibit presentation */
957 	    END_TEXT("INP");
958 	    /* No-op. */
959 	    break;
960 	case SCS_IRS:	/* inter-record separator */
961 	    END_TEXT("IRS");
962 	case SCS_NL:	/* new line */
963 	    if (*cp == SCS_NL) {
964 		END_TEXT("NL");
965 	    }
966 	    if (dump_scs_line(true, true) < 0) {
967 		return PDS_FAILED;
968 	    }
969 	    break;
970 	case SCS_VT:	/* vertical tab */
971 	    END_TEXT("VT");
972 	    for (i = line + 1; i <= MAX_MPL; i++){
973 		if (vtabs[i]) {
974 		    break;
975 		}
976 	    }
977 	    if (i <= MAX_MPL) {
978 		if (dump_scs_line(false, true) < 0) {
979 		    return PDS_FAILED;
980 		}
981 		while (line < i) {
982 		    if (options.crlf) {
983 			if (stash('\r') < 0) {
984 			    return PDS_FAILED;
985 			}
986 		    }
987 		    if (stash('\n') < 0) {
988 			return PDS_FAILED;
989 		    }
990 		    line++;
991 		}
992 		break;
993 	    } else {
994 		/* fall through... */
995 	    }
996 	case SCS_VCS:	/* vertical channel select */
997 	    if (*cp == SCS_VCS) {
998 		END_TEXT("VCS");
999 	    }
1000 	    /* fall through... */
1001 	case SCS_LF:	/* line feed */
1002 	    if (*cp == SCS_LF)
1003 		    END_TEXT("LF");
1004 	    if (dump_scs_line(false, true) < 0)
1005 		    return PDS_FAILED;
1006 	    break;
1007 	case SCS_GE:	/* graphic escape */
1008 	    END_TEXT("GE");
1009 	    if ((cp + 1) >= buf + buflen) {
1010 		LEFTOVER;
1011 		break;
1012 	    }
1013 	    /* Skip over the order. */
1014 	    cp++;
1015 	    /* No support, so all characters are spaces. */
1016 	    trace_ds(" %02x", *cp);
1017 	    if (add_scs(' ') < 0) {
1018 		return PDS_FAILED;
1019 	    }
1020 	    break;
1021 	case SCS_SA:	/* set attribute */
1022 	    END_TEXT("SA");
1023 	    if ((cp + 2) >= buf + buflen) {
1024 		LEFTOVER;
1025 		break;
1026 	    }
1027 	    switch (*(cp + 1)) {
1028 	    case SCS_SA_RESET:
1029 		trace_ds(" Reset(%02x)", *(cp + 2));
1030 		scs_dbcs_subfield = 0;
1031 		scs_cs = 0;
1032 		break;
1033 	    case SCS_SA_HIGHLIGHT:
1034 		trace_ds(" Highlight(%02x)", *(cp + 2));
1035 		break;
1036 	    case SCS_SA_CS:
1037 		trace_ds(" CharacterSet(%02x)", *(cp + 2));
1038 		if (scs_cs != *(cp + 2)) {
1039 		    if (scs_cs == 0xf8) {
1040 			scs_dbcs_subfield = 0;
1041 		    } else if (*(cp + 2) == 0xf8) {
1042 			scs_dbcs_subfield = 1;
1043 		    }
1044 		    scs_cs = *(cp + 2);
1045 		}
1046 		break;
1047 	    case SCS_SA_GRID:
1048 		trace_ds(" Grid(%02x)", *(cp + 2));
1049 		break;
1050 	    default:
1051 		trace_ds(" Unknown(%02x %02x)", *(cp + 1), *(cp + 2));
1052 		break;
1053 	    }
1054 	    /* Skip it. */
1055 	    cp += 2;
1056 	    break;
1057 	case SCS_TRN:	/* transparent */
1058 	    END_TEXT("TRN");
1059 	    /* Make sure a length byte is present. */
1060 	    if ((cp + 1) >= buf + buflen) {
1061 		LEFTOVER;
1062 		break;
1063 	    }
1064 	    /* Skip over the order. */
1065 	    cp++;
1066 	    /*
1067 	     * Next byte is the length of the transparent data,
1068 	     * not including the length byte itself.
1069 	     */
1070 	    cnt = *cp;
1071 	    if (cp + cnt - 1 >= buf + buflen) {
1072 		cp--;
1073 		LEFTOVER;
1074 		break;
1075 	    }
1076 	    trace_ds("(%d)", cnt);
1077 	    /* Copy out the data literally. */
1078 	    add_scs_trn(cp+1, cnt);
1079 	    cp += cnt;
1080 	    scs_dbcs_subfield = 0;
1081 	    break;
1082 	case SCS_SET:	/* set... */
1083 	    /* Skip over the first byte of the order. */
1084 	    if (cp + 2 >= buf + buflen ||
1085 		cp + *(cp + 2) - 1 >= buf + buflen) {
1086 		END_TEXT("SET");
1087 		LEFTOVER;
1088 		break;
1089 	    }
1090 	    switch (*++cp) {
1091 	    case SCS_SHF:	/* set horizontal format */
1092 		END_TEXT("SHF");
1093 		/* Take defaults first. */
1094 		init_scs_horiz();
1095 		/*
1096 		 * The length is next.  It includes the
1097 		 * length field itself.
1098 		 */
1099 		cnt = *++cp;
1100 		trace_ds("(%d)", cnt);
1101 		if (cnt < 2) {
1102 		    break;	/* no more data */
1103 		}
1104 		/* Skip over the length byte. */
1105 		if (!--cnt || cp + 1 >= buf + buflen) {
1106 		    break;
1107 		}
1108 		/* The MPP is next. */
1109 		mpp = *++cp;
1110 		trace_ds(" mpp=%d", mpp);
1111 		if (!mpp || mpp > MAX_MPP) {
1112 		    mpp = MAX_MPP;
1113 		}
1114 		/* Skip over the MPP. */
1115 		if (!--cnt || cp + 1 >= buf + buflen) {
1116 		    break;
1117 		}
1118 		/* The LM is next. */
1119 		lm = *++cp;
1120 		trace_ds(" lm=%d", lm);
1121 		if (lm < 1 || lm >= mpp) {
1122 		    lm = 1;
1123 		}
1124 		/* Skip over the LM. */
1125 		if (!--cnt || cp + 1 >= buf + buflen) {
1126 		    break;
1127 		}
1128 		/* Skip over the RM. */
1129 		cp++;
1130 		trace_ds(" rm=%d", *cp);
1131 		/* Next are the tab stops. */
1132 		while (--cnt && cp + 1 < buf + buflen) {
1133 		    tab = *++cp;
1134 		    trace_ds(" tab=%d", tab);
1135 		    if (tab >= 1 && tab <= mpp) {
1136 			htabs[tab] = 1;
1137 		    }
1138 		}
1139 		break;
1140 	    case SCS_SLD:	/* set line density */
1141 		END_TEXT("SLD");
1142 		/*
1143 		 * Skip over the second byte of the
1144 		 * order.
1145 		 */
1146 		cp++;
1147 		/*
1148 		 * The length is next.  It does not
1149 		 * include length field itself.
1150 		 */
1151 		if (cp >= buf + buflen) {
1152 		    break;
1153 		}
1154 		cnt = *cp;
1155 		trace_ds("(%d)", cnt);
1156 		if (cnt != 2) {
1157 		    break; /* be gentle */
1158 		}
1159 		cnt--;
1160 		trace_ds(" %02x", *(cp + 1));
1161 		cp += cnt;
1162 		break;
1163 	    case SCS_SVF:	/* set vertical format */
1164 		END_TEXT("SVF");
1165 		/* Take defaults first. */
1166 		init_scs_vert();
1167 		/*
1168 		 * Skip over the second byte of the
1169 		 * order.
1170 		 */
1171 		cp++;
1172 		/*
1173 		 * The length is next.  It includes the
1174 		 * length field itself.
1175 		 */
1176 		if (cp >= buf + buflen) {
1177 		    break;
1178 		}
1179 		cnt = *cp;
1180 		trace_ds("(%d)", cnt);
1181 		if (cnt < 2) {
1182 		    break;	/* no more data */
1183 		}
1184 		/* Skip over the length byte. */
1185 		cp++;
1186 		cnt--;
1187 		if (!cnt || cp >= buf + buflen) {
1188 		    break;
1189 		}
1190 		/* The MPL is next. */
1191 		mpl = *cp;
1192 		trace_ds(" mpl=%d", mpl);
1193 		if (!mpl || mpl > MAX_MPL) {
1194 		    mpl = 1;
1195 		}
1196 		if (cnt < 2) {
1197 		    bm = mpl;
1198 		    break;
1199 		}
1200 		/* Skip over the MPL. */
1201 		cp++;
1202 		cnt--;
1203 		if (!cnt || cp >= buf + buflen) {
1204 		    break;
1205 		}
1206 		/* The TM is next. */
1207 		tm = *cp;
1208 		trace_ds(" tm=%d", tm);
1209 		if (tm < 1 || tm >= mpl) {
1210 		    tm = 1;
1211 		}
1212 		if (cnt < 2) {
1213 		    break;
1214 		}
1215 		/* Skip over the TM. */
1216 		cp++;
1217 		cnt--;
1218 		if (!cnt || cp >= buf + buflen) {
1219 		    break;
1220 		}
1221 		/* The BM is next. */
1222 		bm = *cp;
1223 		trace_ds(" bm=%d", bm);
1224 		if (bm < tm || bm >= mpl) {
1225 		    bm = mpl;
1226 		}
1227 		if (cnt < 2) {
1228 		    break;
1229 		}
1230 		/* Skip over the BM. */
1231 		cp++;
1232 		cnt--;
1233 		/* Next are the tab stops. */
1234 		while (cnt > 1 && cp < buf + buflen) {
1235 		    tab = *cp;
1236 		    trace_ds(" tab=%d", tab);
1237 		    if (tab >= 1 && tab <= mpp) {
1238 			vtabs[tab] = 1;
1239 		    }
1240 		    cp++;
1241 		    cnt--;
1242 		}
1243 		break;
1244 	    default:
1245 		END_TEXT("SET(?");
1246 		trace_ds("%02x)", *cp);
1247 		cp += *(cp + 1);
1248 		break;
1249 	    }
1250 	    break;
1251 	case SCS_SO:	/* DBCS subfield start */
1252 	    END_TEXT("SO");
1253 	    scs_dbcs_subfield = 1;
1254 	    break;
1255 	case SCS_SI:	/* DBCS subfield end */
1256 	    END_TEXT("SI");
1257 	    scs_dbcs_subfield = 0;
1258 	    break;
1259 	default:
1260 	    /*
1261 	     * Stray control codes are spaces, all else gets
1262 	     * translated from EBCDIC to ASCII.
1263 	     */
1264 	    if (*cp <= 0x3f) {
1265 		END_TEXT("?");
1266 		trace_ds("%02x", *cp);
1267 		if (add_scs(' ') < 0) {
1268 		    return PDS_FAILED;
1269 		}
1270 		break;
1271 	    }
1272 
1273 	    if (last == NONE) {
1274 		trace_ds("'");
1275 	    } else if (last == ORDER) {
1276 		trace_ds(" '");
1277 	    }
1278 	    if (scs_dbcs_subfield && dbcs) {
1279 		if (scs_dbcs_subfield % 2) {
1280 		    scs_dbcs_c1 = *cp;
1281 		} else {
1282 		    uc = ebcdic_to_unicode( (scs_dbcs_c1 << 8) | *cp, CS_BASE,
1283 			    EUO_NONE);
1284 		    if (uc == 0) {
1285 			/* No translation. */
1286 			trace_ds("?DBCS(X'%02x%02x')", scs_dbcs_c1, *cp);
1287 			if (add_scs(' ') < 0) {
1288 			    return PDS_FAILED;
1289 			}
1290 			if (add_scs(' ') < 0) {
1291 			    return PDS_FAILED;
1292 			}
1293 		    } else {
1294 			/*
1295 			 * Add the Unicode character
1296 			 * and a no-op to account for
1297 			 * the right-hand side.
1298 			 */
1299 			trace_ds("DBCS(X'%02x%02x')", scs_dbcs_c1, *cp);
1300 			if (add_scs(uc) < 0) {
1301 			    return PDS_FAILED;
1302 			}
1303 			if (add_scs(FCORDER_NOP) < 0) {
1304 				return PDS_FAILED;
1305 			}
1306 		    }
1307 		}
1308 		scs_dbcs_subfield++;
1309 		last = DATA;
1310 		break;
1311 	    }
1312 	    uc = ebcdic_to_unicode(*cp, CS_BASE, EUO_NONE);
1313 	    {
1314 		char mb[16];
1315 
1316 		unicode_to_multibyte(uc, mb, sizeof(mb));
1317 		trace_ds("%s", mb);
1318 	    }
1319 	    if (add_scs(uc) < 0) {
1320 		return PDS_FAILED;
1321 	    }
1322 	    last = DATA;
1323 	    break;
1324 	}
1325     }
1326 
1327     if (last == DATA) {
1328 	trace_ds("'");
1329     }
1330     trace_ds("\n");
1331     if (prflush() < 0) {
1332 	return PDS_FAILED;
1333     }
1334     return PDS_OKAY_NO_OUTPUT;
1335 }
1336 
1337 /*
1338  * 'External' SCS function.  Handles leftover data from any previous,
1339  * incomplete SCS record.
1340  */
1341 enum pds
process_scs(unsigned char * buf,size_t buflen)1342 process_scs(unsigned char *buf, size_t buflen)
1343 {
1344     enum pds r;
1345 
1346     if (scs_leftover_len) {
1347 	unsigned char *contig = Malloc(scs_leftover_len + buflen);
1348 	size_t total_len;
1349 
1350 	memcpy(contig, scs_leftover_buf, scs_leftover_len);
1351 	memcpy(contig + scs_leftover_len, buf, buflen);
1352 	total_len = scs_leftover_len + buflen;
1353 	scs_leftover_len = 0;
1354 	r = process_scs_contig(contig, total_len);
1355 	Free(contig);
1356     } else {
1357 	r = process_scs_contig(buf, buflen);
1358     }
1359     return r;
1360 }
1361 
1362 #if !defined(_WIN32) /*[*/
1363 /*
1364  * SIGCHLD handler.  Does nothing, but on systems that conform to the Single
1365  * Unix Specification, defining it ensures that the print command process will
1366  * become a zombie if it exits prematurely.
1367  */
1368 static void
sigchld_handler(int sig)1369 sigchld_handler(int sig)
1370 {
1371 }
1372 
1373 /*
1374  * Special version of popen where the child ignores SIGINT.
1375  */
1376 static FILE *
popen_no_sigint(const char * command)1377 popen_no_sigint(const char *command)
1378 {
1379     int fds[2];
1380     FILE *f;
1381 
1382     /* Create a pipe. */
1383     if (pipe(fds) < 0) {
1384 	return NULL;
1385     }
1386 
1387     /* Create a stdio stream from the write end. */
1388     f = fdopen(fds[1], "w");
1389     if (f == NULL) {
1390 	close(fds[0]);
1391 	close(fds[1]);
1392 	return NULL;
1393     }
1394 
1395     /* Handle SIGCHLD signals. */
1396     signal(SIGCHLD, sigchld_handler);
1397 
1398     /* Fork a child process. */
1399     switch ((prpid = fork())) {
1400     case 0:		/* child */
1401 	fclose(f);
1402 	dup2(fds[0], 0);
1403 	close(fds[1]);
1404 	signal(SIGINT, SIG_IGN);
1405 	execl("/bin/sh", "sh", "-c", command, NULL);
1406 
1407 	/* execl failed, return nonzero status */
1408 	exit(1);
1409 	break;
1410     case -1:	/* parent, error */
1411 	fclose(f);
1412 	close(fds[0]);
1413 	return NULL;
1414     default:	/* parent, success */
1415 	close(fds[0]);
1416 	break;
1417     }
1418 
1419     return f;
1420 }
1421 
1422 static int
pclose_no_sigint(FILE * f)1423 pclose_no_sigint(FILE *f)
1424 {
1425     int rc;
1426     int status;
1427 
1428     fclose(f);
1429     do {
1430 	rc = waitpid(prpid, &status, 0);
1431     } while (rc < 0 && errno == EINTR);
1432     prpid = -1;
1433     if (rc < 0) {
1434 	return rc;
1435     } else {
1436 	return status;
1437     }
1438 }
1439 #endif /*]*/
1440 
1441 /*
1442  * Send a character to the printer.
1443  */
1444 static int
stash(unsigned char c)1445 stash(unsigned char c)
1446 {
1447 #if defined(_WIN32) /*[*/
1448     if (!ws_initted) {
1449 	if (ws_start(options.printer) < 0) {
1450 	    return -1;
1451 	}
1452 	ws_initted = 1;
1453     }
1454     if (ws_needpre) {
1455 	if ((options.trnpre != NULL) && copyfile(options.trnpre) < 0) {
1456 	    return -1;
1457 	}
1458 	ws_needpre = 0;
1459     }
1460 
1461     trace_pdc(c);
1462     if (ws_putc((char)c)) {
1463 	return -1;
1464     }
1465 #else /*][*/
1466     if (prfile == NULL) {
1467 	prfile = popen_no_sigint(options.command);
1468 	if (prfile == NULL) {
1469 	    errmsg("%s: %s", options.command, strerror(errno));
1470 	    return -1;
1471 	}
1472 	if ((options.trnpre != NULL) && copyfile(options.trnpre) < 0) {
1473 	    pclose_no_sigint(prfile);
1474 	    prfile = NULL;
1475 	    return -1;
1476 	}
1477     }
1478 
1479     trace_pdc(c);
1480     if (fputc(c, prfile) == EOF) {
1481 	errmsg("Write error to '%s': %s", options.command, strerror(errno));
1482 	pclose_no_sigint(prfile);
1483 	prfile = NULL;
1484 	return -1;
1485     }
1486 #endif /*]*/
1487 
1488     return 0;
1489 }
1490 
1491 /*
1492  * Flush the pipe going to the printer process, to try to flush out any
1493  * pending errors.
1494  */
1495 static int
prflush(void)1496 prflush(void)
1497 {
1498 #if defined(_WIN32) /*[*/
1499     if (ws_initted && ws_flush() < 0) {
1500 	return -1;
1501     }
1502 #else /*][*/
1503     if (prfile != NULL) {
1504 	if (fflush(prfile) < 0) {
1505 	    errmsg("Flush error to '%s': %s", options.command, strerror(errno));
1506 	    pclose_no_sigint(prfile);
1507 	    prfile = NULL;
1508 	    return -1;
1509 	}
1510     }
1511 #endif /*]*/
1512     return 0;
1513 }
1514 
1515 /*
1516  * Change a character in the 3270 buffer.
1517  */
1518 void
ctlr_add(unsigned char ebc,ucs4_t c,unsigned char cs,unsigned char gr)1519 ctlr_add(unsigned char ebc, ucs4_t c, unsigned char cs, unsigned char gr)
1520 {
1521     /* Map control characters, according to the write mode. */
1522     if (c < ' ') {
1523 	if (wcc_line_length) {
1524 	    /*
1525 	     * When formatted, all control characters but FFs and
1526 	     * the funky VISIBLE/INVISIBLE controls are translated
1527 	     * to NULLs, so they don't display, and don't
1528 	     * contribute to empty lines.
1529 	     */
1530 	    if (c != FCORDER_FF && c != VISIBLE && c != INVISIBLE) {
1531 		c = '\0';
1532 	    }
1533 	} else {
1534 	    /*
1535 	     * Unformatted, all control characters but CR/NL/FF/EM
1536 	     * are displayed as spaces.
1537 	     */
1538 	    if (c != FCORDER_CR && c != FCORDER_NL &&
1539 		c != FCORDER_FF && c != FCORDER_EM) {
1540 		c = ' ';
1541 	    }
1542 	}
1543     }
1544 
1545     /* Add the character. */
1546     page_buf[baddr] = c;
1547     if (ebc >= 0x40)
1548 	    xlate_len[baddr] = xtable_lookup(ebc, &xlate_buf[baddr]);
1549     baddr = (baddr + 1) % MAX_BUF;
1550     any_3270_output = 1;
1551     ffeoj_last = false;
1552 
1553     /* Implement -emflush mode. */
1554     if (options.emflush && !wcc_line_length && c == FCORDER_EM) {
1555 	/* XXX: Unfortunately, we do not return error status here. */
1556 	dump_unformatted();
1557 	baddr = 1;
1558 	any_3270_output = 0;
1559     }
1560 }
1561 
1562 static struct {
1563     char buf;			/* printable data */
1564     unsigned char *trn;		/* transparent data */
1565     unsigned trn_len;		/* length of transparent data */
1566 } uo_data[MAX_UNF_MPP + 2];	/* room for full line plus carriage control */
1567 static unsigned uo_col;		/* current output column */
1568 static unsigned uo_maxcol;	/* maximum column buffered */
1569 static bool uo_last_cr = false; /* last data was CR */
1570 
1571 /*
1572  * Dump and free any transparent unformatted data at col.
1573  */
1574 static int
dump_uo_trn(unsigned col)1575 dump_uo_trn(unsigned col)
1576 {
1577     unsigned i;
1578     int rv = 0;
1579 
1580     if (uo_data[col].trn != NULL) {
1581 	for (i = 0; i < uo_data[col].trn_len; i++) {
1582 	    if (stash(uo_data[col].trn[i]) < 0) {
1583 		rv = -1;
1584 		break;
1585 	    }
1586 	}
1587 	Free(uo_data[col].trn);
1588 	uo_data[col].trn = NULL;
1589 	uo_data[col].trn_len = 0;
1590     }
1591     return rv;
1592 }
1593 
1594 /*
1595  * Dump pending unformatted output.
1596  */
1597 static int
dump_uo(void)1598 dump_uo(void)
1599 {
1600     unsigned i;
1601 
1602     for (i = 0; i < uo_maxcol; i++) {
1603 	if (dump_uo_trn(i) < 0) {
1604 	    return -1;
1605 	}
1606 	if (!i && options.skipcc) {
1607 	    continue;
1608 	}
1609 	if (stash(uo_data[i].buf) < 0) {
1610 	    return -1;
1611 	}
1612     }
1613     if (uo_maxcol < MAX_UNF_MPP + 2) {
1614 	if (dump_uo_trn(uo_maxcol) < 0) {
1615 	    return -1;
1616 	}
1617     }
1618     return 0;
1619 }
1620 
1621 /*
1622  * Unformatted output function.  Processes one character of output data.
1623  *
1624  * This function will buffer up to MPP characters of output, until it is
1625  * passed a '\n' or '\f' character.
1626  *
1627  * By default, it will process '\r' characters like a printer, i.e., it will
1628  * not overwrite a buffered non-space character with a space character.  This
1629  * is how an output line can span multiple 3270 unformatted write commands.
1630  *
1631  * If 'crthru' is set, '\r' characters simply trigger a buffer flush.
1632  */
1633 static int
uoutput(char c)1634 uoutput(char c)
1635 {
1636     switch (c) {
1637     case '\r':
1638 	if (options.crthru) {
1639 	    if (dump_uo() < 0) {
1640 		return -1;
1641 	    }
1642 	    if (stash(c) < 0) {
1643 		return -1;
1644 	    }
1645 	    uo_col = uo_maxcol = 0;
1646 	    uo_last_cr = true;
1647 	} else {
1648 	    uo_col = 0;
1649 	}
1650 	break;
1651     case '\n':
1652 	if (dump_uo() < 0) {
1653 	    return -1;
1654 	}
1655 	if (options.crlf && !uo_last_cr) {
1656 	    if (stash('\r') < 0) {
1657 		return -1;
1658 	    }
1659 	}
1660 	if (stash(c) < 0) {
1661 	    return -1;
1662 	}
1663 	uo_col = uo_maxcol = 0;
1664 	uo_last_cr = false;
1665 	break;
1666     case '\f':
1667 	uo_last_cr = false;
1668 	if (any_3270_printable || !options.ffskip) {
1669 	    if (dump_uo() < 0) {
1670 		return -1;
1671 	    }
1672 	    if (stash(c) < 0) {
1673 		return -1;
1674 	    }
1675 	}
1676 	uo_col = uo_maxcol = 0;
1677 	break;
1678     default:
1679 	uo_last_cr = false;
1680 
1681 	/* Don't overwrite with spaces. */
1682 	if (c == ' ') {
1683 	    if (uo_col >= uo_maxcol) {
1684 		uo_data[uo_col++].buf = c;
1685 	    } else {
1686 		uo_col++;
1687 	    }
1688 	} else {
1689 	    uo_data[uo_col++].buf = c;
1690 	    any_3270_printable = true;
1691 	}
1692 	if (uo_col > uo_maxcol) {
1693 	    uo_maxcol = uo_col;
1694 	}
1695 	break;
1696     }
1697     return 0;
1698 }
1699 
1700 /*
1701  * Add transparent data to the unformatted output buffer.
1702  */
1703 static void
uoutput_trn(const unsigned char * s,int len)1704 uoutput_trn(const unsigned char *s, int len)
1705 {
1706     unsigned char *new;
1707 
1708     if (len <= 0) {
1709 	return;
1710     }
1711     new = Realloc(uo_data[uo_col].trn, uo_data[uo_col].trn_len + len);
1712     if (uo_data[uo_col].trn != NULL) {
1713 	memcpy(new, uo_data[uo_col].trn, uo_data[uo_col].trn_len);
1714     }
1715     memcpy(new + uo_data[uo_col].trn_len, s, len);
1716     uo_data[uo_col].trn = new;
1717     uo_data[uo_col].trn_len += len;
1718 }
1719 
1720 /*
1721  * Dump an unformatted output buffer.
1722  *
1723  * The buffer is treated as a sequence of characters, with control characters
1724  * for new line, carriage return, form feed and end of media.
1725  *
1726  * By definition, the "print position" is 0 when this function begins and ends.
1727  */
1728 static int
dump_unformatted(void)1729 dump_unformatted(void)
1730 {
1731     int i;
1732     int prcol = 0;
1733     ucs4_t c;
1734     int done = 0;
1735     char mb[16];
1736     const char *mbp;
1737     int len;
1738     int j;
1739 
1740     if (!any_3270_output) {
1741 	return 0;
1742     }
1743 
1744     for (i = 0; i < MAX_BUF && !done; i++) {
1745 	switch (c = page_buf[i]) {
1746 	case '\0':
1747 	    break;
1748 	case FCORDER_NOP:
1749 	    break;
1750 	case FCORDER_CR:
1751 	    if (uoutput('\r') < 0) {
1752 		return -1;
1753 	    }
1754 	    prcol = 0;
1755 	    break;
1756 	case FCORDER_NL:
1757 	    if (uoutput('\n') < 0) {
1758 		return -1;
1759 	    }
1760 	    prcol = 0;
1761 	    break;
1762 	case FCORDER_FF:
1763 	    if (uoutput('\f') < 0) {
1764 		return -1;
1765 	    }
1766 	    prcol = 0;
1767 	    break;
1768 	case FCORDER_EM:
1769 	    if (prcol != 0) {
1770 		if (uoutput('\n') < 0) {
1771 		    return -1;
1772 		}
1773 	    }
1774 	    done = 1;
1775 	    break;
1776 	default:	/* printable */
1777 	    /*
1778 	     * Insert a newline if they send a 133rd printable
1779 	     * character on a line.
1780 	     *
1781 	     * If they specified '-skipcc', don't count the first
1782 	     * character on the line as printable.
1783 	     */
1784 	    if (++prcol > options.mpp + (options.skipcc != 0)) {
1785 		if (uoutput('\n') < 0) {
1786 		    return -1;
1787 		}
1788 		prcol = 0;
1789 	    }
1790 
1791 	    /* Handle transparent data. */
1792 	    if (xlate_buf[i] != NULL) {
1793 		uoutput_trn(xlate_buf[i], xlate_len[i]);
1794 		break;
1795 	    }
1796 
1797 #if !defined(_WIN32) /*[*/
1798 	    len = unicode_to_multibyte(c, mb, sizeof(mb));
1799 #else /*][*/
1800 	    len = unicode_to_printer(c, mb, sizeof(mb));
1801 #endif /*]*/
1802 	    if (len == 0) {
1803 		mb[0] = ' ';
1804 		len = 1;
1805 	    } else {
1806 		len--;
1807 	    }
1808 	    mbp = mb;
1809 	    for (j = 0; j < len; j++) {
1810 		if (uoutput(mbp[j]) < 0) {
1811 		    return -1;
1812 		}
1813 	    }
1814 
1815 	    break;
1816 	}
1817     }
1818 
1819     /* If the buffer didn't end with an EM, flush any pending line. */
1820     if (!done) {
1821 	if (uoutput('\n') < 0) {
1822 	    return -1;
1823 	}
1824     }
1825 
1826     /* Clear out the buffer. */
1827     memset(page_buf, '\0', MAX_BUF * sizeof(ucs4_t));
1828     memset(xlate_buf, '\0', MAX_BUF * sizeof(unsigned char *));
1829     memset(xlate_len, '\0', MAX_BUF * sizeof(int));
1830 
1831     /* Clear the output state. */
1832     for (i = 0; i < MAX_UNF_MPP + 2; i++) {
1833 	uo_data[i].buf = 0;
1834 	if (uo_data[i].trn != NULL) {
1835 	    Free(uo_data[i].trn);
1836 	}
1837 	uo_data[i].trn = NULL;
1838 	uo_data[i].trn_len = 0;
1839     }
1840     uo_col = 0;
1841     uo_maxcol = 0;
1842     uo_last_cr = false;
1843 
1844     /* Flush buffered data. */
1845 #if defined(_WIN32) /*[*/
1846     if (ws_initted) {
1847 	ws_flush();
1848     }
1849 #else /*][*/
1850     fflush(prfile);
1851 #endif /*]*/
1852     any_3270_output = 0;
1853 
1854     return 0;
1855 }
1856 
1857 /*
1858  * Dump a formatted output buffer.
1859  *
1860  * The buffer is treated as a sequence of lines, with the length specified by
1861  * the write control character.
1862  *
1863  * Each line is terminated by a newline, with trailing spaces and nulls
1864  * suppressed.
1865  * Nulls are displayed as spaces, except when they constitute an entire line,
1866  * in which case the line is suppressed.
1867  * Formfeeds are passed through, and otherwise treated like nulls.
1868  *
1869  * We do not observe the -skipcc option with formatted data.
1870  */
1871 static int
dump_formatted(void)1872 dump_formatted(void)
1873 {
1874     int i;
1875     ucs4_t *cp = page_buf;
1876     int visible = 1;
1877     int newlines = 0;
1878     bool data_without_newline = false;
1879 
1880     if (!any_3270_output) {
1881 	return 0;
1882     }
1883     for (i = 0; i < MAX_UNF_MPP; i++) {
1884 	int blanks = 0;
1885 	int any_data = 0;
1886 	int j;
1887 
1888 	for (j = 0; j < line_length && ((i * line_length) + j) < MAX_BUF; j++) {
1889 	    char c = *cp++;
1890 
1891 	    switch (c) {
1892 	    case VISIBLE:	/* visible field */
1893 		visible = 1;
1894 		blanks++;
1895 		break;
1896 	    case INVISIBLE:	/* invisible field */
1897 		visible = 0;
1898 		blanks++;
1899 		break;
1900 	    case '\f':
1901 		while (newlines) {
1902 		    if (options.crlf) {
1903 			if (stash('\r') < 0) {
1904 			    return -1;
1905 			}
1906 		    }
1907 		    if (stash('\n') < 0) {
1908 			return -1;
1909 		    }
1910 		    newlines--;
1911 		    data_without_newline = false;
1912 		}
1913 		if (any_3270_printable || !options.ffskip) {
1914 		    if (stash('\f') < 0) {
1915 			return -1;
1916 		    }
1917 		}
1918 		blanks++;
1919 		break;
1920 	    case '\0':
1921 		blanks++;
1922 		break;
1923 	    case ' ':
1924 		blanks++;
1925 		any_data++;
1926 		data_without_newline = true;
1927 		break;
1928 	    default:
1929 		while (newlines) {
1930 		    if (options.crlf) {
1931 			if (stash('\r') < 0) {
1932 			    return -1;
1933 			}
1934 		    }
1935 		    if (stash('\n') < 0) {
1936 			return -1;
1937 		    }
1938 		    newlines--;
1939 		    data_without_newline = false;
1940 		}
1941 		while (blanks) {
1942 		    if (stash(' ') < 0) {
1943 			return -1;
1944 		    }
1945 		    blanks--;
1946 		}
1947 		any_data++;
1948 		data_without_newline = true;
1949 		if (!visible) {
1950 		    if (stash(' ') < 0) {
1951 			return -1;
1952 		    }
1953 		} else {
1954 		    char mb[16];
1955 		    int len;
1956 		    int j;
1957 
1958 #if !defined(_WIN32) /*[*/
1959 		    len = unicode_to_multibyte(c, mb, sizeof(mb));
1960 #else /*][*/
1961 		    len = unicode_to_printer(c, mb, sizeof(mb));
1962 #endif /*]*/
1963 		    if (len == 0) {
1964 			mb[0] = ' ';
1965 			len = 1;
1966 		    } else {
1967 			len--;
1968 		    }
1969 		    for (j = 0; j < len; j++) {
1970 			if (stash(mb[j]) < 0) {
1971 			    return -1;
1972 			}
1973 		    }
1974 
1975 		}
1976 		if (visible) {
1977 		    any_3270_printable = true;
1978 		}
1979 		break;
1980 	    }
1981 	}
1982 	if (any_data || options.blanklines) {
1983 	    newlines++;
1984 	}
1985     }
1986 
1987     /* If there was data on the last line, put out a newline. */
1988     if (data_without_newline) {
1989 	if (options.crlf) {
1990 	    if (stash('\r') < 0) {
1991 		return -1;
1992 	    }
1993 	}
1994 	if (stash('\n') < 0) {
1995 	    return -1;
1996 	}
1997     }
1998 
1999     /* Clear the buffer. */
2000     memset(page_buf, '\0', MAX_BUF * sizeof(ucs4_t));
2001 #if defined(_WIN32) /*[*/
2002     if (ws_initted) {
2003 	    ws_flush();
2004     }
2005 #else /*][*/
2006     fflush(prfile);
2007 #endif /*]*/
2008     any_3270_output = 0;
2009 
2010     return 0;
2011 }
2012 
2013 int
print_eoj(void)2014 print_eoj(void)
2015 {
2016     int rc = 0;
2017 
2018     /* Dump any pending 3270-mode output. */
2019     if (any_3270_output) {
2020 	if (wcc_line_length) {
2021 	    if (dump_formatted() < 0) {
2022 		rc = -1;
2023 	    }
2024 	} else {
2025 	    if (dump_unformatted() < 0) {
2026 		rc = -1;
2027 	    }
2028 	}
2029     }
2030 
2031     /* Dump any pending SCS-mode output. */
2032     if (any_scs_output) {
2033 	if (dump_scs_line(true, false) < 0) {
2034 	    rc = -1;
2035 	}
2036     }
2037 
2038     /* Handle -ffeoj, which blindly adds a formfeed to every page. */
2039     if (options.ffeoj && !ffeoj_last) {
2040 	if (scs_any) {
2041 	    trace_ds("Automatic SCS EOJ formfeed.\n");
2042 	    scs_formfeed(true);
2043 	    if (dump_scs_line(true, false) < 0) {
2044 		rc = -1;
2045 	    }
2046 	} else {
2047 	    trace_ds("Automatic 3270 %s EOJ formfeed.\n",
2048 		    wcc_line_length? "formatted": "unformatted");
2049 	    ctlr_add(0, FCORDER_FF, default_cs, default_gr);
2050 	    if (wcc_line_length) {
2051 		if (dump_formatted() < 0) {
2052 		    rc = -1;
2053 		}
2054 	    } else {
2055 		if (dump_unformatted() < 0) {
2056 		    rc = -1;
2057 		}
2058 	    }
2059 	}
2060 	ffeoj_last = true;
2061     }
2062 
2063     /* Close the stream to the print process. */
2064 #if defined(_WIN32) /*[*/
2065     if (ws_initted) {
2066 	trace_ds("End of print job.\n");
2067 	if (options.trnpost != NULL && copyfile(options.trnpost) < 0) {
2068 	    rc = -1;
2069 	}
2070 	if (ws_endjob() < 0) {
2071 	    rc = -1;
2072 	}
2073 	ws_needpre = 1;
2074     }
2075 #else /*]*/
2076     if (prfile != NULL) {
2077 	trace_ds("End of print job.\n");
2078 	if (options.trnpost != NULL && copyfile(options.trnpost) < 0) {
2079 	    rc = -1;
2080 	}
2081 	rc = pclose_no_sigint(prfile);
2082 	if (rc) {
2083 	    if (rc < 0) {
2084 		errmsg("Close error on '%s': %s", options.command,
2085 			strerror(errno));
2086 	    } else if (WIFEXITED(rc)) {
2087 		errmsg("'%s' exited with status %d", options.command,
2088 			WEXITSTATUS(rc));
2089 	    } else if (WIFSIGNALED(rc)) {
2090 		errmsg("'%s' terminated by signal %d", options.command,
2091 			WTERMSIG(rc));
2092 	    } else {
2093 		errmsg("'%s' returned status %d", options.command, rc);
2094 	    }
2095 	    rc = -1;
2096 	}
2097 	prfile = NULL;
2098     }
2099 #endif /*]*/
2100 
2101     /* Make sure the next 3270 job starts with clean conditions. */
2102     page_buf_initted = 0;
2103 
2104     /* Reset the FF suprpession logic. */
2105     any_3270_printable = false;
2106 
2107     return rc;
2108 }
2109 
2110 void
print_unbind(void)2111 print_unbind(void)
2112 {
2113     /*
2114      * Make sure that the next SCS job starts with clean conditions.
2115      */
2116     scs_initted = false;
2117 }
2118 
2119 static int
ctlr_erase(void)2120 ctlr_erase(void)
2121 {
2122     /* Dump whatever we've got so far. */
2123     /* Dump any pending 3270-mode output. */
2124     if (wcc_line_length) {
2125 	if (dump_formatted() < 0) {
2126 		return -1;
2127 	}
2128     } else {
2129 	    if (dump_unformatted() < 0) {
2130 		return -1;
2131 	    }
2132     }
2133 
2134     /* Dump any pending SCS-mode output. */
2135     if (any_scs_output) {
2136 	if (dump_scs_line(true, false) < 0) { /* XXX: 1st true? */
2137 	    return -1;
2138 	}
2139     }
2140 
2141     /* Make sure the buffer is clean. */
2142     memset(page_buf, '\0', MAX_BUF * sizeof(ucs4_t));
2143     any_3270_output = 0;
2144     baddr = 0;
2145     return 0;
2146 }
2147 
2148 /*
2149  * Copy a -trnpre/-trnpost file to the printer.  We open and read the file
2150  * for each print job, so someone can change their contents while we are
2151  * running (hopefully between print jobs).
2152  */
2153 static int
copyfile(const char * filename)2154 copyfile(const char *filename)
2155 {
2156     FILE *f;
2157     char c;
2158     int rc = 0;
2159 
2160     if ((f = fopen(filename, "rb")) == NULL) {
2161 	errmsg("%s: %s", filename, strerror(errno));
2162 	return -1;
2163     }
2164     while ((c = fgetc(f)) != EOF) {
2165 	trace_pdc((unsigned char)c);
2166 #if defined(_WIN32) /*[*/
2167 	if (ws_putc(c) < 0) {
2168 #else /*][*/
2169 	if (fputc(c, prfile) < 0) {
2170 	    errmsg("write(%s): %s", options.command, strerror(errno));
2171 #endif /*]*/
2172 	    rc = -1;
2173 	    break;
2174 	}
2175     }
2176     fclose(f);
2177     return rc;
2178 }
2179