* lisp.h (malloc, realloc): Declare these to return void *, to
[bpt/emacs.git] / src / sysdep.c
CommitLineData
86a5659e 1/* Interfaces to system-dependent kernel and library entries.
91bac16a 2 Copyright (C) 1985, 1986, 1987, 1988, 1992 Free Software Foundation, Inc.
86a5659e
JB
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 1, or (at your option)
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20
21#include <signal.h>
22#include <setjmp.h>
23
24#include "config.h"
25#include "lisp.h"
9ac0d9e0 26#include "blockinput.h"
86a5659e
JB
27#undef NULL
28
29#define min(x,y) ((x) > (y) ? (y) : (x))
30
31/* In this file, open, read and write refer to the system calls,
32 not our sugared interfaces sys_open, sys_read and sys_write.
33 Contrariwise, for systems where we use the system calls directly,
34 define sys_read, etc. here as aliases for them. */
35#ifndef read
36#define sys_read read
37#define sys_write write
38#endif /* `read' is not a macro */
39
40#undef read
41#undef write
42
43#ifndef close
44#define sys_close close
45#else
46#undef close
47#endif
48
49#ifndef open
50#define sys_open open
51#else /* `open' is a macro */
52#undef open
53#endif /* `open' is a macro */
54
986ffb24
JB
55/* Does anyone other than VMS need this? */
56#ifndef fwrite
57#define sys_fwrite fwrite
58#else
59#undef fwrite
60#endif
61
86a5659e
JB
62#include <stdio.h>
63#include <sys/types.h>
64#include <sys/stat.h>
65#include <errno.h>
66
67extern int errno;
68#ifndef VMS
69extern char *sys_errlist[];
70#endif
71
72#ifdef VMS
73#include <rms.h>
74#include <ttdef.h>
75#include <tt2def.h>
76#include <iodef.h>
77#include <ssdef.h>
78#include <descrip.h>
79#include <fibdef.h>
80#include <atrdef.h>
81#include <ctype.h>
82#include <string.h>
83#ifdef __GNUC__
84#include <sys/file.h>
85#else
86#include <file.h>
87#endif
88#undef F_SETFL
89#ifndef RAB$C_BID
90#include <rab.h>
91#endif
92#define MAXIOSIZE ( 32 * PAGESIZE ) /* Don't I/O more than 32 blocks at a time */
93#endif /* VMS */
94
95#ifndef BSD4_1
96#ifdef BSD /* this is done this way to avoid defined (BSD) || defined (USG)
97 because the vms compiler doesn't grok `defined' */
98#include <fcntl.h>
99#endif
100#ifdef USG
34567704 101#ifndef USG5
86a5659e
JB
102#include <fcntl.h>
103#endif
34567704 104#endif
86a5659e
JB
105#endif /* not 4.1 bsd */
106
107/* Get DGUX definition for FASYNC - DJB */
108#ifdef DGUX
109#include <sys/file.h>
110#endif /* DGUX */
111
112#include <sys/ioctl.h>
e04a4e0d 113#include "systty.h"
86a5659e
JB
114
115#ifdef BSD
116#ifdef BSD4_1
117#include <wait.h>
118#else /* not 4.1 */
119#include <sys/wait.h>
120#endif /* not 4.1 */
121#endif /* BSD */
122
86a5659e
JB
123#ifdef BROKEN_TIOCGWINSZ
124#undef TIOCGWINSZ
125#endif
126
86a5659e
JB
127#ifdef USG
128#include <sys/utsname.h>
129#include <string.h>
130#ifndef MEMORY_IN_STRING_H
131#include <memory.h>
132#endif
133#ifdef TIOCGWINSZ
134#ifdef NEED_SIOCTL
135#include <sys/sioctl.h>
136#endif
137#ifdef NEED_PTEM_H
138#include <sys/stream.h>
139#include <sys/ptem.h>
140#endif
141#endif /* TIOCGWINSZ */
86a5659e
JB
142#endif /* USG */
143
86a5659e
JB
144extern int quit_char;
145
0137dbf7 146#include "frame.h"
86a5659e
JB
147#include "window.h"
148#include "termhooks.h"
149#include "termchar.h"
150#include "termopts.h"
151#include "dispextern.h"
152#include "process.h"
153
154#ifdef NONSYSTEM_DIR_LIBRARY
155#include "ndir.h"
156#endif /* NONSYSTEM_DIR_LIBRARY */
157
91bac16a
JB
158#include "syssignal.h"
159#include "systime.h"
86a5659e
JB
160
161static int baud_convert[] =
162#ifdef BAUD_CONVERT
163 BAUD_CONVERT;
164#else
165 {
166 0, 50, 75, 110, 135, 150, 200, 300, 600, 1200,
167 1800, 2400, 4800, 9600, 19200, 38400
168 };
169#endif
170
171extern short ospeed;
172
91bac16a
JB
173/* The file descriptor for Emacs's input terminal.
174 Under Unix, this is always left zero;
175 under VMS, we place the input channel number here.
176 This allows us to write more code that works for both VMS and Unix. */
177static int input_fd;
178
86a5659e
JB
179discard_tty_input ()
180{
91bac16a 181 struct emacs_tty buf;
86a5659e
JB
182
183 if (noninteractive)
184 return;
185
186 /* Discarding input is not safe when the input could contain
187 replies from the X server. So don't do it. */
188 if (read_socket_hook)
189 return;
190
191#ifdef VMS
192 end_kbd_input ();
91bac16a
JB
193 SYS$QIOW (0, input_fd, IO$_READVBLK|IO$M_PURGE, input_iosb, 0, 0,
194 &buf.main, 0, 0, terminator_mask, 0, 0);
86a5659e
JB
195 queue_kbd_input ();
196#else /* not VMS */
197#ifdef APOLLO
198 {
199 int zero = 0;
200 ioctl (0, TIOCFLUSH, &zero);
201 }
202#else /* not Apollo */
91bac16a
JB
203 EMACS_GET_TTY (input_fd, &buf);
204 EMACS_SET_TTY (input_fd, &buf, 0);
86a5659e
JB
205#endif /* not Apollo */
206#endif /* not VMS */
207}
208
209#ifdef SIGTSTP
210
211stuff_char (c)
212 char c;
213{
214/* Should perhaps error if in batch mode */
215#ifdef TIOCSTI
216 ioctl (0, TIOCSTI, &c);
217#else /* no TIOCSTI */
218 error ("Cannot stuff terminal input characters in this version of Unix.");
219#endif /* no TIOCSTI */
220}
221
222#endif /* SIGTSTP */
223
224init_baud_rate ()
225{
86a5659e
JB
226 if (noninteractive)
227 ospeed = 0;
228 else
229 {
230#ifdef VMS
91bac16a
JB
231 struct sensemode sg;
232
233 SYS$QIOW (0, input_fd, IO$_SENSEMODE, &sg, 0, 0,
86a5659e 234 &sg.class, 12, 0, 0, 0, 0 );
91bac16a
JB
235 ospeed = sg.xmit_baud;
236#else /* not VMS */
e04a4e0d
JB
237#ifdef HAVE_TERMIOS
238 struct termios sg;
91bac16a
JB
239
240 sg.c_cflag = (sg.c_cflag & ~CBAUD) | B9600;
241 tcgetattr (0, &sg);
242 ospeed = sg.c_cflag & CBAUD;
e04a4e0d
JB
243#else /* neither VMS nor TERMIOS */
244#ifdef HAVE_TERMIO
245 struct termio sg;
91bac16a
JB
246
247 sg.c_cflag = (sg.c_cflag & ~CBAUD) | B9600;
e04a4e0d 248#ifdef HAVE_TCATTR
86a5659e 249 tcgetattr (0, &sg);
e04a4e0d 250#else
6c65530f 251 ioctl (input_fd, TCGETA, &sg);
e04a4e0d 252#endif
91bac16a 253 ospeed = sg.c_cflag & CBAUD;
e04a4e0d 254#else /* neither VMS nor TERMIOS nor TERMIO */
91bac16a
JB
255 struct sgttyb sg;
256
257 sg.sg_ospeed = B9600;
258 ioctl (0, TIOCGETP, &sg);
259 ospeed = sg.sg_ospeed;
91bac16a 260#endif /* not HAVE_TERMIO */
e04a4e0d 261#endif /* not HAVE_TERMIOS */
86a5659e 262#endif /* not VMS */
86a5659e
JB
263 }
264
265 baud_rate = (ospeed < sizeof baud_convert / sizeof baud_convert[0]
266 ? baud_convert[ospeed] : 9600);
267 if (baud_rate == 0)
268 baud_rate = 1200;
269}
270
271/*ARGSUSED*/
272set_exclusive_use (fd)
273 int fd;
274{
275#ifdef FIOCLEX
276 ioctl (fd, FIOCLEX, 0);
277#endif
278 /* Ok to do nothing if this feature does not exist */
279}
280
281#ifndef subprocesses
282
283wait_without_blocking ()
284{
285#ifdef BSD
286 wait3 (0, WNOHANG | WUNTRACED, 0);
287#else
288 croak ("wait_without_blocking");
289#endif
290 synch_process_alive = 0;
291}
292
293#endif /* not subprocesses */
294
295int wait_debugging; /* Set nonzero to make following function work under dbx
296 (at least for bsd). */
297
298SIGTYPE
299wait_for_termination_signal ()
300{}
301
302/* Wait for subprocess with process id `pid' to terminate and
303 make sure it will get eliminated (not remain forever as a zombie) */
304
305wait_for_termination (pid)
306 int pid;
307{
308 while (1)
309 {
310#ifdef subprocesses
311#ifdef VMS
312 int status;
313
986ffb24 314 status = SYS$FORCEX (&pid, 0, 0);
86a5659e
JB
315 break;
316#else /* not VMS */
317
318 /* Exit if the process has terminated. */
319 if (!synch_process_alive)
320 break;
321 /* Otherwise wait 1 second or until a signal comes in. */
322 signal (SIGALRM, wait_for_termination_signal);
323 alarm (1);
324 pause ();
325 alarm (0);
326 signal (SIGALRM, SIG_IGN);
327#endif /* not VMS */
328#else /* not subprocesses */
329#ifndef BSD4_1
330 if (kill (pid, 0) < 0)
331 break;
332 wait (0);
333#else /* BSD4_1 */
334 int status;
335 status = wait (0);
336 if (status == pid || status == -1)
337 break;
338#endif /* BSD4_1 */
339#endif /* not subprocesses */
340 }
341}
342
343#ifdef subprocesses
344
345/*
346 * flush any pending output
347 * (may flush input as well; it does not matter the way we use it)
348 */
349
350flush_pending_output (channel)
351 int channel;
352{
353#ifdef HAVE_TERMIOS
354 /* If we try this, we get hit with SIGTTIN, because
355 the child's tty belongs to the child's pgrp. */
356#else
357#ifdef TCFLSH
358 ioctl (channel, TCFLSH, 1);
359#else
360#ifdef TIOCFLUSH
361 int zero = 0;
362 /* 3rd arg should be ignored
363 but some 4.2 kernels actually want the address of an int
364 and nonzero means something different. */
365 ioctl (channel, TIOCFLUSH, &zero);
366#endif
367#endif
368#endif
369}
370
371#ifndef VMS
372/* Set up the terminal at the other end of a pseudo-terminal that
373 we will be controlling an inferior through.
374 It should not echo or do line-editing, since that is done
375 in Emacs. No padding needed for insertion into an Emacs buffer. */
376
377child_setup_tty (out)
378 int out;
379{
91bac16a
JB
380 struct emacs_tty s;
381
382 EMACS_GET_TTY (out, &s);
86a5659e 383
31be8d24 384#if defined (HAVE_TERMIO) || defined (HAVE_TERMIOS)
91bac16a
JB
385 s.main.c_oflag |= OPOST; /* Enable output postprocessing */
386 s.main.c_oflag &= ~ONLCR; /* Disable map of NL to CR-NL on output */
387 s.main.c_oflag &= ~(NLDLY|CRDLY|TABDLY|BSDLY|VTDLY|FFDLY);
388 /* No output delays */
389 s.main.c_lflag &= ~ECHO; /* Disable echo */
390 s.main.c_lflag |= ISIG; /* Enable signals */
391 s.main.c_iflag &= ~IUCLC; /* Disable map of upper case to lower on
392 input */
393 s.main.c_oflag &= ~OLCUC; /* Disable map of lower case to upper on
394 output */
395#if 0
396 /* Said to be unnecesary: */
397 s.main.c_cc[VMIN] = 1; /* minimum number of characters to accept */
398 s.main.c_cc[VTIME] = 0; /* wait forever for at least 1 character */
399#endif
400
401 s.main.c_lflag |= ICANON; /* Enable erase/kill and eof processing */
402 s.main.c_cc[VEOF] = 04; /* insure that EOF is Control-D */
403 s.main.c_cc[VERASE] = 0377; /* disable erase processing */
404 s.main.c_cc[VKILL] = 0377; /* disable kill processing */
405
86a5659e 406#ifdef HPUX
91bac16a 407 s.main.c_cflag = (s.main.c_cflag & ~CBAUD) | B9600; /* baud rate sanity */
86a5659e 408#endif /* HPUX */
91bac16a 409
86a5659e
JB
410#ifdef AIX
411/* AIX enhanced edit loses NULs, so disable it */
412#ifndef IBMR2AIX
91bac16a
JB
413 s.main.c_line = 0;
414 s.main.c_iflag &= ~ASCEDIT;
86a5659e
JB
415#endif
416 /* Also, PTY overloads NUL and BREAK.
417 don't ignore break, but don't signal either, so it looks like NUL. */
91bac16a
JB
418 s.main.c_iflag &= ~IGNBRK;
419 s.main.c_iflag &= ~BRKINT;
420 /* QUIT and INTR work better as signals, so disable character forms */
421 s.main.c_cc[VQUIT] = 0377;
422 s.main.c_cc[VINTR] = 0377;
423 s.main.c_cc[VEOL] = 0377;
424 s.main.c_lflag &= ~ISIG;
425 s.main.c_cflag = (s.main.c_cflag & ~CBAUD) | B9600; /* baud rate sanity */
86a5659e
JB
426#endif /* AIX */
427
428#else /* not HAVE_TERMIO */
91bac16a
JB
429
430 s.main.sg_flags &= ~(ECHO | CRMOD | ANYP | ALLDELAY | RAW | LCASE
431 | CBREAK | TANDEM);
432 s.main.sg_erase = 0377;
433 s.main.sg_kill = 0377;
434
86a5659e
JB
435#endif /* not HAVE_TERMIO */
436
91bac16a 437 EMACS_SET_TTY (out, &s, 0);
86a5659e
JB
438
439#ifdef BSD4_1
440 if (interrupt_input)
441 reset_sigio ();
442#endif /* BSD4_1 */
443#ifdef RTU
444 {
445 int zero = 0;
446 ioctl (out, FIOASYNC, &zero);
447 }
448#endif /* RTU */
449}
450#endif /* not VMS */
451
452#endif /* subprocesses */
453
454/*ARGSUSED*/
455setpgrp_of_tty (pid)
456 int pid;
457{
ffd56f97 458 EMACS_SET_TTY_PGRP (input_fd, &pid);
86a5659e
JB
459}
460
461/* Record a signal code and the handler for it. */
462struct save_signal
463{
464 int code;
465 SIGTYPE (*handler) ();
466};
467
468/* Suspend the Emacs process; give terminal to its superior. */
469
470sys_suspend ()
471{
472#ifdef VMS
88191e36
RS
473 /* "Foster" parentage allows emacs to return to a subprocess that attached
474 to the current emacs as a cheaper than starting a whole new process. This
475 is set up by KEPTEDITOR.COM. */
476 unsigned long parent_id, foster_parent_id;
477 char *fpid_string;
478
479 fpid_string = getenv ("EMACS_PARENT_PID");
480 if (fpid_string != NULL)
481 {
482 sscanf (fpid_string, "%x", &foster_parent_id);
483 if (foster_parent_id != 0)
484 parent_id = foster_parent_id;
485 else
486 parent_id = getppid ();
487 }
488 else
489 parent_id = getppid ();
490
9ac0d9e0 491 xfree (fpid_string); /* On VMS, this was malloc'd */
86a5659e 492
86a5659e
JB
493 if (parent_id && parent_id != 0xffffffff)
494 {
495 SIGTYPE (*oldsig)() = (int) signal (SIGINT, SIG_IGN);
496 int status = LIB$ATTACH (&parent_id) & 1;
497 signal (SIGINT, oldsig);
498 return status;
499 }
500 else
501 {
502 struct {
503 int l;
504 char *a;
505 } d_prompt;
506 d_prompt.l = sizeof ("Emacs: "); /* Our special prompt */
507 d_prompt.a = "Emacs: "; /* Just a reminder */
986ffb24 508 LIB$SPAWN (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, &d_prompt, 0);
86a5659e
JB
509 return 1;
510 }
511 return -1;
512#else
513#ifdef SIGTSTP
514
91bac16a 515 EMACS_KILLPG (getpgrp (0), SIGTSTP);
86a5659e
JB
516
517#else /* No SIGTSTP */
518#ifdef USG_JOBCTRL /* If you don't know what this is don't mess with it */
519 ptrace (0, 0, 0, 0); /* set for ptrace - caught by csh */
520 kill (getpid (), SIGQUIT);
521
522#else /* No SIGTSTP or USG_JOBCTRL */
523
524/* On a system where suspending is not implemented,
525 instead fork a subshell and let it talk directly to the terminal
526 while we wait. */
527 int pid = fork ();
528 struct save_signal saved_handlers[5];
529
530 saved_handlers[0].code = SIGINT;
531 saved_handlers[1].code = SIGQUIT;
532 saved_handlers[2].code = SIGTERM;
533#ifdef SIGIO
534 saved_handlers[3].code = SIGIO;
535 saved_handlers[4].code = 0;
536#else
537 saved_handlers[3].code = 0;
538#endif
539
540 if (pid == -1)
541 error ("Can't spawn subshell");
542 if (pid == 0)
543 {
544 char *sh;
545
546 sh = (char *) egetenv ("SHELL");
547 if (sh == 0)
548 sh = "sh";
549 /* Use our buffer's default directory for the subshell. */
550 {
551 Lisp_Object dir;
552 unsigned char *str;
553 int len;
554
555 /* mentioning current_buffer->buffer would mean including buffer.h,
556 which somehow wedges the hp compiler. So instead... */
557
558 dir = intern ("default-directory");
559 /* Can't use NULL */
560 if (XFASTINT (Fboundp (dir)) == XFASTINT (Qnil))
561 goto xyzzy;
562 dir = Fsymbol_value (dir);
563 if (XTYPE (dir) != Lisp_String)
564 goto xyzzy;
565
566 str = (unsigned char *) alloca (XSTRING (dir)->size + 2);
567 len = XSTRING (dir)->size;
568 bcopy (XSTRING (dir)->data, str, len);
569 if (str[len - 1] != '/') str[len++] = '/';
570 str[len] = 0;
571 chdir (str);
572 }
573 xyzzy:
574#ifdef subprocesses
575 close_process_descs (); /* Close Emacs's pipes/ptys */
576#endif
1593c2fe
JB
577
578#ifdef PRIO_PROCESS
579 {
580 extern int emacs_priority;
581
582 if (emacs_priority)
583 nice (-emacs_priority);
584 }
585#endif
586
86a5659e
JB
587 execlp (sh, sh, 0);
588 write (1, "Can't execute subshell", 22);
589 _exit (1);
590 }
591
592 save_signal_handlers (saved_handlers);
593 wait_for_termination (pid);
594 restore_signal_handlers (saved_handlers);
595
596#endif /* no USG_JOBCTRL */
597#endif /* no SIGTSTP */
598#endif /* not VMS */
599}
600
601save_signal_handlers (saved_handlers)
602 struct save_signal *saved_handlers;
603{
604 while (saved_handlers->code)
605 {
508b171c
JA
606 saved_handlers->handler
607 = (SIGTYPE (*) ()) signal (saved_handlers->code, SIG_IGN);
86a5659e
JB
608 saved_handlers++;
609 }
610}
611
612restore_signal_handlers (saved_handlers)
613 struct save_signal *saved_handlers;
614{
615 while (saved_handlers->code)
616 {
617 signal (saved_handlers->code, saved_handlers->handler);
618 saved_handlers++;
619 }
620}
621\f
622#ifdef F_SETFL
623
624int old_fcntl_flags;
625
626init_sigio ()
627{
628#ifdef FASYNC
629 old_fcntl_flags = fcntl (0, F_GETFL, 0) & ~FASYNC;
630#endif
631 request_sigio ();
632}
633
634reset_sigio ()
635{
636 unrequest_sigio ();
637}
638
639#ifdef FASYNC /* F_SETFL does not imply existance of FASYNC */
640
641request_sigio ()
642{
643#ifdef SIGWINCH
e065a56e 644 sigunblock (sigmask (SIGWINCH));
86a5659e
JB
645#endif
646 fcntl (0, F_SETFL, old_fcntl_flags | FASYNC);
647
648 interrupts_deferred = 0;
649}
650
651unrequest_sigio ()
652{
653#ifdef SIGWINCH
e065a56e 654 sigblock (sigmask (SIGWINCH));
86a5659e
JB
655#endif
656 fcntl (0, F_SETFL, old_fcntl_flags);
657 interrupts_deferred = 1;
658}
659
660#else /* no FASYNC */
661#ifdef STRIDE /* Stride doesn't have FASYNC - use FIOASYNC */
662
663request_sigio ()
664{
665 int on = 1;
666 ioctl (0, FIOASYNC, &on);
667 interrupts_deferred = 0;
668}
669
670unrequest_sigio ()
671{
672 int off = 0;
673
674 ioctl (0, FIOASYNC, &off);
675 interrupts_deferred = 1;
676}
677
678#else /* not FASYNC, not STRIDE */
679
680request_sigio ()
681{
682 croak ("request_sigio");
683}
684
685unrequest_sigio ()
686{
687 croak ("unrequest_sigio");
688}
689
690#endif /* STRIDE */
691#endif /* FASYNC */
692#endif /* F_SETFL */
693\f
68936329
JB
694/* Getting and setting emacs_tty structures. */
695
696/* Set *TC to the parameters associated with the terminal FD.
697 Return zero if all's well, or -1 if we ran into an error we
698 couldn't deal with. */
699int
700emacs_get_tty (fd, settings)
701 int fd;
702 struct emacs_tty *settings;
703{
704 /* Retrieve the primary parameters - baud rate, character size, etcetera. */
705#ifdef HAVE_TCATTR
706 /* We have those nifty POSIX tcmumbleattr functions. */
707 if (tcgetattr (fd, &settings->main) < 0)
708 return -1;
709
710#else
711#ifdef HAVE_TERMIO
712 /* The SYSV-style interface? */
713 if (ioctl (fd, TCGETA, &settings->main) < 0)
714 return -1;
715
716#else
717#ifdef VMS
718 /* Vehemently Monstrous System? :-) */
719 if (! (SYS$QIOW (0, fd, IO$_SENSEMODE, settings, 0, 0,
720 &settings->main.class, 12, 0, 0, 0, 0)
721 & 1))
722 return -1;
723
724#else
725 /* I give up - I hope you have the BSD ioctls. */
726 if (ioctl (fd, TIOCGETP, &settings->main) < 0)
727 return -1;
728
729#endif
730#endif
731#endif
732
733 /* Suivant - Do we have to get struct ltchars data? */
734#ifdef TIOCGLTC
735 if (ioctl (fd, TIOCGLTC, &settings->ltchars) < 0)
736 return -1;
737#endif
738
739 /* How about a struct tchars and a wordful of lmode bits? */
740#ifdef TIOCGETC
741 if (ioctl (fd, TIOCGETC, &settings->tchars) < 0
742 || ioctl (fd, TIOCLGET, &settings->lmode) < 0)
743 return -1;
744#endif
745
746 /* We have survived the tempest. */
747 return 0;
748}
749
750
751/* Set the parameters of the tty on FD according to the contents of
752 *SETTINGS. If WAITP is non-zero, we wait for all queued output to
753 be written before making the change; otherwise, we forget any
754 queued input and make the change immediately.
755 Return 0 if all went well, and -1 if anything failed. */
756int
757emacs_set_tty (fd, settings, waitp)
758 int fd;
759 struct emacs_tty *settings;
760 int waitp;
761{
762 /* Set the primary parameters - baud rate, character size, etcetera. */
763#ifdef HAVE_TCATTR
764 /* We have those nifty POSIX tcmumbleattr functions.
765 William J. Smith <wjs@wiis.wang.com> writes:
766 "POSIX 1003.1 defines tcsetattr() to return success if it was
767 able to perform any of the requested actions, even if some
768 of the requested actions could not be performed.
769 We must read settings back to ensure tty setup properly.
770 AIX requires this to keep tty from hanging occasionally." */
771 for (;;)
772 if (tcsetattr (fd, waitp ? TCSAFLUSH : TCSADRAIN, &settings->main) < 0)
773 {
774 if (errno == EINTR)
775 continue;
776 else
777 return -1;
778 }
779 else
780 {
781 struct termios new;
782
783 /* Get the current settings, and see if they're what we asked for. */
784 tcgetattr (fd, &new);
785 if (memcmp (&new, &settings->main, sizeof (new)))
786 continue;
787 else
788 break;
789 }
790
791#else
792#ifdef HAVE_TERMIO
793 /* The SYSV-style interface? */
794 if (ioctl (fd, waitp ? TCSETAW : TCSETAF, &settings->main) < 0)
795 return -1;
796
797#else
798#ifdef VMS
799 /* Vehemently Monstrous System? :-) */
800 if (! (SYS$QIOW (0, fd, IO$_SETMODE, &input_iosb, 0, 0,
801 &settings->main.class, 12, 0, 0, 0, 0)
802 & 1))
803 return -1;
804
805#else
806 /* I give up - I hope you have the BSD ioctls. */
807 if (ioctl (fd, (waitp) ? TIOCSETP : TIOCSETN, &settings->main) < 0)
808 return -1;
809
810#endif
811#endif
812#endif
813
814 /* Suivant - Do we have to get struct ltchars data? */
815#ifdef TIOCGLTC
816 if (ioctl (fd, TIOCSLTC, &settings->ltchars) < 0)
817 return -1;
818#endif
819
820 /* How about a struct tchars and a wordful of lmode bits? */
821#ifdef TIOCGETC
822 if (ioctl (fd, TIOCSETC, &settings->tchars) < 0
823 || ioctl (fd, TIOCLSET, &settings->lmode) < 0)
824 return -1;
825#endif
826
827 /* We have survived the tempest. */
828 return 0;
829}
830
831\f
91bac16a
JB
832/* The initial tty mode bits */
833struct emacs_tty old_tty;
86a5659e
JB
834
835int term_initted; /* 1 if outer tty status has been recorded */
836
91bac16a
JB
837#ifdef BSD4_1
838/* BSD 4.1 needs to keep track of the lmode bits in order to start
839 sigio. */
840int lmode;
841#endif
842
86a5659e
JB
843#ifdef F_SETOWN
844int old_fcntl_owner;
845#endif /* F_SETOWN */
846
86a5659e
JB
847/* This may also be defined in stdio,
848 but if so, this does no harm,
849 and using the same name avoids wasting the other one's space. */
850
851#if defined (USG) || defined (DGUX)
852unsigned char _sobuf[BUFSIZ+8];
853#else
854char _sobuf[BUFSIZ];
855#endif
856
857#ifdef TIOCGLTC
858static struct ltchars new_ltchars = {-1,-1,-1,-1,-1,-1};
859#endif
860#ifdef TIOCGETC
861 static struct tchars new_tchars = {-1,-1,-1,-1,-1,-1};
862#endif
863
864init_sys_modes ()
865{
91bac16a
JB
866 struct emacs_tty tty;
867
86a5659e
JB
868#ifdef VMS
869#if 0
870 static int oob_chars[2] = {0, 1 << 7}; /* catch C-g's */
871 extern int (*interrupt_signal) ();
872#endif
873#endif
874
875 if (noninteractive)
876 return;
877
878#ifdef VMS
879 if (!input_ef)
880 input_ef = get_kbd_event_flag ();
881 /* LIB$GET_EF (&input_ef); */
882 SYS$CLREF (input_ef);
883 waiting_for_ast = 0;
884 if (!timer_ef)
885 timer_ef = get_timer_event_flag ();
886 /* LIB$GET_EF (&timer_ef); */
887 SYS$CLREF (timer_ef);
210b2b4f 888#if 0
86a5659e
JB
889 if (!process_ef)
890 {
891 LIB$GET_EF (&process_ef);
892 SYS$CLREF (process_ef);
893 }
894 if (input_ef / 32 != process_ef / 32)
895 croak ("Input and process event flags in different clusters.");
210b2b4f 896#endif
86a5659e 897 if (input_ef / 32 != timer_ef / 32)
210b2b4f
JB
898 croak ("Input and timer event flags in different clusters.");
899#if 0
86a5659e
JB
900 input_eflist = ((unsigned) 1 << (input_ef % 32)) |
901 ((unsigned) 1 << (process_ef % 32));
210b2b4f 902#endif
86a5659e
JB
903 timer_eflist = ((unsigned) 1 << (input_ef % 32)) |
904 ((unsigned) 1 << (timer_ef % 32));
86a5659e
JB
905#ifndef VMS4_4
906 sys_access_reinit ();
907#endif
86a5659e 908#endif /* not VMS */
91bac16a
JB
909
910 EMACS_GET_TTY (input_fd, &old_tty);
911
86a5659e
JB
912 if (!read_socket_hook && EQ (Vwindow_system, Qnil))
913 {
91bac16a 914 tty = old_tty;
86a5659e 915
31be8d24 916#if defined (HAVE_TERMIO) || defined (HAVE_TERMIOS)
91bac16a
JB
917 tty.main.c_iflag |= (IGNBRK); /* Ignore break condition */
918 tty.main.c_iflag &= ~ICRNL; /* Disable map of CR to NL on input */
86a5659e 919#ifdef ISTRIP
91bac16a 920 tty.main.c_iflag &= ~ISTRIP; /* don't strip 8th bit on input */
86a5659e 921#endif
91bac16a
JB
922 tty.main.c_lflag &= ~ECHO; /* Disable echo */
923 tty.main.c_lflag &= ~ICANON; /* Disable erase/kill processing */
e2b40c23
RS
924#ifdef IEXTEN
925 tty.main.c_iflag &= ~IEXTEN; /* Disable other editing characters. */
926#endif
91bac16a 927 tty.main.c_lflag |= ISIG; /* Enable signals */
86a5659e
JB
928 if (flow_control)
929 {
91bac16a 930 tty.main.c_iflag |= IXON; /* Enable start/stop output control */
86a5659e 931#ifdef IXANY
91bac16a 932 tty.main.c_iflag &= ~IXANY;
86a5659e
JB
933#endif /* IXANY */
934 }
935 else
91bac16a
JB
936 tty.main.c_iflag &= ~IXON; /* Disable start/stop output control */
937 tty.main.c_oflag &= ~ONLCR; /* Disable map of NL to CR-NL
938 on output */
939 tty.main.c_oflag &= ~TAB3; /* Disable tab expansion */
86a5659e
JB
940#ifdef CS8
941 if (meta_key)
942 {
91bac16a
JB
943 tty.main.c_cflag |= CS8; /* allow 8th bit on input */
944 tty.main.c_cflag &= ~PARENB;/* Don't check parity */
86a5659e
JB
945 }
946#endif
91bac16a 947 tty.main.c_cc[VINTR] = quit_char; /* C-g (usually) gives SIGINT */
86a5659e
JB
948 /* Set up C-g for both SIGQUIT and SIGINT.
949 We don't know which we will get, but we handle both alike
950 so which one it really gives us does not matter. */
91bac16a
JB
951 tty.main.c_cc[VQUIT] = quit_char;
952 tty.main.c_cc[VMIN] = 1; /* Input should wait for at least 1 char */
953 tty.main.c_cc[VTIME] = 0; /* no matter how long that takes. */
86a5659e 954#ifdef VSWTCH
e2b40c23 955 tty.main.c_cc[VSWTCH] = CDISABLE; /* Turn off shell layering use
91bac16a 956 of C-z */
86a5659e
JB
957#endif /* VSWTCH */
958#if defined (mips) || defined (HAVE_TCATTR)
86a5659e 959#ifdef VSUSP
e2b40c23 960 tty.main.c_cc[VSUSP] = CDISABLE; /* Turn off mips handling of C-z. */
86a5659e
JB
961#endif /* VSUSP */
962#ifdef V_DSUSP
e2b40c23 963 tty.main.c_cc[V_DSUSP] = CDISABLE; /* Turn off mips handling of C-y. */
86a5659e 964#endif /* V_DSUSP */
e2b40c23
RS
965#ifdef VDSUSP /* Some systems have VDSUSP, some have V_DSUSP. */
966 tty.main.c_cc[VDSUSP] = CDISABLE;
967#endif /* VDSUSP */
86a5659e
JB
968#endif /* mips or HAVE_TCATTR */
969#ifdef AIX
970#ifndef IBMR2AIX
971 /* AIX enhanced edit loses NULs, so disable it */
91bac16a
JB
972 tty.main.c_line = 0;
973 tty.main.c_iflag &= ~ASCEDIT;
86a5659e 974#else
91bac16a
JB
975 tty.main.c_cc[VSTRT] = 255;
976 tty.main.c_cc[VSTOP] = 255;
977 tty.main.c_cc[VSUSP] = 255;
978 tty.main.c_cc[VDSUSP] = 255;
86a5659e
JB
979#endif /* IBMR2AIX */
980 /* Also, PTY overloads NUL and BREAK.
981 don't ignore break, but don't signal either, so it looks like NUL.
982 This really serves a purpose only if running in an XTERM window
983 or via TELNET or the like, but does no harm elsewhere. */
91bac16a
JB
984 tty.main.c_iflag &= ~IGNBRK;
985 tty.main.c_iflag &= ~BRKINT;
86a5659e
JB
986#endif
987#else /* if not HAVE_TERMIO */
988#ifdef VMS
91bac16a 989 tty.main.tt_char |= TT$M_NOECHO;
86a5659e 990 if (meta_key)
986ffb24 991 tty.main.tt_char |= TT$M_EIGHTBIT;
86a5659e 992 if (flow_control)
91bac16a 993 tty.main.tt_char |= TT$M_TTSYNC;
86a5659e 994 else
91bac16a
JB
995 tty.main.tt_char &= ~TT$M_TTSYNC;
996 tty.main.tt2_char |= TT2$M_PASTHRU | TT2$M_XON;
86a5659e 997#else /* not VMS (BSD, that is) */
91bac16a 998 tty.main.sg_flags &= ~(ECHO | CRMOD | XTABS);
86a5659e 999 if (meta_key)
91bac16a
JB
1000 tty.main.sg_flags |= ANYP;
1001 tty.main.sg_flags |= interrupt_input ? RAW : CBREAK;
86a5659e
JB
1002#endif /* not VMS (BSD, that is) */
1003#endif /* not HAVE_TERMIO */
1004
91bac16a
JB
1005 /* If going to use CBREAK mode, we must request C-g to interrupt
1006 and turn off start and stop chars, etc. If not going to use
1007 CBREAK mode, do this anyway so as to turn off local flow
1008 control for user coming over network on 4.2; in this case,
1009 only t_stopc and t_startc really matter. */
1010#ifndef HAVE_TERMIO
1011#ifdef TIOCGETC
1012 /* Note: if not using CBREAK mode, it makes no difference how we
1013 set this */
1014 tty.tchars = new_tchars;
1015 tty.tchars.t_intrc = quit_char;
1016 if (flow_control)
1017 {
1018 tty.tchars.t_startc = '\021';
1019 tty.tchars.t_stopc = '\023';
1020 }
1021
1022/* LPASS8 is new in 4.3, and makes cbreak mode provide all 8 bits. */
1023#ifndef LPASS8
1024#define LPASS8 0
86a5659e 1025#endif
91bac16a
JB
1026
1027#ifdef BSD4_1
1028#define LNOFLSH 0100000
1029#endif
1030
1031 tty.lmode = LDECCTQ | LLITOUT | LPASS8 | LNOFLSH | old_tty.lmode;
1032
1033#ifdef BSD4_1
1034 lmode = tty.lmode;
1035#endif
1036
1037#endif /* TIOCGETC */
1038#endif /* not HAVE_TERMIO */
1039
1040#ifdef TIOCGLTC
1041 tty.ltchars = new_ltchars;
1042#endif /* TIOCGLTC */
1043
1044 EMACS_SET_TTY (input_fd, &tty, 0);
86a5659e
JB
1045
1046 /* This code added to insure that, if flow-control is not to be used,
0137dbf7 1047 we have an unlocked terminal at the start. */
91bac16a 1048
86a5659e
JB
1049#ifdef TCXONC
1050 if (!flow_control) ioctl (0, TCXONC, 1);
1051#endif
1052#ifndef APOLLO
1053#ifdef TIOCSTART
1054 if (!flow_control) ioctl (0, TIOCSTART, 0);
1055#endif
1056#endif
1057
1058#ifdef AIX
1059 hft_init ();
1060#ifdef IBMR2AIX
1061 {
1062 /* IBM's HFT device usually thinks a ^J should be LF/CR. We need it
1063 to be only LF. This is the way that is done. */
1064 struct termio tty;
1065
1066 if (ioctl (1, HFTGETID, &tty) != -1)
1067 write (1, "\033[20l", 5);
1068 }
1069#endif
1070#endif
1071
86a5659e
JB
1072#ifdef VMS
1073/* Appears to do nothing when in PASTHRU mode.
91bac16a 1074 SYS$QIOW (0, input_fd, IO$_SETMODE|IO$M_OUTBAND, 0, 0, 0,
86a5659e
JB
1075 interrupt_signal, oob_chars, 0, 0, 0, 0);
1076*/
1077 queue_kbd_input (0);
1078#endif /* VMS */
1079 }
1080
1081#ifdef F_SETFL
1082#ifdef F_GETOWN /* F_SETFL does not imply existance of F_GETOWN */
1083 if (interrupt_input)
1084 {
1085 old_fcntl_owner = fcntl (0, F_GETOWN, 0);
1086 fcntl (0, F_SETOWN, getpid ());
1087 init_sigio ();
1088 }
1089#endif /* F_GETOWN */
1090#endif /* F_SETFL */
1091
1092#ifdef BSD4_1
1093 if (interrupt_input)
1094 init_sigio ();
1095#endif
1096
1097#ifdef VMS /* VMS sometimes has this symbol but lacks setvbuf. */
1098#undef _IOFBF
1099#endif
1100#ifdef _IOFBF
1101 /* This symbol is defined on recent USG systems.
1102 Someone says without this call USG won't really buffer the file
1103 even with a call to setbuf. */
1104 setvbuf (stdout, _sobuf, _IOFBF, sizeof _sobuf);
1105#else
1106 setbuf (stdout, _sobuf);
1107#endif
1108 set_terminal_modes ();
1109 if (term_initted && no_redraw_on_reenter)
1110 {
1111 if (display_completed)
1112 direct_output_forward_char (0);
1113 }
1114 else
1115 {
0137dbf7
JB
1116 frame_garbaged = 1;
1117#ifdef MULTI_FRAME
1118 if (FRAMEP (Vterminal_frame))
1119 FRAME_GARBAGED_P (XFRAME (Vterminal_frame)) = 1;
86a5659e
JB
1120#endif
1121 }
91bac16a 1122
86a5659e
JB
1123 term_initted = 1;
1124}
1125
1126/* Return nonzero if safe to use tabs in output.
1127 At the time this is called, init_sys_modes has not been done yet. */
1128
1129tabs_safe_p ()
1130{
91bac16a
JB
1131 struct emacs_tty tty;
1132
1133 EMACS_GET_TTY (input_fd, &tty);
1134 return EMACS_TTY_TABS_OK (&tty);
86a5659e
JB
1135}
1136
1137/* Get terminal size from system.
1138 Store number of lines into *heightp and width into *widthp.
1139 If zero or a negative number is stored, the value is not valid. */
1140
0137dbf7 1141get_frame_size (widthp, heightp)
86a5659e
JB
1142 int *widthp, *heightp;
1143{
86a5659e 1144
86a5659e 1145#ifdef TIOCGWINSZ
91bac16a
JB
1146
1147 /* BSD-style. */
86a5659e 1148 struct winsize size;
91bac16a
JB
1149
1150 if (ioctl (input_fd, TIOCGWINSZ, &size) == -1)
1151 *widthp = *heightp = 0;
1152 else
1153 {
1154 *widthp = size.ws_col;
1155 *heightp = size.ws_row;
1156 }
1157
1158#else
1159#ifdef TIOCGSIZE
1160
1161 /* SunOS - style. */
1162 struct ttysize size;
1163
1164 if (ioctl (input_fd, TIOCGSIZE, &size) == -1)
1165 *widthp = *heightp = 0;
1166 else
1167 {
1168 *widthp = size.ts_cols;
1169 *heightp = size.ts_lines;
1170 }
1171
1172#else
86a5659e 1173#ifdef VMS
91bac16a
JB
1174
1175 struct sensemode tty;
1176
1177 SYS$QIOW (0, input_fd, IO$_SENSEMODE, &tty, 0, 0,
86a5659e
JB
1178 &tty.class, 12, 0, 0, 0, 0);
1179 *widthp = tty.scr_wid;
1180 *heightp = tty.scr_len;
91bac16a 1181
86a5659e 1182#else /* system doesn't know size */
91bac16a 1183
86a5659e
JB
1184 *widthp = 0;
1185 *heightp = 0;
91bac16a
JB
1186
1187#endif /* not VMS */
1188#endif /* not SunOS-style */
1189#endif /* not BSD-style */
86a5659e 1190}
91bac16a 1191
86a5659e 1192\f
91bac16a 1193/* Prepare the terminal for exiting Emacs; move the cursor to the
0137dbf7 1194 bottom of the frame, turn off interrupt-driven I/O, etc. */
86a5659e
JB
1195reset_sys_modes ()
1196{
1197 if (noninteractive)
1198 {
1199 fflush (stdout);
1200 return;
1201 }
1202 if (!term_initted)
1203 return;
1204 if (read_socket_hook || !EQ (Vwindow_system, Qnil))
1205 return;
0137dbf7
JB
1206 cursor_to (FRAME_HEIGHT (selected_frame) - 1, 0);
1207 clear_end_of_line (FRAME_WIDTH (selected_frame));
86a5659e 1208 /* clear_end_of_line may move the cursor */
0137dbf7 1209 cursor_to (FRAME_HEIGHT (selected_frame) - 1, 0);
86a5659e
JB
1210#ifdef IBMR2AIX
1211 {
1212 /* HFT devices normally use ^J as a LF/CR. We forced it to
1213 do the LF only. Now, we need to reset it. */
1214 struct termio tty;
1215
1216 if (ioctl (1, HFTGETID, &tty) != -1)
1217 write (1, "\033[20h", 5);
1218 }
1219#endif
1220
1221 reset_terminal_modes ();
1222 fflush (stdout);
1223#ifdef BSD
1224#ifndef BSD4_1
1225 /* Avoid possible loss of output when changing terminal modes. */
1226 fsync (fileno (stdout));
1227#endif
1228#endif
91bac16a 1229
86a5659e
JB
1230#ifdef F_SETFL
1231#ifdef F_SETOWN /* F_SETFL does not imply existance of F_SETOWN */
1232 if (interrupt_input)
1233 {
1234 reset_sigio ();
1235 fcntl (0, F_SETOWN, old_fcntl_owner);
1236 }
1237#endif /* F_SETOWN */
1238#endif /* F_SETFL */
1239#ifdef BSD4_1
1240 if (interrupt_input)
1241 reset_sigio ();
1242#endif /* BSD4_1 */
91bac16a 1243
97741d05 1244 while (! EMACS_SET_TTY (input_fd, &old_tty, 0) && errno == EINTR)
91bac16a 1245 ;
86a5659e
JB
1246
1247#ifdef AIX
1248 hft_reset ();
1249#endif
1250}
1251\f
1252#ifdef HAVE_PTYS
1253
1254/* Set up the proper status flags for use of a pty. */
1255
1256setup_pty (fd)
1257 int fd;
1258{
1259 /* I'm told that TOICREMOTE does not mean control chars
1260 "can't be sent" but rather that they don't have
1261 input-editing or signaling effects.
1262 That should be good, because we have other ways
1263 to do those things in Emacs.
1264 However, telnet mode seems not to work on 4.2.
1265 So TIOCREMOTE is turned off now. */
1266
1267 /* Under hp-ux, if TIOCREMOTE is turned on, some calls
1268 will hang. In particular, the "timeout" feature (which
1269 causes a read to return if there is no data available)
1270 does this. Also it is known that telnet mode will hang
1271 in such a way that Emacs must be stopped (perhaps this
1272 is the same problem).
1273
1274 If TIOCREMOTE is turned off, then there is a bug in
1275 hp-ux which sometimes loses data. Apparently the
1276 code which blocks the master process when the internal
1277 buffer fills up does not work. Other than this,
1278 though, everything else seems to work fine.
1279
1280 Since the latter lossage is more benign, we may as well
1281 lose that way. -- cph */
1282#ifdef FIONBIO
1283#ifdef SYSV_PTYS
1284 {
1285 int on = 1;
1286 ioctl (fd, FIONBIO, &on);
1287 }
1288#endif
1289#endif
1290#ifdef IBMRTAIX
1291 /* On AIX, the parent gets SIGHUP when a pty attached child dies. So, we */
1292 /* ignore SIGHUP once we've started a child on a pty. Note that this may */
1293 /* cause EMACS not to die when it should, i.e., when its own controlling */
1294 /* tty goes away. I've complained to the AIX developers, and they may */
1295 /* change this behavior, but I'm not going to hold my breath. */
1296 signal (SIGHUP, SIG_IGN);
1297#endif
1298}
1299#endif /* HAVE_PTYS */
1300\f
1301#ifdef VMS
1302
1303/* Assigning an input channel is done at the start of Emacs execution.
1304 This is called each time Emacs is resumed, also, but does nothing
1305 because input_chain is no longer zero. */
1306
1307init_vms_input ()
1308{
1309 int status;
1310
91bac16a 1311 if (input_fd == 0)
86a5659e 1312 {
91bac16a 1313 status = SYS$ASSIGN (&input_dsc, &input_fd, 0, 0);
86a5659e
JB
1314 if (! (status & 1))
1315 LIB$STOP (status);
1316 }
1317}
1318
1319/* Deassigning the input channel is done before exiting. */
1320
1321stop_vms_input ()
1322{
91bac16a 1323 return SYS$DASSGN (input_fd);
86a5659e
JB
1324}
1325
1326short input_buffer;
1327
1328/* Request reading one character into the keyboard buffer.
1329 This is done as soon as the buffer becomes empty. */
1330
1331queue_kbd_input ()
1332{
1333 int status;
210b2b4f
JB
1334 extern kbd_input_ast ();
1335
86a5659e
JB
1336 waiting_for_ast = 0;
1337 stop_input = 0;
91bac16a 1338 status = SYS$QIO (0, input_fd, IO$_READVBLK,
86a5659e
JB
1339 &input_iosb, kbd_input_ast, 1,
1340 &input_buffer, 1, 0, terminator_mask, 0, 0);
1341}
1342
1343int input_count;
1344
1345/* Ast routine that is called when keyboard input comes in
1346 in accord with the SYS$QIO above. */
1347
1348kbd_input_ast ()
1349{
1350 register int c = -1;
1351 int old_errno = errno;
ffd56f97 1352 extern EMACS_TIME *input_available_clear_time;
86a5659e
JB
1353
1354 if (waiting_for_ast)
1355 SYS$SETEF (input_ef);
1356 waiting_for_ast = 0;
1357 input_count++;
1358#ifdef ASTDEBUG
1359 if (input_count == 25)
1360 exit (1);
1361 printf ("Ast # %d,", input_count);
1362 printf (" iosb = %x, %x, %x, %x",
1363 input_iosb.offset, input_iosb.status, input_iosb.termlen,
1364 input_iosb.term);
1365#endif
1366 if (input_iosb.offset)
1367 {
1368 c = input_buffer;
1369#ifdef ASTDEBUG
1370 printf (", char = 0%o", c);
1371#endif
1372 }
1373#ifdef ASTDEBUG
1374 printf ("\n");
1375 fflush (stdout);
1376 sleep (1);
1377#endif
1378 if (! stop_input)
1379 queue_kbd_input ();
1380 if (c >= 0)
1381 {
1382 struct input_event e;
1383 e.kind = ascii_keystroke;
210b2b4f
JB
1384 XSET (e.code, Lisp_Int, c);
1385#ifdef MULTI_FRAME
1386 XSET(e.frame_or_window, Lisp_Frame, selected_frame);
1387#else
1388 e.frame_or_window = Qnil;
1389#endif
86a5659e
JB
1390 kbd_buffer_store_event (&e);
1391 }
ffd56f97
JB
1392 if (input_available_clear_time)
1393 EMACS_SET_SECS_USECS (*input_available_clear_time, 0, 0);
86a5659e
JB
1394 errno = old_errno;
1395}
1396
1397/* Wait until there is something in kbd_buffer. */
1398
1399wait_for_kbd_input ()
1400{
1401 extern int have_process_input, process_exited;
1402
1403 /* If already something, avoid doing system calls. */
1404 if (detect_input_pending ())
1405 {
1406 return;
1407 }
1408 /* Clear a flag, and tell ast routine above to set it. */
1409 SYS$CLREF (input_ef);
1410 waiting_for_ast = 1;
1411 /* Check for timing error: ast happened while we were doing that. */
1412 if (!detect_input_pending ())
1413 {
1414 /* No timing error: wait for flag to be set. */
1415 set_waiting_for_input (0);
1416 SYS$WFLOR (input_ef, input_eflist);
1417 clear_waiting_for_input (0);
1418 if (!detect_input_pending ())
1419 /* Check for subprocess input availability */
1420 {
1421 int dsp = have_process_input || process_exited;
1422
1423 SYS$CLREF (process_ef);
1424 if (have_process_input)
1425 process_command_input ();
1426 if (process_exited)
1427 process_exit ();
1428 if (dsp)
1429 {
1430 update_mode_lines++;
1431 redisplay_preserve_echo_area ();
1432 }
1433 }
1434 }
1435 waiting_for_ast = 0;
1436}
1437
1438/* Get rid of any pending QIO, when we are about to suspend
1439 or when we want to throw away pending input.
1440 We wait for a positive sign that the AST routine has run
1441 and therefore there is no I/O request queued when we return.
1442 SYS$SETAST is used to avoid a timing error. */
1443
1444end_kbd_input ()
1445{
1446#ifdef ASTDEBUG
1447 printf ("At end_kbd_input.\n");
1448 fflush (stdout);
1449 sleep (1);
1450#endif
1451 if (LIB$AST_IN_PROG ()) /* Don't wait if suspending from kbd_buffer_store_event! */
1452 {
91bac16a 1453 SYS$CANCEL (input_fd);
86a5659e
JB
1454 return;
1455 }
1456
1457 SYS$SETAST (0);
1458 /* Clear a flag, and tell ast routine above to set it. */
1459 SYS$CLREF (input_ef);
1460 waiting_for_ast = 1;
1461 stop_input = 1;
91bac16a 1462 SYS$CANCEL (input_fd);
86a5659e
JB
1463 SYS$SETAST (1);
1464 SYS$WAITFR (input_ef);
1465 waiting_for_ast = 0;
1466}
1467
1468/* Wait for either input available or time interval expiry. */
1469
1470input_wait_timeout (timeval)
1471 int timeval; /* Time to wait, in seconds */
1472{
1473 int time [2];
1474 static int zero = 0;
1475 static int large = -10000000;
1476
1477 LIB$EMUL (&timeval, &large, &zero, time); /* Convert to VMS format */
1478
1479 /* If already something, avoid doing system calls. */
1480 if (detect_input_pending ())
1481 {
1482 return;
1483 }
1484 /* Clear a flag, and tell ast routine above to set it. */
1485 SYS$CLREF (input_ef);
1486 waiting_for_ast = 1;
1487 /* Check for timing error: ast happened while we were doing that. */
1488 if (!detect_input_pending ())
1489 {
1490 /* No timing error: wait for flag to be set. */
1491 SYS$CANTIM (1, 0);
1492 if (SYS$SETIMR (timer_ef, time, 0, 1) & 1) /* Set timer */
1493 SYS$WFLOR (timer_ef, timer_eflist); /* Wait for timer expiry or input */
1494 }
1495 waiting_for_ast = 0;
1496}
1497
1498/* The standard `sleep' routine works some other way
1499 and it stops working if you have ever quit out of it.
1500 This one continues to work. */
1501
1502sys_sleep (timeval)
1503 int timeval;
1504{
1505 int time [2];
1506 static int zero = 0;
1507 static int large = -10000000;
1508
1509 LIB$EMUL (&timeval, &large, &zero, time); /* Convert to VMS format */
1510
1511 SYS$CANTIM (1, 0);
1512 if (SYS$SETIMR (timer_ef, time, 0, 1) & 1) /* Set timer */
1513 SYS$WAITFR (timer_ef); /* Wait for timer expiry only */
1514}
1515
1516init_sigio ()
1517{
1518 request_sigio ();
1519}
1520
1521reset_sigio ()
1522{
1523 unrequest_sigio ();
1524}
1525
1526request_sigio ()
1527{
1528 croak ("request sigio");
1529}
1530
1531unrequest_sigio ()
1532{
1533 croak ("unrequest sigio");
1534}
1535
1536#endif /* VMS */
1537\f
1538/* Note that VMS compiler won't accept defined (CANNOT_DUMP). */
1539#ifndef CANNOT_DUMP
1540#define NEED_STARTS
1541#endif
1542
1543#ifndef SYSTEM_MALLOC
1544#ifndef NEED_STARTS
1545#define NEED_STARTS
1546#endif
1547#endif
1548
1549#ifdef NEED_STARTS
1550/* Some systems that cannot dump also cannot implement these. */
1551
1552/*
1553 * Return the address of the start of the text segment prior to
1554 * doing an unexec. After unexec the return value is undefined.
1555 * See crt0.c for further explanation and _start.
1556 *
1557 */
1558
1559#ifndef CANNOT_UNEXEC
1560char *
1561start_of_text ()
1562{
1563#ifdef TEXT_START
1564 return ((char *) TEXT_START);
1565#else
1566#ifdef GOULD
1567 extern csrt ();
1568 return ((char *) csrt);
1569#else /* not GOULD */
1570 extern int _start ();
1571 return ((char *) _start);
1572#endif /* GOULD */
1573#endif /* TEXT_START */
1574}
1575#endif /* not CANNOT_UNEXEC */
1576
1577/*
1578 * Return the address of the start of the data segment prior to
1579 * doing an unexec. After unexec the return value is undefined.
1580 * See crt0.c for further information and definition of data_start.
1581 *
1582 * Apparently, on BSD systems this is etext at startup. On
1583 * USG systems (swapping) this is highly mmu dependent and
1584 * is also dependent on whether or not the program is running
1585 * with shared text. Generally there is a (possibly large)
1586 * gap between end of text and start of data with shared text.
1587 *
1588 * On Uniplus+ systems with shared text, data starts at a
1589 * fixed address. Each port (from a given oem) is generally
1590 * different, and the specific value of the start of data can
1591 * be obtained via the UniPlus+ specific "uvar" system call,
1592 * however the method outlined in crt0.c seems to be more portable.
1593 *
1594 * Probably what will have to happen when a USG unexec is available,
1595 * at least on UniPlus, is temacs will have to be made unshared so
1596 * that text and data are contiguous. Then once loadup is complete,
1597 * unexec will produce a shared executable where the data can be
1598 * at the normal shared text boundry and the startofdata variable
1599 * will be patched by unexec to the correct value.
1600 *
1601 */
1602
1603char *
1604start_of_data ()
1605{
1606#ifdef DATA_START
1607 return ((char *) DATA_START);
6c65530f
JB
1608#else
1609#ifdef ORDINARY_LINK
1610 /*
1611 * This is a hack. Since we're not linking crt0.c or pre_crt0.c,
1612 * data_start isn't defined. We take the address of environ, which
1613 * is known to live at or near the start of the system crt0.c, and
1614 * we don't sweat the handful of bytes that might lose.
1615 */
1616 extern char **environ;
1617
1618 return((char *) &environ);
86a5659e
JB
1619#else
1620 extern int data_start;
1621 return ((char *) &data_start);
6c65530f
JB
1622#endif /* ORDINARY_LINK */
1623#endif /* DATA_START */
86a5659e
JB
1624}
1625#endif /* NEED_STARTS (not CANNOT_DUMP or not SYSTEM_MALLOC) */
1626
1627#ifndef CANNOT_DUMP
1628/* Some systems that cannot dump also cannot implement these. */
1629
1630/*
1631 * Return the address of the end of the text segment prior to
1632 * doing an unexec. After unexec the return value is undefined.
1633 */
1634
1635char *
1636end_of_text ()
1637{
1638#ifdef TEXT_END
1639 return ((char *) TEXT_END);
1640#else
1641 extern int etext;
1642 return ((char *) &etext);
1643#endif
1644}
1645
1646/*
1647 * Return the address of the end of the data segment prior to
1648 * doing an unexec. After unexec the return value is undefined.
1649 */
1650
1651char *
1652end_of_data ()
1653{
1654#ifdef DATA_END
1655 return ((char *) DATA_END);
1656#else
1657 extern int edata;
1658 return ((char *) &edata);
1659#endif
1660}
1661
1662#endif /* not CANNOT_DUMP */
1663\f
1664/* Get_system_name returns as its value
1665 a string for the Lisp function system-name to return. */
1666
1667#ifdef BSD4_1
1668#include <whoami.h>
1669#endif
1670
e36ba278
RS
1671/* Can't have this within the function since `static' is #defined to
1672 nothing for some USG systems. */
86a5659e 1673#ifdef USG
e36ba278
RS
1674#ifdef HAVE_GETHOSTNAME
1675static char get_system_name_name[256];
1676#else /* not HAVE_GETHOSTNAME */
86a5659e 1677static struct utsname get_system_name_name;
e36ba278
RS
1678#endif /* not HAVE_GETHOSTNAME */
1679#endif /* USG */
86a5659e
JB
1680
1681char *
1682get_system_name ()
1683{
1684#ifdef USG
e36ba278
RS
1685#ifdef HAVE_GETHOSTNAME
1686 gethostname (get_system_name_name, sizeof (get_system_name_name));
1687 return get_system_name_name;
1688#else /* not HAVE_GETHOSTNAME */
86a5659e
JB
1689 uname (&get_system_name_name);
1690 return (get_system_name_name.nodename);
e36ba278 1691#endif /* not HAVE_GETHOSTNAME */
86a5659e
JB
1692#else /* Not USG */
1693#ifdef BSD4_1
1694 return sysname;
1695#else /* not USG, not 4.1 */
1696 static char system_name_saved[32];
1697#ifdef VMS
1698 char *sp;
1699 if ((sp = egetenv ("SYS$NODE")) == 0)
1700 sp = "vax-vms";
1701 else
1702 {
1703 char *end;
1704
1705 if ((end = index (sp, ':')) != 0)
1706 *end = '\0';
1707 }
1708 strcpy (system_name_saved, sp);
1709#else /* not VMS */
1710 gethostname (system_name_saved, sizeof (system_name_saved));
1711#endif /* not VMS */
1712 return system_name_saved;
1713#endif /* not USG, not 4.1 */
1714#endif /* not USG */
1715}
210b2b4f
JB
1716
1717#ifdef VMS
1718#ifndef HAVE_GETHOSTNAME
1719void gethostname(buf, len)
1720 char *buf;
1721 int len;
1722{
1723 char *s;
1724 s = getenv ("SYS$NODE");
1725 if (s == NULL)
1726 buf[0] = '\0';
1727 else {
1728 strncpy (buf, s, len - 2);
1729 buf[len - 1] = '\0';
1730 } /* else */
1731} /* static void gethostname */
1732#endif /* ! HAVE_GETHOSTNAME */
1733#endif /* VMS */
1734
86a5659e
JB
1735\f
1736#ifndef VMS
1737#ifndef HAVE_SELECT
1738
1739#ifdef HAVE_X_WINDOWS
1740/* Cause explanatory error message at compile time,
1741 since the select emulation is not good enough for X. */
1742int *x = &x_windows_lose_if_no_select_system_call;
1743#endif
1744
1745/* Emulate as much as select as is possible under 4.1 and needed by Gnu Emacs
1746 * Only checks read descriptors.
1747 */
1748/* How long to wait between checking fds in select */
1749#define SELECT_PAUSE 1
1750int select_alarmed;
1751
1752/* For longjmp'ing back to read_input_waiting. */
1753
1754jmp_buf read_alarm_throw;
1755
1756/* Nonzero if the alarm signal should throw back to read_input_waiting.
1757 The read_socket_hook function sets this to 1 while it is waiting. */
1758
1759int read_alarm_should_throw;
1760
1761SIGTYPE
1762select_alarm ()
1763{
1764 select_alarmed = 1;
1765#ifdef BSD4_1
1766 sigrelse (SIGALRM);
1767#else /* not BSD4_1 */
1768 signal (SIGALRM, SIG_IGN);
1769#endif /* not BSD4_1 */
1770 if (read_alarm_should_throw)
1771 longjmp (read_alarm_throw, 1);
1772}
1773
1774/* Only rfds are checked. */
1775int
1776select (nfds, rfds, wfds, efds, timeout)
1777 int nfds;
1778 int *rfds, *wfds, *efds, *timeout;
1779{
1780 int ravail = 0, orfds = 0, old_alarm;
1781 int timeoutval = timeout ? *timeout : 100000;
1782 int *local_timeout = &timeoutval;
1783 extern int proc_buffered_char[];
1784#ifndef subprocesses
1785 int process_tick = 0, update_tick = 0;
1786#else
1787 extern int process_tick, update_tick;
1788#endif
1789 SIGTYPE (*old_trap) ();
1790 unsigned char buf;
1791
1792 if (rfds)
1793 {
1794 orfds = *rfds;
1795 *rfds = 0;
1796 }
1797 if (wfds)
1798 *wfds = 0;
1799 if (efds)
1800 *efds = 0;
1801
1802 /* If we are looking only for the terminal, with no timeout,
1803 just read it and wait -- that's more efficient. */
1804 if (orfds == 1 && *local_timeout == 100000 && process_tick == update_tick)
1805 {
1806 if (! detect_input_pending ())
1807 read_input_waiting ();
1808 *rfds = 1;
1809 return 1;
1810 }
1811
1812 /* Once a second, till the timer expires, check all the flagged read
1813 * descriptors to see if any input is available. If there is some then
1814 * set the corresponding bit in the return copy of rfds.
1815 */
1816 while (1)
1817 {
1818 register int to_check, bit, fd;
1819
1820 if (rfds)
1821 {
1822 for (to_check = nfds, bit = 1, fd = 0; --to_check >= 0; bit <<= 1, fd++)
1823 {
1824 if (orfds & bit)
1825 {
1826 int avail = 0, status = 0;
1827
1828 if (bit == 1)
1829 avail = detect_input_pending (); /* Special keyboard handler */
1830 else
1831 {
1832#ifdef FIONREAD
1833 status = ioctl (fd, FIONREAD, &avail);
1834#else /* no FIONREAD */
1835 /* Hoping it will return -1 if nothing available
1836 or 0 if all 0 chars requested are read. */
1837 if (proc_buffered_char[fd] >= 0)
1838 avail = 1;
1839 else
1840 {
1841 avail = read (fd, &buf, 1);
1842 if (avail > 0)
1843 proc_buffered_char[fd] = buf;
1844 }
1845#endif /* no FIONREAD */
1846 }
1847 if (status >= 0 && avail > 0)
1848 {
1849 (*rfds) |= bit;
1850 ravail++;
1851 }
1852 }
1853 }
1854 }
1855 if (*local_timeout == 0 || ravail != 0 || process_tick != update_tick)
1856 break;
1857 old_alarm = alarm (0);
34567704 1858 old_trap = signal (SIGALRM, select_alarm);
86a5659e
JB
1859 select_alarmed = 0;
1860 alarm (SELECT_PAUSE);
1861 /* Wait for a SIGALRM (or maybe a SIGTINT) */
1862 while (select_alarmed == 0 && *local_timeout != 0
1863 && process_tick == update_tick)
1864 {
1865 /* If we are interested in terminal input,
1866 wait by reading the terminal.
1867 That makes instant wakeup for terminal input at least. */
1868 if (orfds & 1)
1869 {
1870 read_input_waiting ();
1871 if (detect_input_pending ())
1872 select_alarmed = 1;
1873 }
1874 else
1875 pause ();
1876 }
1877 (*local_timeout) -= SELECT_PAUSE;
1878 /* Reset the old alarm if there was one */
1879 alarm (0);
1880 signal (SIGALRM, old_trap);
1881 if (old_alarm != 0)
1882 {
1883 /* Reset or forge an interrupt for the original handler. */
1884 old_alarm -= SELECT_PAUSE;
1885 if (old_alarm <= 0)
1886 kill (getpid (), SIGALRM); /* Fake an alarm with the orig' handler */
1887 else
1888 alarm (old_alarm);
1889 }
1890 if (*local_timeout == 0) /* Stop on timer being cleared */
1891 break;
1892 }
1893 return ravail;
1894}
1895
1896/* Read keyboard input into the standard buffer,
1897 waiting for at least one character. */
1898
1899/* Make all keyboard buffers much bigger when using X windows. */
1900#ifdef HAVE_X_WINDOWS
1901#define BUFFER_SIZE_FACTOR 16
1902#else
1903#define BUFFER_SIZE_FACTOR 1
1904#endif
1905
1906read_input_waiting ()
1907{
1908 char buf[256 * BUFFER_SIZE_FACTOR];
1909 struct input_event e;
34567704
JB
1910 int nread, i;
1911 extern int quit_char;
86a5659e
JB
1912
1913 if (read_socket_hook)
1914 {
1915 read_alarm_should_throw = 0;
1916 if (! setjmp (read_alarm_throw))
1917 nread = (*read_socket_hook) (0, buf, 256 * BUFFER_SIZE_FACTOR, 1, 0);
1918 else
1919 nread = -1;
1920 }
1921 else
1922 nread = read (fileno (stdin), buf, 1);
1923
1924 /* Scan the chars for C-g and store them in kbd_buffer. */
1925 e.kind = ascii_keystroke;
6c65530f 1926 e.frame_or_window = selected_frame;
57ef1664 1927 e.modifiers = 0;
86a5659e
JB
1928 for (i = 0; i < nread; i++)
1929 {
1930 XSET (e.code, Lisp_Int, buf[i]);
1931 kbd_buffer_store_event (&e);
1932 /* Don't look at input that follows a C-g too closely.
1933 This reduces lossage due to autorepeat on C-g. */
34567704 1934 if (buf[i] == quit_char)
86a5659e
JB
1935 break;
1936 }
1937}
1938
1939#endif /* not HAVE_SELECT */
1940#endif /* not VMS */
1941\f
1942#ifdef BSD4_1
86a5659e
JB
1943/*
1944 * Partially emulate 4.2 open call.
1945 * open is defined as this in 4.1.
1946 *
1947 * - added by Michael Bloom @ Citicorp/TTI
1948 *
1949 */
1950
1951int
1952sys_open (path, oflag, mode)
1953 char *path;
1954 int oflag, mode;
1955{
1956 if (oflag & O_CREAT)
1957 return creat (path, mode);
1958 else
1959 return open (path, oflag);
1960}
1961
1962init_sigio ()
1963{
1964 if (noninteractive)
1965 return;
1966 lmode = LINTRUP | lmode;
1967 ioctl (0, TIOCLSET, &lmode);
1968}
1969
1970reset_sigio ()
1971{
1972 if (noninteractive)
1973 return;
1974 lmode = ~LINTRUP & lmode;
1975 ioctl (0, TIOCLSET, &lmode);
1976}
1977
1978request_sigio ()
1979{
1980 sigrelse (SIGTINT);
1981
1982 interrupts_deferred = 0;
1983}
1984
1985unrequest_sigio ()
1986{
1987 sighold (SIGTINT);
1988
1989 interrupts_deferred = 1;
1990}
1991
1992/* still inside #ifdef BSD4_1 */
1993#ifdef subprocesses
1994
1995int sigheld; /* Mask of held signals */
1996
1997sigholdx (signum)
1998 int signum;
1999{
2000 sigheld |= sigbit (signum);
2001 sighold (signum);
2002}
2003
2004sigisheld (signum)
2005 int signum;
2006{
2007 sigheld |= sigbit (signum);
2008}
2009
2010sigunhold (signum)
2011 int signum;
2012{
2013 sigheld &= ~sigbit (signum);
2014 sigrelse (signum);
2015}
2016
2017sigfree () /* Free all held signals */
2018{
2019 int i;
2020 for (i = 0; i < NSIG; i++)
2021 if (sigheld & sigbit (i))
2022 sigrelse (i);
2023 sigheld = 0;
2024}
2025
2026sigbit (i)
2027{
2028 return 1 << (i - 1);
2029}
2030#endif /* subprocesses */
2031#endif /* BSD4_1 */
2032\f
2033/* POSIX signals support - DJB */
2034/* Anyone with POSIX signals should have ANSI C declarations */
2035
2036#ifdef POSIX_SIGNALS
2037
2038sigset_t old_mask, empty_mask, full_mask, temp_mask;
2039static struct sigaction new_action, old_action;
2040
2041init_signals ()
2042{
2043#ifdef POSIX_SIGNALS
2044 sigemptyset (&signal_empty_mask);
2045 sigfillset (&signal_full_mask);
2046#endif
2047}
2048
2049int (*signal_handler_t) ();
2050
2051signal_handler_t
2052sys_signal (int signal_number, signal_handler_t action)
2053{
2054#ifdef DGUX
2055 /* This gets us restartable system calls for efficiency.
2056 The "else" code will works as well. */
2057 return (berk_signal (signal_number, action));
2058#else
2059 sigemptyset (&new_action.sa_mask);
2060 new_action.sa_handler = action;
2061 new_action.sa_flags = NULL;
d32b2f3c 2062 sigaction (signal_number, &new_action, &old_action);
86a5659e
JB
2063 return (old_action.sa_handler);
2064#endif /* DGUX */
2065}
2066
e065a56e
JB
2067#ifndef __GNUC__
2068/* If we're compiling with GCC, we don't need this function, since it
2069 can be written as a macro. */
2070sigset_t
2071sys_sigmask (int sig)
2072{
2073 sigset_t mask;
2074 sigemptyset (&mask);
2075 sigaddset (&mask, sig);
2076 return mask;
2077}
2078#endif
2079
86a5659e
JB
2080int
2081sys_sigpause (sigset_t new_mask)
2082{
2083 /* pause emulating berk sigpause... */
2084 sigsuspend (&new_mask);
2085 return (EINTR);
2086}
2087
2088/* I'd like to have these guys return pointers to the mask storage in here,
2089 but there'd be trouble if the code was saving multiple masks. I'll be
2090 safe and pass the structure. It normally won't be more than 2 bytes
2091 anyhow. - DJB */
2092
2093sigset_t
2094sys_sigblock (sigset_t new_mask)
2095{
2096 sigset_t old_mask;
2097 sigprocmask (SIG_BLOCK, &new_mask, &old_mask);
2098 return (old_mask);
2099}
2100
2101sigset_t
2102sys_sigunblock (sigset_t new_mask)
2103{
2104 sigset_t old_mask;
2105 sigprocmask (SIG_UNBLOCK, &new_mask, &old_mask);
2106 return (old_mask);
2107}
2108
2109sigset_t
2110sys_sigsetmask (sigset_t new_mask)
2111{
2112 sigset_t old_mask;
2113 sigprocmask (SIG_SETMASK, &new_mask, &old_mask);
2114 return (old_mask);
2115}
2116
2117#endif /* POSIX_SIGNALS */
2118\f
2119#ifndef BSTRING
2120
2121void
2122bzero (b, length)
2123 register char *b;
2124 register int length;
2125{
2126#ifdef VMS
2127 short zero = 0;
2128 long max_str = 65535;
2129
2130 while (length > max_str) {
2131 (void) LIB$MOVC5 (&zero, &zero, &zero, &max_str, b);
2132 length -= max_str;
2133 b += max_str;
2134 }
2135 max_str = length;
2136 (void) LIB$MOVC5 (&zero, &zero, &zero, &max_str, b);
2137#else
2138 while (length-- > 0)
2139 *b++ = 0;
2140#endif /* not VMS */
2141}
2142
2143/* Saying `void' requires a declaration, above, where bcopy is used
2144 and that declaration causes pain for systems where bcopy is a macro. */
2145bcopy (b1, b2, length)
2146 register char *b1;
2147 register char *b2;
2148 register int length;
2149{
2150#ifdef VMS
2151 long max_str = 65535;
2152
2153 while (length > max_str) {
2154 (void) LIB$MOVC3 (&max_str, b1, b2);
2155 length -= max_str;
2156 b1 += max_str;
2157 b2 += max_str;
2158 }
2159 max_str = length;
2160 (void) LIB$MOVC3 (&length, b1, b2);
2161#else
2162 while (length-- > 0)
2163 *b2++ = *b1++;
2164#endif /* not VMS */
2165}
2166
2167int
2168bcmp (b1, b2, length) /* This could be a macro! */
2169 register char *b1;
2170 register char *b2;
2171 register int length;
2172{
2173#ifdef VMS
2174 struct dsc$descriptor_s src1 = {length, DSC$K_DTYPE_T, DSC$K_CLASS_S, b1};
2175 struct dsc$descriptor_s src2 = {length, DSC$K_DTYPE_T, DSC$K_CLASS_S, b2};
2176
2177 return STR$COMPARE (&src1, &src2);
2178#else
2179 while (length-- > 0)
2180 if (*b1++ != *b2++)
2181 return 1;
2182
2183 return 0;
2184#endif /* not VMS */
2185}
2186#endif /* not BSTRING */
2187\f
9927a7b1 2188#ifndef HAVE_RANDOM
86a5659e
JB
2189#ifdef USG
2190/*
2191 * The BSD random returns numbers in the range of
2192 * 0 to 2e31 - 1. The USG rand returns numbers in the
2193 * range of 0 to 2e15 - 1. This is probably not significant
2194 * in this usage.
2195 */
2196
2197long
2198random ()
2199{
2200 /* Arrange to return a range centered on zero. */
2201 return (rand () << 15) + rand () - (1 << 29);
2202}
2203
2204srandom (arg)
2205 int arg;
2206{
2207 srand (arg);
2208}
2209
2210#endif /* USG */
2211
2212#ifdef BSD4_1
2213long random ()
2214{
2215 /* Arrange to return a range centered on zero. */
2216 return (rand () << 15) + rand () - (1 << 29);
2217}
2218
2219srandom (arg)
2220 int arg;
2221{
2222 srand (arg);
2223}
2224#endif /* BSD4_1 */
9927a7b1 2225#endif
86a5659e
JB
2226\f
2227#ifdef WRONG_NAME_INSQUE
2228
2229insque (q,p)
2230 caddr_t q,p;
2231{
2232 _insque (q,p);
2233}
2234
2235#endif
2236\f
2237#ifdef VMS
2238
2239#ifdef getenv
2240/* If any place else asks for the TERM variable,
2241 allow it to be overridden with the EMACS_TERM variable
2242 before attempting to translate the logical name TERM. As a last
2243 resort, ask for VAX C's special idea of the TERM variable. */
2244#undef getenv
2245char *
2246sys_getenv (name)
2247 char *name;
2248{
2249 register char *val;
2250 static char buf[256];
2251 static struct dsc$descriptor_s equiv
2252 = {sizeof (buf), DSC$K_DTYPE_T, DSC$K_CLASS_S, buf};
2253 static struct dsc$descriptor_s d_name
2254 = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
2255 short eqlen;
2256
2257 if (!strcmp (name, "TERM"))
2258 {
2259 val = (char *) getenv ("EMACS_TERM");
2260 if (val)
2261 return val;
2262 }
2263
2264 d_name.dsc$w_length = strlen (name);
2265 d_name.dsc$a_pointer = name;
986ffb24 2266 if (LIB$SYS_TRNLOG (&d_name, &eqlen, &equiv) == 1)
86a5659e
JB
2267 {
2268 char *str = (char *) xmalloc (eqlen + 1);
2269 bcopy (buf, str, eqlen);
2270 str[eqlen] = '\0';
2271 /* This is a storage leak, but a pain to fix. With luck,
2272 no one will ever notice. */
2273 return str;
2274 }
2275 return (char *) getenv (name);
2276}
2277#endif /* getenv */
2278
2279#ifdef abort
2280/* Since VMS doesn't believe in core dumps, the only way to debug this beast is
2281 to force a call on the debugger from within the image. */
2282#undef abort
2283sys_abort ()
2284{
2285 reset_sys_modes ();
2286 LIB$SIGNAL (SS$_DEBUG);
2287}
2288#endif /* abort */
2289#endif /* VMS */
2290\f
2291#ifdef VMS
2292#ifdef LINK_CRTL_SHARE
2293#ifdef SHAREABLE_LIB_BUG
2294/* Variables declared noshare and initialized in shareable libraries
2295 cannot be shared. The VMS linker incorrectly forces you to use a private
2296 version which is uninitialized... If not for this "feature", we
2297 could use the C library definition of sys_nerr and sys_errlist. */
2298int sys_nerr = 35;
2299char *sys_errlist[] =
2300 {
2301 "error 0",
2302 "not owner",
2303 "no such file or directory",
2304 "no such process",
2305 "interrupted system call",
2306 "i/o error",
2307 "no such device or address",
2308 "argument list too long",
2309 "exec format error",
2310 "bad file number",
2311 "no child process",
2312 "no more processes",
2313 "not enough memory",
2314 "permission denied",
2315 "bad address",
2316 "block device required",
2317 "mount devices busy",
2318 "file exists",
2319 "cross-device link",
2320 "no such device",
2321 "not a directory",
2322 "is a directory",
2323 "invalid argument",
2324 "file table overflow",
2325 "too many open files",
2326 "not a typewriter",
2327 "text file busy",
2328 "file too big",
2329 "no space left on device",
2330 "illegal seek",
2331 "read-only file system",
2332 "too many links",
2333 "broken pipe",
2334 "math argument",
2335 "result too large",
2336 "I/O stream empty",
2337 "vax/vms specific error code nontranslatable error"
2338 };
2339#endif /* SHAREABLE_LIB_BUG */
2340#endif /* LINK_CRTL_SHARE */
2341#endif /* VMS */
2342\f
2343#ifdef INTERRUPTIBLE_OPEN
2344
2345int
2346/* VARARGS 2 */
2347sys_open (path, oflag, mode)
2348 char *path;
2349 int oflag, mode;
2350{
2351 register int rtnval;
2352
2353 while ((rtnval = open (path, oflag, mode)) == -1
2354 && (errno == EINTR));
2355 return (rtnval);
2356}
2357
2358#endif /* INTERRUPTIBLE_OPEN */
2359
2360#ifdef INTERRUPTIBLE_CLOSE
2361
2362sys_close (fd)
2363 int fd;
2364{
2365 register int rtnval;
2366
2367 while ((rtnval = close (fd)) == -1
2368 && (errno == EINTR));
2369 return rtnval;
2370}
2371
2372#endif /* INTERRUPTIBLE_CLOSE */
2373
2374#ifdef INTERRUPTIBLE_IO
2375
2376int
2377sys_read (fildes, buf, nbyte)
2378 int fildes;
2379 char *buf;
2380 unsigned int nbyte;
2381{
2382 register int rtnval;
2383
2384 while ((rtnval = read (fildes, buf, nbyte)) == -1
2385 && (errno == EINTR));
2386 return (rtnval);
2387}
2388
2389int
2390sys_write (fildes, buf, nbyte)
2391 int fildes;
2392 char *buf;
2393 unsigned int nbyte;
2394{
2395 register int rtnval;
2396
2397 while ((rtnval = write (fildes, buf, nbyte)) == -1
2398 && (errno == EINTR));
2399 return (rtnval);
2400}
2401
2402#endif /* INTERRUPTIBLE_IO */
2403\f
2404#ifdef USG
2405/*
2406 * All of the following are for USG.
2407 *
2408 * On USG systems the system calls are INTERRUPTIBLE by signals
2409 * that the user program has elected to catch. Thus the system call
2410 * must be retried in these cases. To handle this without massive
2411 * changes in the source code, we remap the standard system call names
2412 * to names for our own functions in sysdep.c that do the system call
2413 * with retries. Actually, for portability reasons, it is good
2414 * programming practice, as this example shows, to limit all actual
2415 * system calls to a single occurance in the source. Sure, this
2416 * adds an extra level of function call overhead but it is almost
2417 * always negligible. Fred Fish, Unisoft Systems Inc.
2418 */
2419
2420char *sys_siglist[NSIG + 1] =
2421{
2422#ifdef AIX
2423/* AIX has changed the signals a bit */
2424 "bogus signal", /* 0 */
2425 "hangup", /* 1 SIGHUP */
2426 "interrupt", /* 2 SIGINT */
2427 "quit", /* 3 SIGQUIT */
2428 "illegal instruction", /* 4 SIGILL */
2429 "trace trap", /* 5 SIGTRAP */
2430 "IOT instruction", /* 6 SIGIOT */
2431 "crash likely", /* 7 SIGDANGER */
2432 "floating point exception", /* 8 SIGFPE */
2433 "kill", /* 9 SIGKILL */
2434 "bus error", /* 10 SIGBUS */
2435 "segmentation violation", /* 11 SIGSEGV */
2436 "bad argument to system call", /* 12 SIGSYS */
2437 "write on a pipe with no one to read it", /* 13 SIGPIPE */
2438 "alarm clock", /* 14 SIGALRM */
2439 "software termination signum", /* 15 SIGTERM */
2440 "user defined signal 1", /* 16 SIGUSR1 */
2441 "user defined signal 2", /* 17 SIGUSR2 */
2442 "death of a child", /* 18 SIGCLD */
2443 "power-fail restart", /* 19 SIGPWR */
2444 "bogus signal", /* 20 */
2445 "bogus signal", /* 21 */
2446 "bogus signal", /* 22 */
2447 "bogus signal", /* 23 */
2448 "bogus signal", /* 24 */
2449 "LAN I/O interrupt", /* 25 SIGAIO */
2450 "PTY I/O interrupt", /* 26 SIGPTY */
2451 "I/O intervention required", /* 27 SIGIOINT */
2452 "HFT grant", /* 28 SIGGRANT */
2453 "HFT retract", /* 29 SIGRETRACT */
2454 "HFT sound done", /* 30 SIGSOUND */
2455 "HFT input ready", /* 31 SIGMSG */
2456#else /* not AIX */
2457 "bogus signal", /* 0 */
2458 "hangup", /* 1 SIGHUP */
2459 "interrupt", /* 2 SIGINT */
2460 "quit", /* 3 SIGQUIT */
2461 "illegal instruction", /* 4 SIGILL */
2462 "trace trap", /* 5 SIGTRAP */
2463 "IOT instruction", /* 6 SIGIOT */
2464 "EMT instruction", /* 7 SIGEMT */
2465 "floating point exception", /* 8 SIGFPE */
2466 "kill", /* 9 SIGKILL */
2467 "bus error", /* 10 SIGBUS */
2468 "segmentation violation", /* 11 SIGSEGV */
2469 "bad argument to system call", /* 12 SIGSYS */
2470 "write on a pipe with no one to read it", /* 13 SIGPIPE */
2471 "alarm clock", /* 14 SIGALRM */
2472 "software termination signum", /* 15 SIGTERM */
2473 "user defined signal 1", /* 16 SIGUSR1 */
2474 "user defined signal 2", /* 17 SIGUSR2 */
2475 "death of a child", /* 18 SIGCLD */
2476 "power-fail restart", /* 19 SIGPWR */
2477#endif /* not AIX */
2478 0
2479 };
2480
2481/*
2482 * Warning, this function may not duplicate 4.2 action properly
2483 * under error conditions.
2484 */
2485
2486#ifndef MAXPATHLEN
2487/* In 4.1, param.h fails to define this. */
2488#define MAXPATHLEN 1024
2489#endif
2490
2491#ifndef HAVE_GETWD
2492
2493char *
2494getwd (pathname)
2495 char *pathname;
2496{
2497 char *npath, *spath;
2498 extern char *getcwd ();
2499
9ac0d9e0 2500 BLOCK_INPUT; /* getcwd uses malloc */
86a5659e
JB
2501 spath = npath = getcwd ((char *) 0, MAXPATHLEN);
2502 /* On Altos 3068, getcwd can return @hostname/dir, so discard
2503 up to first slash. Should be harmless on other systems. */
2504 while (*npath && *npath != '/')
2505 npath++;
2506 strcpy (pathname, npath);
2507 free (spath); /* getcwd uses malloc */
9ac0d9e0 2508 UNBLOCK_INPUT;
86a5659e
JB
2509 return pathname;
2510}
2511
2512#endif /* HAVE_GETWD */
2513
2514/*
2515 * Emulate rename using unlink/link. Note that this is
2516 * only partially correct. Also, doesn't enforce restriction
2517 * that files be of same type (regular->regular, dir->dir, etc).
2518 */
2519
4746118a
JB
2520#ifndef HAVE_RENAME
2521
86a5659e
JB
2522rename (from, to)
2523 char *from;
2524 char *to;
2525{
2526 if (access (from, 0) == 0)
2527 {
2528 unlink (to);
2529 if (link (from, to) == 0)
2530 if (unlink (from) == 0)
2531 return (0);
2532 }
2533 return (-1);
2534}
2535
4746118a
JB
2536#endif
2537
86a5659e
JB
2538#ifndef HAVE_VFORK
2539
2540/*
2541 * Substitute fork for vfork on USG flavors.
2542 */
2543
2544vfork ()
2545{
2546 return (fork ());
2547}
2548
2549#endif /* not HAVE_VFORK */
2550
2551#ifdef MISSING_UTIMES
2552
2553/* HPUX (among others) sets HAVE_TIMEVAL but does not implement utimes. */
2554
2555utimes ()
2556{
2557}
2558#endif
2559
2560#ifdef IRIS_UTIME
2561
2562/* The IRIS (3.5) has timevals, but uses sys V utime, and doesn't have the
2563 utimbuf structure defined anywhere but in the man page. */
2564
2565struct utimbuf
2566 {
2567 long actime;
2568 long modtime;
2569 };
2570
2571utimes (name, tvp)
2572 char *name;
2573 struct timeval tvp[];
2574{
2575 struct utimbuf utb;
2576 utb.actime = tvp[0].tv_sec;
2577 utb.modtime = tvp[1].tv_sec;
2578 utime (name, &utb);
2579}
2580#endif /* IRIS_UTIME */
2581
2582
2583#ifdef HPUX
2584#ifndef HAVE_PERROR
2585
2586/* HPUX curses library references perror, but as far as we know
2587 it won't be called. Anyway this definition will do for now. */
2588
2589perror ()
2590{
2591}
2592
2593#endif /* not HAVE_PERROR */
2594#endif /* HPUX */
2595
2596#ifndef HAVE_DUP2
2597
2598/*
2599 * Emulate BSD dup2. First close newd if it already exists.
2600 * Then, attempt to dup oldd. If not successful, call dup2 recursively
2601 * until we are, then close the unsuccessful ones.
2602 */
2603
2604dup2 (oldd, newd)
2605 int oldd;
2606 int newd;
2607{
2608 register int fd, ret;
2609
2610 sys_close (newd);
2611
2612#ifdef F_DUPFD
2613 fd = fcntl (oldd, F_DUPFD, newd);
2614 if (fd != newd)
2615 error ("can't dup2 (%i,%i) : %s", oldd, newd, sys_errlist[errno]);
2616#else
2617 fd = dup (old);
2618 if (fd == -1)
2619 return -1;
2620 if (fd == new)
2621 return new;
2622 ret = dup2 (old,new);
2623 sys_close (fd);
2624 return ret;
2625#endif
2626}
2627
2628#endif /* not HAVE_DUP2 */
2629
2630/*
2631 * Gettimeofday. Simulate as much as possible. Only accurate
2632 * to nearest second. Emacs doesn't use tzp so ignore it for now.
2633 * Only needed when subprocesses are defined.
2634 */
2635
2636#ifdef subprocesses
2637#ifndef VMS
2638#ifndef HAVE_GETTIMEOFDAY
2639#ifdef HAVE_TIMEVAL
2640
2641/* ARGSUSED */
2642gettimeofday (tp, tzp)
2643 struct timeval *tp;
2644 struct timezone *tzp;
2645{
2646 extern long time ();
2647
2648 tp->tv_sec = time ((long *)0);
2649 tp->tv_usec = 0;
2650 tzp->tz_minuteswest = -1;
2651}
2652
2653#endif
2654#endif
2655#endif
2656#endif /* subprocess && !HAVE_GETTIMEOFDAY && HAVE_TIMEVAL && !VMS */
2657
2658/*
2659 * This function will go away as soon as all the stubs fixed. (fnf)
2660 */
2661
2662croak (badfunc)
2663 char *badfunc;
2664{
2665 printf ("%s not yet implemented\r\n", badfunc);
2666 reset_sys_modes ();
2667 exit (1);
2668}
2669
2670#endif /* USG */
2671\f
2672#ifdef DGUX
2673
2674char *sys_siglist[NSIG + 1] =
2675{
2676 "null signal", /* 0 SIGNULL */
2677 "hangup", /* 1 SIGHUP */
2678 "interrupt", /* 2 SIGINT */
2679 "quit", /* 3 SIGQUIT */
2680 "illegal instruction", /* 4 SIGILL */
2681 "trace trap", /* 5 SIGTRAP */
2682 "abort termination", /* 6 SIGABRT */
2683 "SIGEMT", /* 7 SIGEMT */
2684 "floating point exception", /* 8 SIGFPE */
2685 "kill", /* 9 SIGKILL */
2686 "bus error", /* 10 SIGBUS */
2687 "segmentation violation", /* 11 SIGSEGV */
2688 "bad argument to system call", /* 12 SIGSYS */
2689 "write on a pipe with no reader", /* 13 SIGPIPE */
2690 "alarm clock", /* 14 SIGALRM */
2691 "software termination signal", /* 15 SIGTERM */
2692 "user defined signal 1", /* 16 SIGUSR1 */
2693 "user defined signal 2", /* 17 SIGUSR2 */
2694 "child stopped or terminated", /* 18 SIGCLD */
2695 "power-fail restart", /* 19 SIGPWR */
2696 "window size changed", /* 20 SIGWINCH */
2697 "undefined", /* 21 */
2698 "pollable event occured", /* 22 SIGPOLL */
2699 "sendable stop signal not from tty", /* 23 SIGSTOP */
2700 "stop signal from tty", /* 24 SIGSTP */
2701 "continue a stopped process", /* 25 SIGCONT */
2702 "attempted background tty read", /* 26 SIGTTIN */
2703 "attempted background tty write", /* 27 SIGTTOU */
2704 "undefined", /* 28 */
2705 "undefined", /* 29 */
2706 "undefined", /* 30 */
2707 "undefined", /* 31 */
2708 "undefined", /* 32 */
2709 "socket (TCP/IP) urgent data arrival", /* 33 SIGURG */
2710 "I/O is possible", /* 34 SIGIO */
2711 "exceeded cpu time limit", /* 35 SIGXCPU */
2712 "exceeded file size limit", /* 36 SIGXFSZ */
2713 "virtual time alarm", /* 37 SIGVTALRM */
2714 "profiling time alarm", /* 38 SIGPROF */
2715 "undefined", /* 39 */
2716 "file record locks revoked", /* 40 SIGLOST */
2717 "undefined", /* 41 */
2718 "undefined", /* 42 */
2719 "undefined", /* 43 */
2720 "undefined", /* 44 */
2721 "undefined", /* 45 */
2722 "undefined", /* 46 */
2723 "undefined", /* 47 */
2724 "undefined", /* 48 */
2725 "undefined", /* 49 */
2726 "undefined", /* 50 */
2727 "undefined", /* 51 */
2728 "undefined", /* 52 */
2729 "undefined", /* 53 */
2730 "undefined", /* 54 */
2731 "undefined", /* 55 */
2732 "undefined", /* 56 */
2733 "undefined", /* 57 */
2734 "undefined", /* 58 */
2735 "undefined", /* 59 */
2736 "undefined", /* 60 */
2737 "undefined", /* 61 */
2738 "undefined", /* 62 */
2739 "undefined", /* 63 */
2740 "notification message in mess. queue", /* 64 SIGDGNOTIFY */
2741 0
2742};
2743
2744#endif /* DGUX */
2745\f
2746/* Directory routines for systems that don't have them. */
2747
2748#ifdef SYSV_SYSTEM_DIR
2749
2750#include <dirent.h>
2751
2752#ifndef AIX
2753int
2754closedir (dirp)
2755 register DIR *dirp; /* stream from opendir */
2756{
2757 sys_close (dirp->dd_fd);
9ac0d9e0
JB
2758 xfree ((char *) dirp->dd_buf); /* directory block defined in <dirent.h> */
2759 xfree ((char *) dirp);
86a5659e
JB
2760}
2761#endif /* not AIX */
2762#endif /* SYSV_SYSTEM_DIR */
2763
2764#ifdef NONSYSTEM_DIR_LIBRARY
2765
2766DIR *
2767opendir (filename)
2768 char *filename; /* name of directory */
2769{
2770 register DIR *dirp; /* -> malloc'ed storage */
2771 register int fd; /* file descriptor for read */
2772 struct stat sbuf; /* result of fstat */
2773
2774 fd = sys_open (filename, 0);
2775 if (fd < 0)
2776 return 0;
2777
9ac0d9e0 2778 BLOCK_INPUT;
86a5659e
JB
2779 if (fstat (fd, &sbuf) < 0
2780 || (sbuf.st_mode & S_IFMT) != S_IFDIR
2781 || (dirp = (DIR *) malloc (sizeof (DIR))) == 0)
2782 {
2783 sys_close (fd);
9ac0d9e0 2784 UNBLOCK_INPUT;
86a5659e
JB
2785 return 0; /* bad luck today */
2786 }
9ac0d9e0 2787 UNBLOCK_INPUT;
86a5659e
JB
2788
2789 dirp->dd_fd = fd;
2790 dirp->dd_loc = dirp->dd_size = 0; /* refill needed */
2791
2792 return dirp;
2793}
2794
2795void
2796closedir (dirp)
2797 register DIR *dirp; /* stream from opendir */
2798{
2799 sys_close (dirp->dd_fd);
9ac0d9e0 2800 xfree ((char *) dirp);
86a5659e
JB
2801}
2802
2803
2804#ifndef VMS
2805#define DIRSIZ 14
2806struct olddir
2807 {
2808 ino_t od_ino; /* inode */
2809 char od_name[DIRSIZ]; /* filename */
2810 };
2811#endif /* not VMS */
2812
2813struct direct dir_static; /* simulated directory contents */
2814
2815/* ARGUSED */
2816struct direct *
2817readdir (dirp)
2818 register DIR *dirp; /* stream from opendir */
2819{
2820#ifndef VMS
2821 register struct olddir *dp; /* -> directory data */
2822#else /* VMS */
2823 register struct dir$_name *dp; /* -> directory data */
2824 register struct dir$_version *dv; /* -> version data */
2825#endif /* VMS */
2826
2827 for (; ;)
2828 {
2829 if (dirp->dd_loc >= dirp->dd_size)
2830 dirp->dd_loc = dirp->dd_size = 0;
2831
2832 if (dirp->dd_size == 0 /* refill buffer */
2833 && (dirp->dd_size = sys_read (dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ)) <= 0)
2834 return 0;
2835
2836#ifndef VMS
2837 dp = (struct olddir *) &dirp->dd_buf[dirp->dd_loc];
2838 dirp->dd_loc += sizeof (struct olddir);
2839
2840 if (dp->od_ino != 0) /* not deleted entry */
2841 {
2842 dir_static.d_ino = dp->od_ino;
2843 strncpy (dir_static.d_name, dp->od_name, DIRSIZ);
2844 dir_static.d_name[DIRSIZ] = '\0';
2845 dir_static.d_namlen = strlen (dir_static.d_name);
2846 dir_static.d_reclen = sizeof (struct direct)
2847 - MAXNAMLEN + 3
2848 + dir_static.d_namlen - dir_static.d_namlen % 4;
2849 return &dir_static; /* -> simulated structure */
2850 }
2851#else /* VMS */
2852 dp = (struct dir$_name *) dirp->dd_buf;
2853 if (dirp->dd_loc == 0)
2854 dirp->dd_loc = (dp->dir$b_namecount&1) ? dp->dir$b_namecount + 1
2855 : dp->dir$b_namecount;
2856 dv = (struct dir$_version *)&dp->dir$t_name[dirp->dd_loc];
2857 dir_static.d_ino = dv->dir$w_fid_num;
2858 dir_static.d_namlen = dp->dir$b_namecount;
2859 dir_static.d_reclen = sizeof (struct direct)
2860 - MAXNAMLEN + 3
2861 + dir_static.d_namlen - dir_static.d_namlen % 4;
2862 strncpy (dir_static.d_name, dp->dir$t_name, dp->dir$b_namecount);
2863 dir_static.d_name[dir_static.d_namlen] = '\0';
2864 dirp->dd_loc = dirp->dd_size; /* only one record at a time */
2865 return &dir_static;
2866#endif /* VMS */
2867 }
2868}
2869
2870#ifdef VMS
2871/* readdirver is just like readdir except it returns all versions of a file
2872 as separate entries. */
2873
2874/* ARGUSED */
2875struct direct *
2876readdirver (dirp)
2877 register DIR *dirp; /* stream from opendir */
2878{
2879 register struct dir$_name *dp; /* -> directory data */
2880 register struct dir$_version *dv; /* -> version data */
2881
2882 if (dirp->dd_loc >= dirp->dd_size - sizeof (struct dir$_name))
2883 dirp->dd_loc = dirp->dd_size = 0;
2884
2885 if (dirp->dd_size == 0 /* refill buffer */
2886 && (dirp->dd_size = sys_read (dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ)) <= 0)
2887 return 0;
2888
2889 dp = (struct dir$_name *) dirp->dd_buf;
2890 if (dirp->dd_loc == 0)
2891 dirp->dd_loc = (dp->dir$b_namecount & 1) ? dp->dir$b_namecount + 1
2892 : dp->dir$b_namecount;
2893 dv = (struct dir$_version *) &dp->dir$t_name[dirp->dd_loc];
2894 strncpy (dir_static.d_name, dp->dir$t_name, dp->dir$b_namecount);
2895 sprintf (&dir_static.d_name[dp->dir$b_namecount], ";%d", dv->dir$w_version);
2896 dir_static.d_namlen = strlen (dir_static.d_name);
2897 dir_static.d_ino = dv->dir$w_fid_num;
2898 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3
2899 + dir_static.d_namlen - dir_static.d_namlen % 4;
2900 dirp->dd_loc = ((char *) (++dv) - dp->dir$t_name);
2901 return &dir_static;
2902}
2903
2904#endif /* VMS */
2905
2906#endif /* NONSYSTEM_DIR_LIBRARY */
2907\f
2908/* Functions for VMS */
2909#ifdef VMS
91bac16a 2910#include "vms-pwd.h"
86a5659e
JB
2911#include <acldef.h>
2912#include <chpdef.h>
2913#include <jpidef.h>
2914
2915/* Return as a string the VMS error string pertaining to STATUS.
2916 Reuses the same static buffer each time it is called. */
2917
2918char *
2919vmserrstr (status)
2920 int status; /* VMS status code */
2921{
2922 int bufadr[2];
2923 short len;
2924 static char buf[257];
2925
2926 bufadr[0] = sizeof buf - 1;
2927 bufadr[1] = (int) buf;
2928 if (! (SYS$GETMSG (status, &len, bufadr, 0x1, 0) & 1))
2929 return "untranslatable VMS error status";
2930 buf[len] = '\0';
2931 return buf;
2932}
2933
2934#ifdef access
2935#undef access
2936
2937/* The following is necessary because 'access' emulation by VMS C (2.0) does
2938 * not work correctly. (It also doesn't work well in version 2.3.)
2939 */
2940
2941#ifdef VMS4_4
2942
2943#define DESCRIPTOR(name,string) struct dsc$descriptor_s name = \
2944 { strlen (string), DSC$K_DTYPE_T, DSC$K_CLASS_S, string }
2945
2946typedef union {
2947 struct {
2948 unsigned short s_buflen;
2949 unsigned short s_code;
2950 char *s_bufadr;
2951 unsigned short *s_retlenadr;
2952 } s;
2953 int end;
2954} item;
2955#define buflen s.s_buflen
2956#define code s.s_code
2957#define bufadr s.s_bufadr
2958#define retlenadr s.s_retlenadr
2959
2960#define R_OK 4 /* test for read permission */
2961#define W_OK 2 /* test for write permission */
2962#define X_OK 1 /* test for execute (search) permission */
2963#define F_OK 0 /* test for presence of file */
2964
2965int
2966sys_access (path, mode)
2967 char *path;
2968 int mode;
2969{
2970 static char *user = NULL;
2971 char dir_fn[512];
2972
2973 /* translate possible directory spec into .DIR file name, so brain-dead
2974 * access can treat the directory like a file. */
2975 if (directory_file_name (path, dir_fn))
2976 path = dir_fn;
2977
2978 if (mode == F_OK)
2979 return access (path, mode);
2980 if (user == NULL && (user = (char *) getenv ("USER")) == NULL)
2981 return -1;
2982 {
2983 int stat;
2984 int flags;
2985 int acces;
2986 unsigned short int dummy;
2987 item itemlst[3];
2988 static int constant = ACL$C_FILE;
2989 DESCRIPTOR (path_desc, path);
2990 DESCRIPTOR (user_desc, user);
2991
2992 flags = 0;
2993 acces = 0;
2994 if ((mode & X_OK) && ((stat = access (path, mode)) < 0 || mode == X_OK))
2995 return stat;
2996 if (mode & R_OK)
2997 acces |= CHP$M_READ;
2998 if (mode & W_OK)
2999 acces |= CHP$M_WRITE;
3000 itemlst[0].buflen = sizeof (int);
3001 itemlst[0].code = CHP$_FLAGS;
3002 itemlst[0].bufadr = (char *) &flags;
3003 itemlst[0].retlenadr = &dummy;
3004 itemlst[1].buflen = sizeof (int);
3005 itemlst[1].code = CHP$_ACCESS;
3006 itemlst[1].bufadr = (char *) &acces;
3007 itemlst[1].retlenadr = &dummy;
3008 itemlst[2].end = CHP$_END;
3009 stat = SYS$CHECK_ACCESS (&constant, &path_desc, &user_desc, itemlst);
3010 return stat == SS$_NORMAL ? 0 : -1;
3011 }
3012}
3013
3014#else /* not VMS4_4 */
3015
3016#include <prvdef.h>
3017#define ACE$M_WRITE 2
3018#define ACE$C_KEYID 1
3019
3020static unsigned short memid, grpid;
3021static unsigned int uic;
3022
3023/* Called from init_sys_modes, so it happens not very often
3024 but at least each time Emacs is loaded. */
3025sys_access_reinit ()
3026{
3027 uic = 0;
3028}
3029
3030int
3031sys_access (filename, type)
3032 char * filename;
3033 int type;
3034{
3035 struct FAB fab;
3036 struct XABPRO xab;
3037 int status, size, i, typecode, acl_controlled;
3038 unsigned int *aclptr, *aclend, aclbuf[60];
3039 union prvdef prvmask;
3040
3041 /* Get UIC and GRP values for protection checking. */
3042 if (uic == 0)
3043 {
3044 status = LIB$GETJPI (&JPI$_UIC, 0, 0, &uic, 0, 0);
3045 if (! (status & 1))
3046 return -1;
3047 memid = uic & 0xFFFF;
3048 grpid = uic >> 16;
3049 }
3050
3051 if (type != 2) /* not checking write access */
3052 return access (filename, type);
3053
3054 /* Check write protection. */
3055
3056#define CHECKPRIV(bit) (prvmask.bit)
3057#define WRITEABLE(field) (! ((xab.xab$w_pro >> field) & XAB$M_NOWRITE))
3058
3059 /* Find privilege bits */
986ffb24 3060 status = SYS$SETPRV (0, 0, 0, prvmask);
86a5659e
JB
3061 if (! (status & 1))
3062 error ("Unable to find privileges: %s", vmserrstr (status));
3063 if (CHECKPRIV (PRV$V_BYPASS))
3064 return 0; /* BYPASS enabled */
3065 fab = cc$rms_fab;
3066 fab.fab$b_fac = FAB$M_GET;
3067 fab.fab$l_fna = filename;
3068 fab.fab$b_fns = strlen (filename);
3069 fab.fab$l_xab = &xab;
3070 xab = cc$rms_xabpro;
3071 xab.xab$l_aclbuf = aclbuf;
3072 xab.xab$w_aclsiz = sizeof (aclbuf);
986ffb24 3073 status = SYS$OPEN (&fab, 0, 0);
86a5659e
JB
3074 if (! (status & 1))
3075 return -1;
986ffb24 3076 SYS$CLOSE (&fab, 0, 0);
86a5659e
JB
3077 /* Check system access */
3078 if (CHECKPRIV (PRV$V_SYSPRV) && WRITEABLE (XAB$V_SYS))
3079 return 0;
3080 /* Check ACL entries, if any */
3081 acl_controlled = 0;
3082 if (xab.xab$w_acllen > 0)
3083 {
3084 aclptr = aclbuf;
3085 aclend = &aclbuf[xab.xab$w_acllen / 4];
3086 while (*aclptr && aclptr < aclend)
3087 {
3088 size = (*aclptr & 0xff) / 4;
3089 typecode = (*aclptr >> 8) & 0xff;
3090 if (typecode == ACE$C_KEYID)
3091 for (i = size - 1; i > 1; i--)
3092 if (aclptr[i] == uic)
3093 {
3094 acl_controlled = 1;
3095 if (aclptr[1] & ACE$M_WRITE)
3096 return 0; /* Write access through ACL */
3097 }
3098 aclptr = &aclptr[size];
3099 }
3100 if (acl_controlled) /* ACL specified, prohibits write access */
3101 return -1;
3102 }
3103 /* No ACL entries specified, check normal protection */
3104 if (WRITEABLE (XAB$V_WLD)) /* World writeable */
3105 return 0;
3106 if (WRITEABLE (XAB$V_GRP) &&
3107 (unsigned short) (xab.xab$l_uic >> 16) == grpid)
3108 return 0; /* Group writeable */
3109 if (WRITEABLE (XAB$V_OWN) &&
3110 (xab.xab$l_uic & 0xFFFF) == memid)
3111 return 0; /* Owner writeable */
3112
3113 return -1; /* Not writeable */
3114}
3115#endif /* not VMS4_4 */
3116#endif /* access */
3117
3118static char vtbuf[NAM$C_MAXRSS+1];
3119
3120/* translate a vms file spec to a unix path */
3121char *
3122sys_translate_vms (vfile)
3123 char * vfile;
3124{
3125 char * p;
3126 char * targ;
3127
3128 if (!vfile)
3129 return 0;
3130
3131 targ = vtbuf;
3132
3133 /* leading device or logical name is a root directory */
3134 if (p = strchr (vfile, ':'))
3135 {
3136 *targ++ = '/';
3137 while (vfile < p)
3138 *targ++ = *vfile++;
3139 vfile++;
3140 *targ++ = '/';
3141 }
3142 p = vfile;
3143 if (*p == '[' || *p == '<')
3144 {
3145 while (*++vfile != *p + 2)
3146 switch (*vfile)
3147 {
3148 case '.':
3149 if (vfile[-1] == *p)
3150 *targ++ = '.';
3151 *targ++ = '/';
3152 break;
3153
3154 case '-':
3155 *targ++ = '.';
3156 *targ++ = '.';
3157 break;
3158
3159 default:
3160 *targ++ = *vfile;
3161 break;
3162 }
3163 vfile++;
3164 *targ++ = '/';
3165 }
3166 while (*vfile)
3167 *targ++ = *vfile++;
3168
3169 return vtbuf;
3170}
3171
3172static char utbuf[NAM$C_MAXRSS+1];
3173
3174/* translate a unix path to a VMS file spec */
3175char *
3176sys_translate_unix (ufile)
3177 char * ufile;
3178{
3179 int slash_seen = 0;
3180 char *p;
3181 char * targ;
3182
3183 if (!ufile)
3184 return 0;
3185
3186 targ = utbuf;
3187
3188 if (*ufile == '/')
3189 {
3190 ufile++;
3191 }
3192
3193 while (*ufile)
3194 {
3195 switch (*ufile)
3196 {
3197 case '/':
3198 if (slash_seen)
3199 if (index (&ufile[1], '/'))
3200 *targ++ = '.';
3201 else
3202 *targ++ = ']';
3203 else
3204 {
3205 *targ++ = ':';
3206 if (index (&ufile[1], '/'))
3207 *targ++ = '[';
3208 slash_seen = 1;
3209 }
3210 break;
3211
3212 case '.':
3213 if (strncmp (ufile, "./", 2) == 0)
3214 {
3215 if (!slash_seen)
3216 {
3217 *targ++ = '[';
3218 slash_seen = 1;
3219 }
3220 ufile++; /* skip the dot */
3221 if (index (&ufile[1], '/'))
3222 *targ++ = '.';
3223 else
3224 *targ++ = ']';
3225 }
3226 else if (strncmp (ufile, "../", 3) == 0)
3227 {
3228 if (!slash_seen)
3229 {
3230 *targ++ = '[';
3231 slash_seen = 1;
3232 }
3233 *targ++ = '-';
3234 ufile += 2; /* skip the dots */
3235 if (index (&ufile[1], '/'))
3236 *targ++ = '.';
3237 else
3238 *targ++ = ']';
3239 }
3240 else
3241 *targ++ = *ufile;
3242 break;
3243
3244 default:
3245 *targ++ = *ufile;
3246 break;
3247 }
3248 ufile++;
3249 }
3250 *targ = '\0';
3251
3252 return utbuf;
3253}
3254
3255char *
3256getwd (pathname)
3257 char *pathname;
3258{
3259 char *ptr;
210b2b4f 3260 extern char *getcwd ();
86a5659e 3261
210b2b4f
JB
3262#define MAXPATHLEN 1024
3263
9ac0d9e0 3264 ptr = xmalloc (MAXPATHLEN);
210b2b4f
JB
3265 getcwd (ptr, MAXPATHLEN);
3266 strcpy (pathname, ptr);
9ac0d9e0 3267 xfree (ptr);
210b2b4f
JB
3268
3269 return pathname;
86a5659e
JB
3270}
3271
3272getppid ()
3273{
3274 long item_code = JPI$_OWNER;
3275 unsigned long parent_id;
3276 int status;
3277
3278 if (((status = LIB$GETJPI (&item_code, 0, 0, &parent_id)) & 1) == 0)
3279 {
3280 errno = EVMSERR;
3281 vaxc$errno = status;
3282 return -1;
3283 }
3284 return parent_id;
3285}
3286
3287#undef getuid
3288unsigned
3289sys_getuid ()
3290{
3291 return (getgid () << 16) | getuid ();
3292}
3293
3294int
3295sys_read (fildes, buf, nbyte)
3296 int fildes;
3297 char *buf;
3298 unsigned int nbyte;
3299{
3300 return read (fildes, buf, (nbyte < MAXIOSIZE ? nbyte : MAXIOSIZE));
3301}
3302
3303#if 0
3304int
3305sys_write (fildes, buf, nbyte)
3306 int fildes;
3307 char *buf;
3308 unsigned int nbyte;
3309{
3310 register int nwrote, rtnval = 0;
3311
3312 while (nbyte > MAXIOSIZE && (nwrote = write (fildes, buf, MAXIOSIZE)) > 0) {
3313 nbyte -= nwrote;
3314 buf += nwrote;
3315 rtnval += nwrote;
3316 }
3317 if (nwrote < 0)
3318 return rtnval ? rtnval : -1;
3319 if ((nwrote = write (fildes, buf, nbyte)) < 0)
3320 return rtnval ? rtnval : -1;
3321 return (rtnval + nwrote);
3322}
3323#endif /* 0 */
3324
3325/*
3326 * VAX/VMS VAX C RTL really loses. It insists that records
3327 * end with a newline (carriage return) character, and if they
3328 * don't it adds one (nice of it isn't it!)
3329 *
3330 * Thus we do this stupidity below.
3331 */
3332
3333int
3334sys_write (fildes, buf, nbytes)
3335 int fildes;
3336 char *buf;
3337 unsigned int nbytes;
3338{
3339 register char *p;
3340 register char *e;
23b0668c
JB
3341 int sum = 0;
3342 struct stat st;
3343
3344 fstat (fildes, &st);
86a5659e 3345 p = buf;
86a5659e
JB
3346 while (nbytes > 0)
3347 {
23b0668c
JB
3348 int len, retval;
3349
3350 /* Handle fixed-length files with carriage control. */
3351 if (st.st_fab_rfm == FAB$C_FIX
3352 && ((st.st_fab_rat & (FAB$M_FTN | FAB$M_CR)) != 0))
3353 {
3354 len = st.st_fab_mrs;
3355 retval = write (fildes, p, min (len, nbytes));
3356 if (retval != len)
3357 return -1;
3358 retval++; /* This skips the implied carriage control */
3359 }
3360 else
3361 {
3362 e = p + min (MAXIOSIZE, nbytes) - 1;
3363 while (*e != '\n' && e > p) e--;
3364 if (p == e) /* Ok.. so here we add a newline... sigh. */
3365 e = p + min (MAXIOSIZE, nbytes) - 1;
3366 len = e + 1 - p;
3367 retval = write (fildes, p, len);
3368 if (retval != len)
3369 return -1;
3370 }
3371 p += retval;
3372 sum += retval;
86a5659e
JB
3373 nbytes -= retval;
3374 }
3375 return sum;
3376}
3377
3378/* Create file NEW copying its attributes from file OLD. If
3379 OLD is 0 or does not exist, create based on the value of
3380 vms_stmlf_recfm. */
3381
3382/* Protection value the file should ultimately have.
3383 Set by create_copy_attrs, and use by rename_sansversions. */
3384static unsigned short int fab_final_pro;
3385
3386int
3387creat_copy_attrs (old, new)
3388 char *old, *new;
3389{
3390 struct FAB fab = cc$rms_fab;
3391 struct XABPRO xabpro;
3392 char aclbuf[256]; /* Choice of size is arbitrary. See below. */
3393 extern int vms_stmlf_recfm;
3394
3395 if (old)
3396 {
3397 fab.fab$b_fac = FAB$M_GET;
3398 fab.fab$l_fna = old;
3399 fab.fab$b_fns = strlen (old);
3400 fab.fab$l_xab = (char *) &xabpro;
3401 xabpro = cc$rms_xabpro;
3402 xabpro.xab$l_aclbuf = aclbuf;
3403 xabpro.xab$w_aclsiz = sizeof aclbuf;
3404 /* Call $OPEN to fill in the fab & xabpro fields. */
986ffb24 3405 if (SYS$OPEN (&fab, 0, 0) & 1)
86a5659e 3406 {
986ffb24 3407 SYS$CLOSE (&fab, 0, 0);
86a5659e
JB
3408 fab.fab$l_alq = 0; /* zero the allocation quantity */
3409 if (xabpro.xab$w_acllen > 0)
3410 {
3411 if (xabpro.xab$w_acllen > sizeof aclbuf)
3412 /* If the acl buffer was too short, redo open with longer one.
3413 Wouldn't need to do this if there were some system imposed
3414 limit on the size of an ACL, but I can't find any such. */
3415 {
3416 xabpro.xab$l_aclbuf = (char *) alloca (xabpro.xab$w_acllen);
3417 xabpro.xab$w_aclsiz = xabpro.xab$w_acllen;
986ffb24
JB
3418 if (SYS$OPEN (&fab, 0, 0) & 1)
3419 SYS$CLOSE (&fab, 0, 0);
86a5659e
JB
3420 else
3421 old = 0;
3422 }
3423 }
3424 else
3425 xabpro.xab$l_aclbuf = 0;
3426 }
3427 else
3428 old = 0;
3429 }
3430 fab.fab$l_fna = new;
3431 fab.fab$b_fns = strlen (new);
3432 if (!old)
3433 {
3434 fab.fab$l_xab = 0;
3435 fab.fab$b_rfm = vms_stmlf_recfm ? FAB$C_STMLF : FAB$C_VAR;
3436 fab.fab$b_rat = FAB$M_CR;
3437 }
3438
3439 /* Set the file protections such that we will be able to manipulate
3440 this file. Once we are done writing and renaming it, we will set
3441 the protections back. */
3442 if (old)
3443 fab_final_pro = xabpro.xab$w_pro;
3444 else
986ffb24 3445 SYS$SETDFPROT (0, &fab_final_pro);
86a5659e
JB
3446 xabpro.xab$w_pro &= 0xff0f; /* set O:rewd for now. This is set back later. */
3447
3448 /* Create the new file with either default attrs or attrs copied
3449 from old file. */
3450 if (!(SYS$CREATE (&fab, 0, 0) & 1))
3451 return -1;
986ffb24 3452 SYS$CLOSE (&fab, 0, 0);
86a5659e
JB
3453 /* As this is a "replacement" for creat, return a file descriptor
3454 opened for writing. */
3455 return open (new, O_WRONLY);
3456}
3457
3458#ifdef creat
3459#undef creat
3460#include <varargs.h>
3461#ifdef __GNUC__
3462#ifndef va_count
3463#define va_count(X) ((X) = *(((int *) &(va_alist)) - 1))
3464#endif
3465#endif
3466
3467sys_creat (va_alist)
3468 va_dcl
3469{
3470 va_list list_incrementor;
3471 char *name;
3472 int mode;
3473 int rfd; /* related file descriptor */
3474 int fd; /* Our new file descriptor */
3475 int count;
3476 struct stat st_buf;
3477 char rfm[12];
3478 char rat[15];
3479 char mrs[13];
3480 char fsz[13];
3481 extern int vms_stmlf_recfm;
3482
3483 va_count (count);
3484 va_start (list_incrementor);
3485 name = va_arg (list_incrementor, char *);
3486 mode = va_arg (list_incrementor, int);
3487 if (count > 2)
3488 rfd = va_arg (list_incrementor, int);
3489 va_end (list_incrementor);
3490 if (count > 2)
3491 {
3492 /* Use information from the related file descriptor to set record
3493 format of the newly created file. */
3494 fstat (rfd, &st_buf);
3495 switch (st_buf.st_fab_rfm)
3496 {
3497 case FAB$C_FIX:
3498 strcpy (rfm, "rfm = fix");
3499 sprintf (mrs, "mrs = %d", st_buf.st_fab_mrs);
3500 strcpy (rat, "rat = ");
3501 if (st_buf.st_fab_rat & FAB$M_CR)
3502 strcat (rat, "cr");
3503 else if (st_buf.st_fab_rat & FAB$M_FTN)
3504 strcat (rat, "ftn");
3505 else if (st_buf.st_fab_rat & FAB$M_PRN)
3506 strcat (rat, "prn");
3507 if (st_buf.st_fab_rat & FAB$M_BLK)
3508 if (st_buf.st_fab_rat & (FAB$M_CR|FAB$M_FTN|FAB$M_PRN))
3509 strcat (rat, ", blk");
3510 else
3511 strcat (rat, "blk");
3512 return creat (name, 0, rfm, rat, mrs);
3513
3514 case FAB$C_VFC:
3515 strcpy (rfm, "rfm = vfc");
3516 sprintf (fsz, "fsz = %d", st_buf.st_fab_fsz);
3517 strcpy (rat, "rat = ");
3518 if (st_buf.st_fab_rat & FAB$M_CR)
3519 strcat (rat, "cr");
3520 else if (st_buf.st_fab_rat & FAB$M_FTN)
3521 strcat (rat, "ftn");
3522 else if (st_buf.st_fab_rat & FAB$M_PRN)
3523 strcat (rat, "prn");
3524 if (st_buf.st_fab_rat & FAB$M_BLK)
3525 if (st_buf.st_fab_rat & (FAB$M_CR|FAB$M_FTN|FAB$M_PRN))
3526 strcat (rat, ", blk");
3527 else
3528 strcat (rat, "blk");
3529 return creat (name, 0, rfm, rat, fsz);
3530
3531 case FAB$C_STM:
3532 strcpy (rfm, "rfm = stm");
3533 break;
3534
3535 case FAB$C_STMCR:
3536 strcpy (rfm, "rfm = stmcr");
3537 break;
3538
3539 case FAB$C_STMLF:
3540 strcpy (rfm, "rfm = stmlf");
3541 break;
3542
3543 case FAB$C_UDF:
3544 strcpy (rfm, "rfm = udf");
3545 break;
3546
3547 case FAB$C_VAR:
3548 strcpy (rfm, "rfm = var");
3549 break;
3550 }
3551 strcpy (rat, "rat = ");
3552 if (st_buf.st_fab_rat & FAB$M_CR)
3553 strcat (rat, "cr");
3554 else if (st_buf.st_fab_rat & FAB$M_FTN)
3555 strcat (rat, "ftn");
3556 else if (st_buf.st_fab_rat & FAB$M_PRN)
3557 strcat (rat, "prn");
3558 if (st_buf.st_fab_rat & FAB$M_BLK)
3559 if (st_buf.st_fab_rat & (FAB$M_CR|FAB$M_FTN|FAB$M_PRN))
3560 strcat (rat, ", blk");
3561 else
3562 strcat (rat, "blk");
3563 }
3564 else
3565 {
3566 strcpy (rfm, vms_stmlf_recfm ? "rfm = stmlf" : "rfm=var");
3567 strcpy (rat, "rat=cr");
3568 }
3569 /* Until the VAX C RTL fixes the many bugs with modes, always use
3570 mode 0 to get the user's default protection. */
3571 fd = creat (name, 0, rfm, rat);
3572 if (fd < 0 && errno == EEXIST)
3573 {
3574 if (unlink (name) < 0)
3575 report_file_error ("delete", build_string (name));
3576 fd = creat (name, 0, rfm, rat);
3577 }
3578 return fd;
3579}
3580#endif /* creat */
3581
3582/* fwrite to stdout is S L O W. Speed it up by using fputc...*/
3583sys_fwrite (ptr, size, num, fp)
3584 register char * ptr;
3585 FILE * fp;
3586{
3587 register int tot = num * size;
3588
3589 while (tot--)
3590 fputc (*ptr++, fp);
3591}
3592
3593/*
3594 * The VMS C library routine creat actually creates a new version of an
3595 * existing file rather than truncating the old version. There are times
3596 * when this is not the desired behavior, for instance, when writing an
3597 * auto save file (you only want one version), or when you don't have
3598 * write permission in the directory containing the file (but the file
3599 * itself is writable). Hence this routine, which is equivalent to
3600 * "close (creat (fn, 0));" on Unix if fn already exists.
3601 */
3602int
3603vms_truncate (fn)
3604 char *fn;
3605{
3606 struct FAB xfab = cc$rms_fab;
3607 struct RAB xrab = cc$rms_rab;
3608 int status;
3609
3610 xfab.fab$l_fop = FAB$M_TEF; /* free allocated but unused blocks on close */
3611 xfab.fab$b_fac = FAB$M_TRN | FAB$M_GET; /* allow truncate and get access */
3612 xfab.fab$b_shr = FAB$M_NIL; /* allow no sharing - file must be locked */
3613 xfab.fab$l_fna = fn;
3614 xfab.fab$b_fns = strlen (fn);
3615 xfab.fab$l_dna = ";0"; /* default to latest version of the file */
3616 xfab.fab$b_dns = 2;
3617 xrab.rab$l_fab = &xfab;
3618
3619 /* This gibberish opens the file, positions to the first record, and
3620 deletes all records from there until the end of file. */
986ffb24 3621 if ((SYS$OPEN (&xfab) & 01) == 01)
86a5659e 3622 {
986ffb24
JB
3623 if ((SYS$CONNECT (&xrab) & 01) == 01 &&
3624 (SYS$FIND (&xrab) & 01) == 01 &&
3625 (SYS$TRUNCATE (&xrab) & 01) == 01)
86a5659e
JB
3626 status = 0;
3627 else
3628 status = -1;
3629 }
3630 else
3631 status = -1;
986ffb24 3632 SYS$CLOSE (&xfab);
86a5659e
JB
3633 return status;
3634}
3635
3636/* Define this symbol to actually read SYSUAF.DAT. This requires either
3637 SYSPRV or a readable SYSUAF.DAT. */
3638
3639#ifdef READ_SYSUAF
3640/*
3641 * getuaf.c
3642 *
3643 * Routine to read the VMS User Authorization File and return
3644 * a specific user's record.
3645 */
3646
3647static struct UAF retuaf;
3648
3649struct UAF *
3650get_uaf_name (uname)
3651 char * uname;
3652{
3653 register status;
3654 struct FAB uaf_fab;
3655 struct RAB uaf_rab;
3656
3657 uaf_fab = cc$rms_fab;
3658 uaf_rab = cc$rms_rab;
3659 /* initialize fab fields */
3660 uaf_fab.fab$l_fna = "SYS$SYSTEM:SYSUAF.DAT";
3661 uaf_fab.fab$b_fns = 21;
3662 uaf_fab.fab$b_fac = FAB$M_GET;
3663 uaf_fab.fab$b_org = FAB$C_IDX;
3664 uaf_fab.fab$b_shr = FAB$M_GET|FAB$M_PUT|FAB$M_UPD|FAB$M_DEL;
3665 /* initialize rab fields */
3666 uaf_rab.rab$l_fab = &uaf_fab;
3667 /* open the User Authorization File */
986ffb24 3668 status = SYS$OPEN (&uaf_fab);
86a5659e
JB
3669 if (!(status&1))
3670 {
3671 errno = EVMSERR;
3672 vaxc$errno = status;
3673 return 0;
3674 }
986ffb24 3675 status = SYS$CONNECT (&uaf_rab);
86a5659e
JB
3676 if (!(status&1))
3677 {
3678 errno = EVMSERR;
3679 vaxc$errno = status;
3680 return 0;
3681 }
3682 /* read the requested record - index is in uname */
3683 uaf_rab.rab$l_kbf = uname;
3684 uaf_rab.rab$b_ksz = strlen (uname);
3685 uaf_rab.rab$b_rac = RAB$C_KEY;
3686 uaf_rab.rab$l_ubf = (char *)&retuaf;
3687 uaf_rab.rab$w_usz = sizeof retuaf;
986ffb24 3688 status = SYS$GET (&uaf_rab);
86a5659e
JB
3689 if (!(status&1))
3690 {
3691 errno = EVMSERR;
3692 vaxc$errno = status;
3693 return 0;
3694 }
3695 /* close the User Authorization File */
986ffb24 3696 status = SYS$DISCONNECT (&uaf_rab);
86a5659e
JB
3697 if (!(status&1))
3698 {
3699 errno = EVMSERR;
3700 vaxc$errno = status;
3701 return 0;
3702 }
986ffb24 3703 status = SYS$CLOSE (&uaf_fab);
86a5659e
JB
3704 if (!(status&1))
3705 {
3706 errno = EVMSERR;
3707 vaxc$errno = status;
3708 return 0;
3709 }
3710 return &retuaf;
3711}
3712
3713struct UAF *
3714get_uaf_uic (uic)
3715 unsigned long uic;
3716{
3717 register status;
3718 struct FAB uaf_fab;
3719 struct RAB uaf_rab;
3720
3721 uaf_fab = cc$rms_fab;
3722 uaf_rab = cc$rms_rab;
3723 /* initialize fab fields */
3724 uaf_fab.fab$l_fna = "SYS$SYSTEM:SYSUAF.DAT";
3725 uaf_fab.fab$b_fns = 21;
3726 uaf_fab.fab$b_fac = FAB$M_GET;
3727 uaf_fab.fab$b_org = FAB$C_IDX;
3728 uaf_fab.fab$b_shr = FAB$M_GET|FAB$M_PUT|FAB$M_UPD|FAB$M_DEL;
3729 /* initialize rab fields */
3730 uaf_rab.rab$l_fab = &uaf_fab;
3731 /* open the User Authorization File */
986ffb24 3732 status = SYS$OPEN (&uaf_fab);
86a5659e
JB
3733 if (!(status&1))
3734 {
3735 errno = EVMSERR;
3736 vaxc$errno = status;
3737 return 0;
3738 }
986ffb24 3739 status = SYS$CONNECT (&uaf_rab);
86a5659e
JB
3740 if (!(status&1))
3741 {
3742 errno = EVMSERR;
3743 vaxc$errno = status;
3744 return 0;
3745 }
3746 /* read the requested record - index is in uic */
3747 uaf_rab.rab$b_krf = 1; /* 1st alternate key */
3748 uaf_rab.rab$l_kbf = (char *) &uic;
3749 uaf_rab.rab$b_ksz = sizeof uic;
3750 uaf_rab.rab$b_rac = RAB$C_KEY;
3751 uaf_rab.rab$l_ubf = (char *)&retuaf;
3752 uaf_rab.rab$w_usz = sizeof retuaf;
986ffb24 3753 status = SYS$GET (&uaf_rab);
86a5659e
JB
3754 if (!(status&1))
3755 {
3756 errno = EVMSERR;
3757 vaxc$errno = status;
3758 return 0;
3759 }
3760 /* close the User Authorization File */
986ffb24 3761 status = SYS$DISCONNECT (&uaf_rab);
86a5659e
JB
3762 if (!(status&1))
3763 {
3764 errno = EVMSERR;
3765 vaxc$errno = status;
3766 return 0;
3767 }
986ffb24 3768 status = SYS$CLOSE (&uaf_fab);
86a5659e
JB
3769 if (!(status&1))
3770 {
3771 errno = EVMSERR;
3772 vaxc$errno = status;
3773 return 0;
3774 }
3775 return &retuaf;
3776}
3777
3778static struct passwd retpw;
3779
3780struct passwd *
3781cnv_uaf_pw (up)
3782 struct UAF * up;
3783{
3784 char * ptr;
3785
3786 /* copy these out first because if the username is 32 chars, the next
3787 section will overwrite the first byte of the UIC */
3788 retpw.pw_uid = up->uaf$w_mem;
3789 retpw.pw_gid = up->uaf$w_grp;
3790
3791 /* I suppose this is not the best sytle, to possibly overwrite one
3792 byte beyond the end of the field, but what the heck... */
3793 ptr = &up->uaf$t_username[UAF$S_USERNAME];
3794 while (ptr[-1] == ' ')
3795 ptr--;
3796 *ptr = '\0';
3797 strcpy (retpw.pw_name, up->uaf$t_username);
3798
3799 /* the rest of these are counted ascii strings */
3800 strncpy (retpw.pw_gecos, &up->uaf$t_owner[1], up->uaf$t_owner[0]);
3801 retpw.pw_gecos[up->uaf$t_owner[0]] = '\0';
3802 strncpy (retpw.pw_dir, &up->uaf$t_defdev[1], up->uaf$t_defdev[0]);
3803 retpw.pw_dir[up->uaf$t_defdev[0]] = '\0';
3804 strncat (retpw.pw_dir, &up->uaf$t_defdir[1], up->uaf$t_defdir[0]);
3805 retpw.pw_dir[up->uaf$t_defdev[0] + up->uaf$t_defdir[0]] = '\0';
3806 strncpy (retpw.pw_shell, &up->uaf$t_defcli[1], up->uaf$t_defcli[0]);
3807 retpw.pw_shell[up->uaf$t_defcli[0]] = '\0';
3808
3809 return &retpw;
3810}
3811#else /* not READ_SYSUAF */
3812static struct passwd retpw;
3813#endif /* not READ_SYSUAF */
3814
3815struct passwd *
3816getpwnam (name)
3817 char * name;
3818{
3819#ifdef READ_SYSUAF
3820 struct UAF *up;
3821#else
3822 char * user;
3823 char * dir;
3824 unsigned char * full;
3825#endif /* READ_SYSUAF */
3826 char *ptr = name;
3827
3828 while (*ptr)
3829 {
3830 if ('a' <= *ptr && *ptr <= 'z')
3831 *ptr -= 040;
3832 ptr++;
3833 }
3834#ifdef READ_SYSUAF
3835 if (!(up = get_uaf_name (name)))
3836 return 0;
3837 return cnv_uaf_pw (up);
3838#else
3839 if (strcmp (name, getenv ("USER")) == 0)
3840 {
3841 retpw.pw_uid = getuid ();
3842 retpw.pw_gid = getgid ();
3843 strcpy (retpw.pw_name, name);
3844 if (full = egetenv ("FULLNAME"))
3845 strcpy (retpw.pw_gecos, full);
3846 else
3847 *retpw.pw_gecos = '\0';
3848 strcpy (retpw.pw_dir, egetenv ("HOME"));
3849 *retpw.pw_shell = '\0';
3850 return &retpw;
3851 }
3852 else
3853 return 0;
3854#endif /* not READ_SYSUAF */
3855}
3856
3857struct passwd *
3858getpwuid (uid)
3859 unsigned long uid;
3860{
3861#ifdef READ_SYSUAF
3862 struct UAF * up;
3863
3864 if (!(up = get_uaf_uic (uid)))
3865 return 0;
3866 return cnv_uaf_pw (up);
3867#else
3868 if (uid == sys_getuid ())
3869 return getpwnam (egetenv ("USER"));
3870 else
3871 return 0;
3872#endif /* not READ_SYSUAF */
3873}
3874
3875/* return total address space available to the current process. This is
3876 the sum of the current p0 size, p1 size and free page table entries
3877 available. */
3878vlimit ()
3879{
3880 int item_code;
3881 unsigned long free_pages;
3882 unsigned long frep0va;
3883 unsigned long frep1va;
3884 register status;
3885
3886 item_code = JPI$_FREPTECNT;
3887 if (((status = LIB$GETJPI (&item_code, 0, 0, &free_pages)) & 1) == 0)
3888 {
3889 errno = EVMSERR;
3890 vaxc$errno = status;
3891 return -1;
3892 }
3893 free_pages *= 512;
3894
3895 item_code = JPI$_FREP0VA;
3896 if (((status = LIB$GETJPI (&item_code, 0, 0, &frep0va)) & 1) == 0)
3897 {
3898 errno = EVMSERR;
3899 vaxc$errno = status;
3900 return -1;
3901 }
3902 item_code = JPI$_FREP1VA;
3903 if (((status = LIB$GETJPI (&item_code, 0, 0, &frep1va)) & 1) == 0)
3904 {
3905 errno = EVMSERR;
3906 vaxc$errno = status;
3907 return -1;
3908 }
3909
3910 return free_pages + frep0va + (0x7fffffff - frep1va);
3911}
3912
3913define_logical_name (varname, string)
3914 char *varname;
3915 char *string;
3916{
3917 struct dsc$descriptor_s strdsc =
3918 {strlen (string), DSC$K_DTYPE_T, DSC$K_CLASS_S, string};
3919 struct dsc$descriptor_s envdsc =
3920 {strlen (varname), DSC$K_DTYPE_T, DSC$K_CLASS_S, varname};
3921 struct dsc$descriptor_s lnmdsc =
3922 {7, DSC$K_DTYPE_T, DSC$K_CLASS_S, "LNM$JOB"};
3923
3924 return LIB$SET_LOGICAL (&envdsc, &strdsc, &lnmdsc, 0, 0);
3925}
3926
3927delete_logical_name (varname)
3928 char *varname;
3929{
3930 struct dsc$descriptor_s envdsc =
3931 {strlen (varname), DSC$K_DTYPE_T, DSC$K_CLASS_S, varname};
3932 struct dsc$descriptor_s lnmdsc =
3933 {7, DSC$K_DTYPE_T, DSC$K_CLASS_S, "LNM$JOB"};
3934
3935 return LIB$DELETE_LOGICAL (&envdsc, &lnmdsc);
3936}
3937
3938ulimit ()
3939{}
3940
86a5659e
JB
3941setpgrp ()
3942{}
3943
3944execvp ()
3945{
3946 error ("execvp system call not implemented");
3947}
3948
3949int
3950rename (from, to)
3951 char *from, *to;
3952{
3953 int status;
3954 struct FAB from_fab = cc$rms_fab, to_fab = cc$rms_fab;
3955 struct NAM from_nam = cc$rms_nam, to_nam = cc$rms_nam;
3956 char from_esn[NAM$C_MAXRSS];
3957 char to_esn[NAM$C_MAXRSS];
3958
3959 from_fab.fab$l_fna = from;
3960 from_fab.fab$b_fns = strlen (from);
3961 from_fab.fab$l_nam = &from_nam;
3962 from_fab.fab$l_fop = FAB$M_NAM;
3963
3964 from_nam.nam$l_esa = from_esn;
3965 from_nam.nam$b_ess = sizeof from_esn;
3966
3967 to_fab.fab$l_fna = to;
3968 to_fab.fab$b_fns = strlen (to);
3969 to_fab.fab$l_nam = &to_nam;
3970 to_fab.fab$l_fop = FAB$M_NAM;
3971
3972 to_nam.nam$l_esa = to_esn;
3973 to_nam.nam$b_ess = sizeof to_esn;
3974
3975 status = SYS$RENAME (&from_fab, 0, 0, &to_fab);
3976
3977 if (status & 1)
3978 return 0;
3979 else
3980 {
3981 if (status == RMS$_DEV)
3982 errno = EXDEV;
3983 else
3984 errno = EVMSERR;
3985 vaxc$errno = status;
3986 return -1;
3987 }
3988}
3989
3990/* This function renames a file like `rename', but it strips
3991 the version number from the "to" filename, such that the "to" file is
3992 will always be a new version. It also sets the file protection once it is
3993 finished. The protection that we will use is stored in fab_final_pro,
3994 and was set when we did a creat_copy_attrs to create the file that we
3995 are renaming.
3996
3997 We could use the chmod function, but Eunichs uses 3 bits per user category
3998 to describe the protection, and VMS uses 4 (write and delete are seperate
3999 bits). To maintain portability, the VMS implementation of `chmod' wires
4000 the W and D bits together. */
4001
4002
4003static struct fibdef fib; /* We need this initialized to zero */
4004char vms_file_written[NAM$C_MAXRSS];
4005
4006int
4007rename_sans_version (from,to)
4008 char *from, *to;
4009{
4010 short int chan;
4011 int stat;
4012 short int iosb[4];
4013 int status;
4014 struct FAB to_fab = cc$rms_fab;
4015 struct NAM to_nam = cc$rms_nam;
4016 struct dsc$descriptor fib_d ={sizeof (fib),0,0,(char*) &fib};
4017 struct dsc$descriptor fib_attr[2]
4018 = {{sizeof (fab_final_pro),ATR$C_FPRO,0,(char*) &fab_final_pro},{0,0,0,0}};
4019 char to_esn[NAM$C_MAXRSS];
4020
4021 $DESCRIPTOR (disk,to_esn);
4022
4023 to_fab.fab$l_fna = to;
4024 to_fab.fab$b_fns = strlen (to);
4025 to_fab.fab$l_nam = &to_nam;
4026 to_fab.fab$l_fop = FAB$M_NAM;
4027
4028 to_nam.nam$l_esa = to_esn;
4029 to_nam.nam$b_ess = sizeof to_esn;
4030
4031 status = SYS$PARSE (&to_fab, 0, 0); /* figure out the full file name */
4032
4033 if (to_nam.nam$l_fnb && NAM$M_EXP_VER)
4034 *(to_nam.nam$l_ver) = '\0';
4035
4036 stat = rename (from, to_esn);
4037 if (stat < 0)
4038 return stat;
4039
4040 strcpy (vms_file_written, to_esn);
4041
4042 to_fab.fab$l_fna = vms_file_written; /* this points to the versionless name */
4043 to_fab.fab$b_fns = strlen (vms_file_written);
4044
4045 /* Now set the file protection to the correct value */
986ffb24 4046 SYS$OPEN (&to_fab, 0, 0); /* This fills in the nam$w_fid fields */
86a5659e
JB
4047
4048 /* Copy these fields into the fib */
4049 fib.fib$r_fid_overlay.fib$w_fid[0] = to_nam.nam$w_fid[0];
4050 fib.fib$r_fid_overlay.fib$w_fid[1] = to_nam.nam$w_fid[1];
4051 fib.fib$r_fid_overlay.fib$w_fid[2] = to_nam.nam$w_fid[2];
4052
986ffb24 4053 SYS$CLOSE (&to_fab, 0, 0);
86a5659e 4054
986ffb24 4055 stat = SYS$ASSIGN (&disk, &chan, 0, 0); /* open a channel to the disk */
86a5659e 4056 if (!stat)
986ffb24
JB
4057 LIB$SIGNAL (stat);
4058 stat = SYS$QIOW (0, chan, IO$_MODIFY, iosb, 0, 0, &fib_d,
86a5659e
JB
4059 0, 0, 0, &fib_attr, 0);
4060 if (!stat)
986ffb24
JB
4061 LIB$SIGNAL (stat);
4062 stat = SYS$DASSGN (chan);
86a5659e 4063 if (!stat)
986ffb24 4064 LIB$SIGNAL (stat);
0137dbf7 4065 strcpy (vms_file_written, to_esn); /* We will write this to the terminal*/
86a5659e
JB
4066 return 0;
4067}
4068
4069link (file, new)
4070 char * file, * new;
4071{
4072 register status;
4073 struct FAB fab;
4074 struct NAM nam;
4075 unsigned short fid[3];
4076 char esa[NAM$C_MAXRSS];
4077
4078 fab = cc$rms_fab;
4079 fab.fab$l_fop = FAB$M_OFP;
4080 fab.fab$l_fna = file;
4081 fab.fab$b_fns = strlen (file);
4082 fab.fab$l_nam = &nam;
4083
4084 nam = cc$rms_nam;
4085 nam.nam$l_esa = esa;
4086 nam.nam$b_ess = NAM$C_MAXRSS;
4087
4088 status = SYS$PARSE (&fab);
4089 if ((status & 1) == 0)
4090 {
4091 errno = EVMSERR;
4092 vaxc$errno = status;
4093 return -1;
4094 }
4095 status = SYS$SEARCH (&fab);
4096 if ((status & 1) == 0)
4097 {
4098 errno = EVMSERR;
4099 vaxc$errno = status;
4100 return -1;
4101 }
4102
4103 fid[0] = nam.nam$w_fid[0];
4104 fid[1] = nam.nam$w_fid[1];
4105 fid[2] = nam.nam$w_fid[2];
4106
4107 fab.fab$l_fna = new;
4108 fab.fab$b_fns = strlen (new);
4109
4110 status = SYS$PARSE (&fab);
4111 if ((status & 1) == 0)
4112 {
4113 errno = EVMSERR;
4114 vaxc$errno = status;
4115 return -1;
4116 }
4117
4118 nam.nam$w_fid[0] = fid[0];
4119 nam.nam$w_fid[1] = fid[1];
4120 nam.nam$w_fid[2] = fid[2];
4121
4122 nam.nam$l_esa = nam.nam$l_name;
4123 nam.nam$b_esl = nam.nam$b_name + nam.nam$b_type + nam.nam$b_ver;
4124
4125 status = SYS$ENTER (&fab);
4126 if ((status & 1) == 0)
4127 {
4128 errno = EVMSERR;
4129 vaxc$errno = status;
4130 return -1;
4131 }
4132
4133 return 0;
4134}
4135
4136croak (badfunc)
4137 char *badfunc;
4138{
4139 printf ("%s not yet implemented\r\n", badfunc);
4140 reset_sys_modes ();
4141 exit (1);
4142}
4143
4144long
4145random ()
4146{
4147 /* Arrange to return a range centered on zero. */
4148 return rand () - (1 << 30);
4149}
4150
4151srandom (seed)
4152{
4153 srand (seed);
4154}
4155#endif /* VMS */
4156\f
4157#ifdef AIX
4158
4159/* Called from init_sys_modes. */
4160hft_init ()
4161{
4162 int junk;
4163
4164 /* If we're not on an HFT we shouldn't do any of this. We determine
4165 if we are on an HFT by trying to get an HFT error code. If this
4166 call fails, we're not on an HFT. */
4167#ifdef IBMR2AIX
4168 if (ioctl (0, HFQERROR, &junk) < 0)
4169 return;
4170#else /* not IBMR2AIX */
4171 if (ioctl (0, HFQEIO, 0) < 0)
4172 return;
4173#endif /* not IBMR2AIX */
4174
4175 /* On AIX the default hft keyboard mapping uses backspace rather than delete
4176 as the rubout key's ASCII code. Here this is changed. The bug is that
4177 there's no way to determine the old mapping, so in reset_sys_modes
4178 we need to assume that the normal map had been present. Of course, this
4179 code also doesn't help if on a terminal emulator which doesn't understand
4180 HFT VTD's. */
4181 {
4182 struct hfbuf buf;
4183 struct hfkeymap keymap;
4184
4185 buf.hf_bufp = (char *)&keymap;
4186 buf.hf_buflen = sizeof (keymap);
4187 keymap.hf_nkeys = 2;
4188 keymap.hfkey[0].hf_kpos = 15;
4189 keymap.hfkey[0].hf_kstate = HFMAPCHAR | HFSHFNONE;
4190#ifdef IBMR2AIX
4191 keymap.hfkey[0].hf_keyidh = '<';
4192#else /* not IBMR2AIX */
4193 keymap.hfkey[0].hf_page = '<';
4194#endif /* not IBMR2AIX */
4195 keymap.hfkey[0].hf_char = 127;
4196 keymap.hfkey[1].hf_kpos = 15;
4197 keymap.hfkey[1].hf_kstate = HFMAPCHAR | HFSHFSHFT;
4198#ifdef IBMR2AIX
4199 keymap.hfkey[1].hf_keyidh = '<';
4200#else /* not IBMR2AIX */
4201 keymap.hfkey[1].hf_page = '<';
4202#endif /* not IBMR2AIX */
4203 keymap.hfkey[1].hf_char = 127;
4204 hftctl (0, HFSKBD, &buf);
4205 }
4206 /* The HFT system on AIX doesn't optimize for scrolling, so it's really ugly
4207 at times. */
4208 line_ins_del_ok = char_ins_del_ok = 0;
4209}
4210
4211/* Reset the rubout key to backspace. */
4212
4213hft_reset ()
4214{
4215 struct hfbuf buf;
4216 struct hfkeymap keymap;
4217 int junk;
4218
4219#ifdef IBMR2AIX
4220 if (ioctl (0, HFQERROR, &junk) < 0)
4221 return;
4222#else /* not IBMR2AIX */
4223 if (ioctl (0, HFQEIO, 0) < 0)
4224 return;
4225#endif /* not IBMR2AIX */
4226
4227 buf.hf_bufp = (char *)&keymap;
4228 buf.hf_buflen = sizeof (keymap);
4229 keymap.hf_nkeys = 2;
4230 keymap.hfkey[0].hf_kpos = 15;
4231 keymap.hfkey[0].hf_kstate = HFMAPCHAR | HFSHFNONE;
4232#ifdef IBMR2AIX
4233 keymap.hfkey[0].hf_keyidh = '<';
4234#else /* not IBMR2AIX */
4235 keymap.hfkey[0].hf_page = '<';
4236#endif /* not IBMR2AIX */
4237 keymap.hfkey[0].hf_char = 8;
4238 keymap.hfkey[1].hf_kpos = 15;
4239 keymap.hfkey[1].hf_kstate = HFMAPCHAR | HFSHFSHFT;
4240#ifdef IBMR2AIX
4241 keymap.hfkey[1].hf_keyidh = '<';
4242#else /* not IBMR2AIX */
4243 keymap.hfkey[1].hf_page = '<';
4244#endif /* not IBMR2AIX */
4245 keymap.hfkey[1].hf_char = 8;
4246 hftctl (0, HFSKBD, &buf);
4247}
4248
4249#endif /* AIX */