initial commit
[profile/ivi/xterm.git] / os2main.c
1 /* $XTermId: os2main.c,v 1.265 2010/06/20 21:27:07 tom Exp $ */
2
3 /* removed all foreign stuff to get the code more clear (hv)
4  * and did some rewrite for the obscure OS/2 environment
5  */
6
7 /***********************************************************
8
9 Copyright (c) 1987, 1988  X Consortium
10
11 Permission is hereby granted, free of charge, to any person obtaining a copy
12 of this software and associated documentation files (the "Software"), to deal
13 in the Software without restriction, including without limitation the rights
14 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 copies of the Software, and to permit persons to whom the Software is
16 furnished to do so, subject to the following conditions:
17
18 The above copyright notice and this permission notice shall be included in
19 all copies or substantial portions of the Software.
20
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
24 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
25 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
28 Except as contained in this notice, the name of the X Consortium shall not be
29 used in advertising or otherwise to promote the sale, use or other dealings
30 in this Software without prior written authorization from the X Consortium.
31
32 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard.
33
34                         All Rights Reserved
35
36 Permission to use, copy, modify, and distribute this software and its
37 documentation for any purpose and without fee is hereby granted,
38 provided that the above copyright notice appear in all copies and that
39 both that copyright notice and this permission notice appear in
40 supporting documentation, and that the name of Digital not be used in
41 advertising or publicity pertaining to distribution of the software
42 without specific, written prior permission.
43
44 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
45 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
46 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
47 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
48 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
49 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
50 SOFTWARE.
51
52 ******************************************************************/
53
54 /* os2main.c */
55 #define INCL_DOSFILEMGR
56 #define INCL_DOSDEVIOCTL
57 #define INCL_DOSSEMAPHORES
58 #ifdef __INNOTEK_LIBC__
59 #define INCL_DOSDEVICES
60 #endif
61 #define I_NEED_OS2_H
62 #include <os2.h>
63 #define XTERM_MAIN
64
65 #define RES_OFFSET(field)       XtOffsetOf(XTERM_RESOURCE, field)
66
67 #include <xterm.h>
68
69 #include <X11/cursorfont.h>
70 #ifdef I18N
71 #include <X11/Xlocale.h>
72 #endif
73
74 #if OPT_TOOLBAR
75
76 #if defined(HAVE_LIB_XAW)
77 #include <X11/Xaw/Form.h>
78 #elif defined(HAVE_LIB_XAW3D)
79 #include <X11/Xaw3d/Form.h>
80 #elif defined(HAVE_LIB_NEXTAW)
81 #include <X11/neXtaw/Form.h>
82 #elif defined(HAVE_LIB_XAWPLUS)
83 #include <X11/XawPlus/Form.h>
84 #endif
85
86 #endif /* OPT_TOOLBAR */
87
88 #include <pwd.h>
89 #include <ctype.h>
90
91 #include <data.h>
92 #include <error.h>
93 #include <menu.h>
94 #include <main.h>
95 #include <xstrings.h>
96 #include <xtermcap.h>
97 #include <xterm_io.h>
98
99 #if OPT_WIDE_CHARS
100 #include <charclass.h>
101 #endif
102
103 int
104 setpgrp(pid_t pid, gid_t pgid)
105 {
106     return 0;
107 }
108
109 int
110 chown(const char *fn, pid_t pid, gid_t gid)
111 {
112     return 0;
113 }
114
115 char *
116 ttyname(int fd)
117 {
118     return "/dev/tty";
119 }
120
121 #include <sys/stat.h>
122 #include <sys/param.h>          /* for NOFILE */
123 #include <stdio.h>
124 #include <signal.h>
125
126 static SIGNAL_T reapchild(int n);
127 static int spawnXTerm(XtermWidget /* xw */ );
128 static void resize_termcap(XtermWidget xw);
129 static void set_owner(char *device, uid_t uid, gid_t gid, mode_t mode);
130
131 static Bool added_utmp_entry = False;
132
133 static uid_t save_ruid;
134 static gid_t save_rgid;
135
136 /*
137 ** Ordinarily it should be okay to omit the assignment in the following
138 ** statement. Apparently the c89 compiler on AIX 4.1.3 has a bug, or does
139 ** it? Without the assignment though the compiler will init command_to_exec
140 ** to 0xffffffff instead of NULL; and subsequent usage, e.g. in spawnXTerm() to
141 ** SEGV.
142 */
143 static char **command_to_exec = NULL;
144
145 #if OPT_LUIT_PROG
146 static char **command_to_exec_with_luit = NULL;
147 #endif
148
149 /* The following structures are initialized in main() in order
150 ** to eliminate any assumptions about the internal order of their
151 ** contents.
152 */
153 static struct termio d_tio;
154
155 /* allow use of system default characters if defined and reasonable */
156 #ifndef CEOF
157 #define CEOF CONTROL('D')
158 #endif
159 #ifndef CEOL
160 #define CEOL 0
161 #endif
162 #ifndef CFLUSH
163 #define CFLUSH CONTROL('O')
164 #endif
165 #ifndef CLNEXT
166 #define CLNEXT CONTROL('V')
167 #endif
168 #ifndef CNUL
169 #define CNUL 0
170 #endif
171 #ifndef CQUIT
172 #define CQUIT CONTROL('\\')
173 #endif
174 #ifndef CRPRNT
175 #define CRPRNT CONTROL('R')
176 #endif
177 #ifndef CSTART
178 #define CSTART CONTROL('Q')
179 #endif
180 #ifndef CSTOP
181 #define CSTOP CONTROL('S')
182 #endif
183 #ifndef CSUSP
184 #define CSUSP CONTROL('Z')
185 #endif
186 #ifndef CSWTCH
187 #define CSWTCH 0
188 #endif
189 #ifndef CWERASE
190 #define CWERASE CONTROL('W')
191 #endif
192
193 #define TERMIO_STRUCT struct termio
194
195 /*
196  * SYSV has the termio.c_cc[V] and ltchars; BSD has tchars and ltchars;
197  * SVR4 has only termio.c_cc, but it includes everything from ltchars.
198  * POSIX termios has termios.c_cc, which is similar to SVR4.
199  */
200 #define TTYMODE(name) { name, sizeof(name)-1, 0, 0 }
201 static Boolean override_tty_modes = False;
202 /* *INDENT-OFF* */
203 static struct _xttymodes {
204     const char *name;
205     size_t len;
206     int set;
207     int value;
208 } ttymodelist[] = {
209     TTYMODE("intr"),            /* tchars.t_intrc ; VINTR */
210 #define XTTYMODE_intr   0
211     TTYMODE("quit"),            /* tchars.t_quitc ; VQUIT */
212 #define XTTYMODE_quit   1
213     TTYMODE("erase"),           /* sgttyb.sg_erase ; VERASE */
214 #define XTTYMODE_erase  2
215     TTYMODE("kill"),            /* sgttyb.sg_kill ; VKILL */
216 #define XTTYMODE_kill   3
217     TTYMODE("eof"),             /* tchars.t_eofc ; VEOF */
218 #define XTTYMODE_eof    4
219     TTYMODE("eol"),             /* VEOL */
220 #define XTTYMODE_eol    5
221     TTYMODE("swtch"),           /* VSWTCH */
222 #define XTTYMODE_swtch  6
223     TTYMODE("start"),           /* tchars.t_startc ; VSTART */
224 #define XTTYMODE_start  7
225     TTYMODE("stop"),            /* tchars.t_stopc ; VSTOP */
226 #define XTTYMODE_stop   8
227     TTYMODE("brk"),             /* tchars.t_brkc */
228 #define XTTYMODE_brk    9
229     TTYMODE("susp"),            /* ltchars.t_suspc ; VSUSP */
230 #define XTTYMODE_susp   10
231     TTYMODE("dsusp"),           /* ltchars.t_dsuspc ; VDSUSP */
232 #define XTTYMODE_dsusp  11
233     TTYMODE("rprnt"),           /* ltchars.t_rprntc ; VREPRINT */
234 #define XTTYMODE_rprnt  12
235     TTYMODE("flush"),           /* ltchars.t_flushc ; VDISCARD */
236 #define XTTYMODE_flush  13
237     TTYMODE("weras"),           /* ltchars.t_werasc ; VWERASE */
238 #define XTTYMODE_weras  14
239     TTYMODE("lnext"),           /* ltchars.t_lnextc ; VLNEXT */
240 #define XTTYMODE_lnext  15
241     { NULL,     0, 0, '\0' },   /* end of data */
242 };
243 /* *INDENT-ON* */
244
245 #define TMODE(ind,var) if (ttymodelist[ind].set) var = ttymodelist[ind].value
246
247 static int parse_tty_modes(char *s, struct _xttymodes *modelist);
248
249 static char passedPty[2];       /* name if pty if slave */
250
251 static int Console;
252 #include <X11/Xmu/SysUtil.h>    /* XmuGetHostname */
253 #define MIT_CONSOLE_LEN 12
254 #define MIT_CONSOLE "MIT_CONSOLE_"
255 static char mit_console_name[255 + MIT_CONSOLE_LEN + 1] = MIT_CONSOLE;
256 static Atom mit_console;
257
258 static int tslot;
259 static jmp_buf env;
260
261 /* used by VT (charproc.c) */
262
263 static XtResource application_resources[] =
264 {
265     Sres("name", "Name", xterm_name, DFT_TERMTYPE),
266     Sres("iconGeometry", "IconGeometry", icon_geometry, NULL),
267     Sres(XtNtitle, XtCTitle, title, NULL),
268     Sres(XtNiconName, XtCIconName, icon_name, NULL),
269     Sres("termName", "TermName", term_name, NULL),
270     Sres("ttyModes", "TtyModes", tty_modes, NULL),
271     Bres("hold", "Hold", hold_screen, False),
272     Bres("utmpInhibit", "UtmpInhibit", utmpInhibit, False),
273     Bres("utmpDisplayId", "UtmpDisplayId", utmpDisplayId, True),
274     Bres("messages", "Messages", messages, True),
275     Ires("minBufSize", "MinBufSize", minBufSize, 4096),
276     Ires("maxBufSize", "MaxBufSize", maxBufSize, 32768),
277     Sres("menuLocale", "MenuLocale", menuLocale, ""),
278     Sres("keyboardType", "KeyboardType", keyboardType, "unknown"),
279 #if OPT_SUNPC_KBD
280     Bres("sunKeyboard", "SunKeyboard", sunKeyboard, False),
281 #endif
282 #if OPT_HP_FUNC_KEYS
283     Bres("hpFunctionKeys", "HpFunctionKeys", hpFunctionKeys, False),
284 #endif
285 #if OPT_SCO_FUNC_KEYS
286     Bres("scoFunctionKeys", "ScoFunctionKeys", scoFunctionKeys, False),
287 #endif
288 #if OPT_SUN_FUNC_KEYS
289     Bres("sunFunctionKeys", "SunFunctionKeys", sunFunctionKeys, False),
290 #endif
291 #if OPT_TCAP_FKEYS
292     Bres("tcapFunctionKeys", "TcapFunctionKeys", termcapKeys, False),
293 #endif
294 #if OPT_INITIAL_ERASE
295     Bres("ptyInitialErase", "PtyInitialErase", ptyInitialErase, DEF_INITIAL_ERASE),
296     Bres("backarrowKeyIsErase", "BackarrowKeyIsErase", backarrow_is_erase, DEF_BACKARO_ERASE),
297 #endif
298     Bres("useInsertMode", "UseInsertMode", useInsertMode, False),
299 #if OPT_ZICONBEEP
300     Ires("zIconBeep", "ZIconBeep", zIconBeep, 0),
301 #endif
302 #if OPT_PTY_HANDSHAKE
303     Bres("waitForMap", "WaitForMap", wait_for_map, False),
304     Bres("ptyHandshake", "PtyHandshake", ptyHandshake, True),
305     Bres("ptySttySize", "PtySttySize", ptySttySize, DEF_PTY_STTY_SIZE),
306 #endif
307 #if OPT_SAME_NAME
308     Bres("sameName", "SameName", sameName, True),
309 #endif
310 #if OPT_SESSION_MGT
311     Bres("sessionMgt", "SessionMgt", sessionMgt, True),
312 #endif
313 #if OPT_TOOLBAR
314     Bres(XtNtoolBar, XtCToolBar, toolBar, True),
315 #endif
316 #if OPT_MAXIMIZE
317     Bres(XtNmaximized, XtCMaximized, maximized, False),
318 #endif
319 };
320
321 static String fallback_resources[] =
322 {
323     "*SimpleMenu*menuLabel.vertSpace: 100",
324     "*SimpleMenu*HorizontalMargins: 16",
325     "*SimpleMenu*Sme.height: 16",
326     "*SimpleMenu*Cursor: left_ptr",
327     "*mainMenu.Label:  Main Options (no app-defaults)",
328     "*vtMenu.Label:  VT Options (no app-defaults)",
329     "*fontMenu.Label:  VT Fonts (no app-defaults)",
330 #if OPT_TEK4014
331     "*tekMenu.Label:  Tek Options (no app-defaults)",
332 #endif
333     NULL
334 };
335
336 /* Command line options table.  Only resources are entered here...there is a
337    pass over the remaining options after XrmParseCommand is let loose. */
338 /* *INDENT-OFF* */
339 static XrmOptionDescRec optionDescList[] = {
340 {"-geometry",   "*vt100.geometry",XrmoptionSepArg,      (XPointer) NULL},
341 {"-132",        "*c132",        XrmoptionNoArg,         (XPointer) "on"},
342 {"+132",        "*c132",        XrmoptionNoArg,         (XPointer) "off"},
343 {"-ah",         "*alwaysHighlight", XrmoptionNoArg,     (XPointer) "on"},
344 {"+ah",         "*alwaysHighlight", XrmoptionNoArg,     (XPointer) "off"},
345 {"-aw",         "*autoWrap",    XrmoptionNoArg,         (XPointer) "on"},
346 {"+aw",         "*autoWrap",    XrmoptionNoArg,         (XPointer) "off"},
347 #ifndef NO_ACTIVE_ICON
348 {"-ai",         "*activeIcon",  XrmoptionNoArg,         (XPointer) "off"},
349 {"+ai",         "*activeIcon",  XrmoptionNoArg,         (XPointer) "on"},
350 #endif /* NO_ACTIVE_ICON */
351 {"-b",          "*internalBorder",XrmoptionSepArg,      (XPointer) NULL},
352 {"-bc",         "*cursorBlink", XrmoptionNoArg,         (XPointer) "on"},
353 {"+bc",         "*cursorBlink", XrmoptionNoArg,         (XPointer) "off"},
354 {"-bcf",        "*cursorOffTime",XrmoptionSepArg,       (XPointer) NULL},
355 {"-bcn",        "*cursorOnTime",XrmoptionSepArg,        (XPointer) NULL},
356 {"-bdc",        "*colorBDMode", XrmoptionNoArg,         (XPointer) "off"},
357 {"+bdc",        "*colorBDMode", XrmoptionNoArg,         (XPointer) "on"},
358 {"-cb",         "*cutToBeginningOfLine", XrmoptionNoArg, (XPointer) "off"},
359 {"+cb",         "*cutToBeginningOfLine", XrmoptionNoArg, (XPointer) "on"},
360 {"-cc",         "*charClass",   XrmoptionSepArg,        (XPointer) NULL},
361 {"-cm",         "*colorMode",   XrmoptionNoArg,         (XPointer) "off"},
362 {"+cm",         "*colorMode",   XrmoptionNoArg,         (XPointer) "on"},
363 {"-cn",         "*cutNewline",  XrmoptionNoArg,         (XPointer) "off"},
364 {"+cn",         "*cutNewline",  XrmoptionNoArg,         (XPointer) "on"},
365 {"-cr",         "*cursorColor", XrmoptionSepArg,        (XPointer) NULL},
366 {"-cu",         "*curses",      XrmoptionNoArg,         (XPointer) "on"},
367 {"+cu",         "*curses",      XrmoptionNoArg,         (XPointer) "off"},
368 {"-dc",         "*dynamicColors",XrmoptionNoArg,        (XPointer) "off"},
369 {"+dc",         "*dynamicColors",XrmoptionNoArg,        (XPointer) "on"},
370 {"-fb",         "*boldFont",    XrmoptionSepArg,        (XPointer) NULL},
371 {"-fbb",        "*freeBoldBox", XrmoptionNoArg,         (XPointer)"off"},
372 {"+fbb",        "*freeBoldBox", XrmoptionNoArg,         (XPointer)"on"},
373 {"-fbx",        "*forceBoxChars", XrmoptionNoArg,       (XPointer)"off"},
374 {"+fbx",        "*forceBoxChars", XrmoptionNoArg,       (XPointer)"on"},
375 #ifndef NO_ACTIVE_ICON
376 {"-fi",         "*iconFont",    XrmoptionSepArg,        (XPointer) NULL},
377 #endif /* NO_ACTIVE_ICON */
378 #if OPT_RENDERFONT
379 {"-fa",         "*faceName",    XrmoptionSepArg,        (XPointer) NULL},
380 {"-fd",         "*faceNameDoublesize", XrmoptionSepArg, (XPointer) NULL},
381 {"-fs",         "*faceSize",    XrmoptionSepArg,        (XPointer) NULL},
382 #endif
383 #if OPT_WIDE_CHARS
384 {"-fw",         "*wideFont",    XrmoptionSepArg,        (XPointer) NULL},
385 {"-fwb",        "*wideBoldFont", XrmoptionSepArg,       (XPointer) NULL},
386 #endif
387 #if OPT_INPUT_METHOD
388 {"-fx",         "*ximFont",     XrmoptionSepArg,        (XPointer) NULL},
389 #endif
390 #if OPT_HIGHLIGHT_COLOR
391 {"-hc",         "*highlightColor", XrmoptionSepArg,     (XPointer) NULL},
392 {"-hm",         "*highlightColorMode", XrmoptionNoArg,  (XPointer) "on"},
393 {"+hm",         "*highlightColorMode", XrmoptionNoArg,  (XPointer) "off"},
394 {"-selfg",      "*highlightTextColor", XrmoptionSepArg, (XPointer) NULL},
395 {"-selbg",      "*highlightColor", XrmoptionSepArg,     (XPointer) NULL},
396 #endif
397 #if OPT_HP_FUNC_KEYS
398 {"-hf",         "*hpFunctionKeys",XrmoptionNoArg,       (XPointer) "on"},
399 {"+hf",         "*hpFunctionKeys",XrmoptionNoArg,       (XPointer) "off"},
400 #endif
401 {"-hold",       "*hold",        XrmoptionNoArg,         (XPointer) "on"},
402 {"+hold",       "*hold",        XrmoptionNoArg,         (XPointer) "off"},
403 #if OPT_INITIAL_ERASE
404 {"-ie",         "*ptyInitialErase", XrmoptionNoArg,     (XPointer) "on"},
405 {"+ie",         "*ptyInitialErase", XrmoptionNoArg,     (XPointer) "off"},
406 #endif
407 {"-j",          "*jumpScroll",  XrmoptionNoArg,         (XPointer) "on"},
408 {"+j",          "*jumpScroll",  XrmoptionNoArg,         (XPointer) "off"},
409 #if OPT_C1_PRINT
410 {"-k8",         "*allowC1Printable", XrmoptionNoArg,    (XPointer) "on"},
411 {"+k8",         "*allowC1Printable", XrmoptionNoArg,    (XPointer) "off"},
412 #endif
413 {"-kt",         "*keyboardType", XrmoptionSepArg,       (XPointer) NULL},
414 {"+kt",         "*keyboardType", XrmoptionSepArg,       (XPointer) NULL},
415 /* parse logging options anyway for compatibility */
416 {"-l",          "*logging",     XrmoptionNoArg,         (XPointer) "on"},
417 {"+l",          "*logging",     XrmoptionNoArg,         (XPointer) "off"},
418 {"-lf",         "*logFile",     XrmoptionSepArg,        (XPointer) NULL},
419 {"-ls",         "*loginShell",  XrmoptionNoArg,         (XPointer) "on"},
420 {"+ls",         "*loginShell",  XrmoptionNoArg,         (XPointer) "off"},
421 {"-mb",         "*marginBell",  XrmoptionNoArg,         (XPointer) "on"},
422 {"+mb",         "*marginBell",  XrmoptionNoArg,         (XPointer) "off"},
423 {"-mc",         "*multiClickTime", XrmoptionSepArg,     (XPointer) NULL},
424 {"-mesg",       "*messages",    XrmoptionNoArg,         (XPointer) "off"},
425 {"+mesg",       "*messages",    XrmoptionNoArg,         (XPointer) "on"},
426 {"-ms",         "*pointerColor",XrmoptionSepArg,        (XPointer) NULL},
427 {"-nb",         "*nMarginBell", XrmoptionSepArg,        (XPointer) NULL},
428 {"-nul",        "*underLine",   XrmoptionNoArg,         (XPointer) "off"},
429 {"+nul",        "*underLine",   XrmoptionNoArg,         (XPointer) "on"},
430 {"-pc",         "*boldColors",  XrmoptionNoArg,         (XPointer) "on"},
431 {"+pc",         "*boldColors",  XrmoptionNoArg,         (XPointer) "off"},
432 {"-rw",         "*reverseWrap", XrmoptionNoArg,         (XPointer) "on"},
433 {"+rw",         "*reverseWrap", XrmoptionNoArg,         (XPointer) "off"},
434 {"-s",          "*multiScroll", XrmoptionNoArg,         (XPointer) "on"},
435 {"+s",          "*multiScroll", XrmoptionNoArg,         (XPointer) "off"},
436 {"-sb",         "*scrollBar",   XrmoptionNoArg,         (XPointer) "on"},
437 {"+sb",         "*scrollBar",   XrmoptionNoArg,         (XPointer) "off"},
438 #ifdef SCROLLBAR_RIGHT
439 {"-leftbar",    "*rightScrollBar", XrmoptionNoArg,      (XPointer) "off"},
440 {"-rightbar",   "*rightScrollBar", XrmoptionNoArg,      (XPointer) "on"},
441 #endif
442 {"-rvc",        "*colorRVMode", XrmoptionNoArg,         (XPointer) "off"},
443 {"+rvc",        "*colorRVMode", XrmoptionNoArg,         (XPointer) "on"},
444 {"-sf",         "*sunFunctionKeys", XrmoptionNoArg,     (XPointer) "on"},
445 {"+sf",         "*sunFunctionKeys", XrmoptionNoArg,     (XPointer) "off"},
446 {"-si",         "*scrollTtyOutput", XrmoptionNoArg,     (XPointer) "off"},
447 {"+si",         "*scrollTtyOutput", XrmoptionNoArg,     (XPointer) "on"},
448 {"-sk",         "*scrollKey",   XrmoptionNoArg,         (XPointer) "on"},
449 {"+sk",         "*scrollKey",   XrmoptionNoArg,         (XPointer) "off"},
450 {"-sl",         "*saveLines",   XrmoptionSepArg,        (XPointer) NULL},
451 #if OPT_SUNPC_KBD
452 {"-sp",         "*sunKeyboard", XrmoptionNoArg,         (XPointer) "on"},
453 {"+sp",         "*sunKeyboard", XrmoptionNoArg,         (XPointer) "off"},
454 #endif
455 #if OPT_TEK4014
456 {"-t",          "*tekStartup",  XrmoptionNoArg,         (XPointer) "on"},
457 {"+t",          "*tekStartup",  XrmoptionNoArg,         (XPointer) "off"},
458 #endif
459 {"-ti",         "*decTerminalID",XrmoptionSepArg,       (XPointer) NULL},
460 {"-tm",         "*ttyModes",    XrmoptionSepArg,        (XPointer) NULL},
461 {"-tn",         "*termName",    XrmoptionSepArg,        (XPointer) NULL},
462 #if OPT_WIDE_CHARS
463 {"-u8",         "*utf8",        XrmoptionNoArg,         (XPointer) "2"},
464 {"+u8",         "*utf8",        XrmoptionNoArg,         (XPointer) "0"},
465 #endif
466 #if OPT_LUIT_PROG
467 {"-lc",         "*locale",      XrmoptionNoArg,         (XPointer) "on"},
468 {"+lc",         "*locale",      XrmoptionNoArg,         (XPointer) "off"},
469 {"-lcc",        "*localeFilter",XrmoptionSepArg,        (XPointer) NULL},
470 {"-en",         "*locale",      XrmoptionSepArg,        (XPointer) NULL},
471 #endif
472 {"-uc",         "*cursorUnderLine", XrmoptionNoArg,     (XPointer) "on"},
473 {"+uc",         "*cursorUnderLine", XrmoptionNoArg,     (XPointer) "off"},
474 {"-ulc",        "*colorULMode", XrmoptionNoArg,         (XPointer) "off"},
475 {"+ulc",        "*colorULMode", XrmoptionNoArg,         (XPointer) "on"},
476 {"-ulit",       "*italicULMode", XrmoptionNoArg,        (XPointer) "off"},
477 {"+ulit",       "*italicULMode", XrmoptionNoArg,        (XPointer) "on"},
478 {"-ut",         "*utmpInhibit", XrmoptionNoArg,         (XPointer) "on"},
479 {"+ut",         "*utmpInhibit", XrmoptionNoArg,         (XPointer) "off"},
480 {"-im",         "*useInsertMode", XrmoptionNoArg,       (XPointer) "on"},
481 {"+im",         "*useInsertMode", XrmoptionNoArg,       (XPointer) "off"},
482 {"-vb",         "*visualBell",  XrmoptionNoArg,         (XPointer) "on"},
483 {"+vb",         "*visualBell",  XrmoptionNoArg,         (XPointer) "off"},
484 {"-pob",        "*popOnBell",   XrmoptionNoArg,         (XPointer) "on"},
485 {"+pob",        "*popOnBell",   XrmoptionNoArg,         (XPointer) "off"},
486 #if OPT_WIDE_CHARS
487 {"-wc",         "*wideChars",   XrmoptionNoArg,         (XPointer) "on"},
488 {"+wc",         "*wideChars",   XrmoptionNoArg,         (XPointer) "off"},
489 {"-mk_width",   "*mkWidth",     XrmoptionNoArg,         (XPointer) "on"},
490 {"+mk_width",   "*mkWidth",     XrmoptionNoArg,         (XPointer) "off"},
491 {"-cjk_width",  "*cjkWidth",    XrmoptionNoArg,         (XPointer) "on"},
492 {"+cjk_width",  "*cjkWidth",    XrmoptionNoArg,         (XPointer) "off"},
493 #endif
494 {"-wf",         "*waitForMap",  XrmoptionNoArg,         (XPointer) "on"},
495 {"+wf",         "*waitForMap",  XrmoptionNoArg,         (XPointer) "off"},
496 #if OPT_ZICONBEEP
497 {"-ziconbeep",  "*zIconBeep",   XrmoptionSepArg,        (XPointer) NULL},
498 #endif
499 #if OPT_SAME_NAME
500 {"-samename",   "*sameName",    XrmoptionNoArg,         (XPointer) "on"},
501 {"+samename",   "*sameName",    XrmoptionNoArg,         (XPointer) "off"},
502 #endif
503 #if OPT_SESSION_MGT
504 {"-sm",         "*sessionMgt",  XrmoptionNoArg,         (XPointer) "on"},
505 {"+sm",         "*sessionMgt",  XrmoptionNoArg,         (XPointer) "off"},
506 #endif
507 #if OPT_TOOLBAR
508 {"-tb",         "*"XtNtoolBar,  XrmoptionNoArg,         (XPointer) "on"},
509 {"+tb",         "*"XtNtoolBar,  XrmoptionNoArg,         (XPointer) "off"},
510 #endif
511 #if OPT_MAXIMIZE
512 {"-maximized",  "*maximized",   XrmoptionNoArg,         (XPointer) "on"},
513 {"+maximized",  "*maximized",   XrmoptionNoArg,         (XPointer) "off"},
514 #endif
515 /* options that we process ourselves */
516 {"-help",       NULL,           XrmoptionSkipNArgs,     (XPointer) NULL},
517 {"-version",    NULL,           XrmoptionSkipNArgs,     (XPointer) NULL},
518 {"-class",      NULL,           XrmoptionSkipArg,       (XPointer) NULL},
519 {"-e",          NULL,           XrmoptionSkipLine,      (XPointer) NULL},
520 {"-into",       NULL,           XrmoptionSkipArg,       (XPointer) NULL},
521 /* bogus old compatibility stuff for which there are
522    standard XtOpenApplication options now */
523 {"%",           "*tekGeometry", XrmoptionStickyArg,     (XPointer) NULL},
524 {"#",           ".iconGeometry",XrmoptionStickyArg,     (XPointer) NULL},
525 {"-T",          ".title",       XrmoptionSepArg,        (XPointer) NULL},
526 {"-n",          "*iconName",    XrmoptionSepArg,        (XPointer) NULL},
527 {"-r",          "*reverseVideo",XrmoptionNoArg,         (XPointer) "on"},
528 {"+r",          "*reverseVideo",XrmoptionNoArg,         (XPointer) "off"},
529 {"-rv",         "*reverseVideo",XrmoptionNoArg,         (XPointer) "on"},
530 {"+rv",         "*reverseVideo",XrmoptionNoArg,         (XPointer) "off"},
531 {"-w",          ".borderWidth", XrmoptionSepArg,        (XPointer) NULL},
532 };
533
534 static OptionHelp xtermOptions[] = {
535 { "-version",              "print the version number" },
536 { "-help",                 "print out this message" },
537 { "-display displayname",  "X server to contact" },
538 { "-geometry geom",        "size (in characters) and position" },
539 { "-/+rv",                 "turn on/off reverse video" },
540 { "-bg color",             "background color" },
541 { "-fg color",             "foreground color" },
542 { "-bd color",             "border color" },
543 { "-bw number",            "border width in pixels" },
544 { "-fn fontname",          "normal text font" },
545 { "-fb fontname",          "bold text font" },
546 { "-/+fbb",                "turn on/off normal/bold font comparison inhibit"},
547 { "-/+fbx",                "turn off/on linedrawing characters"},
548 #if OPT_RENDERFONT
549 { "-fa pattern",           "FreeType font-selection pattern" },
550 { "-fd pattern",           "FreeType Doublesize font-selection pattern" },
551 { "-fs size",              "FreeType font-size" },
552 #endif
553 #if OPT_WIDE_CHARS
554 { "-fw fontname",          "doublewidth text font" },
555 { "-fwb fontname",         "doublewidth bold text font" },
556 #endif
557 #if OPT_INPUT_METHOD
558 { "-fx fontname",          "XIM fontset" },
559 #endif
560 { "-iconic",               "start iconic" },
561 { "-name string",          "client instance, icon, and title strings" },
562 { "-class string",         "class string (XTerm)" },
563 { "-title string",         "title string" },
564 { "-xrm resourcestring",   "additional resource specifications" },
565 { "-/+132",                "turn on/off 80/132 column switching" },
566 { "-/+ah",                 "turn on/off always highlight" },
567 #ifndef NO_ACTIVE_ICON
568 { "-/+ai",                 "turn off/on active icon" },
569 { "-fi fontname",          "icon font for active icon" },
570 #endif /* NO_ACTIVE_ICON */
571 { "-b number",             "internal border in pixels" },
572 { "-/+bc",                 "turn on/off text cursor blinking" },
573 { "-bcf milliseconds",     "time text cursor is off when blinking"},
574 { "-bcn milliseconds",     "time text cursor is on when blinking"},
575 { "-/+bdc",                "turn off/on display of bold as color"},
576 { "-/+cb",                 "turn on/off cut-to-beginning-of-line inhibit" },
577 { "-cc classrange",        "specify additional character classes" },
578 { "-/+cm",                 "turn off/on ANSI color mode" },
579 { "-/+cn",                 "turn on/off cut newline inhibit" },
580 { "-cr color",             "text cursor color" },
581 { "-/+cu",                 "turn on/off curses emulation" },
582 { "-/+dc",                 "turn off/on dynamic color selection" },
583 #if OPT_HIGHLIGHT_COLOR
584 { "-/+hm",                 "turn on/off selection-color override" },
585 { "-selbg color",          "selection background color" },
586 { "-selfg color",          "selection foreground color" },
587 #endif
588 #if OPT_HP_FUNC_KEYS
589 { "-/+hf",                 "turn on/off HP Function Key escape codes" },
590 #endif
591 { "-/+hold",               "turn on/off logic that retains window after exit" },
592 #if OPT_INITIAL_ERASE
593 { "-/+ie",                 "turn on/off initialization of 'erase' from pty" },
594 #endif
595 { "-/+im",                 "use insert mode for TERMCAP" },
596 { "-/+j",                  "turn on/off jump scroll" },
597 #if OPT_C1_PRINT
598 { "-/+k8",                 "turn on/off C1-printable classification"},
599 #endif
600 { "-kt keyboardtype",      "set keyboard type:" KEYBOARD_TYPES },
601 #ifdef ALLOWLOGGING
602 { "-/+l",                  "turn on/off logging" },
603 { "-lf filename",          "logging filename" },
604 #else
605 { "-/+l",                  "turn on/off logging (not supported)" },
606 { "-lf filename",          "logging filename (not supported)" },
607 #endif
608 { "-/+ls",                 "turn on/off login shell" },
609 { "-/+mb",                 "turn on/off margin bell" },
610 { "-mc milliseconds",      "multiclick time in milliseconds" },
611 { "-/+mesg",               "forbid/allow messages" },
612 { "-ms color",             "pointer color" },
613 { "-nb number",            "margin bell in characters from right end" },
614 { "-/+nul",                "turn off/on display of underlining" },
615 { "-/+aw",                 "turn on/off auto wraparound" },
616 { "-/+pc",                 "turn on/off PC-style bold colors" },
617 { "-/+rw",                 "turn on/off reverse wraparound" },
618 { "-/+s",                  "turn on/off multiscroll" },
619 { "-/+sb",                 "turn on/off scrollbar" },
620 #ifdef SCROLLBAR_RIGHT
621 { "-rightbar",             "force scrollbar right (default left)" },
622 { "-leftbar",              "force scrollbar left" },
623 #endif
624 { "-/+rvc",                "turn off/on display of reverse as color" },
625 { "-/+sf",                 "turn on/off Sun Function Key escape codes" },
626 { "-/+si",                 "turn on/off scroll-on-tty-output inhibit" },
627 { "-/+sk",                 "turn on/off scroll-on-keypress" },
628 { "-sl number",            "number of scrolled lines to save" },
629 #if OPT_SUNPC_KBD
630 { "-/+sp",                 "turn on/off Sun/PC Function/Keypad mapping" },
631 #endif
632 #if OPT_TEK4014
633 { "-/+t",                  "turn on/off Tek emulation window" },
634 #endif
635 #if OPT_TOOLBAR
636 { "-/+tb",                 "turn on/off toolbar" },
637 #endif
638 { "-ti termid",            "terminal identifier" },
639 { "-tm string",            "terminal mode keywords and characters" },
640 { "-tn name",              "TERM environment variable name" },
641 #if OPT_WIDE_CHARS
642 { "-/+u8",                 "turn on/off UTF-8 mode (implies wide-characters)" },
643 #endif
644 #if OPT_LUIT_PROG
645 { "-/+lc",                 "turn on/off locale mode using luit" },
646 { "-lcc path",             "filename of locale converter (" DEFLOCALEFILTER ")" },
647 #endif
648 { "-/+uc",                 "turn on/off underline cursor" },
649 { "-/+ulc",                "turn off/on display of underline as color" },
650 { "-/+ut",                 "turn on/off utmp inhibit (not supported)" },
651 { "-/+ulit",               "turn off/on display of underline as italics" },
652 { "-/+vb",                 "turn on/off visual bell" },
653 { "-/+pob",                "turn on/off pop on bell" },
654 #if OPT_WIDE_CHARS
655 { "-/+wc",                 "turn on/off wide-character mode" },
656 { "-/+mk_width",           "turn on/off simple width convention" },
657 { "-/+cjk_width",          "turn on/off legacy CJK width convention" },
658 #endif
659 { "-/+wf",                 "turn on/off wait for map before command exec" },
660 { "-e command args ...",   "command to execute" },
661 #if OPT_TEK4014
662 { "%geom",                 "Tek window geometry" },
663 #endif
664 { "#geom",                 "icon window geometry" },
665 { "-T string",             "title name for window" },
666 { "-n string",             "icon name for window" },
667 { "-C",                    "intercept console messages" },
668 { "-Sccn",                 "slave mode on \"ttycc\", file descriptor \"n\"" },
669 { "-into windowId",        "use the window id given to -into as the parent window rather than the default root window" },
670 #if OPT_ZICONBEEP
671 { "-ziconbeep percent",    "beep and flag icon of window having hidden output" },
672 #endif
673 #if OPT_SAME_NAME
674 { "-/+samename",           "turn on/off the no-flicker option for title and icon name" },
675 #endif
676 #if OPT_SESSION_MGT
677 { "-/+sm",                 "turn on/off the session-management support" },
678 #endif
679 #if OPT_MAXIMIZE
680 {"-/+maximized",           "turn on/off maxmize on startup" },
681 #endif
682 { NULL, NULL }};
683 /* *INDENT-ON* */
684
685 #ifdef DBG_CONSOLE
686 FILE *confd;
687
688 static void
689 closecons(void)
690 {
691     if (confs != 0) {
692         fclose(confd);
693         confd = 0;
694     }
695 }
696 static void
697 opencons(void)
698 {
699     closecons();
700     if ((confd = fopen("/dev/console$", "w")) < 0) {
701         fputs("!!! Cannot open console device.\n",
702               stderr);
703         exit(1);
704     }
705 }
706 #else
707 #define opencons()              /* nothing */
708 #define closecons()             /* nothing */
709 #endif
710
711 static const char *message[] =
712 {
713     "Fonts should be fixed width and, if both normal and bold are specified, should",
714     "have the same size.  If only a normal font is specified, it will be used for",
715     "both normal and bold text (by doing overstriking).  The -e option, if given,",
716     "must appear at the end of the command line, otherwise the user's default shell",
717     "will be started.  Options that start with a plus sign (+) restore the default.",
718     NULL};
719
720 /*
721  * Decode a key-definition.  This combines the termcap and ttyModes, for
722  * comparison.  Note that octal escapes in ttyModes are done by the normal
723  * resource translation.  Also, ttyModes allows '^-' as a synonym for disabled.
724  */
725 static int
726 decode_keyvalue(char **ptr, int termcap)
727 {
728     char *string = *ptr;
729     int value = -1;
730
731     TRACE(("...decode '%s'\n", string));
732     if (*string == '^') {
733         switch (*++string) {
734         case '?':
735             value = A2E(ANSI_DEL);
736             break;
737         case '-':
738             if (!termcap) {
739                 errno = 0;
740 #if defined(_POSIX_VDISABLE) && defined(HAVE_UNISTD_H)
741                 value = _POSIX_VDISABLE;
742 #endif
743 #if defined(_PC_VDISABLE)
744                 if (value == -1) {
745                     value = fpathconf(0, _PC_VDISABLE);
746                     if (value == -1) {
747                         if (errno != 0)
748                             break;      /* skip this (error) */
749                         value = 0377;
750                     }
751                 }
752 #elif defined(VDISABLE)
753                 if (value == -1)
754                     value = VDISABLE;
755 #endif
756                 break;
757             }
758             /* FALLTHRU */
759         default:
760             value = CONTROL(*string);
761             break;
762         }
763         ++string;
764     } else if (termcap && (*string == '\\')) {
765         char *d;
766         int temp = strtol(string + 1, &d, 8);
767         if (temp > 0 && d != string) {
768             value = temp;
769             string = d;
770         }
771     } else {
772         value = CharOf(*string);
773         ++string;
774     }
775     *ptr = string;
776     return value;
777 }
778
779 static int
780 abbrev(const char *tst, const char *cmp, size_t need)
781 {
782     size_t len = strlen(tst);
783     return ((len >= need) && (!strncmp(tst, cmp, len)));
784 }
785
786 static void
787 Syntax(char *badOption)
788 {
789     OptionHelp *opt;
790     OptionHelp *list = sortedOpts(xtermOptions, optionDescList, XtNumber(optionDescList));
791     int col;
792
793     fprintf(stderr, "%s:  bad command line option \"%s\"\r\n\n",
794             ProgramName, badOption);
795
796     fprintf(stderr, "usage:  %s", ProgramName);
797     col = 8 + (int) strlen(ProgramName);
798     for (opt = list; opt->opt; opt++) {
799         int len = 3 + (int) strlen(opt->opt);   /* space [ string ] */
800         if (col + len > 79) {
801             fprintf(stderr, "\r\n   ");         /* 3 spaces */
802             col = 3;
803         }
804         fprintf(stderr, " [%s]", opt->opt);
805         col += len;
806     }
807
808     fprintf(stderr, "\r\n\nType %s -help for a full description.\r\n\n",
809             ProgramName);
810     exit(1);
811 }
812
813 static void
814 Version(void)
815 {
816     printf("%s\n", xtermVersion());
817     fflush(stdout);
818 }
819
820 static void
821 Help(void)
822 {
823     OptionHelp *opt;
824     OptionHelp *list = sortedOpts(xtermOptions, optionDescList, XtNumber(optionDescList));
825     const char **cpp;
826
827     printf("%s usage:\n    %s [-options ...] [-e command args]\n\n",
828            xtermVersion(), ProgramName);
829     printf("where options include:\n");
830     for (opt = list; opt->opt; opt++) {
831         printf("    %-28s %s\n", opt->opt, opt->desc);
832     }
833
834     putchar('\n');
835     for (cpp = message; *cpp; cpp++)
836         puts(*cpp);
837     putchar('\n');
838     fflush(stdout);
839 }
840
841 /* ARGSUSED */
842 static Boolean
843 ConvertConsoleSelection(Widget w GCC_UNUSED,
844                         Atom * selection GCC_UNUSED,
845                         Atom * target GCC_UNUSED,
846                         Atom * type GCC_UNUSED,
847                         XtPointer *value GCC_UNUSED,
848                         unsigned long *length GCC_UNUSED,
849                         int *format GCC_UNUSED)
850 {
851     /* we don't save console output, so can't offer it */
852     return False;
853 }
854
855 #if OPT_SESSION_MGT
856 static void
857 die_callback(Widget w GCC_UNUSED,
858              XtPointer client_data GCC_UNUSED,
859              XtPointer call_data GCC_UNUSED)
860 {
861     Cleanup(0);
862 }
863
864 static void
865 save_callback(Widget w GCC_UNUSED,
866               XtPointer client_data GCC_UNUSED,
867               XtPointer call_data)
868 {
869     XtCheckpointToken token = (XtCheckpointToken) call_data;
870     /* we have nothing to save */
871     token->save_success = True;
872 }
873
874 static void
875 icewatch(IceConn iceConn,
876          IcePointer clientData GCC_UNUSED,
877          Bool opening,
878          IcePointer * watchData GCC_UNUSED)
879 {
880     if (opening) {
881         ice_fd = IceConnectionNumber(iceConn);
882         TRACE(("got IceConnectionNumber %d\n", ice_fd));
883     } else {
884         ice_fd = -1;
885         TRACE(("reset IceConnectionNumber\n"));
886     }
887 }
888
889 #endif /* OPT_SESSION_MGT */
890
891 /*
892  * DeleteWindow(): Action proc to implement ICCCM delete_window.
893  */
894 /* ARGSUSED */
895 static void
896 DeleteWindow(Widget w,
897              XEvent * event GCC_UNUSED,
898              String * params GCC_UNUSED,
899              Cardinal *num_params GCC_UNUSED)
900 {
901 #if OPT_TEK4014
902     if (w == toplevel) {
903         if (TEK4014_SHOWN(term))
904             hide_vt_window();
905         else
906             do_hangup(w, (XtPointer) 0, (XtPointer) 0);
907     } else if (TScreenOf(term)->Vshow)
908         hide_tek_window();
909     else
910 #endif
911         do_hangup(w, (XtPointer) 0, (XtPointer) 0);
912 }
913
914 /* ARGSUSED */
915 static void
916 KeyboardMapping(Widget w GCC_UNUSED,
917                 XEvent * event,
918                 String * params GCC_UNUSED,
919                 Cardinal *num_params GCC_UNUSED)
920 {
921     switch (event->type) {
922     case MappingNotify:
923         XRefreshKeyboardMapping(&event->xmapping);
924         break;
925     }
926 }
927
928 static XtActionsRec actionProcs[] =
929 {
930     {"DeleteWindow", DeleteWindow},
931     {"KeyboardMapping", KeyboardMapping},
932 };
933
934 char **gblenvp;
935
936 int
937 main(int argc, char **argv ENVP_ARG)
938 {
939     Widget form_top, menu_top;
940     Dimension menu_high;
941     TScreen *screen;
942     int mode;
943     char *my_class = DEFCLASS;
944     Window winToEmbedInto = None;
945 #if OPT_COLOR_RES
946     Bool reversed = False;
947 #endif
948
949     ProgramName = argv[0];
950
951     save_ruid = getuid();
952     save_rgid = getgid();
953
954     /* Do these first, since we may not be able to open the display */
955     TRACE_OPTS(xtermOptions, optionDescList, XtNumber(optionDescList));
956     TRACE_ARGV("Before XtOpenApplication", argv);
957     if (argc > 1) {
958         int n;
959         unsigned unique = 2;
960         Bool quit = True;
961
962         for (n = 1; n < argc; n++) {
963             TRACE(("parsing %s\n", argv[n]));
964             if (abbrev(argv[n], "-version", unique)) {
965                 Version();
966             } else if (abbrev(argv[n], "-help", unique)) {
967                 Help();
968             } else if (abbrev(argv[n], "-class", 3)) {
969                 if ((my_class = argv[++n]) == 0) {
970                     Help();
971                 } else {
972                     quit = False;
973                 }
974                 unique = 3;
975             } else {
976 #if OPT_COLOR_RES
977                 if (abbrev(argv[n], "-reverse", 2)
978                     || !strcmp("-rv", argv[n])) {
979                     reversed = True;
980                 } else if (!strcmp("+rv", argv[n])) {
981                     reversed = False;
982                 }
983 #endif
984                 quit = False;
985                 unique = 3;
986             }
987         }
988         if (quit)
989             exit(0);
990     }
991
992     /* XXX: for some obscure reason EMX seems to lose the value of
993      * the environ variable, don't understand why, so save it recently
994      */
995     gblenvp = envp;
996
997 #ifdef I18N
998     setlocale(LC_ALL, NULL);
999 #endif
1000
1001     opencons();
1002
1003     ttydev = TypeMallocN(char, PTMS_BUFSZ);
1004     ptydev = TypeMallocN(char, PTMS_BUFSZ);
1005     if (!ttydev || !ptydev) {
1006         fprintf(stderr,
1007                 "%s:  unable to allocate memory for ttydev or ptydev\n",
1008                 ProgramName);
1009         exit(1);
1010     }
1011     strcpy(ttydev, TTYDEV);
1012     strcpy(ptydev, PTYDEV);
1013
1014     /* Initialization is done here rather than above in order
1015      * to prevent any assumptions about the order of the contents
1016      * of the various terminal structures (which may change from
1017      * implementation to implementation).
1018      */
1019     d_tio.c_iflag = ICRNL | IXON;
1020     d_tio.c_oflag = OPOST | ONLCR | TAB3;
1021     d_tio.c_cflag = B38400 | CS8 | CREAD | PARENB | HUPCL;
1022     d_tio.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK;
1023     d_tio.c_line = 0;
1024     d_tio.c_cc[VINTR] = CONTROL('C');   /* '^C' */
1025     d_tio.c_cc[VERASE] = ANSI_DEL;      /* DEL  */
1026     d_tio.c_cc[VKILL] = CONTROL('U');   /* '^U' */
1027     d_tio.c_cc[VQUIT] = CQUIT;  /* '^\' */
1028     d_tio.c_cc[VEOF] = CEOF;    /* '^D' */
1029     d_tio.c_cc[VEOL] = CEOL;    /* '^@' */
1030
1031     XtSetErrorHandler(xt_error);
1032 #if OPT_SESSION_MGT
1033     toplevel = XtOpenApplication(&app_con, my_class,
1034                                  optionDescList,
1035                                  XtNumber(optionDescList),
1036                                  &argc, argv, fallback_resources,
1037                                  sessionShellWidgetClass,
1038                                  NULL, 0);
1039     IceAddConnectionWatch(icewatch, NULL);
1040 #else
1041     toplevel = XtAppInitialize(&app_con, my_class,
1042                                optionDescList,
1043                                XtNumber(optionDescList),
1044                                &argc, argv, fallback_resources,
1045                                NULL, 0);
1046 #endif /* OPT_SESSION_MGT */
1047     XtSetErrorHandler((XtErrorHandler) 0);
1048
1049     XtGetApplicationResources(toplevel, (XtPointer) &resource,
1050                               application_resources,
1051                               XtNumber(application_resources), NULL, 0);
1052     TRACE_XRES();
1053
1054     /*
1055      * ICCCM delete_window.
1056      */
1057     XtAppAddActions(app_con, actionProcs, XtNumber(actionProcs));
1058
1059     /*
1060      * fill in terminal modes
1061      */
1062     if (resource.tty_modes) {
1063         int n = parse_tty_modes(resource.tty_modes, ttymodelist);
1064         if (n < 0) {
1065             fprintf(stderr, "%s:  bad tty modes \"%s\"\n",
1066                     ProgramName, resource.tty_modes);
1067         } else if (n > 0) {
1068             override_tty_modes = True;
1069         }
1070     }
1071 #if OPT_ZICONBEEP
1072     if (resource.zIconBeep > 100 || resource.zIconBeep < -100) {
1073         resource.zIconBeep = 0; /* was 100, but I prefer to defaulting off. */
1074         fprintf(stderr,
1075                 "a number between -100 and 100 is required for zIconBeep.  0 used by default\n");
1076     }
1077 #endif /* OPT_ZICONBEEP */
1078     hold_screen = resource.hold_screen ? 1 : 0;
1079     xterm_name = resource.xterm_name;
1080     if (strcmp(xterm_name, "-") == 0)
1081         xterm_name = DFT_TERMTYPE;
1082     if (resource.icon_geometry != NULL) {
1083         int scr, junk;
1084         int ix, iy;
1085         Arg args[2];
1086
1087         for (scr = 0;           /* yyuucchh */
1088              XtScreen(toplevel) != ScreenOfDisplay(XtDisplay(toplevel), scr);
1089              scr++) ;
1090
1091         args[0].name = XtNiconX;
1092         args[1].name = XtNiconY;
1093         XGeometry(XtDisplay(toplevel), scr, resource.icon_geometry, "",
1094                   0, 0, 0, 0, 0, &ix, &iy, &junk, &junk);
1095         args[0].value = (XtArgVal) ix;
1096         args[1].value = (XtArgVal) iy;
1097         XtSetValues(toplevel, args, 2);
1098     }
1099
1100     XtSetValues(toplevel, ourTopLevelShellArgs,
1101                 number_ourTopLevelShellArgs);
1102
1103 #if OPT_WIDE_CHARS
1104     /* seems as good a place as any */
1105     init_classtab();
1106 #endif
1107
1108     /* Parse the rest of the command line */
1109     TRACE_ARGV("After XtOpenApplication", argv);
1110     for (argc--, argv++; argc > 0; argc--, argv++) {
1111         if (**argv != '-')
1112             Syntax(*argv);
1113
1114         TRACE(("parsing %s\n", argv[0]));
1115         switch (argv[0][1]) {
1116         case 'h':               /* -help */
1117             Help();
1118             continue;
1119         case 'v':               /* -version */
1120             Version();
1121             continue;
1122         case 'C':
1123             {
1124                 struct stat sbuf;
1125
1126                 /* Must be owner and have read/write permission.
1127                    xdm cooperates to give the console the right user. */
1128                 if (!stat("/dev/console", &sbuf) &&
1129                     (sbuf.st_uid == save_ruid) &&
1130                     !access("/dev/console", R_OK | W_OK)) {
1131                     Console = True;
1132                 } else
1133                     Console = False;
1134             }
1135             continue;
1136         case 'S':
1137             if (sscanf(*argv + 2, "%c%c%d", passedPty, passedPty + 1,
1138                        &am_slave) != 3)
1139                 Syntax(*argv);
1140             continue;
1141 #ifdef DEBUG
1142         case 'D':
1143             debug = True;
1144             continue;
1145 #endif /* DEBUG */
1146         case 'c':               /* -class param */
1147             if (strcmp(argv[0] + 1, "class") == 0)
1148                 argc--, argv++;
1149             else
1150                 Syntax(*argv);
1151             continue;
1152         case 'e':
1153             if (argc <= 1)
1154                 Syntax(*argv);
1155             command_to_exec = ++argv;
1156             break;
1157         case 'i':
1158             if (argc <= 1) {
1159                 Syntax(*argv);
1160             } else {
1161                 char *endPtr;
1162                 --argc;
1163                 ++argv;
1164                 winToEmbedInto = (Window) strtol(argv[0], &endPtr, 10);
1165             }
1166             continue;
1167
1168         default:
1169             Syntax(*argv);
1170         }
1171         break;
1172     }
1173
1174     SetupMenus(toplevel, &form_top, &menu_top, &menu_high);
1175
1176     term = (XtermWidget) XtVaCreateManagedWidget("vt100", xtermWidgetClass,
1177                                                  form_top,
1178 #if OPT_TOOLBAR
1179                                                  XtNmenuBar, menu_top,
1180                                                  XtNresizable, True,
1181                                                  XtNfromVert, menu_top,
1182                                                  XtNleft, XawChainLeft,
1183                                                  XtNright, XawChainRight,
1184                                                  XtNtop, XawChainTop,
1185                                                  XtNbottom, XawChainBottom,
1186                                                  XtNmenuHeight, menu_high,
1187 #endif
1188                                                  (XtPointer) 0);
1189     decode_keyboard_type(term, &resource);
1190
1191     screen = TScreenOf(term);
1192     screen->inhibit = 0;
1193
1194 #ifdef ALLOWLOGGING
1195     if (term->misc.logInhibit)
1196         screen->inhibit |= I_LOG;
1197 #endif
1198     if (term->misc.signalInhibit)
1199         screen->inhibit |= I_SIGNAL;
1200 #if OPT_TEK4014
1201     if (term->misc.tekInhibit)
1202         screen->inhibit |= I_TEK;
1203 #endif
1204
1205     /*
1206      * We might start by showing the tek4014 window.
1207      */
1208 #if OPT_TEK4014
1209     if (screen->inhibit & I_TEK)
1210         TEK4014_ACTIVE(term) = False;
1211
1212     if (TEK4014_ACTIVE(term) && !TekInit())
1213         SysError(ERROR_INIT);
1214 #endif
1215
1216     /*
1217      * Start the toolbar at this point, after the first window has been setup.
1218      */
1219 #if OPT_TOOLBAR
1220     ShowToolbar(resource.toolBar);
1221 #endif
1222
1223 #if OPT_SESSION_MGT
1224     if (resource.sessionMgt) {
1225         TRACE(("Enabling session-management callbacks\n"));
1226         XtAddCallback(toplevel, XtNdieCallback, die_callback, NULL);
1227         XtAddCallback(toplevel, XtNsaveCallback, save_callback, NULL);
1228     }
1229 #endif
1230
1231     /*
1232      * Set title and icon name if not specified
1233      */
1234     if (command_to_exec) {
1235         Arg args[2];
1236
1237         if (!resource.title) {
1238             if (command_to_exec) {
1239                 resource.title = x_basename(command_to_exec[0]);
1240             }                   /* else not reached */
1241         }
1242
1243         if (!resource.icon_name)
1244             resource.icon_name = resource.title;
1245         XtSetArg(args[0], XtNtitle, resource.title);
1246         XtSetArg(args[1], XtNiconName, resource.icon_name);
1247
1248         TRACE(("setting:\n\ttitle \"%s\"\n\ticon \"%s\"\n\tbased on command \"%s\"\n",
1249                resource.title,
1250                resource.icon_name,
1251                *command_to_exec));
1252
1253         XtSetValues(toplevel, args, 2);
1254     }
1255 #if OPT_LUIT_PROG
1256     if (term->misc.callfilter) {
1257         int u = (term->misc.use_encoding ? 2 : 0);
1258         if (command_to_exec) {
1259             int n;
1260             char **c;
1261             for (n = 0, c = command_to_exec; *c; n++, c++) ;
1262             c = TypeMallocN(char *, n + 3 + u);
1263             if (c == NULL)
1264                 SysError(ERROR_LUMALLOC);
1265             memcpy(c + 2 + u, command_to_exec, (n + 1) * sizeof(char *));
1266             c[0] = term->misc.localefilter;
1267             if (u) {
1268                 c[1] = "-encoding";
1269                 c[2] = term->misc.locale_str;
1270             }
1271             c[1 + u] = "--";
1272             command_to_exec_with_luit = c;
1273         } else {
1274             static char *luit[6];
1275             luit[0] = term->misc.localefilter;
1276             if (u) {
1277                 luit[1] = "-encoding";
1278                 luit[2] = term->misc.locale_str;
1279                 luit[3] = NULL;
1280             } else
1281                 luit[1] = NULL;
1282             command_to_exec_with_luit = luit;
1283         }
1284     }
1285 #endif
1286
1287 #ifdef DEBUG
1288     {
1289         /* Set up stderr properly.  Opening this log file cannot be
1290            done securely by a privileged xterm process (although we try),
1291            so the debug feature is disabled by default. */
1292         char dbglogfile[45];
1293         int i = -1;
1294         if (debug) {
1295             timestamp_filename(dbglogfile, "xterm.debug.log.");
1296             if (creat_as(save_ruid, save_rgid, False, dbglogfile, 0666) > 0) {
1297                 i = open(dbglogfile, O_WRONLY | O_TRUNC);
1298             }
1299         }
1300         if (i >= 0) {
1301             dup2(i, 2);
1302
1303             /* mark this file as close on exec */
1304             (void) fcntl(i, F_SETFD, 1);
1305         }
1306     }
1307 #endif /* DEBUG */
1308
1309     spawnXTerm(term);
1310
1311     /* Child process is out there, let's catch its termination */
1312     (void) signal(SIGCHLD, reapchild);
1313
1314     /* Realize procs have now been executed */
1315
1316     if (am_slave >= 0) {        /* Write window id so master end can read and use */
1317         char buf[80];
1318
1319         buf[0] = '\0';
1320         sprintf(buf, "%lx\n", XtWindow(SHELL_OF(CURRENT_EMU())));
1321         IGNORE_RC(write(screen->respond, buf, strlen(buf)));
1322     }
1323
1324     if (0 > (mode = fcntl(screen->respond, F_GETFL, 0)))
1325         SysError(ERROR_F_GETFL);
1326     mode |= O_NDELAY;
1327
1328     if (fcntl(screen->respond, F_SETFL, mode))
1329         SysError(ERROR_F_SETFL);
1330
1331     FD_ZERO(&pty_mask);
1332     FD_ZERO(&X_mask);
1333     FD_ZERO(&Select_mask);
1334     FD_SET(screen->respond, &pty_mask);
1335     FD_SET(ConnectionNumber(screen->display), &X_mask);
1336     FD_SET(screen->respond, &Select_mask);
1337     FD_SET(ConnectionNumber(screen->display), &Select_mask);
1338     max_plus1 = ((screen->respond < ConnectionNumber(screen->display))
1339                  ? (1 + ConnectionNumber(screen->display))
1340                  : (1 + screen->respond));
1341
1342 #ifdef DEBUG
1343     if (debug)
1344         printf("debugging on\n");
1345 #endif /* DEBUG */
1346     XSetErrorHandler(xerror);
1347     XSetIOErrorHandler(xioerror);
1348
1349     initPtyData(&VTbuffer);
1350 #ifdef ALLOWLOGGING
1351     if (term->misc.log_on) {
1352         StartLog(term);
1353     }
1354 #endif
1355
1356     if (winToEmbedInto != None) {
1357         XtRealizeWidget(toplevel);
1358         /*
1359          * This should probably query the tree or check the attributes of
1360          * winToEmbedInto in order to verify that it exists, but I'm still not
1361          * certain what is the best way to do it -GPS
1362          */
1363         XReparentWindow(XtDisplay(toplevel),
1364                         XtWindow(toplevel),
1365                         winToEmbedInto, 0, 0);
1366     }
1367 #if OPT_COLOR_RES
1368     TRACE(("checking resource values rv %s fg %s, bg %s\n",
1369            BtoS(term->misc.re_verse0),
1370            NonNull(TScreenOf(term)->Tcolors[TEXT_FG].resource),
1371            NonNull(TScreenOf(term)->Tcolors[TEXT_BG].resource)));
1372
1373     if ((reversed && term->misc.re_verse0)
1374         && ((TScreenOf(term)->Tcolors[TEXT_FG].resource
1375              && !isDefaultForeground(TScreenOf(term)->Tcolors[TEXT_FG].resource))
1376             || (TScreenOf(term)->Tcolors[TEXT_BG].resource
1377                 && !isDefaultBackground(TScreenOf(term)->Tcolors[TEXT_BG].resource))
1378         ))
1379         ReverseVideo(term);
1380 #endif /* OPT_COLOR_RES */
1381
1382 #if OPT_MAXIMIZE
1383     if (resource.maximized)
1384         RequestMaximize(term, True);
1385 #endif
1386     for (;;) {
1387 #if OPT_TEK4014
1388         if (TEK4014_ACTIVE(term))
1389             TekRun();
1390         else
1391 #endif
1392             VTRun(term);
1393     }
1394     return 0;
1395 }
1396
1397 /*
1398  * Called from get_pty to iterate over likely pseudo terminals
1399  * we might allocate.  Used on those systems that do not have
1400  * a functional interface for allocating a pty.
1401  * Returns 0 if found a pty, 1 if fails.
1402  */
1403 static int
1404 pty_search(int *pty)
1405 {
1406     char namebuf[PTMS_BUFSZ];
1407
1408     /* ask the PTY manager */
1409     int fd = open("/dev/ptms$", 0);
1410     if (fd && ptioctl(fd, PTMS_GETPTY, namebuf) == 0) {
1411         strcpy(ttydev, namebuf);
1412         strcpy(ptydev, namebuf);
1413         *x_basename(ttydev) = 't';
1414         close(fd);
1415         if ((*pty = open(ptydev, O_RDWR)) >= 0) {
1416 #ifdef PTYDEBUG
1417             ptioctl(*pty, XTY_TRACE, 0);
1418 #endif
1419             return 0;
1420         } else {
1421             fprintf(stderr, "Unable to open %s, errno=%d\n", ptydev, errno);
1422         }
1423     }
1424     return 1;
1425 }
1426
1427 /*
1428  * This function opens up a pty master and stuffs its value into pty.
1429  *
1430  * If it finds one, it returns a value of 0.  If it does not find one,
1431  * it returns a value of !0.  This routine is designed to be re-entrant,
1432  * so that if a pty master is found and later, we find that the slave
1433  * has problems, we can re-enter this function and get another one.
1434  */
1435 static int
1436 get_pty(int *pty)
1437 {
1438     return pty_search(pty);
1439 }
1440
1441 /*
1442  * The only difference in /etc/termcap between 4014 and 4015 is that
1443  * the latter has support for switching character sets.  We support the
1444  * 4015 protocol, but ignore the character switches.  Therefore, we
1445  * choose 4014 over 4015.
1446  *
1447  * Features of the 4014 over the 4012: larger (19") screen, 12-bit
1448  * graphics addressing (compatible with 4012 10-bit addressing),
1449  * special point plot mode, incremental plot mode (not implemented in
1450  * later Tektronix terminals), and 4 character sizes.
1451  * All of these are supported by xterm.
1452  */
1453
1454 #if OPT_TEK4014
1455 static char *tekterm[] =
1456 {
1457     "tek4014",
1458     "tek4015",                  /* 4014 with APL character set support */
1459     "tek4012",                  /* 4010 with lower case */
1460     "tek4013",                  /* 4012 with APL character set support */
1461     "tek4010",                  /* small screen, upper-case only */
1462     "dumb",
1463     0
1464 };
1465 #endif
1466
1467 /* The VT102 is a VT100 with the Advanced Video Option included standard.
1468  * It also adds Escape sequences for insert/delete character/line.
1469  * The VT220 adds 8-bit character sets, selective erase.
1470  * The VT320 adds a 25th status line, terminal state interrogation.
1471  * The VT420 has up to 48 lines on the screen.
1472  */
1473
1474 static char *vtterm[] =
1475 {
1476 #ifdef USE_X11TERM
1477     "x11term",                  /* for people who want special term name */
1478 #endif
1479     DFT_TERMTYPE,               /* for people who want special term name */
1480     "xterm",                    /* the prefered name, should be fastest */
1481     "vt102",
1482     "vt100",
1483     "ansi",
1484     "dumb",
1485     0
1486 };
1487
1488 /* ARGSUSED */
1489 static SIGNAL_T
1490 hungtty(int i GCC_UNUSED)
1491 {
1492     longjmp(env, 1);
1493     SIGNAL_RETURN;
1494 }
1495
1496 #if OPT_PTY_HANDSHAKE
1497 struct {
1498     int rows;
1499     int cols;
1500 } handshake = {
1501
1502     -1, -1
1503 };
1504
1505 void
1506 first_map_occurred(void)
1507 {
1508     if (resource.wait_for_map) {
1509         TScreen *screen = TScreenOf(term);
1510         handshake.rows = screen->max_row;
1511         handshake.cols = screen->max_col;
1512         resource.wait_for_map = False;
1513     }
1514 }
1515 #endif /* OPT_PTY_HANDSHAKE else !OPT_PTY_HANDSHAKE */
1516
1517 static void
1518 set_owner(char *device, uid_t uid, gid_t gid, mode_t mode)
1519 {
1520     int why;
1521
1522     if (chown(device, uid, gid) < 0) {
1523         why = errno;
1524         if (why != ENOENT
1525             && save_ruid == 0) {
1526             fprintf(stderr, "Cannot chown %s to %ld,%ld: %s\n",
1527                     device, (long) uid, (long) gid,
1528                     strerror(why));
1529         }
1530     }
1531 }
1532
1533 #define THE_PARENT 1
1534 #define THE_CHILD  2
1535 int whoami = -1;
1536
1537 SIGNAL_T
1538 killit(int sig)
1539 {
1540     switch (whoami) {
1541     case -1:
1542         signal(sig, killit);
1543         kill(-getpid(), sig);
1544         break;
1545     case THE_PARENT:
1546         wait(NULL);
1547         signal(SIGTERM, SIG_DFL);
1548         kill(-getpid(), SIGTERM);
1549         Exit(0);
1550         break;
1551     case THE_CHILD:
1552         signal(SIGTERM, SIG_DFL);
1553         kill(-getppid(), SIGTERM);
1554         Exit(0);
1555         break;
1556     }
1557
1558     SIGNAL_RETURN;
1559 }
1560
1561 #define close_fd(fd) close(fd), fd = -1
1562
1563 static int
1564 spawnXTerm(XtermWidget xw)
1565 /*
1566  *  Inits pty and tty and forks a login process.
1567  *  Does not close fd Xsocket.
1568  *  If slave, the pty named in passedPty is already open for use
1569  */
1570 {
1571     TScreen *screen = TScreenOf(xw);
1572     int Xsocket = ConnectionNumber(screen->display);
1573
1574     int ttyfd = -1;
1575     TERMIO_STRUCT tio;
1576     int status;
1577     Bool ok_termcap;
1578
1579     char *TermName = NULL;
1580     char *ptr, *shname, buf[64];
1581     int i, no_dev_tty = False;
1582     char *dev_tty_name = (char *) 0;
1583     TTYSIZE_STRUCT ts;
1584     int pgrp = getpid();
1585     char numbuf[12], **envnew;
1586
1587     screen->uid = save_ruid;
1588     screen->gid = save_rgid;
1589
1590     if (am_slave >= 0) {
1591         screen->respond = am_slave;
1592         ptydev[strlen(ptydev) - 2] =
1593             ttydev[strlen(ttydev) - 2] = passedPty[0];
1594         ptydev[strlen(ptydev) - 1] =
1595             ttydev[strlen(ttydev) - 1] = passedPty[1];
1596
1597         (void) xtermResetIds(screen);
1598     } else {
1599         Bool tty_got_hung;
1600
1601         /*
1602          * Sometimes /dev/tty hangs on open (as in the case of a pty
1603          * that has gone away).  Simply make up some reasonable
1604          * defaults.
1605          */
1606
1607         signal(SIGALRM, hungtty);
1608         alarm(2);               /* alarm(1) might return too soon */
1609         if (!setjmp(env)) {
1610             ttyfd = open("/dev/tty", O_RDWR);
1611             alarm(0);
1612             tty_got_hung = False;
1613         } else {
1614             tty_got_hung = True;
1615             ttyfd = -1;
1616             errno = ENXIO;
1617         }
1618         signal(SIGALRM, SIG_DFL);
1619
1620         /*
1621          * Check results and ignore current control terminal if
1622          * necessary.  ENXIO is what is normally returned if there is
1623          * no controlling terminal, but some systems (e.g. SunOS 4.0)
1624          * seem to return EIO.  Solaris 2.3 is said to return EINVAL.
1625          */
1626         if (ttyfd < 0) {
1627             if (tty_got_hung || errno == ENXIO || errno == EIO ||
1628                 errno == EINVAL || errno == ENOTTY) {
1629                 no_dev_tty = True;
1630                 tio = d_tio;
1631             } else {
1632                 SysError(ERROR_OPDEVTTY);
1633             }
1634         } else {
1635
1636             /* Get a copy of the current terminal's state,
1637              * if we can.  Some systems (e.g., SVR4 and MacII)
1638              * may not have a controlling terminal at this point
1639              * if started directly from xdm or xinit,
1640              * in which case we just use the defaults as above.
1641              */
1642             if (ioctl(ttyfd, TCGETA, &tio) == -1)
1643                 tio = d_tio;
1644
1645             close_fd(ttyfd);
1646         }
1647
1648         if (get_pty(&screen->respond)) {
1649             /*  no ptys! */
1650             exit(ERROR_PTYS);
1651         }
1652     }
1653
1654     /* avoid double MapWindow requests */
1655     XtSetMappedWhenManaged(SHELL_OF(CURRENT_EMU()), False);
1656
1657     wm_delete_window = XInternAtom(XtDisplay(toplevel), "WM_DELETE_WINDOW",
1658                                    False);
1659
1660     if (!TEK4014_ACTIVE(xw))
1661         VTInit(xw);             /* realize now so know window size for tty driver */
1662
1663     if (Console) {
1664         /*
1665          * Inform any running xconsole program
1666          * that we are going to steal the console.
1667          */
1668         XmuGetHostname(mit_console_name + MIT_CONSOLE_LEN, 255);
1669         mit_console = XInternAtom(screen->display, mit_console_name, False);
1670         /* the user told us to be the console, so we can use CurrentTime */
1671         XtOwnSelection(SHELL_OF(CURRENT_EMU()),
1672                        mit_console, CurrentTime,
1673                        ConvertConsoleSelection, NULL, NULL);
1674     }
1675 #if OPT_TEK4014
1676     if (TEK4014_ACTIVE(xw)) {
1677         envnew = tekterm;
1678     } else
1679 #endif
1680     {
1681         envnew = vtterm;
1682     }
1683
1684     /*
1685      * This used to exit if no termcap entry was found for the specified
1686      * terminal name.  That's a little unfriendly, so instead we'll allow
1687      * the program to proceed (but not to set $TERMCAP) if the termcap
1688      * entry is not found.
1689      */
1690     ok_termcap = True;
1691     if (!get_termcap(TermName = resource.term_name)) {
1692         char *last = NULL;
1693         TermName = *envnew;
1694         ok_termcap = False;
1695         while (*envnew != NULL) {
1696             if ((last == NULL || strcmp(last, *envnew))
1697                 && get_termcap(*envnew)) {
1698                 TermName = *envnew;
1699                 ok_termcap = True;
1700                 break;
1701             }
1702             last = *envnew;
1703             envnew++;
1704         }
1705     }
1706     if (ok_termcap) {
1707         resize_termcap(xw);
1708     }
1709
1710     /* tell tty how big window is */
1711 #if OPT_TEK4014
1712     if (TEK4014_ACTIVE(xw)) {
1713         TTYSIZE_ROWS(ts) = 38;
1714         TTYSIZE_COLS(ts) = 81;
1715         ts.ws_xpixel = TFullWidth(TekScreenOf(tekWidget));
1716         ts.ws_ypixel = TFullHeight(TekScreenOf(tekWidget));
1717     } else
1718 #endif
1719     {
1720         TTYSIZE_ROWS(ts) = MaxRows(screen);
1721         TTYSIZE_COLS(ts) = MaxCols(screen);
1722         ts.ws_xpixel = FullWidth(screen);
1723         ts.ws_ypixel = FullHeight(screen);
1724     }
1725
1726     if (am_slave < 0) {
1727
1728         char sema[40];
1729         HEV sev;
1730         /* start a child process
1731          * use an event sema for sync
1732          */
1733         sprintf(sema, "\\SEM32\\xterm%s", &ptydev[8]);
1734         if (DosCreateEventSem(sema, &sev, DC_SEM_SHARED, False))
1735             SysError(ERROR_FORK);
1736
1737         switch ((screen->pid = fork())) {
1738         case -1:                /* error */
1739             SysError(ERROR_FORK);
1740         default:                /* parent */
1741             whoami = THE_PARENT;
1742             DosWaitEventSem(sev, 1000L);
1743             DosCloseEventSem(sev);
1744             break;
1745         case 0:         /* child */
1746             whoami = THE_CHILD;
1747
1748             opencons();
1749             /* we don't need the socket, or the pty master anymore */
1750             close(ConnectionNumber(screen->display));
1751             close(screen->respond);
1752
1753             /* Now is the time to set up our process group and
1754              * open up the pty slave.
1755              */
1756             if ((ttyfd = open(ttydev, O_RDWR)) < 0) {
1757                 /* dumm gelaufen */
1758                 fprintf(stderr, "Cannot open slave side of PTY\n");
1759                 exit(1);
1760             }
1761
1762             /* use the same tty name that everyone else will use
1763              * (from ttyname)
1764              */
1765 #ifdef EMXNOTBOGUS
1766             if ((ptr = ttyname(ttyfd)) != 0) {
1767                 ttydev = x_strdup(ptr);
1768             }
1769 #else
1770             ptr = ttydev;
1771 #endif
1772             /* for safety: enable DUPs */
1773             ptioctl(ttyfd, XTY_ENADUP, 0);
1774
1775             /* change ownership of tty to real group and user id */
1776             set_owner(ttydev, screen->uid, screen->gid,
1777                       (resource.messages ? 0622U : 0600U));
1778
1779             /* for the xf86sup-pty, we set the pty to bypass: OS/2 does
1780              * not have a line discipline structure
1781              */
1782             {
1783                 TERMIO_STRUCT t, t1;
1784                 if (ptioctl(ttyfd, TCGETA, (char *) &t) < 0)
1785                     t = d_tio;
1786
1787                 t.c_iflag = ICRNL;
1788                 t.c_oflag = OPOST | ONLCR;
1789                 t.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK;
1790
1791                 /* ignore error code, user will see it :-) */
1792                 ptioctl(ttyfd, TCSETA, (char *) &t);
1793
1794                 /* set the console mode */
1795                 if (Console) {
1796                     int on = 1;
1797                     if (ioctl(ttyfd, TIOCCONS, (char *) &on) == -1)
1798                         fprintf(stderr, "%s: cannot open console: %s\n",
1799                                 ProgramName, strerror(errno));
1800                 }
1801             }
1802
1803             signal(SIGCHLD, SIG_DFL);
1804             signal(SIGHUP, SIG_IGN);
1805
1806             /* restore various signals to their defaults */
1807             signal(SIGINT, SIG_DFL);
1808             signal(SIGQUIT, SIG_DFL);
1809             signal(SIGTERM, SIG_DFL);
1810
1811             xtermCopyEnv(gblenvp);
1812
1813             xtermSetenv("TERM", TermName);
1814             if (!TermName)
1815                 *get_tcap_buffer(xw) = 0;
1816
1817             sprintf(buf, "%lu",
1818                     ((unsigned long) XtWindow(SHELL_OF(CURRENT_EMU()))));
1819             xtermSetenv("WINDOWID", buf);
1820
1821             /* put the display into the environment of the shell */
1822             xtermSetenv("DISPLAY", XDisplayString(screen->display));
1823
1824             xtermSetenv("XTERM_VERSION", xtermVersion());
1825             xtermSetenv("XTERM_LOCALE", xtermEnvLocale());
1826
1827             signal(SIGTERM, SIG_DFL);
1828
1829             /* this is the time to go and set up stdin, out, and err
1830              */
1831             /* dup the tty */
1832             for (i = 0; i <= 2; i++)
1833                 if (i != ttyfd) {
1834                     (void) close(i);
1835                     IGNORE_RC(dup(ttyfd));
1836                 }
1837
1838             /* and close the tty */
1839             if (ttyfd > 2)
1840                 close_fd(ttyfd);
1841
1842             setpgrp(0, pgrp);
1843             (void) xtermResetIds(screen);
1844
1845             if (handshake.rows > 0 && handshake.cols > 0) {
1846                 TRACE(("handshake ttysize: %dx%d\n",
1847                        handshake.rows, handshake.cols));
1848                 set_max_row(screen, handshake.rows);
1849                 set_max_col(screen, handshake.cols);
1850                 TTYSIZE_ROWS(ts) = MaxRows(screen);
1851                 TTYSIZE_COLS(ts) = MaxCols(screen);
1852                 ts.ws_xpixel = FullWidth(screen);
1853                 ts.ws_ypixel = FullHeight(screen);
1854             }
1855
1856             sprintf(numbuf, "%d", MaxCols(screen));
1857             xtermSetenv("COLUMNS", numbuf);
1858             sprintf(numbuf, "%d", MaxRows(screen));
1859             xtermSetenv("LINES", numbuf);
1860
1861             gblenvp = environ;
1862
1863             /* need to reset after all the ioctl bashing we did above */
1864             ptioctl(0, TIOCSWINSZ, (char *) &ts);
1865
1866             signal(SIGHUP, SIG_DFL);
1867
1868             /* okay everything seems right, so tell the parent, we are going */
1869             {
1870                 char sema[40];
1871                 HEV sev;
1872                 sprintf(sema, "\\SEM32\\xterm%s", &ttydev[8]);
1873                 DosOpenEventSem(sema, &sev);
1874                 DosPostEventSem(sev);
1875                 DosCloseEventSem(sev);
1876             }
1877
1878 #if OPT_LUIT_PROG
1879             /*
1880              * Use two copies of command_to_exec, in case luit is not actually
1881              * there, or refuses to run.  In that case we will fall-through to
1882              * to command that the user gave anyway.
1883              */
1884             if (command_to_exec_with_luit) {
1885                 xtermSetenv("XTERM_SHELL",
1886                             xtermFindShell(*command_to_exec_with_luit, False));
1887                 TRACE(("spawning command \"%s\"\n", *command_to_exec_with_luit));
1888                 execvp(*command_to_exec_with_luit, command_to_exec_with_luit);
1889                 /* print error message on screen */
1890                 fprintf(stderr, "%s: Can't execvp %s: %s\n",
1891                         ProgramName, *command_to_exec_with_luit, strerror(errno));
1892                 fprintf(stderr, "%s: cannot support your locale.\n",
1893                         ProgramName);
1894             }
1895 #endif
1896             if (command_to_exec) {
1897                 xtermSetenv("XTERM_SHELL",
1898                             xtermFindShell(*command_to_exec, False));
1899                 TRACE(("spawning command \"%s\"\n", *command_to_exec));
1900                 execvpe(*command_to_exec, command_to_exec, gblenvp);
1901
1902                 /* print error message on screen */
1903                 fprintf(stderr, "%s: Can't execvp %s\n",
1904                         ProgramName, *command_to_exec);
1905             }
1906
1907             /* use a layered mechanism to find a shell */
1908             ptr = x_getenv("X11SHELL");
1909             if (!ptr)
1910                 ptr = x_getenv("SHELL");
1911             if (!ptr)
1912                 ptr = x_getenv("OS2_SHELL");
1913             if (!ptr)
1914                 ptr = "SORRY_NO_SHELL_FOUND";
1915             xtermSetenv("XTERM_SHELL", ptr);
1916
1917             shname = x_basename(ptr);
1918             if (command_to_exec) {
1919                 char *exargv[10];       /*XXX */
1920
1921                 exargv[0] = ptr;
1922                 exargv[1] = "/C";
1923                 exargv[2] = command_to_exec[0];
1924                 exargv[3] = command_to_exec[1];
1925                 exargv[4] = command_to_exec[2];
1926                 exargv[5] = command_to_exec[3];
1927                 exargv[6] = command_to_exec[4];
1928                 exargv[7] = command_to_exec[5];
1929                 exargv[8] = command_to_exec[6];
1930                 exargv[9] = 0;
1931                 execvpe(exargv[0], exargv, gblenvp);
1932
1933                 /* print error message on screen */
1934                 fprintf(stderr, "%s: Can't execvp %s\n",
1935                         ProgramName, *command_to_exec);
1936             } else {
1937                 execlpe(ptr, shname, 0, gblenvp);
1938
1939                 /* Exec failed. */
1940                 fprintf(stderr, "%s: Could not exec %s!\n",
1941                         ProgramName, ptr);
1942             }
1943             sleep(5);
1944
1945             /* preventively shoot the parent */
1946             kill(-getppid(), SIGTERM);
1947
1948             exit(ERROR_EXEC);
1949         }                       /* endcase */
1950     }
1951     /* !am_slave */
1952     signal(SIGHUP, SIG_IGN);
1953 /*
1954  * Unfortunately, System V seems to have trouble divorcing the child process
1955  * from the process group of xterm.  This is a problem because hitting the
1956  * INTR or QUIT characters on the keyboard will cause xterm to go away if we
1957  * don't ignore the signals.  This is annoying.
1958  */
1959
1960 /*  signal (SIGINT, SIG_IGN);*/
1961     signal(SIGINT, killit);
1962     signal(SIGTERM, killit);
1963
1964     /* hung shell problem */
1965     signal(SIGQUIT, SIG_IGN);
1966 /*  signal (SIGTERM, SIG_IGN);*/
1967     return 0;
1968 }                               /* end spawnXTerm */
1969
1970 SIGNAL_T
1971 Exit(int n)
1972 {
1973     XtermWidget xw = term;
1974     TScreen *screen = TScreenOf(xw);
1975     int pty = TScreenOf(xw)->respond;
1976     close(pty);                 /* close explicitly to avoid race with slave side */
1977 #ifdef ALLOWLOGGING
1978     if (screen->logging)
1979         CloseLog(xw);
1980 #endif
1981     if (am_slave < 0) {
1982         /* restore ownership of tty and pty */
1983         set_owner(ttydev, 0, 0, 0666U);
1984         set_owner(ptydev, 0, 0, 0666U);
1985     }
1986
1987     /*
1988      * Close after releasing ownership to avoid race condition: other programs 
1989      * grabbing it, and *then* having us release ownership....
1990      */
1991     close(screen->respond);     /* close explicitly to avoid race with slave side */
1992 #ifdef ALLOWLOGGING
1993     if (screen->logging)
1994         CloseLog(xw);
1995 #endif
1996
1997 #ifdef NO_LEAKS
1998     if (n == 0) {
1999         TRACE(("Freeing memory leaks\n"));
2000         if (xw != 0) {
2001             Display *dpy = TScreenOf(xw)->display;
2002
2003             if (toplevel) {
2004                 XtDestroyWidget(toplevel);
2005                 TRACE(("destroyed top-level widget\n"));
2006             }
2007             sortedOpts(0, 0, 0);
2008             noleaks_charproc();
2009             noleaks_ptydata();
2010 #if OPT_WIDE_CHARS
2011             noleaks_CharacterClass();
2012 #endif
2013             /* XrmSetDatabase(dpy, 0); increases leaks ;-) */
2014             XtCloseDisplay(dpy);
2015             XtDestroyApplicationContext(app_con);
2016 #if OPT_SESSION_MGT
2017             IceRemoveConnectionWatch(icewatch, NULL);
2018 #endif
2019             TRACE(("closed display\n"));
2020         }
2021         TRACE((0));
2022     }
2023 #endif
2024
2025     exit(n);
2026     SIGNAL_RETURN;
2027 }
2028
2029 /* ARGSUSED */
2030 static void
2031 resize_termcap(XtermWidget xw)
2032 {
2033 }
2034
2035 /*
2036  * Does a non-blocking wait for a child process.  If the system
2037  * doesn't support non-blocking wait, do nothing.
2038  * Returns the pid of the child, or 0 or -1 if none or error.
2039  */
2040 int
2041 nonblocking_wait(void)
2042 {
2043     pid_t pid;
2044
2045     pid = waitpid(-1, NULL, WNOHANG);
2046     return pid;
2047 }
2048
2049 /* ARGSUSED */
2050 static SIGNAL_T
2051 reapchild(int n GCC_UNUSED)
2052 {
2053     int olderrno = errno;
2054     int pid;
2055
2056     pid = wait(NULL);
2057
2058     /* cannot re-enable signal before waiting for child
2059      * because then SVR4 loops.  Sigh.  HP-UX 9.01 too.
2060      */
2061     (void) signal(SIGCHLD, reapchild);
2062
2063     do {
2064         if (pid == TScreenOf(term)->pid) {
2065 #ifdef DEBUG
2066             if (debug)
2067                 fputs("Exiting\n", stderr);
2068 #endif
2069             if (!hold_screen)
2070                 need_cleanup = True;
2071         }
2072     } while ((pid = nonblocking_wait()) > 0);
2073
2074     errno = olderrno;
2075     SIGNAL_RETURN;
2076 }
2077
2078 /*
2079  * parse_tty_modes accepts lines of the following form:
2080  *
2081  *         [SETTING] ...
2082  *
2083  * where setting consists of the words in the modelist followed by a character
2084  * or ^char.
2085  */
2086 static int
2087 parse_tty_modes(char *s, struct _xttymodes *modelist)
2088 {
2089     struct _xttymodes *mp;
2090     int c;
2091     int count = 0;
2092
2093     TRACE(("parse_tty_modes\n"));
2094     while (1) {
2095         size_t len;
2096
2097         while (*s && isascii(CharOf(*s)) && isspace(CharOf(*s)))
2098             s++;
2099         if (!*s)
2100             return count;
2101
2102         for (len = 0; isalnum(CharOf(s[len])); ++len) ;
2103         for (mp = modelist; mp->name; mp++) {
2104             if (len == mp->len
2105                 && strncmp(s, mp->name, mp->len) == 0)
2106                 break;
2107         }
2108         if (!mp->name)
2109             return -1;
2110
2111         s += mp->len;
2112         while (*s && isascii(CharOf(*s)) && isspace(CharOf(*s)))
2113             s++;
2114         if (!*s)
2115             return -1;
2116
2117         if ((c = decode_keyvalue(&s, False)) != -1) {
2118             mp->value = c;
2119             mp->set = 1;
2120             count++;
2121             TRACE(("...parsed #%d: %s=%#x\n", count, mp->name, c));
2122         }
2123     }
2124 }
2125
2126 int
2127 GetBytesAvailable(int fd)
2128 {
2129     long arg;
2130     ioctl(fd, FIONREAD, (char *) &arg);
2131     return (int) arg;
2132 }
2133
2134 /* Utility function to try to hide system differences from
2135    everybody who used to call killpg() */
2136
2137 int
2138 kill_process_group(int pid, int sig)
2139 {
2140     return kill(-pid, sig);
2141 }
2142
2143 int
2144 ptioctl(int fd, int func, void *data)
2145 {
2146     APIRET rc;
2147     ULONG len;
2148     struct pt_termios pt;
2149     TERMIO_STRUCT *t;
2150     int i;
2151
2152     switch (func) {
2153     case TCGETA:
2154         rc = DosDevIOCtl(fd, XFREE86_PTY, XTY_TIOCGETA,
2155                          NULL, 0, NULL,
2156                          (ULONG *) & pt, sizeof(struct pt_termios), &len);
2157         if (rc)
2158             return -1;
2159         t = (TERMIO_STRUCT *) data;
2160         t->c_iflag = pt.c_iflag;
2161         t->c_oflag = pt.c_oflag;
2162         t->c_cflag = pt.c_cflag;
2163         t->c_lflag = pt.c_lflag;
2164         for (i = 0; i < NCC; i++)
2165             t->c_cc[i] = pt.c_cc[i];
2166         return 0;
2167     case TCSETA:
2168     case TCSETAW:
2169     case TCSETAF:
2170         t = (TERMIO_STRUCT *) data;
2171         pt.c_iflag = t->c_iflag;
2172         pt.c_oflag = t->c_oflag;
2173         pt.c_cflag = t->c_cflag;
2174         pt.c_lflag = t->c_lflag;
2175
2176         for (i = 0; i < NCC; i++)
2177             pt.c_cc[i] = t->c_cc[i];
2178         if (func == TCSETA)
2179             i = XTY_TIOCSETA;
2180         else if (func == TCSETAW)
2181             i = XTY_TIOCSETAW;
2182         else
2183             i = XTY_TIOCSETAF;
2184         rc = DosDevIOCtl(fd, XFREE86_PTY, i,
2185                          (ULONG *) & pt, sizeof(struct pt_termios), &len,
2186                          NULL, 0, NULL);
2187         return (rc) ? -1 : 0;
2188     case TIOCCONS:
2189         return DosDevIOCtl(fd, XFREE86_PTY, XTY_TIOCCONS,
2190                            (ULONG *) data, sizeof(ULONG), &len,
2191                            NULL, 0, NULL);
2192     case TIOCSWINSZ:
2193         return DosDevIOCtl(fd, XFREE86_PTY, XTY_TIOCSWINSZ,
2194                            (ULONG *) data, sizeof(TTYSIZE_STRUCT), &len,
2195                            NULL, 0, NULL);
2196     case TIOCGWINSZ:
2197         return DosDevIOCtl(fd, XFREE86_PTY, XTY_TIOCGWINSZ,
2198                            NULL, 0, NULL,
2199                            (ULONG *) data, sizeof(TTYSIZE_STRUCT), &len);
2200     case XTY_ENADUP:
2201         i = 1;
2202         return DosDevIOCtl(fd, XFREE86_PTY, XTY_ENADUP,
2203                            (ULONG *) & i, sizeof(ULONG), &len,
2204                            NULL, 0, NULL);
2205     case XTY_TRACE:
2206         i = 2;
2207         return DosDevIOCtl(fd, XFREE86_PTY, XTY_TRACE,
2208                            (ULONG *) & i, sizeof(ULONG), &len,
2209                            NULL, 0, NULL);
2210     case PTMS_GETPTY:
2211         i = 1;
2212         return DosDevIOCtl(fd, XFREE86_PTY, PTMS_GETPTY,
2213                            (ULONG *) & i, sizeof(ULONG), &len,
2214                            (UCHAR *) data, 14, &len);
2215     default:
2216         return -1;
2217     }
2218 }