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 /*** Predefined Messages for sending. ***/
15 #define RERUN		1
16 #define PUNT		2
17 #define QUIT		3
18 #define MATHERROR	4
19 #define NOMEMORY	5
20 #define ENDOFILE	6
21 #define ENDOINPUT	7
22 #define IOERROR		8
23 #define CANTOPEN	9
24 #define CRASH		10
25 #define INTERRUPT	11
26 #define SYSERROR	12
27 #define ABORT		13
28 #define SOFTABORT	14
29 #define BADEQN 		15
30 #define CANTCLOSE	16
31 
32 /* The first message number accessible to the user code is 20. */
33 #define USER_MESSAGE(n) (20+n)
34 
35 /* Message variables for the above */
36 extern char *MATHERROR_type;    /* allocated LINE long */
37 extern real  MATHERROR_arg1;
38 extern real  MATHERROR_arg2;
39 extern int   NOMEMORY_num_cells;
40 extern int   NOMEMORY_cell_size;
41 extern char *CANTOPEN_path;     /* allocated PATH_LENGTH long */
42 extern char  CANTOPEN_modechar;
43 extern char *IOERROR_errmsg;    /* allocated LINE long */
44 extern char *IOERROR_linecopy;  /* set the ptr, ths is not allocated */
45 extern char *IOERROR_filename;  /* allocated PATH_LENGTH long */
46 extern char  IOERROR_modechar;
47 extern char *SYSERROR_errmsg;   /* allocated LINE long */
48 extern char *SOFTABORT_msgstr;  /* a ptr, not allocated */
49 extern char *BADEQN_errmsg;
50 extern int   BADEQN_errpos;
51 
52 /* user accessible stuff */
53 extern int msg;		/* the message # */
54 extern char **mname;    /* [msg] => name for this msg # */
55 extern char *msgstr;    /* use for msg vars - is MAXLINE long */
56 
57 void setmsg();	/* sets up a message */
58 /* args int msg; char *msgname; void (*send_proc)(),(*message_proc)();
59    message_proc may be NULL */
60 
61 void untrapped_msg();   /* Deal with unhandled messages - in syscode.c */
62 void trapped_msg();
63 void verbose_untrapped_msg();
64 
65 /* Possible send_procs - happen when we call send(MSG); args: message msg; */
66 void sender();
67 void trapper();
68 void punter();
69 void default_action(); /* DON'T USE */
70 
71 /* Possible message_procs in msglib.c. These produce an error message string
72    for untrapped messages. */
73 void strmsg_default();
74 void strmsg_NOMEMORY();
75 void strmsg_MATHERROR();
76 void strmsg_CANTOPEN();
77 void strmsg_SYSERROR();
78 
79 /* Stuff for internal use only! - see msglib.c */
80 extern jmp_buf stk[];
81 extern int lvl;
82 extern bool exiting1;
83 extern void (*(maction[]))(), (*(mstrmsg[]))();   /* args: int msg; */
84 #define MSGS 	    50
85 #define MSGNAMLEN   39
86 #define TRAP_DEPTH  100
87 #define MAX_IO_FAILURES 20
88 #define MAX_BAD_SIGNALS 20
89 void sigcounter();    /* count weird signals & CRASH if too many */
90 int lvl_plus_plus();  /* return lvl for push onto stk[], chacking overflow */
91 
92 /*****************************************************************************/
93 /* Trap Syntax: (Braces are USUALLY not required for single statements)
94 
95 		run {
96 			blah;	 * Signal() statements can be in this
97 			blah;	 * block or in procedures called from
98 			blah;	 * it- break statements will work in here
99 			blah;	 * return is ABSOLUTELY NOT ALLOWED in here!
100 		} except {       *
101 		  when FOO:      * As this is really a switch statement,
102 			blah;	 * be sure each clause ends with a break,
103 			blah;	 * relay, or return instruction;
104 			break;   *
105 		  when BAR:
106 		        ...
107 		  relay_others;	 * This must exist for unhandled
108 		}  		 * signals to be passed on!
109 */
110 
111 
112 /* These are the basic syntactic elements...
113    The while condition here is never true! (e.g. like while(FALSE)) We use the
114    while so that break statements will work inside run {...} blocks. */
115 
116 #define run 	if ((msg=setjmp(stk[lvl_plus_plus()]))==0) { do
117 #define except	while(--lvl>10000); } else switch(msg)
118 
119 #define send(num) 	(*(maction[num]))(num)
120 #define when 		case
121 #define relay   	sender(msg)
122 #define relay_others 	default: sender(msg)
123 
124 
125 /* An abbreviation to catch only one signal- all others are relayed.
126    Syntax:
127 
128 	run {
129 	...
130 	} except_when(FOO) {	* braces are not required for 1 statement here.
131 	...		 	* break can be used in an except_when clause
132 	}			* to stop a loop surrounding the run... thing
133 */
134 
135 #define except_when(num) \
136   while(--lvl>10000); } else if (msg!=num) { sender(msg); } else
137 
138 /* Trapping() provides nicer syntax for the trivial do-nothing traps.
139    Syntax:
140 
141 	run {
142 	...
143         } trapping(FOO);   	* the same as except_when(FOO) {}
144 */
145 
146 #define trapping(m) except_when(m)
147 
148 
149 /* Another alternative to the except ... when notation shown above.
150    In this case, one block  of code is used to handle all messages, although
151    this block may look at the msg variable to tell what happened.
152    Note that the break statement should  work correctly in an
153    when_aborting { ... } block.
154    Syntax:
155 
156 	run {
157 	    ...
158 	} when_aborting {
159 	    if (msg==FOO) {
160 	    ...
161 	    } else if (msg==BAR) {
162 	    ...
163 	    } else relay; 		* remember to add this if you don't
164 	}				* just want to fall out.
165 */
166 
167 #define when_aborting	 while(--lvl>10000); } else
168 #define on_error	 while(--lvl>10000); } else
169 
170 
171 /* Yet another way to do traps. On_exit is similar to the
172    when_aborting construct shown above, except that the on_exit clause is
173    always executed, whether there was a message or whether it was just
174    "fallen into". As with when_aborting, the variable msg will be set
175    within this code correctly (msg==0 if no msg). Note that the break
176    statement should also work correctly in an on_exit { ... } block.
177 
178    For example, the following code will never leave a chunk of malloced space
179    around. If array() fails, NOMEMORY is sent to the caller, after an error
180    message is printed. This code behaves correctly, freeing all malloced
181    space, even if the first array() call succeeds and the second fails!
182 
183 	p=q=NULL;  * This must be here as the pointers may not be initialized,
184 	...        * which might cause us to try to unarray a bad pointer!
185 	run {
186 	    array(p, ... );
187 	    array(q, ... );
188 	    ...
189 	} on_exit {
190 	    unarray(p,...);
191 	    unarray(q,...);
192 	    relay_messages;
193 	}
194 */
195 
196 #define on_exit			\
197      while(--lvl>10000);	\
198   } 				\
199   for (exiting1=TRUE; exiting1; exiting1=FALSE)
200 
201 #define relay_messages sender(msg) /* nicer syntax than relay for this */
202 
203 /* We use stack_check() to check to see if the run stack is where it
204    was last time this was called with the given variable (an int). Use
205    init_stack_check() to set it sometime before calling stack check().
206    Remember to call stack_check() from some toplevel loop which should
207    not be building up run...except calls.  If stack_check() fails, the
208    program should be aborted! */
209 
210 bool stack_check();       /* args: int *var; return TRUE if all is OK */
211 void init_stack_check();  /* args: int *var; */
212 
213 
214 /******************** Support for Unix style signals ********************/
215 
216 /* Signal trap functions for signal_trap_init (which is in syscode.c) */
217 SIGHANDLE handle_quit();
218 SIGHANDLE handle_matherror();
219 SIGHANDLE handle_weird_signal();
220 SIGHANDLE handle_interrupt();
221 SIGHANDLE handle_buserror();
222 
223 void signal_trap_init(); /* no args; in syscode.c */
224 void msg_init();         /* no args; in syscode.c */
225 
226 
227 /***** THE FOLLOWING IS AS YET UNUSED, AND MAYBE BEST LEFT THAT WAY *****/
228 
229 /* After any run...except... thing, msg will be set to either 0 or a
230 valid message number. Therefore, we can use it as a state variable to
231 keep track of whether we aborted or fell through to after the except { }
232 clause..  However use this with extreme care (eg: only use it in a
233 function AFTER executing a run...except... thing). */
234 
235 #define relay_trapped_msg   sender(msg)
236 
237 extern bool in_tty_gets;
238 extern bool hit_interrupt;
239 
240 
241 
242 
243 
244