1 /******************************************************************************
2 
3   ####    #   #   ####    ####    ####   #####   ######           ####
4  #         # #   #       #    #  #    #  #    #  #               #    #
5   ####      #     ####   #       #    #  #    #  #####           #
6       #     #         #  #       #    #  #    #  #        ###    #
7  #    #     #    #    #  #    #  #    #  #    #  #        ###    #    #
8   ####      #     ####    ####    ####   #####   ######   ###     ####
9 
10 ******************************************************************************/
11 /* This file is part of MAPMAKER 3.0b, Copyright 1987-1992, Whitehead Institute
12    for Biomedical Research. All rights reserved. See READ.ME for license. */
13 
14 /**************** SYSCODE.C - SYSTEM SPECIFIC CODE ***************************/
15 /* Most of this file is doccumented in system.h - it contains most of the
16    system dependent code for the helpers library. */
17 
18 #define INC_LIB
19 #define INC_EQN
20 #define INC_HELP_DEFS
21 #include "system.h"
22 
23 #ifdef _GNU_READLINE
24 #include "readline/readline.h"
25 #include "readline/history.h"
26 #endif
27 
28 /*********************** C-Library Extensions ********************************/
29 
30 /***** Time functions *****/
31 /* Note that time() and ctime() seem to be the only portable time functions.
32    However, time() returns different types with different C compilers! */
33 
34 TIME_TYPE old_stamp, new_stamp;   /* For local use only! */
35 
usertime(do_reset)36 real usertime(do_reset) /* return time in seconds, or -1.0 if fail */
37 bool do_reset;
38 {
39     real rtime;
40     new_stamp= time((TIME_TYPE *)NULL); rtime= (real)(new_stamp - old_stamp);
41     if (do_reset) old_stamp= new_stamp;
42     return(rtime);
43 }
44 
time_string()45 char *time_string()    /* return ptr to "" if fail */
46 {
47     TIME_TYPE the_time;  /* note that asctime() does not always exist */
48     char *str;
49     int end;
50 
51     the_time=time((TIME_TYPE *)NULL);
52     str=ctime(&the_time);
53     if (str==NULL) return(ptr_to(""));
54     end=len(str)-1;
55     if (str[end]=='\n') str[end]='\0';
56     return(str);
57 }
58 
59 
60 /***** subprocess functions *****/
61 
62 
shell_command(cmd)63 bool shell_command(cmd)
64 char *cmd;
65 {
66     bool success, had_curses;
67     success=FALSE;
68 
69 #ifdef NO_SYSTEM_FUNC
70     return(FALSE);
71 #else
72 /* NEED WIMP HOOK */
73 #ifdef HAVE_CURSES
74     had_curses= curses;
75     if (curses) curses_end();  /* DO SOMETHING */
76 #endif
77 #ifndef VMS
78     if (system(cmd)==0) success=TRUE;
79 #endif
80 #ifdef VMS
81     if (system(cmd)!=0) success=TRUE;
82 #endif
83 #ifdef HAVE_CURSES
84     if (success && had_curses) curses_refresh();
85 #endif
86     return(success);
87 #endif
88 }
89 
90 
subshell()91 bool subshell()
92 {
93         char *shell_name, cmd[120];
94 	bool success=FALSE, had_curses;
95 
96 #ifdef NO_SYSTEM_FUNC
97     return(FALSE);
98 #else
99 /* NEED WIMP HOOK */
100 #ifdef HAVE_CURSES
101 	had_curses= curses;
102 	if (curses) curses_end();  /* DO SOMETHING */
103 #endif
104 #ifdef TRY_SHELL_VAR
105 	if ((shell_name=getenv("SHELL"))!=NULL && !nullstr(shell_name)) {
106 	    nstrcpy(cmd,shell_name,100); /* maxstrcat(cmd," -i",110); why? */
107 	    if (system(cmd)==0) success=TRUE;
108 	}
109 #endif
110 #ifdef TRY_COMSPEC_VAR
111 	if (!success && (shell_name=getenv("COMSPEC"))!=NULL &&
112 	    !nullstr(shell_name)) {
113 	    if (system(shell_name)==0) success=TRUE;
114 	}
115 #endif
116 #ifdef TRY_SHELL_CMD
117 	if (!success && !nullstr(TRY_SHELL_CMD)) {
118 	    if (system(TRY_SHELL_CMD)==0) success=TRUE;
119 	}
120 #endif
121 #ifdef HAVE_CURSES
122 	if (success && had_curses) curses_refresh();
123 #endif
124 	return(success);
125 #endif
126 }
127 
128 
129 /***** get/set directories *****/
130 
change_directory(dir)131 bool change_directory(dir)
132 char *dir;
133 {
134     if (dir==NULL) send(CRASH);
135 #ifdef HAVE_CHDIR
136     if (chdir(dir)==0) return(TRUE);
137 #endif
138     return(FALSE);
139 }
140 
get_directory(buf)141 bool get_directory(buf)
142 char *buf;
143 {
144     if (buf==NULL) send(CRASH);
145 #ifdef HAVE_GETCWD
146     if (getcwd(buf,PATH_LENGTH-2)!=NULL) return(TRUE);
147 #endif
148     return(FALSE);
149 }
150 
get_home_directory(buf)151 bool get_home_directory(buf)
152 char *buf;
153 {
154     char *dir;
155     if (buf==NULL) send(CRASH);
156 #ifdef HAVE_GETENV
157     if ((dir=getenv("HOME"))!=NULL)
158       { nstrcpy(buf,dir,PATH_LENGTH); return(TRUE); }
159 #endif
160     return(FALSE);
161 }
162 
get_code_directory(buf)163 bool get_code_directory(buf)
164 char *buf;
165 {
166     char *dir;
167     if (buf==NULL) send(CRASH);
168 #ifdef HAVE_GETENV
169     if ((dir=getenv("MAPM_LIB"))!=NULL)
170       { nstrcpy(buf,dir,PATH_LENGTH); return(TRUE); }
171 #endif
172 #ifdef _CODE_DIR /* compiled in default */
173     if (!nullstr(_CODE_DIR))
174       { nstrcpy(buf,_CODE_DIR,PATH_LENGTH); return(TRUE); }
175 #endif
176     return(FALSE);
177 }
178 
rename_file(original_name,new_name)179 bool rename_file(original_name,new_name)
180 char *original_name, *new_name;
181 {
182 #ifdef _SYS_DOS
183     sf(ps,"copy %s %s",original_name,new_name);
184     if (system(ps)==0) return(TRUE);
185     else return(FALSE);
186 #else
187     if (rename(original_name,new_name)==-1) return(FALSE);
188     else return(TRUE);
189 #endif
190 }
191 
192 
fgoto_line(fp,index)193 bool fgoto_line(fp,index)
194 FILE *fp;
195 long index;
196 {
197 #ifdef REPLACE_FSEEK
198     long fseekvalue= 0L;
199     frewind(fp);
200     run while (fseekvalue < index-1) {
201 	fgetln_(help_file);
202 	fseekvalue+=len(ln)+1;
203     } except_when(ENDOFILE) return(FALSE);
204     return(TRUE);
205 #endif
206     return(fseek(fp,index,0)!=-1);
207 }
208 
209 /***** random number functions *****/
210 
mkseed(x)211 long mkseed(x) long x;
212 { if (x==RANDOM) return((long)time(NULL)); else return(x); }
213 
214 #ifdef USE_RANDOM
do_seedrand(x)215 void do_seedrand(x) long x; { srandom((int)mkseed(x)); }
randnum()216 real randnum() { return(((real)random())/2147483648.0); }
217 #else
218 #ifdef USE_DRAND48
do_seedrand(x)219 void do_seedrand(x) long x; { srand48(mkseed(x)); }
randnum()220 real randnum() { return(drand48()); }
221 #else /* USE_SRAND */
do_seedrand(x)222 void do_seedrand(x) long x; { srand((int)mkseed(x)); }
randnum()223 real randnum() { return(((real)rand())/((real)(RAND_MAX+1))); }
224 #endif
225 #endif
226 
227 
228 /***** message and signal handling *****/
229 
untrapped_msg()230 void untrapped_msg() /* DO NOT ASSUME THAT MSGNAME IS SET! */
231 {
232     /* if (msg!=IOERROR) flush(); most are disk errors */
233     if (msg<1 || msg>MSGS)
234       { fprintf(stderr, "Untrapped error %d (???)\n",msg); exit(1); }
235     fprintf(stderr,"Untrapped error %d (%s)\n",msg,mname[msg]);
236     (*(mstrmsg[msg]))(ps_); fprintf(stderr,ps_); fprintf(stderr,"\n");
237 }
238 
trapped_msg()239 void trapped_msg() /* DO NOT ASSUME THAT MSGNAME IS SET! */
240 {
241     /* if (msg!=IOERROR) flush(); most are disk errors */
242     if (msg<1 || msg>MSGS)
243       { fprintf(stderr,"Error %d (???)\n",msg); exit(1); }
244     fprintf(stderr,"Error %d (%s)\n",msg,mname[msg]);
245     (*(mstrmsg[msg]))(ps_); fprintf(stderr,ps_); fprintf(stderr,"\n");
246 }
247 
248 #define SHUTDOWN1 "NOTE: In some extreme cases you may have to shut down and "
249 #define SHUTDOWN2 "restart the\nprogram in order to resume proper operation. "
250 #define SHUTDOWN3 "Hit <return> to continue..."
251 
verbose_untrapped_msg()252 void verbose_untrapped_msg() /* DO NOT ASSUME THAT MSGNAME IS SET! */
253 {
254   fprintf(stderr,"*** Drats! An unhandled internal error occured. ***\n");
255   if (msg<1 || msg>MSGS) { fprintf(stderr,"error #%d (???)\n",msg); exit(1); }
256     else fprintf(stderr,"Error message #%d (%s) was sent.\n",msg,mname[msg]);
257   (*(mstrmsg[msg]))(ps_); fprintf(stderr,ps_);
258   if (!nullstr(ps_)) fprintf(stderr,"\n");
259   fprintf(stderr,SHUTDOWN1); fprintf(stderr,SHUTDOWN2);
260   fprintf(stderr,SHUTDOWN3); fgets(ps_,MAXLINE,stdin);
261   fprintf(stderr,"\n");
262 }
263 
do_trap()264 void do_trap()
265 {
266   if (msg<1 || msg>MSGS)
267       { fprintf(stderr,"Illegal trap message\n"); exit(1); }
268   fprintf(stderr,"Trapped message %d (%s)\n",msg,mname[msg]);
269   (*(mstrmsg[msg]))(ps_); fprintf(stderr,ps_);
270 }
271 
272 
273 int signals;
274 
sigcounter()275 void sigcounter()
276 { signals++; if (signals>MAX_BAD_SIGNALS) send(CRASH); }
277 
278 
signal_trap_init()279 void signal_trap_init()
280 {
281   signals=0;
282 
283   signal(SIGQUIT, handle_quit);		/* ANSI Signals - for Microsoft C */
284   signal(SIGINT,  handle_interrupt);
285   signal(SIGFPE,  handle_matherror);
286   signal(SIGILL,  handle_weird_signal);
287   signal(SIGSEGV, handle_buserror);
288   signal(SIGTERM, handle_quit);
289 }
290 
291 
292 
293 /********************************** I/O *************************************/
294 
295 void get_screen_preferences();
296 void tty_hello();
297 
298 int old_term, old_lines, old_scrollback, old_more, dos_output;
299 bool tried_curses, tried_wimp, tried_split, have_drawn_top;
300 int tty_errors, file_errors, puts_errors;
301 int curses, split, wimp, use_gnu_readline; /* externed global bools */
302 char **file_arg;
303 int num_file_args, prep_it, append_it;
304 
305 
do_gnu_readline(prompt,str,num)306 bool do_gnu_readline(prompt,str,num)
307 char *prompt, *str;
308 int num;
309 {
310 #ifndef _GNU_READLINE
311     send(CRASH);
312     return(FALSE);
313 #else
314     char *result=NULL;
315 
316     result= readline(prompt);
317     if (result==NULL) return(FALSE); /* EOF */
318 
319     nstrcpy(str,result,num-2);
320     add_history(str);
321     free((char*)result);
322     return(TRUE);
323 #endif
324 }
325 
326 
do_gnu_edit(prompt,str,num,initial)327 bool do_gnu_edit(prompt,str,num,initial)
328 char *prompt, *str;
329 int num;
330 char *initial; /* initial may be = str */
331 {
332 #ifndef _GNU_READLINE
333     send(CRASH);
334     return(FALSE);
335 #else
336     char *result=NULL, *hist_entry=NULL;
337 
338     result= gnu_edit_this(prompt,initial);
339     if (result==NULL) return(FALSE); /* EOF */
340 
341     nstrcpy(str,result,num-2);
342     add_history(str);
343     free((char*)result);
344     return(TRUE);
345 #endif
346 }
347 
348 
gnu_copyright(str)349 bool gnu_copyright(str)
350 char *str; /* side-effected, so it must be big enough */
351 {
352 #ifndef _GNU_READLINE
353     return(FALSE);
354 #else
355     if (!use_gnu_readline) return(FALSE);
356     sf(str,"GNU Readline Copyright 1988-1989, Free Software Foundation");
357     return(TRUE);
358 #endif
359 }
360 
361 
tty_gets(str,num)362 bool tty_gets(str, num)
363 char *str;  /* must be num+2 chars long, but use num<<len just in case */
364 int num;    /* num chars, not including the '\n' or '\0', will be read */
365 /* May send IOERROR, or (hopefully never) CRASH. Return FALSE on EOF.
366    In general, we probably want num to be huge (eg: MAXLINE),
367       as exceeding it causes an I/O error message to be sent.
368    If fgets() works correctly, then line should be valid on EOF, although
369       FALSE is still returned. The operating system is responsible for
370       any post-processing. */
371 {
372     int n, i;
373 
374     in_tty_gets = TRUE; hit_interrupt = FALSE;
375 
376     if (num<2) send(CRASH);
377     for (i=0; i<num+2; i++) str[i]='\0';      /* To get ok string if EOF */
378 
379     if (fgets(str,num+1,in)==NULL) {         /* EOF or error */
380 	str[num]='\0';                       /* in case fgets() is weird */
381 	if (++tty_errors>MAX_IO_FAILURES) send(CRASH);
382 	if ((n=ferror(in))!=0) ioerror(strerror(n),in,str); /* error */
383 	if (feof(in)) return(FALSE);         /* else must be EOF */
384 	ioerror("fgets() failed",in,str);    /* I dunno? */
385     }
386 
387     if(hit_interrupt) { str[0] = '\n'; str[1] = '\0'; }
388     in_tty_gets = FALSE;
389 
390     cursor=0; printed_lines=0;
391     if (str[0]=='\0' || str[len(str)-1]!='\n') { /* no \n => truncated */
392 	if (++tty_errors>MAX_IO_FAILURES) send(CRASH);
393 	else ioerror("input line too long",in,str);
394     }
395     tty_errors= 0;
396     return(TRUE);
397 }
398 
399 
file_gets(fp,str,num)400 bool file_gets(fp,str,num)
401 FILE *fp;   /* must be opened with file_open() */
402 char *str;  /* must be num+2 chars long, but use num+3 in case of weirdness */
403 int num;    /* num chars, not including the '\n' or '\0', will be read */
404 {
405     int i, c, n;
406 
407     for (i=0; (c=fgetc(fp))!='\n'; i++)
408       if (c==EOF) { /* error or EOF */
409 	  str[i]='\0';
410 	  if (++file_errors>MAX_IO_FAILURES) send(CRASH);
411 	  else if (feof(fp)) { if (i==0) return(FALSE); else return(TRUE); }
412 	  else if ((n=ferror(fp))!=0) { ioerror(strerror(n),fp,str); }
413 	  else ioerror("fgetc() failed",fp,str);
414       } else if (i==num-1) {
415 	  str[i]='\0';
416 	  while ((c=fgetc(fp))!='\n') if (c==EOF) break;
417 	  if (++file_errors>MAX_IO_FAILURES) send(CRASH);
418 	  ioerror("input line too long",fp,str);
419       } else { /* all is OK */
420 	  str[i]=c; continue;
421       }
422     str[i]='\0';
423     file_errors= 0;
424     return(TRUE);
425 }
426 
427 
lib_puts(fp,str)428 void lib_puts(fp,str)
429 FILE *fp;
430 char *str;
431 {
432     int i, n;
433     char c;
434 
435     if (fp==NULL || str==NULL) send(CRASH);
436 #ifdef HAVE_CURSES
437     if (curses && fp==out) { curses_puts(str); } else
438 #endif
439     {
440 	for (i=0; (c=str[i])!='\0'; i++) {
441 	    if (c=='\n' && dos_output && fp!=out && !xputc('\015',fp)) {
442 		if (++puts_errors>=MAX_IO_FAILURES) send(CRASH);
443 		if ((n=ferror(fp))!=0) ioerror(strerror(n),fp,str);
444 		else ioerror("xputc() failed",fp,str);
445 	    }
446 	    if (!xputc(c,fp)) {
447 		if (++puts_errors>=MAX_IO_FAILURES) send(CRASH);
448 		if ((n=ferror(fp))!=0) ioerror(strerror(n),fp,str);
449 		else ioerror("xputc() failed",fp,str);
450 	    }
451 	}
452 	fflush(out);
453     }
454     puts_errors= 0;
455 }
456 
457 
iocheck()458 void iocheck() { return; }
459 
460 
tty_init()461 void tty_init()
462 {
463     char *tty_type, *num_lines, copy[10], bp[1025];
464     int x;
465 
466 /* THIS HAS NO WIMP HOOK - IT SHOULD NEVER BE CALLED IF WIMP I/O IS USED! */
467 
468 #ifdef TRY_ISATTY
469     if (!isatty(fileno(stdin)))  { interactive=FALSE; ignore_eof=FALSE; }
470     if (!isatty(fileno(stdout))) { screen=FALSE; }
471 #endif
472     if (!screen) return; /* term=TERM_UNKNOWN, more_mode=scrollback=FALSE */
473 
474 /* If we DO assume that a tty type has scrollback, we should NOT clear
475 its screen, NOR should more_mode be on by default. If it does NOT have
476 scrollback, we MAY clear its screen and might turn on more_mode (more
477 mode will be way ugly w/o cursor motion however). In some sense,
478 scrollback=TRUE is the conservative option.*/
479 
480 #ifdef TRY_GETENV_TERM
481     if ((tty_type=getenv("TERM"))!=NULL) {
482 	nstrcpy(copy,tty_type,9); crunch(copy);
483 	if (nstreq(copy,"hp",2))
484 	  { term=HP_TERM; scrollback=TRUE; tty_lines=24; }
485 	else if (nstreq(copy,"300h",4)) /* hp series 300 console */
486 	  { term=HP_TERM; scrollback= TRUE; tty_lines=46; }
487 	else if (nstreq(copy,"ansi",4) || nstreq(copy,"vt",2) ||
488 		 nstreq(copy,"dec",3)  || nstreq(copy,"mac",3))
489 	  { term=ANSI; scrollback=TRUE; tty_lines=24; }
490 	else if (nstreq(copy,"xterm",5)) /* X-Windows terminal emulator */
491 	  { term=ANSI; scrollback=TRUE; tty_lines=24; }
492 	else if (nstreq(copy,"sun",3)) /* sun console/cmdtool/shelltool */
493 	  { term=ANSI; scrollback=TRUE; tty_lines=34; }
494 	else if (nstreq(copy,"pc",2)) /* pc console */
495 	  { term=ANSI; scrollback=FALSE; tty_lines=25; }
496 #ifdef _GNU_READLINE
497     /* the cmd-line override '-simple' sets this back to FALSE */
498     if (interactive) use_gnu_readline=TRUE; /* else was set to FALSE */
499 #endif
500 #ifdef TRY_TERMCAP
501     if (!nullstr(tty_type)) {
502 	tgetent(bp,tty_type);
503 	if ((x=tgetnum("li"))>0) tty_lines=x;
504     }
505 #endif
506     } else /* can't getenv("TERM") */
507 #endif /* TRY_GETENV_TERM */
508 
509     if (term==TERM_UNKNOWN) {
510 	/* either no TERM environment variable or its value is unknown */
511 	use_gnu_readline=FALSE; /* it will fail anyway w/o TERM var */
512 	if (DEFAULT_TERM_TYPE==HP_TERM) /* all HP_TERMs scrollback? */
513 	  { scrollback=TRUE; term=HP_TERM; tty_lines=24; }
514 	else if (DEFAULT_TERM_TYPE==SCROLLING_ANSI)
515 	  { scrollback=TRUE; term=ANSI; tty_lines=24; }
516 	else if (DEFAULT_TERM_TYPE==NONSCROLLING_ANSI)
517 	  { scrollback=FALSE; term=ANSI; tty_lines=24; }
518 	else if (DEFAULT_TERM_TYPE==PC_CONSOLE)
519 	  { scrollback=FALSE; term=ANSI; tty_lines=25; }
520 	else if (DEFAULT_TERM_TYPE==MAC_WINDOW)
521 	  { scrollback=FALSE; term=MAC_WINDOW;  tty_lines=24; }
522 	else /* default is TERM_UNKNOWN terminal type */
523 	  { scrollback=TRUE; term=TERM_UNKNOWN; tty_lines=24; }
524     }
525 
526 #ifdef TRY_GETENV_LINES
527     if ((num_lines=getenv("LINES"))!=NULL && sscanf(num_lines,"%d",&x)==1)
528       tty_lines=x;
529 #endif
530     check_tty_lines(); /* ioctl will always over-ride */
531 #ifdef DEFAULT_SCROLLBACK
532     scrollback=DEFAULT_SCROLLBACK;  /* override the settings above */
533 #endif
534     /* if (term!=TERM_UNKNOWN) screen=TRUE; else screen=FALSE; */
535 }
536 
537 
check_tty_lines()538 bool check_tty_lines() /* return TRUE and set tty_lines if changed */
539 {
540 /* maybe add some weird PC thing here to get #lines */
541 #ifdef TRY_WINSIZE
542     struct winsize thesize;
543     if (screen && ioctl(fileno(stdout),TIOCGWINSZ,&thesize)==0)
544       tty_lines= thesize.ws_row;
545 #endif
546 }
547 
548 
549 /* Use lib_puts(out,...) (not print()) for these screen handling routines!
550    flush() will be executed immediately beforehand.... */
551 
552 int save_cursor;
553 char Tcmd[100];
554 
555 /* These have been tested on a Xterm and vt220 */
556 #define ansi_tty_init()      lib_puts(out,"\033[0m\n")
557 #define ansi_clr_scrn()      lib_puts(out,"\033[1;1H\033[2J")
558 #define ansi_highlight(on)   lib_puts(out,on ? "\033[7m":"\033[0m")
559 #define ansi_del_prev_ln()   lib_puts(out,"\033[99D\033[K\033[1A\033[K")
560 #define ansi_boing()         lib_puts(out,"\007")
ansi_cursor_left(i,s)561 void ansi_cursor_left(i,s) int i; char *s;
562 { if(i<0) sf(Tcmd,"\033[99D\033[K%s",s); else sf(Tcmd,"\033[%dD\033[K%s",i,s);
563   lib_puts(out,Tcmd); }
564 
565 #define hp_tty_init()        lib_puts(out,"\n\033&d@\n")
566 #define hp_clr_scrn()        lib_puts(out,"\033H\033J")
567 #define hp_highlight(on)     lib_puts(out,on ? "\033&dB":"\033&d@")
568 #define hp_del_prev_ln()     lib_puts(out,"\033&a0C\033K\033A\033K")
569 #define hp_boing()           lib_puts(out,"\007")
hp_cursor_left(i,s)570 void hp_cursor_left(i,s) int i; char *s;
571 { if(i<0) sf(Tcmd,"\033&a0C\033K%s",s); else sf(Tcmd,"\033&a-%dC\033K%s",i,s);
572   lib_puts(out,Tcmd); }
573 
574 /* These should be filled in for the Mac's ThinkC "console package" */
575 #define mac_tty_init()   	printf("\n") /* printf() opens window */
576 #define mac_clr_scrn()      	{}
577 #define mac_highlight(on)   	{}
578 #define mac_del_prev_ln()   	{}
579 #define mac_boing()       	{}
mac_cursor_left()580 void mac_cursor_left()		{}
581 
tty_hello()582 void tty_hello()
583 {
584     if (term==HP_TERM) hp_tty_init();
585     else if (term==ANSI) ansi_tty_init();
586     else lib_puts(out,"\n");
587     if (!scrollback) { do_clear_screen(); lib_puts(out,"\n"); }
588 
589 #ifdef _GNU_READLINE
590     if (use_gnu_readline) rl_bind_key('\t', rl_insert); /* completion off */
591 #endif
592 }
593 
594 
do_clear_screen()595 bool do_clear_screen()
596 {
597 /* NEEDS WIMP AND MAC CONSOLE HOOK */
598     if (term==HP_TERM)     { hp_clr_scrn();   fflush(out); return(TRUE); }
599     else if (term==ANSI)   { ansi_clr_scrn(); fflush(out); return(TRUE); }
600 #ifdef HAVE_CURSES
601     else if (term==CURSES) { curses_clr_scrn(); return(TRUE); }
602 #endif
603     else return(FALSE);
604 }
605 
606 
do_delete_previous_line()607 bool do_delete_previous_line() /* Needed for the "Hit RETURN for more" thing */
608 {
609 /* NEEDS WIMP AND MAC CONSOLE HOOK */
610     if (term==HP_TERM)     { hp_del_prev_ln();   fflush(out); return(TRUE); }
611     else if (term==ANSI)   { ansi_del_prev_ln(); fflush(out); return(TRUE); }
612 #ifdef HAVE_CURSES
613     else if (term==CURSES) { curses_del_prev_ln(); return(TRUE); }
614 #endif
615     else return(FALSE);
616 }
617 
618 
do_highlight(reverse)619 bool do_highlight(reverse)
620 bool reverse;
621 {
622 /* NEEDS WIMP AND MAC CONSOLE HOOK */
623 #ifdef HAVE_CURSES
624     if (term==CURSES)    { curses_set_highlight(reverse); return(TRUE); }
625 #endif
626     if (term==HP_TERM)   { hp_highlight(reverse);  fflush(out); return(TRUE); }
627     else if (term==ANSI) { ansi_highlight(reverse);fflush(out); return(TRUE); }
628     else return(FALSE);
629 }
630 
631 
do_cursor_left(num_spaces,str_to_print)632 bool do_cursor_left(num_spaces,str_to_print)
633 int num_spaces; /* might be FAR_LEFT */
634 char *str_to_print;
635 {
636 /* NEEDS WIMP AND MAC CONSOLE HOOK */
637     if (term==HP_TERM)     { hp_cursor_left(num_spaces,str_to_print); }
638     else if (term==ANSI)   { ansi_cursor_left(num_spaces,str_to_print); }
639 #ifdef HAVE_CURSES
640     else if (term==CURSES) { curses_cursor_left(num_spaces,str_to_print); }
641 #endif
642     else return(FALSE);
643     return(TRUE);
644 }
645 
646 
boing()647 bool boing()
648 {
649 /* NEEDS WIMP AND MAC CONSOLE HOOK */
650     if (term==HP_TERM)     { hp_boing(); return(TRUE); }
651     else if (term==ANSI)   { ansi_boing(); return(TRUE); }
652 #ifdef HAVE_CURSES
653     else if (term==CURSES) { curses_boing(); return(TRUE); }
654 #endif
655     else return(FALSE);
656 }
657 
658 
659 /****************************** TOPLEVEL STUFF ******************************/
660 
misc_init()661 void misc_init() /* init this file */
662 {
663     int i;
664     matrix(file_arg,MAX_FILE_ARGS,PATH_LENGTH+1,char);
665     for (i=0; i<MAX_FILE_ARGS; i++) file_arg[i][0]='\0';
666     old_stamp=new_stamp=time(NULL); dos_output=FALSE;
667 }
668 
669 
custom_lib_init()670 void custom_lib_init()
671 {
672 /* These init routines shouldn't really DO much - they really are meant for
673    initializing variables, mallocing structures, and so forth. Serious work
674    (for ex kicking off fancy screen I/O) should happen elsewhere. */
675 
676     mem_init();  /* memlib.c */
677     msg_init();  /* msglib.c */
678     io_init();   /* iolib.c - just allocates things etc for the I/O lib */
679     str_init();  /* strlib.c */
680     math_init(); /* mathlib.c */
681     eqn_init();  /* eqn.c */
682     misc_init(); /* syscode.c (this file, dummy) */
683     tty_init();  /* also in this file */
684 }
685 
lib_init()686 void lib_init()
687 {
688     custom_lib_init();
689     tty_hello();
690 }
691 
lib_inits(argc_ptr,argv)692 void lib_inits(argc_ptr,argv)
693 int *argc_ptr;
694 char *argv[];
695 {
696     custom_lib_init();
697     /* if (!screen_init(argc_ptr,argv)) */
698     get_cmd_line_args(argc_ptr,argv);
699     tty_hello();
700 }
701 
702 
703 /* This is a little specialized for MAPMAKER right now. Generalize soon... */
704 #define ERROR_BADARG \
705   "%s error: unrecognized option '%s'\ntype '%s -help' for help\n"
706 #define ERROR_ONEFILE   "%s error: only one %s argument allowed\n"
707 #define ERROR_BADFILE   "%s error: bad %s file name '%s'\n"
708 #define ERROR_NOFILE    "%s error: can't open %s file '%s'\n"
709 #define ERROR_EMPTYFILE "%s error: %s file '%s' is empty\n"
710 #define ERROR_NOTSCREEN "%s error: output is not a terminal, can't use %s\n"
711 #define HELP_ARG_MSG "\
712 %s optional arguments: [%csimple] [%cnomore] [%cclear] [%chelp] \n\
713   [%cload file] [%cprep file] [%crun file] [%cphoto file] [%cout file]\n\
714 run %s and type 'help' for help with commands and other information \n"
715 
716 #define NOTSCREEN_ \
717 { fprintf(stderr,ERROR_NOTSCREEN,argv[0],argv[i]); abnormal_exit(); }
718 
get_cmd_line_args(argc_ptr,argv)719 void get_cmd_line_args(argc_ptr,argv)
720 int *argc_ptr;
721 char *argv[];
722 {
723     int i, n;
724 
725     for (i=1; i<*argc_ptr; i++) {
726 	if (argv[i][0]!=ARG_CHAR) {
727 	    fprintf(stderr,ERROR_BADARG,argv[0],argv[i],argv[0]);
728 	    abnormal_exit();
729 
730 	} else if (matches(argv[i]+1,"simple")) {
731 	    if (!screen) NOTSCREEN_
732 	      term=TERM_UNKNOWN; use_gnu_readline=FALSE;
733 	    argv[i][0]='\0';
734 	} else if (matches(argv[i]+1,"nomore")) {
735 	    if (!screen) NOTSCREEN_
736 	      more_mode=FALSE;
737 	    argv[i][0]='\0';
738 	} else if (matches(argv[i]+1,"clear")) {
739 	    if (!screen) NOTSCREEN_
740 	      if (term==PC_CONSOLE) scrollback=TRUE; else scrollback=FALSE;
741 	    argv[i][0]='\0';
742 
743 	} else if (matches(argv[i]+1,"load")) {
744 	    check_file_arg(*argc_ptr-i,argv[i+1],file_arg[LOAD_FILE_ARG],
745 			   WRS("load"),WRS("data"),argv[0],READ);
746 	    prep_it=FALSE;
747 	    argv[i++][0]='\0'; argv[i][0]='\0';
748 	} else if (matches(argv[i]+1,"prep")) {
749 	    check_file_arg(*argc_ptr-i,argv[i+1],file_arg[LOAD_FILE_ARG],
750 			   WRS("prep"),WRS("raw"),argv[0],READ);
751 	    prep_it=TRUE;
752 	    argv[i++][0]='\0'; argv[i][0]='\0';
753 	} else if (matches(argv[i]+1,"run")) {
754 	    check_file_arg(*argc_ptr-i,argv[i+1],file_arg[RUN_FILE_ARG],
755 			   WRS("run"),WRS("in"),argv[0],READ);
756 	    argv[i++][0]='\0'; argv[i][0]='\0';
757 	} else if (matches(argv[i]+1,"photo")) {
758 	    check_file_arg(*argc_ptr-i,argv[i+1],file_arg[PHOTO_FILE_ARG],
759 			   WRS("photo"),WRS("out"),argv[0],APPEND);
760 	    append_it=TRUE;
761 	    argv[i++][0]='\0'; argv[i][0]='\0';
762 	} else if (matches(argv[i]+1,"out")) {
763 	    check_file_arg(*argc_ptr-i,argv[i+1],file_arg[PHOTO_FILE_ARG],
764 			   WRS("photo"),WRS("out"),argv[0],WRITE);
765 	    append_it=FALSE;
766 	    argv[i++][0]='\0'; argv[i][0]='\0';
767 	} else if (matches(argv[i]+1,"help")) {
768 	    fprintf(stderr,HELP_ARG_MSG,argv[0],ARG_CHAR,ARG_CHAR,ARG_CHAR,
769 		    ARG_CHAR,ARG_CHAR,ARG_CHAR,ARG_CHAR,ARG_CHAR,ARG_CHAR,
770 		    argv[0]);
771 	    normal_exit();
772 
773 	} else {
774 	    fprintf(stderr,ERROR_BADARG,argv[0],argv[i],argv[0]);
775 	    abnormal_exit();
776 	}
777     }
778 }
779 
780 
check_file_arg(num,arg,name,type,def_ext,prog,mode)781 bool check_file_arg(num,arg,name,type,def_ext,prog,mode)
782 int num;
783 char *arg, *name, *type, *def_ext, *prog, *mode;
784 {
785     char file[PATH_LENGTH+1];
786     FILE *fp;
787 
788     if (!nullstr(name)) {
789 	fprintf(stderr,ERROR_ONEFILE,prog,type);
790 	abnormal_exit();
791     }
792     nstrcpy(file,arg,PATH_LENGTH);
793     if (!make_filename(file,DEFAULT_EXTENSION,def_ext)) {
794 	fprintf(stderr,ERROR_BADFILE,prog,type,file);
795 	abnormal_exit();
796     }
797     run {
798 	fp=open_file(file,mode);
799 	close_file(fp);
800 	strcpy(name,file);
801     } except {
802 	when IOERROR:
803 	when CANTOPEN:
804 	when CANTCLOSE:
805 	  fprintf(stderr,ERROR_NOFILE,prog,type,file);
806 	  abnormal_exit();
807 	when ENDOFILE:
808 	  fprintf(stderr,ERROR_EMPTYFILE,prog,type,file);
809 	  abnormal_exit();
810 	default:
811 	  relay;
812     }
813 }
814 
815 
update_top()816 bool update_top()
817 { return(FALSE); }
818 
819 
820 
821 
822 #ifdef PUNT_FOR_NOW /*******************************************************/
823 
screen_init(argc_ptr,argv)824 bool screen_init(argc_ptr,argv) /* side-effect wimp, curses, and split */
825 int *argc_ptr;
826 char *argv[];
827 {
828     bool try_curses, try_wimp;
829     get_screen_preferences(argc_ptr,argv,&try_curses,&try_wimp);
830 #ifdef HAVE_WIMP
831     if (!tried_wimp && try_wimp)
832       if (do_wimp_init(argc_ptr,argv)) term=WIMP; /* wimp=TRUE */
833     tried_wimp= TRUE;
834 #endif
835     tty_init();
836 #ifdef HAVE_CURSES
837     if(!wimp && !tried_curses && try_curses)
838 	if (curses_init(&tty_lines)) term=CURSES; /* sets curses=TRUE */
839     tried_curses= TRUE;
840 #endif
841     maybe_clear_screen(); nl(); boing();
842     return(wimp || curses);
843 }
844 
845 
split_screen_init(argc_ptr,argv,top_lines,top_update_function)846 bool split_screen_init(argc_ptr,argv,top_lines,top_update_function)
847 int *argc_ptr;
848 char *argv[];
849 int top_lines;
850 void (*top_update_function)();
851 {
852     bool try_curses, try_wimp;
853     get_screen_preferences(argc_ptr,argv,&try_curses,&try_wimp);
854 #ifdef HAVE_WIMP
855     if (!tried_wimp && try_wimp)
856       if (do_split_wimp_init(top_lines,top_update_function,argc_ptr,argv))
857 	term=WIMP; /* sets wimp=TRUE */
858     tried_wimp= TRUE;
859 #endif
860     tty_init();
861 #ifdef HAVE_CURSES
862     if (!wimp && !tried_curses && try_curses)
863       if (curses_init(&tty_lines)) {
864 	  if (curses_split(top_lines,CURSES_REVERSE_TOP,top_update_function,
865 			   &tty_lines)) term=CURSES; /* sets curses=TRUE */
866 	  else curses_end();
867       }
868     tried_curses= TRUE;
869 #endif
870     maybe_clear_screen(); update_top(); nl(); boing();
871     return(wimp || curses);
872 }
873 
874 
get_screen_preferences(argc_ptr,argv,try_curses,try_wimp)875 void get_screen_preferences(argc_ptr,argv,try_curses,try_wimp)
876 int *argc_ptr;
877 char *argv[];
878 int *try_curses, *try_wimp;
879 {
880     int i, j;
881 
882     *try_curses= *try_wimp= MAYBE;
883     for (i=0; i<*argc_ptr; i++) {
884 	if (nmatches(argv[i],"-window",2)) *try_wimp=TRUE;
885 	else if (nmatches(argv[i],"+window",2)) *try_wimp=FALSE;
886 	else if (nmatches(argv[i],"-nowindow",4)) *try_wimp=FALSE;
887 	else if (nmatches(argv[i],"-screen",2)) *try_curses=TRUE;
888 	else if (nmatches(argv[i],"+screen",2)) *try_curses=FALSE;
889 	else if (nmatches(argv[i],"-noscreen",4)) *try_curses=FALSE;
890 	else if (nmatches(argv[i],"-line",2)) *try_curses= *try_wimp= FALSE;
891 	else continue;
892 	/* matched argument, so delete it from the list */
893 	for (j=i+1; j<*argc_ptr; j++) argv[j-1]= argv[j];
894 	--*argc_ptr;
895     }
896     if (*try_curses==MAYBE) *try_curses=DEFAULT_TRY_CURSES;
897     if (*try_wimp==MAYBE) *try_wimp=DEFAULT_TRY_WIMP;
898 }
899 
900 
901 /* Custom windows can work similarly to the canned types (text &
902 split), except that the widow code is very application specific: it
903 may respond to mouse clicks and so forth in special ways and have
904 other special stuff, which will probably have to interect with the
905 application code via global variables. Such interfaces could be
906 implemented using a customized do_wimp_init() routine. To make life
907 easy and so that things work similarly, we require (1) that the window
908 have a scrolling text region, (2) that it uses the menu struct (see
909 shell.c), (3) that it only need to know about state variable changes
910 that already call update_top() (or maybe_ok()), and (4) that it
911 effects state changes only when inhibit_menus is FALSE (see shell.c).
912 Like all init routines, do_custom_wimp_init() should do very little -
913 do_wimp_start() in shell.c should do this. */
914 
915 
update_top()916 bool update_top()
917 {
918 /* NEEDS WIMP HOOK */
919 #ifdef HAVE_CURSES
920     if (curses && split) {
921 	if (!have_drawn_top) curses_draw_top(); else curses_update_top();
922 	have_drawn_top=TRUE; return(TRUE);
923     }
924 #endif
925     return(FALSE);
926 }
927 
928 
screen_end()929 void screen_end() {
930 /* NEEDS WIMP HOOK */
931 /* ALSO NEEDS a "Hit return" hook for quiting under a window system */
932 #ifdef HAVE_CURSES
933     if (curses) curses_end(FALSE);
934 #endif
935 }
936 
937 
string_editor(prompt,str,num)938 bool string_editor(prompt,str,num)
939 char *prompt, *str;
940 int num; /* max #chars in str */
941 {
942     bool successful;
943 
944 /* NEEDS WIMP HOOK */
945     successful = FALSE;
946 #ifdef HAVE_CURSES
947     if(curses)
948       successful = curses_string_editor(str,num);
949 #endif
950     return(successful);
951 }
952 
953 
954 #ifdef HAVE_CURSES
curses_error(where)955 void curses_error(where)
956 char *where;
957 {
958     curses_end(TRUE);
959     printed_lines=4; more_break_pending=FALSE;
960     term= old_term;  tty_lines=old_lines;
961     more= old_more;  scrollback= old_scrollback;
962     clear_screen();
963 
964     if (where==NULL) where=ptr_to("???");
965     fprintf(stderr,"\nwarning: curses failed in %-50s\n",where);
966     fprintf(stderr,"attempting to continue in line mode...\n\n");
967     flush();
968 }
969 #endif
970 
971 #endif /* PUNT_FOR_NOW */
972