#include "config.h" /* * HISTORY * {1} 19-Mar-91 Henk D. Davids * History started. Added default input file name so you do not * have to specify name or type if you want it to be *. * Changes indicated by "-hdd" in comment. * * 2. 4/4/91 John E. Davis * I added code to read the teminal size for unix systems-- at least it * works on a sun4 (BSD ?). In addition I have also recently added file * deletion code for both unix and vms. */ #ifdef VMS #include #include #include #include #include #include #include #include #include #ifndef NO_STDLIB_H # include #endif /* #include */ #endif /* VMS */ #ifdef USE_SLANG #include "slang.h" #endif #ifdef unix # include # ifdef SYSV # include # include # endif # include #endif #include #include "sysdep.h" #include "display.h" #include "window.h" #include "most.h" #ifdef VMS typedef struct { /* I/O status block */ short i_cond; /* Condition value */ short i_xfer; /* Transfer count */ long i_info; /* Device information */ } iosb; typedef struct { /* Terminal characteristics */ char t_class; /* Terminal class */ char t_type; /* Terminal type */ short t_width; /* Terminal width in characters */ long t_mandl; /* Terminal's mode and length */ long t_extend; /* Extended terminal characteristics */ } termchar; static short TTY_CHANNEL_GLOBAL; static int zero = 0; #else int TTY_DESCR; #endif /* VMS */ /* * * * SHELL COMMANDS * */ #ifdef VMS /* these two from emacs source */ #if 0 static define_logical_name (char *varname, char *string) { static char sstring[200], svarname[200]; struct dsc$descriptor_s strdsc = {strlen (string), DSC$K_DTYPE_T, DSC$K_CLASS_S, sstring}; struct dsc$descriptor_s envdsc = {strlen (varname), DSC$K_DTYPE_T, DSC$K_CLASS_S, svarname}; struct dsc$descriptor_s lnmdsc = {7, DSC$K_DTYPE_T, DSC$K_CLASS_S, "LNM$JOB"}; strcpy(sstring, string); strcpy(svarname, varname); LIB$SET_LOGICAL (&envdsc, &strdsc, &lnmdsc, 0, 0); } static delete_logical_name (char *varname) { struct dsc$descriptor_s envdsc = {strlen (varname), DSC$K_DTYPE_T, DSC$K_CLASS_S, varname}; struct dsc$descriptor_s lnmdsc = {7, DSC$K_DTYPE_T, DSC$K_CLASS_S, "LNM$JOB"}; LIB$DELETE_LOGICAL (&envdsc, &lnmdsc); } int most_do_emacs_command() { unsigned long pid; char *pidstr; if((pidstr = getenv("EMACS_PID")) != NULL) { (void) sscanf(pidstr,"%X",&pid); if (lib$attach(&pid) == SS$_NORMAL) /* we attach to emacs */ return(1); else return(0); /* printf("Can't attach to pid %X\n",pid); */ } else return(0); } #endif /* if 0 */ static unsigned long SHELL_PID = 0; /* returns 0 on success */ int most_do_shell_command() { /* here we try to attach to the parent otherwise just spawn a new one */ unsigned long parent_pid; unsigned long status = 0; char str[80]; $DESCRIPTOR(MOST_$_descr, "MOST > "); if (Most_Secure_Mode) { most_message ("Spawning not permitted in secure mode.", 1); return 0; } parent_pid = getppid(); if (parent_pid && parent_pid != 0xffffffff) /* we attach to parent */ status = lib$attach(&parent_pid); else if (SHELL_PID && SHELL_PID != 0xffffffff) /* try to attach to previous shell */ status = lib$attach (&SHELL_PID); if (status != SS$_NORMAL) /* others fail so spawn a new shell */ { status = 0; most_send_string_to_term("Spawning MOST DCL SUBPROCESS (Logout when finished)..."); lib$spawn(0,0,0,0,0,&SHELL_PID,&status,0,0,0,&MOST_$_descr); /* if we attach back, status may come back unchanged */ if ((status != 0) && (status != SS$_NORMAL)) { sprintf(str,"Unable to spawn subprocess. Error = %X", status); most_message(str,1); return(0); } } most_message(" ",0); /* make sure message window is restored */ return(1); } #endif /* VMS */ /* * FILE IO * */ #ifdef VMS int most_expand_file_name(char *file,char *expanded_file) { unsigned long status; static int context = 0, len = 0; static char inputname[MAX_PATHLEN] = ""; $DESCRIPTOR(file_desc,inputname); $DESCRIPTOR(default_dsc,"SYS$DISK:[]*.*;"); static struct dsc$descriptor_s result = {0, DSC$K_DTYPE_T, DSC$K_CLASS_D, NULL}; if (strcmp(inputname, file)) { if (context) { lib$find_file_end(&context); } context = 0; strcpy(inputname, file); len = strlen(inputname); } file_desc.dsc$w_length = len; if (RMS$_NORMAL == lib$find_file(&file_desc,&result,&context, &default_dsc,0,0,&zero)) { memcpy(expanded_file, result.dsc$a_pointer, result.dsc$w_length); expanded_file[result.dsc$w_length] = '\0'; return (1); } else { expanded_file[0] = '\0'; /* so file comes back as zero width */ return(0); } } #endif /* VMS */ /* * * * Terminal IO * */ #ifdef VMS /* * Exit Handler Control Block */ static struct argument_block { int forward_link; int (*exit_routine)(); int arg_count; int *status_address; int exit_status; } Exit_Block = { 0, NULL, 1, &Exit_Block.exit_status, 0 }; /* ** For deciding whether to request a terminal channel. */ #ifndef USE_SLANG static int first_request_for_MostTT_chan = 1; #endif #endif /* VMS */ #ifdef unix #include #if !defined(sun) # include #endif #ifndef NO_UNISTD_H # include #endif #if HAS_TERMIOS # include #endif #ifdef SYSV # include # include # include # include #endif #include #include #include #ifndef USE_SLANG #if !HAS_TERMIOS struct ttystuff { struct tchars t; struct ltchars lt; struct sgttyb s; }; static struct ttystuff OLDTTY; #else static struct termios OLDTTY; #endif /* this next works on ultrix for setting termios */ #ifdef TCGETS # define GET_TERMIOS(fd, x) ioctl(fd, TCGETS, x) # define SET_TERMIOS(fd, x) ioctl(fd, TCSETS, x) #else # if !HAS_TERMIOS # define X(x,m) &(((struct ttystuff*)(x))->m) # define GET_TERMIOS(fd, x) \ if(ioctl(fd, TIOCGETC, X(x,t))<0 || \ ioctl(fd, TIOCGLTC, X(x,lt))<0 || \ ioctl(fd, TIOCGETP, X(x,s))<0)exit_error("Can't get terminal info") # define SET_TERMIOS(fd, x) \ if(ioctl(fd, TIOCSETC, X(x,t))<0 || \ ioctl(fd, TIOCSLTC, X(x,lt))<0 || \ ioctl(fd, TIOCSETP, X(x,s))<0)exit_error("Can't set terminal info") # else # define GET_TERMIOS(fd, x) tcgetattr(fd, x) # define SET_TERMIOS(fd, x) tcsetattr(fd, TCSANOW, x) # endif #endif static void open_term(void) { if ((TTY_DESCR = open("/dev/tty",O_RDONLY)) < 0) { most_exit_error("Unable to open tty."); } } #endif /* USE_SLANG */ #ifdef SIGHUP void unix_hangup(int sig) { most_exit_error ("Hangup signal caught."); } #endif #endif /* unix */ /* This routine may be problematic when there are more windows than * the new screen size can support. Until I think of what to do, * I have not touched this routine. */ void most_resize_display (int sig) { most_get_term_dimensions(&Most_Screen_Width, &Most_Screen_Height); #ifdef SIGWINCH if (Most_Display_Inited == 0) return; if (Most_Win != NULL) { most_delete_other_windows (); Most_Win->bot = Most_Screen_Height - 2; if (sig != 0) most_redraw_display (); } (void) signal(SIGWINCH, most_resize_display); #endif } int Most_TTY_Inited; void most_init_tty() { #ifdef USE_SLANG if (Most_TTY_Inited) return; SLang_init_tty (7, 0, 1); SLang_set_abort_signal (NULL); most_enable_cursor_keys(); #else #ifdef VMS $DESCRIPTOR ( Term, "SYS$ERROR"); if (Most_TTY_Inited) return; if (first_request_for_MostTT_chan) { if (sys$assign ( &Term, &TTY_CHANNEL_GLOBAL, 0, 0 ) != SS$_NORMAL) { fprintf(stderr,"Unable to assign input channel\n"); exit(0); } if (NULL == Exit_Block.exit_routine) { most_reset_tty(); Exit_Block.exit_routine = most_reset_tty; SYS$DCLEXH(&Exit_Block); } first_request_for_MostTT_chan = 0; } #else /* unix */ #if !HAS_TERMIOS struct ttystuff newtty; #else struct termios newtty; #endif most_enable_cursor_keys(); open_term(); GET_TERMIOS(TTY_DESCR, &OLDTTY); GET_TERMIOS(TTY_DESCR, &newtty); #if !HAS_TERMIOS newtty.s.sg_flags &= ~(ECHO); newtty.s.sg_flags &= ~(CRMOD); newtty.t.t_eofc = 1; newtty.t.t_intrc = 255; /* */ newtty.t.t_quitc = 255; newtty.lt.t_suspc = 255; /* to ignore ^Z */ newtty.lt.t_lnextc = 255; newtty.s.sg_flags |= CBREAK; /* do I want cbreak or raw????? */ #else newtty.c_iflag &= ~(ECHO | INLCR | ICRNL); newtty.c_oflag |= ONLCR; /* map newline to cr/newline on out */ newtty.c_oflag &= ~OCRNL; newtty.c_cc[VMIN] = 1; newtty.c_cc[VTIME] = 0; newtty.c_cc[VEOF] = 1; newtty.c_lflag = ISIG | NOFLSH; newtty.c_cc[VINTR] = 255; /* ^G */ newtty.c_cc[VQUIT] = 255; newtty.c_cc[VSUSP] = 255; /* to ignore ^Z */ #ifdef VSWTCH newtty.c_cc[VSWTCH] = 255; /* to ignore who knows what */ #endif #endif /* HAS_TERMIOS */ SET_TERMIOS(TTY_DESCR, &newtty); /* VMS */ #endif #endif /* SLANG */ #ifndef VMS #ifdef SIGHUP signal (SIGHUP, unix_hangup); signal (SIGTERM, unix_hangup); #endif #endif #ifdef SIGWINCH (void) signal(SIGWINCH, most_resize_display); #endif Most_TTY_Inited = 1; } int most_reset_tty() { if (Most_TTY_Inited == 0) return 0; #ifdef USE_SLANG SLang_reset_tty (); #else #ifdef unix SET_TERMIOS(TTY_DESCR, &OLDTTY); close(TTY_DESCR); #endif #endif Most_TTY_Inited = 0; return(0); } #ifndef USE_SLANG static char sys_getkey(void) { char c; #ifndef VMS int status, count = 10;; while (1) { status = read(TTY_DESCR, &c, 1); if (status >= 0) break; if (count == 0) { most_exit_error ("getkey(): read failed."); } sleep (1); count--; } #else /* VMS */ /* see Guide to Programming VAX/VMS */ int status; static int trmmsk [2] = { 0, 0 }; short iosb [4]; status = sys$qiow ( 0, TTY_CHANNEL_GLOBAL, IO$_READVBLK | IO$M_NOECHO | IO$_TTYREADALL, iosb, 0, 0, &c, 1, 0, trmmsk, 0, 0 ); #endif /* VMS */ return(c); } #endif /* USE_SLANG */ char most_getkey() { #ifdef USE_SLANG char ch; ch = (char) SLang_getkey (); SLKeyBoard_Quit = SLang_Error = 0; return ch; #else int ch; ch = sys_getkey(); ch &= 0x7F; return(ch); #endif } /* * * Misc Termial stuff * * */ /* This is to get the size of the terminal */ void most_get_term_dimensions(int *cols, int *rows) { #ifdef VMS int status; iosb iostatus; $DESCRIPTOR(devnam, "SYS$ERROR"); struct { short row_buflen; short row_itmcod; int *row_bufadr; short *row_retlen; short col_buflen; short col_itmcod; int *col_bufadr; short *col_retlen; int listend; } itmlst = { sizeof(*rows), DVI$_TT_PAGE, 0, 0, sizeof(*cols), DVI$_DEVBUFSIZ, 0, 0, 0 }; itmlst.row_bufadr = rows; itmlst.col_bufadr = cols; /* Get current terminal characteristics */ status = sys$getdviw(0, /* Wait on event flag zero */ 0, /* Channel to input terminal */ &devnam, /* device name */ &itmlst, /* Item descriptor List */ &iostatus, /* Status after operation */ 0, 0, /* No AST service */ 0); /* nullarg */ if (status&1) status = iostatus.i_cond; /* Jump out if bad status */ if ((status & 1) == 0) exit(status); #else /* this may need work on other unix-- works for sun4 */ #ifdef TIOCGWINSZ struct winsize wind_struct; if ((-1 == ioctl(TTY_DESCR,TIOCGWINSZ,&wind_struct)) && (-1 == ioctl(0,TIOCGWINSZ,&wind_struct)) && (-1 == ioctl(1,TIOCGWINSZ,&wind_struct)) && (-1 == ioctl(2,TIOCGWINSZ,&wind_struct))) { *rows = 24; *cols = 80; } else { *cols = (int) wind_struct.ws_col; *rows = (int) wind_struct.ws_row; } #else *rows = 24; *cols = 80; #endif #endif /* VMS */ if (*rows <= 0) *rows = 24; else if (*rows < 5) *rows = 5; if (*cols <= 0) *cols = 80; else if (*cols < 5) *cols = 5; } /* returns 0 on failure, 1 on sucess */ int most_delete_file(char *filename) { #ifdef VMS return (1 + delete(filename)); /* 0: sucess; -1 failure */ #else /* unix not ready yet */ return(1 + unlink(filename)); #endif } /* This routine converts unix type names to vms names */ #ifdef VMS static int locate(char ch, char *string) { int i; char c; i = 0; while (c = string[i++], (c != ch) && (c != '\0')); if (c == ch) return(i); else return (0); } char *most_unix2vms(char *file) { int i,device,j,first,last; static char vms_name[MAX_PATHLEN]; char ch; if (locate('[',file)) return(file); /* vms_name syntax */ if (!locate('/',file)) return(file); /* vms_name syntax */ /* search for the ':' which means a device is present */ device = locate(':',file); i = 0; if (device) { while (ch = file[i], i < device) vms_name[i++] = ch; } j = i; /* go from the end looking for a '/' and mark it */ i = strlen(file) - 1; while(ch = file[i], ch != '/' && i-- >= 0); if (ch == '/') { file[i] = ']'; last = 0; } else last = 1; i = j; vms_name[j++] = '['; vms_name[j++] = '.'; first = 0; while(ch = file[i++], ch != '\0') { switch (ch) { case '.': if (last) vms_name[j++] = '.'; if (last) break; ch = file[i++]; if (ch == '.') { if (!first) j--; /* overwrite the dot */ vms_name[j++] = '-'; } else if (ch == '/'); /* './' combinations-- do nothing */ else if (ch == ']') { last = 1; if (vms_name[j-1] == '.') j--; vms_name[j++] = ']'; } else vms_name[j++] = '.'; break; case '/': if (first) { vms_name[j++] = '.'; } else { first = 1; /* if '/' is first char or follows a colon do nothing */ if ((i!=1) && (file[i-2] != ':')) { vms_name[j++] = '.'; } else j--; /* overwrite the '.' following '[' */ } break; case ']': last = 1; if (vms_name[j-1] == '.') j--; vms_name[j++] = ']'; break; default: vms_name[j++] = ch; } } return (vms_name); } /* main(int argc, char **argv) { puts(unix2vms(argv[1])); } */ #endif /* VMS */ #include char *most_get_time() { time_t clock; char *the_time; clock = time((time_t *) 0); the_time = (char *) ctime(&clock); /* returns the form Sun Sep 16 01:03:52 1985\n\0 */ the_time[24] = '\0'; return(the_time); } void most_set_width(int width, int redraw) { #ifdef VMS short fd; int status; iosb iostatus; static termchar tc; /* Terminal characteristics */ $DESCRIPTOR( devnam, "SYS$ERROR"); #else #ifdef TIOCGWINSZ struct winsize wind_struct; #endif #endif /* Switching physical terminal to narrow/wide mode.*/ if(width <= 80) { width = 80; most_narrow_width(); } else { width = 132; most_wide_width(); } Most_Screen_Width = width; #ifdef VMS /* Assign input to a channel */ status = sys$assign(&devnam, &fd, 0, 0); if ((status & 1) == 0) exit(status); /* Get current terminal characteristics */ status = sys$qiow( /* Queue and wait */ 0, /* Wait on event flag zero */ fd, /* Channel to input terminal */ IO$_SENSEMODE, /* Get current characteristic */ &iostatus, /* Status after operation */ 0, 0, /* No AST service */ &tc, /* Terminal characteristics buf */ sizeof(tc), /* Size of the buffer */ 0, 0, 0, 0); /* P3-P6 unused */ /*set terminal characteristics */ tc.t_width=width; status = sys$qiow( /* Queue and wait */ 0, /* Wait on event flag zero */ fd, /* Channel to input terminal */ IO$_SETMODE, /* Get current characteristic */ &iostatus, /* Status after operation */ 0, 0, /* No AST service */ &tc, /* Terminal characteristics buf */ sizeof(tc), /* Size of the buffer */ 0, 0, 0, 0); /* P3-P6 unused */ if( (sys$dassgn(fd) & 1)==0) exit(status); /* here we redraw the screen, on unix, we assume that the terminal * driver sends the appropriate signal that most catches to redraw so we * do not redraw because it is likely that screen will be redrawn twice */ if (redraw) most_redraw_display(); #else #ifdef TIOCGWINSZ /* this may need work on other unix-- works for sun4 */ if (-1 != ioctl(TTY_DESCR,TIOCGWINSZ,&wind_struct)) { wind_struct.ws_col = width; ioctl(TTY_DESCR,TIOCSWINSZ,&wind_struct); } #endif #endif /* VMS */ } int posix_system (char *cmd) { #ifndef VMS void (*old_int)(int); int ret; old_int = signal (SIGINT, SIG_IGN); #ifdef SIGWINCH (void) signal(SIGWINCH, SIG_IGN); #endif ret = system (cmd); signal (SIGINT, old_int); return ret; #else return system (cmd); #endif }