/****************************************************************************** #### # # #### #### #### ##### ###### #### # # # # # # # # # # # # # #### # #### # # # # # ##### # # # # # # # # # # ### # # # # # # # # # # # # # ### # # #### # #### #### #### ##### ###### ### #### ******************************************************************************/ /* This file is part of MAPMAKER 3.0b, Copyright 1987-1992, Whitehead Institute for Biomedical Research. All rights reserved. See READ.ME for license. */ /**************** SYSCODE.C - SYSTEM SPECIFIC CODE ***************************/ /* Most of this file is doccumented in system.h - it contains most of the system dependent code for the helpers library. */ #define INC_LIB #define INC_EQN #define INC_HELP_DEFS #include "system.h" #ifdef _GNU_READLINE #include "readline/readline.h" #include "readline/history.h" #endif /*********************** C-Library Extensions ********************************/ /***** Time functions *****/ /* Note that time() and ctime() seem to be the only portable time functions. However, time() returns different types with different C compilers! */ TIME_TYPE old_stamp, new_stamp; /* For local use only! */ real usertime(do_reset) /* return time in seconds, or -1.0 if fail */ bool do_reset; { real rtime; new_stamp= time((TIME_TYPE *)NULL); rtime= (real)(new_stamp - old_stamp); if (do_reset) old_stamp= new_stamp; return(rtime); } char *time_string() /* return ptr to "" if fail */ { TIME_TYPE the_time; /* note that asctime() does not always exist */ char *str; int end; the_time=time((TIME_TYPE *)NULL); str=ctime(&the_time); if (str==NULL) return(ptr_to("")); end=len(str)-1; if (str[end]=='\n') str[end]='\0'; return(str); } /***** subprocess functions *****/ bool shell_command(cmd) char *cmd; { bool success, had_curses; success=FALSE; #ifdef NO_SYSTEM_FUNC return(FALSE); #else /* NEED WIMP HOOK */ #ifdef HAVE_CURSES had_curses= curses; if (curses) curses_end(); /* DO SOMETHING */ #endif #ifndef VMS if (system(cmd)==0) success=TRUE; #endif #ifdef VMS if (system(cmd)!=0) success=TRUE; #endif #ifdef HAVE_CURSES if (success && had_curses) curses_refresh(); #endif return(success); #endif } bool subshell() { char *shell_name, cmd[120]; bool success=FALSE, had_curses; #ifdef NO_SYSTEM_FUNC return(FALSE); #else /* NEED WIMP HOOK */ #ifdef HAVE_CURSES had_curses= curses; if (curses) curses_end(); /* DO SOMETHING */ #endif #ifdef TRY_SHELL_VAR if ((shell_name=getenv("SHELL"))!=NULL && !nullstr(shell_name)) { nstrcpy(cmd,shell_name,100); /* maxstrcat(cmd," -i",110); why? */ if (system(cmd)==0) success=TRUE; } #endif #ifdef TRY_COMSPEC_VAR if (!success && (shell_name=getenv("COMSPEC"))!=NULL && !nullstr(shell_name)) { if (system(shell_name)==0) success=TRUE; } #endif #ifdef TRY_SHELL_CMD if (!success && !nullstr(TRY_SHELL_CMD)) { if (system(TRY_SHELL_CMD)==0) success=TRUE; } #endif #ifdef HAVE_CURSES if (success && had_curses) curses_refresh(); #endif return(success); #endif } /***** get/set directories *****/ bool change_directory(dir) char *dir; { if (dir==NULL) send(CRASH); #ifdef HAVE_CHDIR if (chdir(dir)==0) return(TRUE); #endif return(FALSE); } bool get_directory(buf) char *buf; { if (buf==NULL) send(CRASH); #ifdef HAVE_GETCWD if (getcwd(buf,PATH_LENGTH-2)!=NULL) return(TRUE); #endif return(FALSE); } bool get_home_directory(buf) char *buf; { char *dir; if (buf==NULL) send(CRASH); #ifdef HAVE_GETENV if ((dir=getenv("HOME"))!=NULL) { nstrcpy(buf,dir,PATH_LENGTH); return(TRUE); } #endif return(FALSE); } bool get_code_directory(buf) char *buf; { char *dir; if (buf==NULL) send(CRASH); #ifdef HAVE_GETENV if ((dir=getenv("MAPM_LIB"))!=NULL) { nstrcpy(buf,dir,PATH_LENGTH); return(TRUE); } #endif #ifdef _CODE_DIR /* compiled in default */ if (!nullstr(_CODE_DIR)) { nstrcpy(buf,_CODE_DIR,PATH_LENGTH); return(TRUE); } #endif return(FALSE); } bool rename_file(original_name,new_name) char *original_name, *new_name; { #ifdef _SYS_DOS sf(ps,"copy %s %s",original_name,new_name); if (system(ps)==0) return(TRUE); else return(FALSE); #else if (rename(original_name,new_name)==-1) return(FALSE); else return(TRUE); #endif } bool fgoto_line(fp,index) FILE *fp; long index; { #ifdef REPLACE_FSEEK long fseekvalue= 0L; frewind(fp); run while (fseekvalue < index-1) { fgetln(help_file); fseekvalue+=len(ln)+1; } except_when(ENDOFILE) return(FALSE); return(TRUE); #endif return(fseek(fp,index,0)!=-1); } /***** random number functions *****/ long mkseed(x) long x; { if (x==RANDOM) return((long)time(NULL)); else return(x); } #ifdef USE_RANDOM void do_seedrand(x) long x; { srandom((int)mkseed(x)); } real randnum() { return(((real)random())/2147483648.0); } #else #ifdef USE_DRAND48 void do_seedrand(x) long x; { srand48(mkseed(x)); } real randnum() { return(drand48()); } #else /* USE_SRAND */ void do_seedrand(x) long x; { srand((int)mkseed(x)); } real randnum() { return(((real)rand())/((real)(RAND_MAX+1))); } #endif #endif /***** message and signal handling *****/ void untrapped_msg() /* DO NOT ASSUME THAT MSGNAME IS SET! */ { /* if (msg!=IOERROR) flush(); most are disk errors */ if (msg<1 || msg>MSGS) { fprintf(stderr, "Untrapped error %d (???)\n",msg); exit(1); } fprintf(stderr,"Untrapped error %d (%s)\n",msg,mname[msg]); (*(mstrmsg[msg]))(ps_); fprintf(stderr,ps_); fprintf(stderr,"\n"); } void trapped_msg() /* DO NOT ASSUME THAT MSGNAME IS SET! */ { /* if (msg!=IOERROR) flush(); most are disk errors */ if (msg<1 || msg>MSGS) { fprintf(stderr,"Error %d (???)\n",msg); exit(1); } fprintf(stderr,"Error %d (%s)\n",msg,mname[msg]); (*(mstrmsg[msg]))(ps_); fprintf(stderr,ps_); fprintf(stderr,"\n"); } #define SHUTDOWN1 "NOTE: In some extreme cases you may have to shut down and " #define SHUTDOWN2 "restart the\nprogram in order to resume proper operation. " #define SHUTDOWN3 "Hit to continue..." void verbose_untrapped_msg() /* DO NOT ASSUME THAT MSGNAME IS SET! */ { fprintf(stderr,"*** Drats! An unhandled internal error occured. ***\n"); if (msg<1 || msg>MSGS) { fprintf(stderr,"error #%d (???)\n",msg); exit(1); } else fprintf(stderr,"Error message #%d (%s) was sent.\n",msg,mname[msg]); (*(mstrmsg[msg]))(ps_); fprintf(stderr,ps_); if (!nullstr(ps_)) fprintf(stderr,"\n"); fprintf(stderr,SHUTDOWN1); fprintf(stderr,SHUTDOWN2); fprintf(stderr,SHUTDOWN3); fgets(ps_,MAXLINE,stdin); fprintf(stderr,"\n"); } void do_trap() { if (msg<1 || msg>MSGS) { fprintf(stderr,"Illegal trap message\n"); exit(1); } fprintf(stderr,"Trapped message %d (%s)\n",msg,mname[msg]); (*(mstrmsg[msg]))(ps_); fprintf(stderr,ps_); } int signals; void sigcounter() { signals++; if (signals>MAX_BAD_SIGNALS) send(CRASH); } void signal_trap_init() { signals=0; signal(SIGQUIT, handle_quit); /* ANSI Signals - for Microsoft C */ signal(SIGINT, handle_interrupt); signal(SIGFPE, handle_matherror); signal(SIGILL, handle_weird_signal); signal(SIGSEGV, handle_buserror); signal(SIGTERM, handle_quit); } /********************************** I/O *************************************/ void get_screen_preferences(); void tty_hello(); int old_term, old_lines, old_scrollback, old_more, dos_output; bool tried_curses, tried_wimp, tried_split, have_drawn_top; int tty_errors, file_errors, puts_errors; int curses, split, wimp, use_gnu_readline; /* externed global bools */ char **file_arg; int num_file_args, prep_it, append_it; bool do_gnu_readline(prompt,str,num) char *prompt, *str; int num; { #ifndef _GNU_READLINE send(CRASH); return(FALSE); #else char *result=NULL; result= readline(prompt); if (result==NULL) return(FALSE); /* EOF */ nstrcpy(str,result,num-2); add_history(str); free((char*)result); return(TRUE); #endif } bool do_gnu_edit(prompt,str,num,initial) char *prompt, *str; int num; char *initial; /* initial may be = str */ { #ifndef _GNU_READLINE send(CRASH); return(FALSE); #else char *result=NULL, *hist_entry=NULL; result= gnu_edit_this(prompt,initial); if (result==NULL) return(FALSE); /* EOF */ nstrcpy(str,result,num-2); add_history(str); free((char*)result); return(TRUE); #endif } bool gnu_copyright(str) char *str; /* side-effected, so it must be big enough */ { #ifndef _GNU_READLINE return(FALSE); #else if (!use_gnu_readline) return(FALSE); sf(str,"GNU Readline Copyright 1988-1989, Free Software Foundation"); return(TRUE); #endif } bool tty_gets(str, num) char *str; /* must be num+2 chars long, but use num<MAX_IO_FAILURES) send(CRASH); if ((n=ferror(in))!=0) ioerror(strerror(n),in,str); /* error */ if (feof(in)) return(FALSE); /* else must be EOF */ ioerror("fgets() failed",in,str); /* I dunno? */ } if(hit_interrupt) { str[0] = '\n'; str[1] = '\0'; } in_tty_gets = FALSE; cursor=0; printed_lines=0; if (str[0]=='\0' || str[len(str)-1]!='\n') { /* no \n => truncated */ if (++tty_errors>MAX_IO_FAILURES) send(CRASH); else ioerror("input line too long",in,str); } tty_errors= 0; return(TRUE); } bool file_gets(fp,str,num) FILE *fp; /* must be opened with file_open() */ char *str; /* must be num+2 chars long, but use num+3 in case of weirdness */ int num; /* num chars, not including the '\n' or '\0', will be read */ { int i, c, n; for (i=0; (c=fgetc(fp))!='\n'; i++) if (c==EOF) { /* error or EOF */ str[i]='\0'; if (++file_errors>MAX_IO_FAILURES) send(CRASH); else if (feof(fp)) { if (i==0) return(FALSE); else return(TRUE); } else if ((n=ferror(fp))!=0) { ioerror(strerror(n),fp,str); } else ioerror("fgetc() failed",fp,str); } else if (i==num-1) { str[i]='\0'; while ((c=fgetc(fp))!='\n') if (c==EOF) break; if (++file_errors>MAX_IO_FAILURES) send(CRASH); ioerror("input line too long",fp,str); } else { /* all is OK */ str[i]=c; continue; } str[i]='\0'; file_errors= 0; return(TRUE); } void lib_puts(fp,str) FILE *fp; char *str; { int i, n; char c; if (fp==NULL || str==NULL) send(CRASH); #ifdef HAVE_CURSES if (curses && fp==out) { curses_puts(str); } else #endif { for (i=0; (c=str[i])!='\0'; i++) { if (c=='\n' && dos_output && fp!=out && !xputc('\015',fp)) { if (++puts_errors>=MAX_IO_FAILURES) send(CRASH); if ((n=ferror(fp))!=0) ioerror(strerror(n),fp,str); else ioerror("xputc() failed",fp,str); } if (!xputc(c,fp)) { if (++puts_errors>=MAX_IO_FAILURES) send(CRASH); if ((n=ferror(fp))!=0) ioerror(strerror(n),fp,str); else ioerror("xputc() failed",fp,str); } } fflush(out); } puts_errors= 0; } void iocheck() { return; } void tty_init() { char *tty_type, *num_lines, copy[10], bp[1025]; int x; /* THIS HAS NO WIMP HOOK - IT SHOULD NEVER BE CALLED IF WIMP I/O IS USED! */ #ifdef TRY_ISATTY if (!isatty(fileno(stdin))) { interactive=FALSE; ignore_eof=FALSE; } if (!isatty(fileno(stdout))) { screen=FALSE; } #endif if (!screen) return; /* term=TERM_UNKNOWN, more_mode=scrollback=FALSE */ /* If we DO assume that a tty type has scrollback, we should NOT clear its screen, NOR should more_mode be on by default. If it does NOT have scrollback, we MAY clear its screen and might turn on more_mode (more mode will be way ugly w/o cursor motion however). In some sense, scrollback=TRUE is the conservative option.*/ #ifdef TRY_GETENV_TERM if ((tty_type=getenv("TERM"))!=NULL) { nstrcpy(copy,tty_type,9); crunch(copy); if (nstreq(copy,"hp",2)) { term=HP_TERM; scrollback=TRUE; tty_lines=24; } else if (nstreq(copy,"300h",4)) /* hp series 300 console */ { term=HP_TERM; scrollback= TRUE; tty_lines=46; } else if (nstreq(copy,"ansi",4) || nstreq(copy,"vt",2) || nstreq(copy,"dec",3) || nstreq(copy,"mac",3)) { term=ANSI; scrollback=TRUE; tty_lines=24; } else if (nstreq(copy,"xterm",5)) /* X-Windows terminal emulator */ { term=ANSI; scrollback=TRUE; tty_lines=24; } else if (nstreq(copy,"sun",3)) /* sun console/cmdtool/shelltool */ { term=ANSI; scrollback=TRUE; tty_lines=34; } else if (nstreq(copy,"pc",2)) /* pc console */ { term=ANSI; scrollback=FALSE; tty_lines=25; } #ifdef _GNU_READLINE /* the cmd-line override '-simple' sets this back to FALSE */ if (interactive) use_gnu_readline=TRUE; /* else was set to FALSE */ #endif #ifdef TRY_TERMCAP if (!nullstr(tty_type)) { tgetent(bp,tty_type); if ((x=tgetnum("li"))>0) tty_lines=x; } #endif } else /* can't getenv("TERM") */ #endif /* TRY_GETENV_TERM */ if (term==TERM_UNKNOWN) { /* either no TERM environment variable or its value is unknown */ use_gnu_readline=FALSE; /* it will fail anyway w/o TERM var */ if (DEFAULT_TERM_TYPE==HP_TERM) /* all HP_TERMs scrollback? */ { scrollback=TRUE; term=HP_TERM; tty_lines=24; } else if (DEFAULT_TERM_TYPE==SCROLLING_ANSI) { scrollback=TRUE; term=ANSI; tty_lines=24; } else if (DEFAULT_TERM_TYPE==NONSCROLLING_ANSI) { scrollback=FALSE; term=ANSI; tty_lines=24; } else if (DEFAULT_TERM_TYPE==PC_CONSOLE) { scrollback=FALSE; term=ANSI; tty_lines=25; } else if (DEFAULT_TERM_TYPE==MAC_WINDOW) { scrollback=FALSE; term=MAC_WINDOW; tty_lines=24; } else /* default is TERM_UNKNOWN terminal type */ { scrollback=TRUE; term=TERM_UNKNOWN; tty_lines=24; } } #ifdef TRY_GETENV_LINES if ((num_lines=getenv("LINES"))!=NULL && sscanf(num_lines,"%d",&x)==1) tty_lines=x; #endif check_tty_lines(); /* ioctl will always over-ride */ #ifdef DEFAULT_SCROLLBACK scrollback=DEFAULT_SCROLLBACK; /* override the settings above */ #endif /* if (term!=TERM_UNKNOWN) screen=TRUE; else screen=FALSE; */ } bool check_tty_lines() /* return TRUE and set tty_lines if changed */ { /* maybe add some weird PC thing here to get #lines */ #ifdef TRY_WINSIZE struct winsize thesize; if (screen && ioctl(fileno(stdout),TIOCGWINSZ,&thesize)==0) tty_lines= thesize.ws_row; #endif } /* Use lib_puts(out,...) (not print()) for these screen handling routines! flush() will be executed immediately beforehand.... */ int save_cursor; char Tcmd[100]; /* These have been tested on a Xterm and vt220 */ #define ansi_tty_init() lib_puts(out,"\033[0m\n") #define ansi_clr_scrn() lib_puts(out,"\033[1;1H\033[2J") #define ansi_highlight(on) lib_puts(out,on ? "\033[7m":"\033[0m") #define ansi_del_prev_ln() lib_puts(out,"\033[99D\033[K\033[1A\033[K") #define ansi_boing() lib_puts(out,"\007") void ansi_cursor_left(i,s) int i; char *s; { if(i<0) sf(Tcmd,"\033[99D\033[K%s",s); else sf(Tcmd,"\033[%dD\033[K%s",i,s); lib_puts(out,Tcmd); } #define hp_tty_init() lib_puts(out,"\n\033&d@\n") #define hp_clr_scrn() lib_puts(out,"\033H\033J") #define hp_highlight(on) lib_puts(out,on ? "\033&dB":"\033&d@") #define hp_del_prev_ln() lib_puts(out,"\033&a0C\033K\033A\033K") #define hp_boing() lib_puts(out,"\007") void hp_cursor_left(i,s) int i; char *s; { if(i<0) sf(Tcmd,"\033&a0C\033K%s",s); else sf(Tcmd,"\033&a-%dC\033K%s",i,s); lib_puts(out,Tcmd); } /* These should be filled in for the Mac's ThinkC "console package" */ #define mac_tty_init() printf("\n") /* printf() opens window */ #define mac_clr_scrn() {} #define mac_highlight(on) {} #define mac_del_prev_ln() {} #define mac_boing() {} void mac_cursor_left() {} void tty_hello() { if (term==HP_TERM) hp_tty_init(); else if (term==ANSI) ansi_tty_init(); else lib_puts(out,"\n"); if (!scrollback) { do_clear_screen(); lib_puts(out,"\n"); } #ifdef _GNU_READLINE if (use_gnu_readline) rl_bind_key('\t', rl_insert); /* completion off */ #endif } bool do_clear_screen() { /* NEEDS WIMP AND MAC CONSOLE HOOK */ if (term==HP_TERM) { hp_clr_scrn(); fflush(out); return(TRUE); } else if (term==ANSI) { ansi_clr_scrn(); fflush(out); return(TRUE); } #ifdef HAVE_CURSES else if (term==CURSES) { curses_clr_scrn(); return(TRUE); } #endif else return(FALSE); } bool do_delete_previous_line() /* Needed for the "Hit RETURN for more" thing */ { /* NEEDS WIMP AND MAC CONSOLE HOOK */ if (term==HP_TERM) { hp_del_prev_ln(); fflush(out); return(TRUE); } else if (term==ANSI) { ansi_del_prev_ln(); fflush(out); return(TRUE); } #ifdef HAVE_CURSES else if (term==CURSES) { curses_del_prev_ln(); return(TRUE); } #endif else return(FALSE); } bool do_highlight(reverse) bool reverse; { /* NEEDS WIMP AND MAC CONSOLE HOOK */ #ifdef HAVE_CURSES if (term==CURSES) { curses_set_highlight(reverse); return(TRUE); } #endif if (term==HP_TERM) { hp_highlight(reverse); fflush(out); return(TRUE); } else if (term==ANSI) { ansi_highlight(reverse);fflush(out); return(TRUE); } else return(FALSE); } bool do_cursor_left(num_spaces,str_to_print) int num_spaces; /* might be FAR_LEFT */ char *str_to_print; { /* NEEDS WIMP AND MAC CONSOLE HOOK */ if (term==HP_TERM) { hp_cursor_left(num_spaces,str_to_print); } else if (term==ANSI) { ansi_cursor_left(num_spaces,str_to_print); } #ifdef HAVE_CURSES else if (term==CURSES) { curses_cursor_left(num_spaces,str_to_print); } #endif else return(FALSE); return(TRUE); } bool boing() { /* NEEDS WIMP AND MAC CONSOLE HOOK */ if (term==HP_TERM) { hp_boing(); return(TRUE); } else if (term==ANSI) { ansi_boing(); return(TRUE); } #ifdef HAVE_CURSES else if (term==CURSES) { curses_boing(); return(TRUE); } #endif else return(FALSE); } /****************************** TOPLEVEL STUFF ******************************/ void misc_init() /* init this file */ { int i; matrix(file_arg,MAX_FILE_ARGS,PATH_LENGTH+1,char); for (i=0; i