1 /************************************************************************
2 * This program is Copyright (C) 1986-1996 by Jonathan Payne. JOVE is *
3 * provided to you without charge, and with no warranty. You may give *
4 * away copies of JOVE, including sources, provided that this notice is *
5 * included in all the files. *
6 ************************************************************************/
7
8 /* Contains the main loop initializations, and some system dependent
9 type things, e.g. putting terminal in CBREAK mode, etc. */
10
11 #include "jove.h"
12 #include "fp.h"
13 #include "jctype.h"
14 #include "chars.h"
15 #include "disp.h"
16 #include "re.h" /* for dosearch() */
17 #include "reapp.h" /* for find_tag(), UseRE */
18 #include "sysprocs.h"
19 #include "rec.h"
20 #include "ask.h"
21 #include "extend.h"
22 #include "fmt.h"
23 #include "macros.h"
24 #include "marks.h"
25 #include "mouse.h"
26 #ifndef MAC /* Mac does without! */
27 # include "paths.h"
28 #endif
29 #include "proc.h"
30 #include "screen.h"
31 #include "term.h"
32 #include "version.h"
33 #include "wind.h"
34
35 #ifdef IPROCS
36 # include "iproc.h"
37 #endif
38
39 #ifdef USE_SELECT
40 # include <sys/time.h>
41 # include "select.h"
42 #endif
43
44 #ifdef SCO /* ??? what is this for? */
45 # include <sys/stream.h>
46 # include <sys/ptem.h>
47 #endif
48
49 #include <signal.h>
50 #include <errno.h>
51
52 #ifdef MAC
53 # include "mac.h"
54 #else /* !MAC */
55 # include <sys/stat.h>
56 #endif /* !MAC */
57
58 #ifdef MSDOS
59 # include <bios.h>
60 # include <dos.h>
61 # include <time.h>
62 # include <process.h>
63 # define SIGHUP 99
64 # if defined(__WATCOMC__)
65 # include <malloc.h> /* for _heapgrow */
66 # endif
67 #endif /* MSDOS */
68
69 #ifdef WIN32
70 # include <windows.h> /* ??? is this needed? */
71 # undef FIONREAD /* This is defined but ioctl isn't so we cannot use it. */
72 #endif
73
74 #ifdef STACK_DECL /* provision for setting up appropriate stack */
75 STACK_DECL
76 #endif
77
78 private void
79 UnsetTerm proto((bool)),
80 DoKeys proto((bool firsttime)),
81 ShowKeyStrokes proto((void));
82
83 #ifdef NONBLOCKINGREAD
84 private void setblock proto((bool on));
85 #endif
86
87 #ifdef POSIX_SIGS
88 SIGHANDLERTYPE
setsighandler(signo,handler)89 setsighandler(signo, handler) /* simulate BSD's safe signal() */
90 int signo;
91 SIGHANDLERTYPE handler;
92 {
93 static struct sigaction act; /* static so unspecified fields are 0 */
94 struct sigaction oact;
95
96 act.sa_handler = handler;
97 sigemptyset(&act.sa_mask);
98 sigaddset(&act.sa_mask, signo);
99 sigaction(signo, &act, &oact);
100 return oact.sa_handler;
101 }
102 #endif
103
104 bool TimeDisplayed = YES; /* is time actually displayed in modeline? */
105
106 #ifdef UNIX
107
108 /* set things up to update the modeline every UpdFreq seconds */
109
110 int UpdFreq = 30; /* VAR: how often to update modeline */
111 bool InSlowRead = NO;
112
113 void
SetClockAlarm(unset)114 SetClockAlarm(unset)
115 bool unset; /* unset alarm if none needed */
116 {
117 if (TimeDisplayed && UpdFreq != 0)
118 (void) alarm((unsigned) (UpdFreq - (time((time_t *)NULL) % UpdFreq)));
119 else if (unset)
120 alarm((unsigned)0);
121 }
122
123 /* AlarmHandler gets all SIGALRMs. It decides, based on InWaitChar,
124 * whether this is an alarm for updating the mode line or for showing
125 * keystrokes. Theoretically, InWaitChar is a state variable that ought
126 * to be reset in complain and other exceptional cases, but waitchar
127 * is called often enough that it turns out to be self-correcting.
128 */
129
130 private volatile bool InWaitChar = NO;
131
132 /*ARGSUSED*/
133 private SIGRESTYPE
AlarmHandler(junk)134 AlarmHandler(junk)
135 int junk; /* passed in on signal; of no interest */
136 {
137 int save_errno = errno; /* Subtle, but necessary! */
138
139 resetsighandler(SIGALRM, AlarmHandler);
140 if (InWaitChar) {
141 if (InSlowRead) {
142 InSlowRead = NO;
143 ShowKeyStrokes();
144 redisplay();
145 InSlowRead = YES;
146 InWaitChar = NO; /* might as well allow modeline updates */
147 SetClockAlarm(NO);
148 } else {
149 alarm((unsigned)1); /* try again later */
150 }
151 } else {
152 UpdModLine = YES;
153 if (InSlowRead) {
154 /* needed because of stupid BSD restartable I/O */
155 InSlowRead = NO;
156 redisplay();
157 InSlowRead = YES;
158 }
159 SetClockAlarm(NO);
160 }
161 errno = save_errno;
162 return SIGRESVALUE;
163 }
164
165 #endif /* UNIX */
166
167 bool stickymsg; /* the last message should stick around */
168
169 char NullStr[] = "";
170 jmp_buf mainjmp;
171
172 #ifdef USE_SELECT
173 fd_set global_fd; /* set of file descriptors of interest (for select) */
174 int global_maxfd;
175 #endif
176
177 /* paths */
178
179 /* path of machine-independent library */
180 #ifdef SHAREDIR
181 char ShareDir[FILESIZE] = SHAREDIR;
182 #else
183 char ShareDir[FILESIZE];
184 #endif
185
186 /* VAR: directory/device to store tmp files */
187 #ifdef TMPDIR
188 char TmpDir[FILESIZE] = TMPDIR;
189 #else
190 char TmpDir[FILESIZE];
191 #endif
192
193 #ifdef SUBSHELL
194 char
195 Shell[FILESIZE] = DFLTSHELL, /* VAR: shell to use */
196 # ifdef MSFILESYSTEM
197 ShFlags[sizeof(ShFlags)] = "/c"; /* VAR: flags to shell */
198 # else
199 ShFlags[sizeof(ShFlags)] = "-c"; /* VAR: flags to shell */
200 # endif /* MSFILESYSTEM */
201 #endif
202
203 /* LibDir: path of machine-dependent library (for Portsrv and Recover) */
204
205 #if defined(SUBSHELL) || defined(PIPEPROCS)
206 # define NEED_LIBDIR 1
207 private char LibDir[FILESIZE] = LIBDIR;
208 #endif
209
210 /* finish: handle bad-news signals.
211 * It also handles internally generated requests for termination.
212 * For most values of code (signal types) an attempt
213 * is made to save the buffers for recovery by "recover".
214 * For most values of code, this routine stops JOVE
215 * by calling abort, which causes a core dump under UNIX.
216 *
217 * - code -1 is an internally generated request to die with an
218 * attempt to save the buffers. It had better not be the code
219 * for some real signal (it cannot be one under UNIX).
220 *
221 * - code 0 is an internally generated request to die quietly.
222 * It had better not be the code for some real signal
223 * (it cannot be one under UNIX). This is the only code
224 * for which buffers are not saved.
225 *
226 * - SIGINT is caused by the user hitting the INTR key.
227 * We give him a choice of death or continuation.
228 *
229 * - SIGHUP is caused by loss of connection. This code and
230 * code 0 are the only ones which don't cause an abort.
231 * Generated by OS and by JOVE itself.
232 */
233
234 SIGRESTYPE
finish(code)235 finish(code)
236 int code;
237 {
238 int save_errno = errno; /* Subtle, but necessary! */
239 bool DelTmps = YES; /* Usually we delete them. */
240
241 if (code == SIGINT) {
242 char c;
243 #ifdef WIN32
244 c = FatalErrorMessage("Fatal interrupt encountered. Abort?");
245 #else /* !WIN32 */
246 # ifdef PIPEPROCS
247 bool started;
248 # endif
249
250 resetsighandler(SIGINT, finish);
251 f_mess("Abort (Type 'n' if you're not sure)? ");
252 Placur(ILI, min(CO - 2, calc_pos(mesgbuf, MAXCOLS)));
253 flushscreen();
254 # ifdef UNIX
255 # ifdef PIPEPROCS
256 started = kbd_stop();
257 # endif
258 /*
259 * Yuk! This doesn't deal with all cases, we really need a
260 * standard jove input routine that's lower than kbd_getch so
261 * that this can use it. The code that this replaces was even
262 * more ugly. What about nonblocking reads? -- MM.
263 */
264 # ifdef NONBLOCKINGREAD
265 setblock(YES); /* turn blocking on (in case it was off) */
266 # endif
267 for (;;) {
268 c = 'n';
269 if (read(0, (UnivPtr) &c, sizeof(c)) < 0) {
270 switch (errno) {
271 case EINTR:
272 # if EWOULDBLOCK != EAGAIN /* aliases in System Vr4 */
273 case EWOULDBLOCK:
274 # endif
275 case EAGAIN:
276 continue;
277 }
278 }
279 break;
280 }
281 # ifdef PIPEPROCS
282 if (started)
283 kbd_strt();
284 # endif /* PIPEPROCS */
285 # endif /* UNIX */
286 # ifdef MSDOS
287 c = getrawinchar();
288 # endif /* MSDOS */
289 message(NullStr);
290 #endif /* !WIN32 */
291 if (c != 'y') {
292 redisplay();
293 errno = save_errno;
294 return SIGRESVALUE;
295 }
296 }
297 DisabledRedisplay = YES;
298 #ifndef MAC
299 UnsetTerm(NO);
300 #endif
301 #ifdef PIPEPROCS
302 kbd_kill(); /* kill the keyboard process */
303 #endif
304 #ifdef RECOVER
305 if (code != 0) {
306 static bool Crashing = NO; /* we are in the middle of crashing */
307
308 if (!Crashing) {
309 Crashing = YES;
310 lsave();
311 SyncRec();
312 writef("JOVE CRASH!! (code %d; last errno %d)\n",
313 code, save_errno);
314 if (ModBufs(YES)) {
315 writef("Your buffers have been saved.\n");
316 writef("Use \"jove -r\" to have a look at them.\n");
317 DelTmps = NO; /* Don't delete anymore. */
318 } else {
319 writef("No buffers needed saving: you didn't lose any work.\n");
320 }
321 } else {
322 writef("\r\nYou may have lost your work!\n");
323 }
324 }
325 #endif /* RECOVER */
326 flushscreen();
327 if (DelTmps) {
328 tmpremove();
329 #ifdef RECOVER
330 recremove();
331 #endif /* RECOVER */
332 }
333 #ifdef UNIX
334 if (code != 0 && code != SIGHUP)
335 abort();
336 # ifdef USE_EXIT
337 exit(0);
338 # else
339 _exit(0);
340 # endif
341 #else /* !UNIX */
342 exit(0);
343 #endif /* !UNIX */
344 /*NOTREACHED*/
345 }
346
347 private char smbuf[20],
348 *bp = smbuf;
349 private int nchars = 0;
350
351 #ifdef NONBLOCKINGREAD
352
353 # include <fcntl.h>
354
355 private void
setblock(on)356 setblock(on) /* turn blocking on or off */
357 bool on;
358 {
359 static int blockf, nonblockf;
360 static bool first = YES;
361
362 if (first) {
363 int flags;
364
365 first = NO;
366 if ((flags = fcntl(0, F_GETFL, 0)) == -1)
367 finish(SIGHUP);
368 # ifdef O_NONBLOCK /* POSIX form */
369 blockf = flags & ~O_NONBLOCK; /* make sure O_NONBLOCK is off */
370 nonblockf = flags | O_NONBLOCK; /* make sure O_NONBLOCK is on */
371 # else /* pre-POSIX form */
372 blockf = flags & ~O_NDELAY; /* make sure O_NDELAY is off */
373 nonblockf = flags | O_NDELAY; /* make sure O_NDELAY is on */
374 # endif
375 }
376 if (fcntl(0, F_SETFL, on ? blockf : nonblockf) == -1)
377 finish(SIGHUP);
378 }
379
380 #endif /* NONBLOCKINGREAD */
381
382 /* To optimize screen refreshing, we try to detect if there is pending input.
383 * If there is, we defer screen updating, hoping that when we eventually
384 * do an update it will be more efficient. To implement this, we use
385 * charp to poll for pending input (from any source but macro body).
386 * "InputPending" records the last value returned by charp, or what
387 * was known by kbd_getch or kbd_ungetch. Note that the kbd_* routines
388 * only consider keyboard input, but charp considers other sources of
389 * input. These are the only routines that should set InputPending
390 * (currently, a fudge to redisplay for the mac also sets it --
391 * this should be fixed).
392 *
393 * This heuristic confuses the user if a command takes a long time:
394 * the screen may be "frozen" in an inaccurate state until the command
395 * completes. The variable "SlowCmd" is a count of the nesting of slow
396 * commands. If it is positive, display updating is not pre-empted.
397 * The macros PreEmptOutput() and CheapPreEmptOutput() implement the tests.
398 */
399
400 int SlowCmd = 0; /* depth of nesting of slow commands */
401
402 bool InputPending = NO; /* is there input waiting to be processed? */
403
404 /* Inputp is used to jam a NUL-terminated string into JOVE's input stream.
405 * It is used to feed each line of the joverc file, to fill in the default
406 * make_cmd in compile-it, and to fill in the default i-search string.
407 * To make this work, we prevent i-search and compile-it from using Inputp
408 * when it is already in use.
409 */
410 char *Inputp = NULL;
411
412 /* kbd_ungetch must only be used to push back a character that
413 * was just returned by kbd_getch.
414 */
415 private ZXchar kbdpeek = EOF;
416
417 void
kbd_ungetch(c)418 kbd_ungetch(c)
419 ZXchar c;
420 {
421 InputPending = YES;
422 kbdpeek = c;
423 }
424
425 ZXchar
kbd_getch()426 kbd_getch()
427 {
428 register ZXchar c;
429
430 if (kbdpeek != EOF) {
431 c = kbdpeek;
432 kbdpeek = EOF;
433 InputPending = nchars > 0;
434 return c;
435 }
436 #if NCHARS != UCHAR_ROOF
437 do {
438 #endif
439 while (nchars <= 0) {
440 bp = smbuf;
441 #ifdef MSDOS
442 *bp = getrawinchar();
443 nchars = 1;
444 #else /* !MSDOS */
445 # ifdef WIN32
446 if (!charp()) {
447 redisplay();
448 flushscreen();
449 }
450 nchars = getInputEvents(smbuf, sizeof(smbuf));
451 # else /* !WIN32 */
452 # ifdef PTYPROCS
453 /* Get a character from the keyboard, first checking for
454 any input from a process. Handle that first, and then
455 deal with the terminal input. */
456 {
457 fd_set reads;
458 int
459 nfds,
460 fd;
461
462 bp = smbuf;
463 for (;;) {
464 while (procs_to_reap)
465 reap_procs(); /* synchronous process reaping */
466 reads = global_fd;
467 InSlowRead = YES;
468 nfds = select(global_maxfd,
469 &reads, (fd_set *)NULL, (fd_set *)NULL,
470 (struct timeval *)NULL);
471 InSlowRead = NO;
472 if (nfds >= 0)
473 break;
474
475 if (errno != EINTR) {
476 complain("\rerror in select: %s", strerror(errno));
477 /* NOTREACHED */
478 }
479 }
480
481 if (FD_ISSET(0, &reads)) {
482 do {
483 nchars = read(0, (UnivPtr) smbuf, sizeof(smbuf));
484 } while (nchars < 0 && errno == EINTR);
485 if (nchars <= 0)
486 finish(SIGHUP);
487 nfds -= 1;
488 }
489 for (fd=1; nfds != 0; fd += 1) {
490 if (FD_ISSET(fd, &reads)) {
491 nfds -= 1;
492 read_pty_proc(fd);
493 if (UpdModLine)
494 redisplay();
495 }
496 }
497 }
498 # else /* !PTYPROCS */
499 # ifdef PIPEPROCS
500 if (NumProcs > 0) {
501 /* Handle process input until kbd input arrives */
502 struct header header;
503 size_t n;
504
505 InSlowRead = YES;
506 n = f_readn(ProcInput, (char *) &header, sizeof(header));
507 InSlowRead = NO;
508
509 if (n != sizeof(header)) {
510 raw_complain("\r\nError reading kbd process, expected %d, got %d bytes", sizeof header, n);
511 finish(SIGHUP);
512 }
513 if (header.pid == kbd_pid) {
514 /* data is from the keyboard process */
515 nchars = f_readn(ProcInput, smbuf, (size_t)header.nbytes);
516 if (nchars != header.nbytes) {
517 raw_complain("\r\nError reading kbd process, expected %d, got %d bytes.", header.nbytes, nchars);
518 finish(SIGHUP);
519 }
520 } else {
521 /* data is from an interactive process */
522 read_pipe_proc(header.pid, header.nbytes);
523 if (NumProcs == 0)
524 (void) kbd_stop();
525 if (UpdModLine)
526 redisplay();
527 }
528 } else /*...*/
529 # endif /* PIPEPROCS */
530 /*...*/ {
531 do {
532 # ifdef UNIX
533 InSlowRead = YES;
534 # endif
535 nchars = read(0, (UnivPtr) smbuf, sizeof smbuf);
536 # ifdef UNIX
537 InSlowRead = NO;
538 # endif
539 } while (nchars < 0 && errno == EINTR);
540 if (nchars <= 0)
541 finish(SIGHUP);
542 }
543 # endif /* !PTYPROCS */
544 # endif /* !WIN32 */
545 #endif /* !MSDOS */
546 }
547 c = ZXRC(*bp++);
548 #if !defined(PCNONASCII) && !defined(MAC) /* if not done elsewhere */
549 if ((c & 0200) && MetaKey) {
550 *--bp = c & ~0200;
551 nchars += 1;
552 c = ESC;
553 }
554 #endif /* !defined(PCNONASCII) && !defined(MAC) */
555 InputPending = --nchars > 0;
556 #if NCHARS != UCHAR_ROOF
557 } while (c >= NCHARS); /* discard c if it is a bad char */
558 #endif
559 return c;
560 }
561
562 /* Returns YES if a character waiting (excluding macro body) */
563
564 bool
charp()565 charp()
566 {
567 if (InJoverc != 0 || kbdpeek != EOF || nchars > 0 || Inputp != NULL)
568 return InputPending = YES;
569 #ifdef FIONREAD
570 {
571 /*
572 * Some manual pages, notably SunOS4.1.3 say 'c' should be
573 * 'long', but that's a lie -- it's an 'int' according to all
574 * kernels I've seen (including SunOS4.1.3) and most other
575 * manual pages. At any rate, 'int' works correctly on 32- and
576 * 64-bit architectures, whereas long breaks on the 64
577 * bitters. -- MM.
578 */
579 int c;
580
581 if (ioctl(0, FIONREAD, (UnivPtr) &c) == -1)
582 c = 0;
583 return InputPending = c > 0;
584 }
585 #else /* !FIONREAD */
586 # ifdef NONBLOCKINGREAD
587 setblock(NO); /* turn blocking off */
588 nchars = read(0, (UnivPtr) smbuf, sizeof smbuf); /* Is anything there? */
589 setblock(YES); /* turn blocking on */
590 bp = smbuf; /* make sure bp points to it */
591 return InputPending = nchars > 0; /* just say we found something */
592 # else /* !NONBLOCKINGREAD */
593 # ifdef USE_SELECT
594 {
595 struct timeval timer;
596 fd_set readfds;
597
598 timer.tv_sec = 0;
599 timer.tv_usec = 0;
600 FD_ZERO(&readfds);
601 FD_SET(0, &readfds);
602 return InputPending = select(1,
603 &readfds, (fd_set *)NULL, (fd_set *)NULL,
604 &timer) > 0;
605 }
606 # else /* !USE_SELECT */
607 # ifdef MSDOS
608 return InputPending = rawkey_ready();
609 # else /* !MSDOS */
610 # ifdef MAC
611 return InputPending = rawchkc();
612 # else
613 # ifdef WIN32
614 return InputPending = inputEventWaiting(0);
615 # else
616 return InputPending = NO; /* who knows? */
617 # endif /* !WIN32 */
618 # endif /* !MAC */
619 # endif /* !MSDOS */
620 # endif /* !USE_SELECT */
621 # endif /* !NONBLOCKINGREAD */
622 #endif /* !FIONREAD */
623 }
624
625 /*
626 * Tries to pause for delay/10 seconds OR until a character is typed at the
627 * keyboard. This works well on systems with select() and not so well on the
628 * rest.
629 */
630
631 #ifdef MAC
632 # include <LoMem.h> /* defines Ticks */
633 #endif
634
635 void
SitFor(delay)636 SitFor(delay)
637 int delay;
638 {
639 #ifdef MAC
640 long
641 start,
642 end;
643
644 Keyonly = YES;
645 redisplay();
646 start = Ticks;
647
648 end = start + delay * 6;
649 do ; while (!charp() && Ticks < end);
650
651 #else /* !MAC */
652
653 # ifndef MSDOS
654 if (!charp()) {
655 # ifdef USE_SELECT
656 struct timeval timer;
657 fd_set readfds;
658
659 /* So messages that aren't error messages don't
660 * hang around forever.
661 * Gross that I had to snarf this from getch()
662 */
663 if (!UpdMesg && !Asking && mesgbuf[0] && !stickymsg)
664 message(NullStr);
665 redisplay();
666
667 timer.tv_sec = (delay / 10);
668 timer.tv_usec = (delay % 10) * 100000;
669 FD_ZERO(&readfds);
670 FD_SET(0, &readfds);
671 (void) select(1,
672 &readfds, (fd_set *)NULL, (fd_set *)NULL,
673 &timer);
674 # else /* ! USE_SELECT */
675 # ifdef WIN32
676 redisplay();
677 inputEventWaiting(delay*100);
678 # else /* ! WIN32 */
679 /* Pause by spitting NULs at the terminal. Ugh! */
680 static const int cps[] = {
681 0,
682 5,
683 7,
684 11,
685 13,
686 15,
687 20,
688 30,
689 60,
690 120,
691 180,
692 240,
693 480,
694 960,
695 1920,
696 1920,
697 };
698 register int nchars,
699 check_cnt;
700
701 nchars = (delay * cps[ospeed]) / 10;
702 check_cnt = ScrBufSize;
703 redisplay();
704 if (!NP) {
705 while ((--nchars > 0) && !InputPending) {
706 scr_putchar(PC);
707 if (--check_cnt == 0) {
708 check_cnt = ScrBufSize;
709 (void) charp();
710 }
711 }
712 }
713 # endif /* !WIN32 */
714 # endif /* !USE_SELECT */
715 }
716 # else /* MSDOS */
717 /* All time representations must wrap eventually.
718 * Since all delays are much less than a minute, we represent
719 * time as hundredths of a second past the minute we start.
720 * NOTE: this is a busy wait. I know of no alternative.
721 */
722 int start,
723 now,
724 end;
725 struct dostime_t tc;
726
727 redisplay();
728 _dos_gettime(&tc);
729 start = tc.second * 100 + tc.hsecond;
730 end = start + delay * 10;
731 for (;;) {
732 if (charp())
733 break;
734 _dos_gettime(&tc);
735 now = tc.second * 100 + tc.hsecond;
736 if (now < start)
737 now += 60 * 100; /* must be in next minute */
738 if (now >= end)
739 break;
740 }
741 # endif /* MSDOS */
742 #endif /* !MAC */
743 }
744
745 #define WAITCHAR_CURSOR_DOWN 1 /* during slow keying, cursor is after displayed prefix */
746
747 private char
748 key_strokes[100],
749 *keys_p = key_strokes;
750
751 private bool in_ask_ks;
752
753 private volatile bool slow_keying = NO; /* for waitchar() */
754
755 void
cmd_sync()756 cmd_sync()
757 {
758 if (this_cmd != ARG_CMD) {
759 clr_arg_value();
760 last_cmd = this_cmd;
761 slow_keying = NO;
762 in_ask_ks = NO;
763 keys_p = key_strokes;
764 }
765 }
766
767 ZXchar
ask_ks()768 ask_ks()
769 {
770 in_ask_ks = YES;
771 keys_p = key_strokes;
772 return waitchar();
773 }
774
775 void
add_stroke(c)776 add_stroke(c)
777 ZXchar c;
778 {
779 if (keys_p < &key_strokes[sizeof (key_strokes) - 1])
780 *keys_p++ = c;
781 }
782
783 void
pp_key_strokes(buffer,size)784 pp_key_strokes(buffer, size)
785 char *buffer;
786 size_t size;
787 {
788 char
789 *buf_end = buffer + size - 1,
790 *kp = key_strokes;
791
792 *buffer = '\0';
793 while (kp != keys_p) {
794 swritef(buffer, (size_t) (buf_end-buffer), "%p ", *kp++);
795 buffer += strlen(buffer);
796 }
797 }
798
799 private void
ShowKeyStrokes()800 ShowKeyStrokes()
801 {
802 char buffer[100];
803
804 slow_keying = YES;
805 pp_key_strokes(buffer, sizeof (buffer));
806 f_mess(in_ask_ks? ": %f %s" : "%s", buffer);
807 #ifdef WAITCHAR_CURSOR_DOWN
808 Asking = YES;
809 AskingWidth = strlen(mesgbuf);
810 #endif
811 }
812
813 #define N_SEC 1 /* will be precisely 1 second on 4.2 */
814
815 ZXchar
waitchar()816 waitchar()
817 {
818 ZXchar c;
819 #ifdef WAITCHAR_CURSOR_DOWN
820 bool oldAsking;
821 int oldAskingWidth;
822 #endif
823
824 /* short circuit, if we can */
825 if (InJoverc || (!Interactive && in_macro()) || InputPending)
826 return getch();
827
828 #ifdef WAITCHAR_CURSOR_DOWN
829 oldAsking = Asking;
830 oldAskingWidth = AskingWidth;
831 #endif
832
833 #ifdef MAC
834 Keyonly = YES;
835 #endif
836 if (!slow_keying) {
837 /* not yet slow_keying */
838 #ifdef UNIX
839 /* set up alarm */
840 InWaitChar = YES;
841 (void) alarm((unsigned) N_SEC);
842 #else /* !UNIX */
843 # ifdef WIN32
844 if (!charp()) {
845 if ((slow_keying = !inputEventWaiting(N_SEC*1000))) {
846 ShowKeyStrokes();
847 }
848 }
849 # else /* !WIN32 */
850 /* NOTE: busy wait (until char typed or timeout)! */
851 time_t sw = N_SEC + time((time_t *)NULL);
852
853 while (!slow_keying && !charp()) {
854 if (time((time_t *)NULL) > sw) {
855 /* transition to slow_keying */
856 # ifdef MAC
857 menus_off();
858 # endif
859 ShowKeyStrokes();
860 }
861 }
862 # endif /* !WIN32 */
863 #endif /* !UNIX */
864 #ifdef WAITCHAR_CURSOR_DOWN
865 } else {
866 /* Already slow_keying: presume bottom line has old keystrokes.
867 * Tell refresh(?) to place cursor at end of them.
868 */
869 Asking = YES;
870 AskingWidth = strlen(mesgbuf);
871 #endif
872 }
873 c = getch();
874 if (slow_keying) {
875 ShowKeyStrokes();
876 #ifdef UNIX
877 } else {
878 /* not yet slow_keying: tear down alarm */
879 InWaitChar = NO;
880 SetClockAlarm(YES);
881 #endif
882 }
883
884 #ifdef WAITCHAR_CURSOR_DOWN
885 Asking = oldAsking;
886 AskingWidth = oldAskingWidth;
887 #endif
888 return c;
889 }
890
891 private void
SetTerm()892 SetTerm()
893 {
894 #ifdef IBMPCDOS
895 pcSetTerm();
896 #endif
897 ttysetattr(YES);
898 #ifdef TERMCAP
899 putpad(TI, 1); /* Cursor addressing start */
900 putpad(VS, 1); /* Visual start */
901 putpad(KS, 1); /* Keypad mode start */
902 # ifdef MOUSE
903 MouseOn();
904 # endif
905 #endif
906 #ifdef UNIX
907 (void) chkmail(YES); /* force it to check so we can be accurate */
908 #endif
909 }
910
911 private void
UnsetTerm(WarnUnwritten)912 UnsetTerm(WarnUnwritten)
913 bool WarnUnwritten;
914 {
915 #ifdef TERMCAP
916 # ifdef ID_CHAR
917 INSmode(NO);
918 # endif /* ID_CHAR */
919 # ifdef MOUSE
920 MouseOff();
921 # endif
922 putpad(KE, 1);
923 putpad(VE, 1);
924 Placur(ILI, 0);
925 putpad(CE, 1);
926 putpad(TE, 1);
927 #else /* !TERMCAP */
928 Placur(ILI, 0);
929 clr_eoln();
930 #endif /* !TERMCAP */
931 flushscreen();
932 #ifdef MSDOS
933 pcUnsetTerm();
934 #endif
935 ttysetattr(NO);
936 if (WarnUnwritten && ModBufs(NO))
937 raw_complain("[There are modified buffers]");
938 }
939
940 #ifdef JOB_CONTROL
941 void
PauseJove()942 PauseJove()
943 {
944 UnsetTerm(YES);
945 (void) kill(0, SIGTSTP);
946 SetTerm();
947 # ifdef WINRESIZE
948 /* Some systems (eg System V Release 4) don't give us SIGWINCHes
949 * that happen while we are away.
950 */
951 ResizePending = YES;
952 # endif
953 ClAndRedraw();
954 }
955 #endif /* JOB_CONTROL */
956
957 #ifdef SUBSHELL
958
959 # ifndef MSDOS
960 void
jcloseall()961 jcloseall()
962 {
963 tmpclose();
964 # ifdef RECOVER
965 recclose();
966 # endif
967 # ifdef IPROCS
968 closeiprocs();
969 # endif
970 }
971 # endif /* !MSDOS */
972
973 void
Push()974 Push()
975 {
976 # ifdef MSDOS_PROCS
977 # ifdef MSDOS
978 UnsetTerm(YES);
979 if (spawnl(0, Shell, basename(Shell), (char *)NULL) == -1)
980 s_mess("[Spawn failed %d]", errno);
981 SetTerm();
982 # ifdef WINRESIZE
983 /* Some systems (eg System V Release 4) don't give us SIGWINCHes
984 * that happen while we are away.
985 */
986 ResizePending = YES;
987 # endif
988 ClAndRedraw();
989 getCWD();
990 # else /* !MSDOS */
991 # ifdef WIN32
992 STARTUPINFO startinfo = { sizeof(STARTUPINFO) };
993 PROCESS_INFORMATION procinfo;
994 CreateProcess(Shell, NULL, NULL, NULL,
995 FALSE, CREATE_NEW_CONSOLE,
996 NULL, NULL,
997 &startinfo, &procinfo);
998 # endif /* WIN32 */
999 # endif /* !MSDOS */
1000 # else /* !MSDOS_PROCS */
1001 /* UNIX, or something like it */
1002 SIGHANDLERTYPE old_int = setsighandler(SIGINT, SIG_IGN);
1003 int forkerr = 0;
1004 # ifdef PIPEPROCS
1005 bool started = kbd_stop();
1006 # endif
1007
1008 UnsetTerm(YES);
1009 switch (ChildPid = fork()) {
1010 case -1:
1011 /* parent, fork failed */
1012 forkerr = errno;
1013 break;
1014
1015 default:
1016 /* parent, fork worked */
1017 dowait((wait_status_t *) NULL);
1018 break;
1019
1020 case 0:
1021 /* child */
1022 /* (void) setsighandler(SIGTERM, SIG_DFL); */
1023 (void) setsighandler(SIGINT, SIG_DFL);
1024 jcloseall();
1025 /* note that curbuf->bfname may be NULL */
1026 execl(Shell, basename(Shell), "-is", pr_name(curbuf->b_fname, NO),
1027 (char *)NULL);
1028 raw_complain("[Execl failed: %s]", strerror(errno));
1029 _exit(1);
1030 /*NOTREACHED*/
1031 }
1032 SetTerm();
1033 # ifdef WINRESIZE
1034 /* Some systems (eg System V Release 4) don't give us SIGWINCHes
1035 * that happen while we are away.
1036 */
1037 ResizePending = YES;
1038 # endif
1039 ClAndRedraw();
1040 (void) setsighandler(SIGINT, old_int);
1041 SetClockAlarm(NO);
1042 # ifdef PIPEPROCS
1043 if (started)
1044 kbd_strt();
1045 # endif
1046 if (forkerr != 0)
1047 complain("[Fork failed: %s]", strerror(errno));
1048 # endif /* !MSDOS_PROCS */
1049 }
1050
1051 #endif /* SUBSHELL */
1052
1053 /* adjust the tty to reflect possible change to JOVE variables */
1054 void
tty_adjust()1055 tty_adjust()
1056 {
1057 ttysetattr(YES);
1058 #ifdef MOUSE
1059 MouseOn(); /* XtermMouse might have changed */
1060 #endif
1061 }
1062
1063 bool Interactive = NO; /* True when we invoke with the command handler? */
1064
1065 ZXchar
1066 peekchar = EOF, /* holds pushed-back getch output */
1067 LastKeyStruck; /* used by SelfInsert and friends */
1068
1069 bool
1070 MetaKey = NO; /* VAR: this terminal has a meta key */
1071
1072 void
Ungetc(c)1073 Ungetc(c)
1074 ZXchar c;
1075 {
1076 peekchar = c;
1077 }
1078
1079 ZXchar
getch()1080 getch()
1081 {
1082 register ZXchar c;
1083
1084 if (Inputp != NULL) {
1085 if ((c = ZXC(*Inputp++)) != '\0')
1086 return LastKeyStruck = c;
1087 Inputp = NULL;
1088 }
1089
1090 if (InJoverc) {
1091 /* somethings wrong if Inputp runs out while
1092 we're reading a .joverc file. */
1093 complain("[command line too short]");
1094 }
1095
1096 #ifdef RECOVER
1097 if (ModCount >= SyncFreq) {
1098 ModCount = 0;
1099 SyncRec();
1100 }
1101 #endif /* RECOVER */
1102
1103 if ((c = peekchar) != EOF) {
1104 /* got input from pushback */
1105 peekchar = EOF;
1106 } else {
1107 if (!Interactive && (c = mac_getc()) != EOF) {
1108 /* got input from macro */
1109 } else {
1110 /* So messages that aren't error messages don't
1111 * hang around forever.
1112 * Note: this code is duplicated in SitFor()!
1113 */
1114 if (!UpdMesg && !Asking && mesgbuf[0] != '\0' && !stickymsg)
1115 message(NullStr);
1116 redisplay();
1117 c = kbd_getch();
1118 if (!Interactive && InMacDefine)
1119 mac_putc(c);
1120 }
1121 add_stroke(c);
1122 }
1123 return LastKeyStruck = c;
1124 }
1125
1126 #if defined(SUBSHELL) && defined(RECOVER)
1127 private void
dorecover()1128 dorecover()
1129 {
1130 char Recover[FILESIZE]; /* path to recover program (in LibDir) */
1131
1132 /* Since recover is a normal cooked mode program, reset the terminal */
1133 UnsetTerm(NO);
1134 # ifdef PIPEPROCS
1135 kbd_kill(); /* kill the keyboard process */
1136 # endif
1137 swritef(Recover, sizeof(Recover), "%s/recover", LibDir);
1138 execl(Recover, "recover", "-d", TmpDir, (char *) NULL);
1139 writef("%s: execl failed! %s\n", Recover, strerror(errno));
1140 flushscreen();
1141 _exit(-1);
1142 /* NOTREACHED */
1143 }
1144 #endif /* defined(SUBSHELL) && defined(RECOVER) */
1145
1146 void
ShowVersion()1147 ShowVersion()
1148 {
1149 s_mess("Jonathan's Own Version of Emacs (%s)", jversion);
1150 }
1151
1152 private void
UNIX_cmdline(argc,argv)1153 UNIX_cmdline(argc, argv)
1154 int argc;
1155 char *argv[];
1156 {
1157 int lineno = 0,
1158 nwinds = 1;
1159 char *pattern = NULL;
1160 Buffer *b;
1161
1162 while (argc > 1) {
1163 switch (argv[1][0]) {
1164 case '+':
1165 if ('0' <= argv[1][1] && argv[1][1] <= '9') {
1166 (void) chr_to_int(&argv[1][1], 10, NO, &lineno);
1167 break;
1168 } else switch (argv[1][1]) {
1169 case '\0':
1170 /* goto end of file just like some people's favourite editor */
1171 lineno = -1;
1172 break;
1173 case '/': /* search for pattern */
1174 /* check if syntax is +/pattern or +/ pattern */
1175 if (argv[1][2] != 0) {
1176 pattern = &argv[1][2];
1177 } else {
1178 argv += 1;
1179 argc -= 1;
1180 if (argv[1] != 0)
1181 pattern = &argv[1][0];
1182 }
1183 break;
1184 default:
1185 error("Invalid switch %s",argv[1]);
1186 break;
1187 }
1188 break;
1189 case '-':
1190 switch (argv[1][1]) {
1191 case 'd': /* Ignore current directory path */
1192 case 'l': /* Ignore libdir path */
1193 case 's': /* Ignore sharedir path */
1194 argv += 1;
1195 argc -= 1;
1196 break;
1197
1198 case 'J': /* Ignore jove.rc in SHAREDIR */
1199 case 'j': /* Ignore ~/.joverc */
1200 break;
1201 case 'p': /* parse errors in file */
1202 argv += 1;
1203 argc -= 1;
1204 if (argv[1] != NULL) {
1205 SetBuf(do_find(curwind, argv[1], YES, YES));
1206 ErrParse();
1207 nwinds = 0;
1208 }
1209 break;
1210 case 't': /* find tag */
1211 /* check if syntax is -tTag or -t Tag */
1212 if (argv[1][2] != '\0') {
1213 find_tag(&(argv[1][2]), YES);
1214 } else {
1215 argv += 1;
1216 argc -= 1;
1217 if (argv[1] != NULL)
1218 find_tag(argv[1], YES);
1219 }
1220 break;
1221
1222 case 'w': /* multiple windows */
1223 if (argv[1][2] == '\0')
1224 nwinds += 1;
1225 else {
1226 int n;
1227
1228 (void) chr_to_int(&argv[1][2], 10, NO, &n);
1229 nwinds += -1 + n;
1230 }
1231 (void) div_wind(curwind, nwinds - 1);
1232 break;
1233 default:
1234 error("Invalid switch %s",argv[1]);
1235 break;
1236 }
1237 break;
1238 default:
1239 {
1240 bool force = (nwinds > 0 || lineno != 0 || pattern != NULL);
1241
1242 minib_add(argv[1], force);
1243 b = do_find(nwinds > 0 ? curwind : (Window *) NULL,
1244 argv[1], force, YES);
1245 if (force) {
1246 SetABuf(curbuf);
1247 SetBuf(b);
1248 if (lineno > 0)
1249 SetLine(next_line(curbuf->b_first, lineno - 1));
1250 else if (lineno == -1)
1251 SetLine(curbuf->b_last);
1252 if (pattern != NULL) {
1253 Bufpos *bufp;
1254
1255 if ((bufp = dosearch(pattern, FORWARD, UseRE)) != NULL
1256 || (bufp = dosearch(pattern, BACKWARD, UseRE)) != NULL)
1257 SetDot(bufp);
1258 else
1259 complain("Couldn't match pattern in file.");
1260 }
1261 if (nwinds > 1)
1262 NextWindow();
1263 if (nwinds > 0)
1264 nwinds -= 1;
1265 }
1266 lineno = 0;
1267 pattern = NULL;
1268 }
1269 break;
1270 }
1271 argv += 1;
1272 argc -= 1;
1273 }
1274 }
1275
1276 #ifdef STDARGS
1277 void
error(const char * fmt,...)1278 error(const char *fmt, ...)
1279 #else
1280 /*VARARGS1*/ void
1281 error(fmt, va_alist)
1282 const char *fmt;
1283 va_dcl
1284 #endif
1285 {
1286 va_list ap;
1287
1288 if (fmt) {
1289 va_init(ap, fmt);
1290 format(mesgbuf, sizeof mesgbuf, fmt, ap);
1291 va_end(ap);
1292 UpdMesg = YES;
1293 }
1294 rbell();
1295 longjmp(mainjmp, JMP_ERROR);
1296 }
1297
1298 #ifdef STDARGS
1299 void
complain(const char * fmt,...)1300 complain(const char *fmt, ...)
1301 #else
1302 /*VARARGS1*/ void
1303 complain(fmt, va_alist)
1304 const char *fmt;
1305 va_dcl
1306 #endif
1307 {
1308 va_list ap;
1309
1310 if (fmt) {
1311 va_init(ap, fmt);
1312 format(mesgbuf, sizeof mesgbuf, fmt, ap);
1313 va_end(ap);
1314 UpdMesg = YES;
1315 }
1316 rbell();
1317 longjmp(mainjmp, JMP_COMPLAIN);
1318 }
1319
1320 /* format and display a message without using the normal display mechanisms */
1321
1322 #ifdef STDARGS
1323 void
raw_complain(const char * fmt,...)1324 raw_complain(const char *fmt, ...)
1325 #else
1326 /*VARARGS1*/ void
1327 raw_complain(fmt, va_alist)
1328 const char *fmt;
1329 va_dcl
1330 #endif
1331 {
1332 char buf[MESG_SIZE];
1333 va_list ap;
1334
1335 va_init(ap, fmt);
1336 format(buf, sizeof(buf) - 2, fmt, ap);
1337 va_end(ap);
1338 strcat(buf, "\r\n"); /* \r *may* be redundant */
1339 (void) write(2, (UnivConstPtr)buf, strlen(buf));
1340 }
1341
1342 #ifdef STDARGS
1343 void
confirm(const char * fmt,...)1344 confirm(const char *fmt, ...)
1345 #else
1346 /*VARARGS1*/ void
1347 confirm(fmt, va_alist)
1348 const char *fmt;
1349 va_dcl
1350 #endif
1351 {
1352 va_list ap;
1353
1354 va_init(ap, fmt);
1355 format(mesgbuf, sizeof mesgbuf, fmt, ap);
1356 va_end(ap);
1357 if (!yes_or_no_p("%s", mesgbuf))
1358 longjmp(mainjmp, JMP_COMPLAIN);
1359 }
1360
1361 /* Recursive edit.
1362 * Guarantee: current buffer will still be current and
1363 * it will be in the current window. If not, complain!
1364 */
1365
1366 int RecDepth = 0;
1367
1368 void
Recur()1369 Recur()
1370 {
1371 Buffer *b = curbuf;
1372 Mark *m;
1373
1374 m = MakeMark(curline, curchar);
1375
1376 RecDepth += 1;
1377 UpdModLine = YES;
1378 DoKeys(NO); /* NO means not first time */
1379 UpdModLine = YES;
1380 RecDepth -= 1;
1381 if (!valid_bp(b))
1382 complain("Buffer gone!");
1383 tiewind(curwind, b);
1384 SetBuf(b);
1385 if (!is_an_arg())
1386 ToMark(m);
1387 DelMark(m);
1388 }
1389
1390 private int iniargc; /* main sets these for DoKeys() */
1391 private char **iniargv;
1392
1393 private void
DoKeys(firsttime)1394 DoKeys(firsttime)
1395 bool firsttime;
1396 {
1397 jmp_buf savejmp;
1398
1399 push_env(savejmp);
1400
1401 switch (setjmp(mainjmp)) {
1402 case 0:
1403 if (firsttime)
1404 UNIX_cmdline(iniargc, iniargv);
1405 break;
1406
1407 case JMP_QUIT:
1408 if (RecDepth == 0) {
1409 if (ModMacs()) {
1410 rbell();
1411 if (!yes_or_no_p("Some MACROS haven't been saved; leave anyway? "))
1412 break;
1413 }
1414 if (ModBufs(NO)) {
1415 rbell();
1416 if (!yes_or_no_p("Some buffers haven't been saved; leave anyway? "))
1417 break;
1418 }
1419 #ifdef IPROCS
1420 if (!KillProcs())
1421 break; /* user chickened out */
1422 #endif
1423 }
1424 pop_env(savejmp);
1425 return;
1426
1427 case JMP_ERROR:
1428 getDOT(); /* God knows what state linebuf was in */
1429 /*FALLTHROUGH*/
1430 case JMP_COMPLAIN:
1431 {
1432 gc_openfiles(); /* close any files we left open */
1433 stickymsg = YES;
1434 unwind_macro_stack();
1435 Asking = NO;
1436 curwind->w_bufp = curbuf;
1437 DisabledRedisplay = NO;
1438 SlowCmd = 0;
1439 redisplay();
1440 break;
1441 }
1442 }
1443
1444 this_cmd = last_cmd = OTHER_CMD;
1445
1446 for (;;) {
1447 #ifdef MAC
1448 setjmp(auxjmp);
1449 #endif
1450 cmd_sync();
1451 #ifdef MAC
1452 HiliteMenu(0);
1453 EventCmd = NO;
1454 menus_on();
1455 #endif
1456 dispatch(getch());
1457 }
1458 }
1459
1460 private char **
scanvec(args,str)1461 scanvec(args, str)
1462 register char **args,
1463 *str;
1464 {
1465 while (*args) {
1466 if (strcmp(*args, str) == 0)
1467 return args;
1468 args += 1;
1469 }
1470 return NULL;
1471 }
1472
1473 #ifdef WINRESIZE
1474 /*ARGSUSED*/
1475 SIGRESTYPE
win_reshape(junk)1476 win_reshape(junk)
1477 int junk; /* passed in when invoked by a signal; of no interest */
1478 {
1479 int save_errno = errno; /* Subtle, but necessary! */
1480
1481 ResizePending = YES;
1482 #ifdef UNIX
1483 resetsighandler(SIGWINCH, win_reshape);
1484 if (InSlowRead) {
1485 /* needed because of stupid BSD restartable I/O */
1486 InSlowRead = NO;
1487 redisplay();
1488 InSlowRead = YES;
1489 }
1490 #else
1491 redisplay();
1492 #endif
1493 errno = save_errno;
1494 return SIGRESVALUE;
1495 }
1496 #endif /* WINRESIZE */
1497
1498 private bool
carefulcpy(to,from,maxsize,mess,raw)1499 carefulcpy(to, from, maxsize, mess, raw)
1500 char *to,*from;
1501 size_t maxsize;
1502 char *mess;
1503 bool raw;
1504 {
1505 if (from != NULL) {
1506 char *ugh;
1507
1508 if (strlen(from) >= maxsize)
1509 ugh = "too long";
1510 else if (*from == '\0')
1511 ugh = "empty";
1512 else {
1513 strcpy(to, from);
1514 return YES;
1515 }
1516 if (raw) {
1517 raw_complain("\r\n%s %s", mess, ugh);
1518 } else {
1519 swritef(mesgbuf, sizeof mesgbuf, "%s %s", mess, ugh);
1520 message(mesgbuf);
1521 }
1522 }
1523 return NO;
1524 }
1525
1526 private void
dojovercs(dosys,dousr)1527 dojovercs(dosys, dousr)
1528 bool dosys;
1529 bool dousr;
1530 {
1531 char Joverc[FILESIZE];
1532
1533 if (dosys) {
1534 swritef(Joverc, sizeof(Joverc), "%s/jove.rc", ShareDir);
1535 (void) joverc(Joverc); /* system wide jove.rc */
1536 }
1537
1538 if (dousr) {
1539 #ifdef MSFILESYSTEM
1540 /* We don't want to run the same rc file twice */
1541 if (!dosys || strcmp(HomeDir, ShareDir) != 0) {
1542 swritef(Joverc, sizeof(Joverc), "%s/jove.rc", HomeDir);
1543 (void) joverc(Joverc); /* jove.rc in home directory */
1544 }
1545 #else
1546 swritef(Joverc, sizeof(Joverc), "%s/.joverc", HomeDir);
1547 (void) joverc(Joverc); /* .joverc in home directory */
1548 #endif
1549 }
1550 }
1551
1552 int
main(argc,argv)1553 main(argc, argv)
1554 int argc;
1555 char *argv[];
1556 {
1557 char **argp;
1558 #ifdef AUTO_BUFS
1559 /* allocate these usually static buffers on the stack:
1560 * preserves addressability on some systems.
1561 */
1562 char s_iobuff[LBSIZE],
1563 s_genbuf[LBSIZE],
1564 s_linebuf[LBSIZE];
1565
1566 iobuff = s_iobuff;
1567 genbuf = s_genbuf;
1568 linebuf = s_linebuf;
1569 #endif
1570
1571 #ifdef MAC
1572 MacInit(); /* initializes all */
1573 argc = getArgs(&argv);
1574 #endif
1575
1576 #if defined(__WATCOMC__) && defined(FAR_LINES)
1577 /* Watcom C under DOS won't grow the near heap after any far
1578 * allocation, so we must bump it up to the full 64K now.
1579 */
1580 _heapgrow();
1581 #endif
1582
1583 iniargc = argc;
1584 iniargv = argv;
1585
1586 if (setjmp(mainjmp)) {
1587 ttysetattr(NO);
1588 writef("\nAck! I can't deal with error \"%s\" now.\n", mesgbuf);
1589 flushscreen();
1590 return 1;
1591 }
1592
1593 #if defined(USE_CTYPE) && !defined(NO_SETLOCALE)
1594 /* make ctype reflect "native environment" */
1595 locale_adjust();
1596 #endif
1597
1598 getTERM(); /* Get terminal. */
1599 #ifndef MAC /* no environment in MacOS */
1600 if (getenv("METAKEY"))
1601 MetaKey = YES;
1602 #endif
1603 ttysetattr(YES);
1604 ttsize();
1605
1606 #ifdef UNIX
1607 # ifdef WINRESIZE
1608 (void) setsighandler(SIGWINCH, win_reshape);
1609 # endif
1610 #endif
1611
1612 #ifdef MAC
1613 InitEvents();
1614 #endif
1615
1616 d_cache_init(); /* initialize the disk buffer cache */
1617
1618 make_scr();
1619 flushscreen(); /* kludge: prevent interleaving output with diagnostic */
1620 mac_init(); /* Initialize Macros */
1621 winit(); /* Initialize Window */
1622 #ifdef PTYPROCS
1623 # ifdef SIGCHLD
1624 (void) setsighandler(SIGCHLD, sigchld_handler);
1625 # endif
1626 #endif
1627 #ifdef USE_SELECT
1628 FD_ZERO(&global_fd);
1629 FD_SET(0, &global_fd);
1630 global_maxfd = 1;
1631 #endif
1632 buf_init();
1633
1634 if ((argp = scanvec(argv, "-d")) != NULL && chkCWD(argp[1]))
1635 setCWD(argp[1]);
1636 else
1637 getCWD(); /* After we setup curbuf in case we have to getwd() */
1638
1639 #ifdef MAC
1640 HomeDir = gethome();
1641 #else /* !MAC */
1642 HomeDir = getenv("HOME");
1643 if (HomeDir == NULL) {
1644 # ifdef MSDOS
1645 HomeDir = copystr(pwd()); /* guess at current (initial) directory */
1646 # else
1647 # ifdef WIN32
1648 /* Following are set up automatically by NT on logon. */
1649 char *homedrive = getenv("HOMEDRIVE");
1650 char *homepath = getenv("HOMEPATH");
1651
1652 if (homedrive != NULL && homepath != NULL) {
1653 HomeDir = emalloc(strlen(homedrive) + strlen(homepath) + 1);
1654 strcpy(HomeDir, homedrive);
1655 strcat(HomeDir, homepath);
1656 } else {
1657 HomeDir = copystr(pwd());
1658 }
1659 # else /* !WIN32 */
1660 HomeDir = "/";
1661 # endif /* !WIN32 */
1662 # endif /* !MSDOS */
1663 }
1664 #endif /* !MAC */
1665 HomeLen = strlen(HomeDir);
1666
1667 InitKeymaps();
1668
1669 settout(); /* not until we know baudrate */
1670 SetTerm();
1671
1672 #ifndef MAC /* no environment in MacOS */
1673 /* Handle overrides for ShareDir and LibDir.
1674 * We take care to use the last specification.
1675 * Even if we don't use LibDir, we accept it.
1676 */
1677 {
1678 char
1679 *so = getenv("JOVESHARE");
1680 # ifdef NEED_LIBDIR
1681 char
1682 *lo = getenv("JOVELIB");
1683 # endif
1684
1685 for (argp = argv; argp[0] != NULL && argp[1] != NULL; argp++) {
1686 if (strcmp(*argp, "-s") == 0)
1687 so = *++argp;
1688 # ifdef NEED_LIBDIR
1689 else if (strcmp(*argp, "-l") == 0)
1690 lo = *++argp;
1691 else if (strcmp(*argp, "-ls") == 0 || strcmp(*argp, "-sl") == 0)
1692 lo = so = *++argp;
1693 # endif
1694 }
1695 if (so != NULL)
1696 if (!carefulcpy(ShareDir, so, sizeof(ShareDir)-9, "ShareDir", YES))
1697 finish(0);
1698 # ifdef NEED_LIBDIR
1699 if (lo != NULL)
1700 if (!carefulcpy(LibDir, lo, sizeof(LibDir)-9, "LibDir", YES))
1701 finish(0);
1702 # ifdef PIPEPROCS
1703 swritef(Portsrv, sizeof(Portsrv), "%s/portsrv", LibDir);
1704 # endif
1705 # endif /* NEED_LIBDIR */
1706 }
1707 #endif /* !MAC */
1708
1709 ShowVersion(); /* but the 'carefulcpy's which follow might overwrite it */
1710
1711 /* import the temporary file path from the environment
1712 and fix the string, so that we can append a slash
1713 safely */
1714 #ifdef MSFILESYSTEM
1715 carefulcpy(TmpDir, getenv("TEMP"), sizeof(TmpDir), "TEMP", NO);
1716 #endif
1717 #ifndef MAC /* no environment in MacOS */
1718 carefulcpy(TmpDir, getenv("TMPDIR"), sizeof(TmpDir), "TMPDIR", NO);
1719 #endif
1720 {
1721 char *cp = &TmpDir[strlen(TmpDir)];
1722
1723 do ; while (cp != TmpDir && (*--cp == '/'
1724 #ifdef MSFILESYSTEM
1725 || *cp == '\\'
1726 #endif
1727 ));
1728 cp[1] = '\0';
1729 }
1730
1731 #ifdef SUBSHELL
1732 # ifdef MSFILESYSTEM /* ??? Is this the right test? */
1733 carefulcpy(Shell, getenv("COMSPEC"), sizeof(Shell), "COMSPEC", NO);
1734 /* SHELL, if present in DOS environment, will take precedence over COMSPEC */
1735 # endif /* MSFILESYSTEM */
1736 carefulcpy(Shell, getenv("SHELL"), sizeof(Shell), "SHELL", NO);
1737 #endif /* SUBSHELL */
1738
1739 #ifdef UNIX
1740 carefulcpy(Mailbox, getenv("MAIL"), sizeof(Mailbox), "MAIL", NO);
1741 #endif
1742
1743 dojovercs(scanvec(argv, "-J") == NULL, scanvec(argv, "-j") == NULL);
1744
1745 #if defined(SUBSHELL) && defined(RECOVER)
1746 if (scanvec(argv, "-r") != NULL)
1747 dorecover();
1748 #endif
1749
1750 #ifdef UNIX
1751 # ifndef DEBUGCRASH
1752 (void) setsighandler(SIGHUP, finish);
1753 (void) setsighandler(SIGINT, finish);
1754 # ifdef SIGBUS
1755 (void) setsighandler(SIGBUS, finish);
1756 # endif /* SIGBUS */
1757 (void) setsighandler(SIGSEGV, finish);
1758 (void) setsighandler(SIGPIPE, finish);
1759 /* ??? Why should we ignore SIGTERM? */
1760 /* (void) setsighandler(SIGTERM, SIG_IGN); */
1761 # endif /* DEBUGCRASH */
1762 (void) setsighandler(SIGALRM, AlarmHandler);
1763 SetClockAlarm(NO);
1764 #endif /* UNIX */
1765 ClAndRedraw();
1766 flushscreen();
1767 RedrawDisplay(); /* start the redisplay process. */
1768 DoKeys(YES);
1769 finish(0);
1770 /* NOTREACHED*/
1771 }
1772