1 /*
2 Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
8
9 - Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11
12 - Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in
14 the documentation and/or other materials provided with the
15 distribution.
16
17 - Neither the name of The Numerical ALgorithms Group Ltd. nor the
18 names of its contributors may be used to endorse or promote products
19 derived from this software without specific prior written permission.
20
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
22 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
24 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
25 OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 /*
35 * This is the main module of the HyperDoc program. It contains the main
36 * routine which initializes all the X stuff, and the tables. Then it passes
37 * control over to the main event loop.
38 */
39
40 /* #define DEBUG 1 */
41
42 /* Include all the needed include files */
43
44 #include "debug.h"
45
46
47 #include "hyper.h"
48
49 #include <sys/signal.h>
50 #include <sys/types.h>
51 #include <sys/wait.h>
52 #include <setjmp.h>
53 #include <X11/cursorfont.h>
54
55 #include "keyin.h"
56 #include "bsdsignal.h"
57
58 #include "all_hyper_proto.H1"
59 #include "sockio-c.H1"
60 #include "bsdsignal.H1"
61
62 static void init_hash(void);
63 static void make_server_connections(void);
64 static void check_arguments(void);
65
66 /*
67 * Here is a flag used to tell me whether I made a good connection to the
68 * menu server. Needed so I don't send spad commands when I should not
69 */
70
71 int MenuServerOpened = 1;
72
73 /* include icon bitmap data */
74
75 #define BITMAPDEPTH 1
76
77 /* X11 display and screen variables */
78
79 Display *gXDisplay;
80 int gXScreenNumber;
81
82 /*
83 * Information about the top level HyperDoc window
84 */
85
86 HDWindow *gWindow = NULL; /* the current window */
87 HDWindow *gParentWindow =NULL; /* the parent window. The one that appears
88 * when you first start HyperDoc */
89
90 HashTable gSessionHashTable; /* hash table of HD windows */
91 HashTable init_page_hash; /* initial hash table of HD pages */
92 HashTable init_macro_hash; /* initial hash table of HD macros */
93 HashTable init_patch_hash; /* initial hash table of HD patches */
94
95 /* The various Cursors we use */
96
97 Cursor gNormalCursor; /* The normal mouse cursor */
98 Cursor gActiveCursor; /* The cursor in active regions */
99 Cursor gBusyCursor; /* The clock cursor for when I am busy */
100
101
102 HashTable gFileHashTable; /* hash table of HyperDoc files */
103 HashTable gImageHashTable; /* hash table for images */
104
105
106 /* Some things needed for Handling interrupts properly */
107
108 int gIsEndOfOutput; /* set to true when spad has finished output */
109 int received_window_request = 0;/* true iff Spad wants a pop-up */
110 int in_next_event = 0; /* true when in XNextEvent */
111 int make_input_file = 0; /* true when making input files from ht */
112 int make_patch_files = 0; /* true when making patch files from ht */
113 int gverify_dates = 0; /* true when we want hypertex to verify ht.db dates */
114
115 Sock *session_server; /* socket connecting to session manager */
116
117 /* true iff HyperDoc is acting as a FriCAS server */
118 int is_fricas_server = 0;
119
120 int kill_spad = 0; /* kill spad when finished with paste file */
121
122 int gSwitch_to_mono=0; /* will be set to 1 if at any time we don't have
123 enough colours for the images. We will know this
124 when read_pixmap_file returns -1. We will use this
125 when deciding what to do in case of \inputimage */
126
127 int gTtFontIs850=0; /* a flag that tells us if the Tt font is a IBM pagecode 850
128 font and hence supports the graphics chars
129 set when the TtFont is opened*/
130
131 /*
132 * Global copies of the command line arguments, so they never have to be
133 * passed as parameters. This is also so any child process starting up also
134 * has the same values.
135 */
136
137 int gArgc;
138 char **gArgv;
139
140 char **input_file_list;
141 int input_file_count;
142
143 /*
144 * SIGUSR2 is raised by the spadbuf program when it is done with the current
145 * command
146 */
147
148 void
sigusr2_handler(int sig)149 sigusr2_handler(int sig)
150 {
151 gIsEndOfOutput = 1;
152 return ;
153 }
154
155 void
sigcld_handler(int sig)156 sigcld_handler(int sig)
157 {
158
159 /* why were we waiting after the child had already died ??
160 because we don't want zombies */
161
162 int x;
163 wait(&x);
164
165 }
166
167 extern jmp_buf env;
168
169
170 /* Clean up spad sockets on exit */
171 void
clean_socket(void)172 clean_socket(void )
173 {
174 char name[256];
175
176 make_server_name(name, MenuServerName);
177 unlink(name);
178 }
179
180 /*
181 * initialize hash tables, signal handlers and windows, then call the main
182 * event handling loop
183 */
184
185 int
main(int argc,char ** argv)186 main(int argc, char **argv)
187 {
188 int ret_status;
189
190 /* Initialize some global values */
191 /* fprintf(stderr,"hyper:main:entered\n");*/
192 gArgc = argc;
193 gArgv = argv;
194 gIsEndOfOutput = 1;
195
196 /* fprintf(stderr,"hyper:main:calling check_arguments\n");*/
197 check_arguments();
198 /* fprintf(stderr,"hyper:main:returned check_arguments\n");*/
199
200 /*
201 * initialize the hash tables for the files and the windows and images
202 */
203 /* fprintf(stderr,"hyper:main:calling init_hash\n");*/
204 init_hash();
205 /* fprintf(stderr,"hyper:main:returned init_hash\n");*/
206
207 /*
208 * initialize the parser keyword hash table
209 */
210 /* fprintf(stderr,"hyper:main:calling parser_init\n");*/
211 parser_init();
212 /* fprintf(stderr,"hyper:main:returned parser_init\n");*/
213
214 /* fprintf(stderr,"hyper:main:calling read_ht_db\n");*/
215 read_ht_db(&init_page_hash, &init_macro_hash, &init_patch_hash);
216 /* fprintf(stderr,"hyper:main:returned read_ht_db\n");*/
217
218 /*
219 * Now initialize x. This includes opening the display, setting the
220 * screen and display global values, and also gets all the fonts and
221 * colors we will need.
222 */
223
224 if (!make_input_file) {
225 /* fprintf(stderr,"hyper:main:calling initializeWindowSystem\n");*/
226 initializeWindowSystem();
227 /* fprintf(stderr,"hyper:main:returned initializeWindowSystem\n");*/
228
229 /*
230 * Initialize some of the global values used by the input string
231 * routines
232 */
233 /* fprintf(stderr,"hyper:main:calling init_keyin\n");*/
234 init_keyin();
235 /* fprintf(stderr,"hyper:main:returned init_keyin\n");*/
236
237 /*
238 * regardless of what else happened, we should always pop up an
239 * initial window.
240 */
241
242 /* fprintf(stderr,"hyper:main:calling init_top_window\n");*/
243 ret_status = init_top_window("RootPage");
244 /* fprintf(stderr,"hyper:main:returned init_top_window\n");*/
245 gParentWindow = gWindow;
246 if (ret_status == -1) {
247 fprintf(stderr,
248 "(HyperDoc) Could not find RootPage for top-level window.\n");
249 exit(-1);
250 }
251
252 /*
253 * Tell it how to handle the user defined signals I may get
254 */
255 bsdSignal(SIGUSR2, sigusr2_handler,RestartSystemCalls);
256 bsdSignal(SIGUSR1, SIG_IGN,RestartSystemCalls);
257 #if defined(BSDplatform) || defined(MACOSXplatform)
258 bsdSignal(SIGCHLD, sigcld_handler,RestartSystemCalls);
259 #else
260 bsdSignal(SIGCLD, sigcld_handler,RestartSystemCalls);
261 #endif
262 bsdSignal(SIGINT, SIG_IGN,RestartSystemCalls);
263
264 /*
265 * Now go to the main event loop. I will never return, so just end
266 * the main routine after that
267 */
268
269 /*
270 * make an input file if requested
271 */
272 }
273 else {
274
275 /*
276 * Try to establish all the socket connections I need. If I am an
277 * is_fricas_server and the routine fails, it will exit for me
278 */
279 /* fprintf(stderr,"hyper:main:in else case\n");*/
280 /* fprintf(stderr,"hyper:main:calling make_server_connections\n");*/
281 make_server_connections();
282 /* fprintf(stderr,"hyper:main:returned make_server_connections\n");*/
283
284
285 if (make_input_file) ht2_input();
286 exit(0);
287 }
288
289 /*
290 * Try to establish all the socket connections I need. If I am an
291 * is_fricas_server and the routine fails, it will exit for me
292 */
293 /* fprintf(stderr,"hyper:main:calling make_server_connections\n");*/
294 make_server_connections();
295 /* fprintf(stderr,"hyper:main:returned make_server_connections\n");*/
296
297
298 /* fprintf(stderr,"hyper:main:calling mainEventLoop\n");*/
299 mainEventLoop();
300 /* fprintf(stderr,"hyper:main:returned mainEventLoop\n");*/
301
302 return 0;
303 }
304
305 /*
306 * Initializes the hash table for Files, and Windows
307 */
308
309 static void
init_hash(void)310 init_hash(void)
311 {
312 hash_init(&gFileHashTable,
313 FileHashSize,
314 (EqualFunction)string_equal,
315 (HashcodeFunction) string_hash);
316 hash_init(&gSessionHashTable,
317 SessionHashSize,
318 (EqualFunction) window_equal,
319 (HashcodeFunction) window_code);
320 hash_init(&gImageHashTable,
321 ImageHashSize,
322 (EqualFunction) string_equal,
323 (HashcodeFunction) string_hash);
324 }
325
326 /* initialize the HyperDoc page hierarchy data structures */
327
328 void
init_page_structs(HDWindow * w)329 init_page_structs(HDWindow *w)
330 {
331 int i;
332
333 w->fMemoStackIndex = 0;
334 for (i = 0; i < MaxMemoDepth; i++) {
335 w->fMemoStack[i] = NULL;
336 w->fDownLinkStackTop[i] = 0;
337 }
338 w->fDownLinkStackIndex = 0;
339 for (i = 0; i < MaxDownlinkDepth; i++)
340 w->fDownLinkStack[i] = NULL;
341 }
342
343 static void
check_arguments(void)344 check_arguments(void)
345 {
346 int i;
347
348 /*
349 * Now check the command line arguments, to see if I am supposed to be a
350 * server or not
351 */
352 for (i = 1; i < gArgc; i++) {
353 if (gArgv[i][0] == '-')
354 switch (gArgv[i][1]) {
355 case 'p':
356 gverify_dates=1;
357 break;
358 case 's':
359 if (!MenuServerOpened) {
360 fprintf(stderr, "(HyperDoc) Server already in use.\n");
361 exit(-1);
362 }
363 is_fricas_server = 1;
364 break;
365 case 'i':
366 if (gArgv[i][2] == 'p')
367 make_patch_files = 1;
368 make_input_file = 1;
369 input_file_list = gArgv + i + 1;
370 input_file_count = gArgc - i - 1;
371 break;
372 case 'k':
373 kill_spad = 1;
374 break;
375 default:
376 fprintf(stderr, "(HyperDoc) Unexpected Command Line Argument %s\n", gArgv[i]);
377 fprintf(stderr, " Usage: hypertex [-s]\n");
378 break;
379 }
380 }
381 }
382
383 static void
make_server_connections(void)384 make_server_connections(void)
385 {
386 int i, wait_time;
387
388 /*
389 * Try to open the menuserver socket, if I can not, then set a flag
390 */
391
392 if (open_server(MenuServerName) == -2) {
393 fprintf(stderr, "(HyperDoc) Warning: Not connected to FriCAS Server!\n");
394 MenuServerOpened = 0;
395 } else {
396 atexit(&clean_socket);
397 MenuServerOpened = 1;
398 }
399
400
401 /*
402 * If I have opened the MenuServer socket, then I should also try to open
403 * the SpadServer socket, so I can send stuff right to SPAD.
404 */
405
406 if (MenuServerOpened) {
407
408 /*
409 * If I am a ht server, then I should not continue on unless I
410 * establish some sort of connection
411 */
412
413 /*
414 * Modified on 11/20 so that it prints an error message every ten for
415 * ten tries at opening the socket. If it fails all ten times, it
416 * gives up and exits.
417 */
418
419 if (!is_fricas_server)
420 wait_time = 2;
421 else
422 wait_time = 1000;
423
424 for (i = 0, spad_socket = NULL; i < 2 && spad_socket == NULL; i++) {
425 spad_socket = connect_to_local_server(SpadServer,
426 MenuServer, wait_time);
427 if (is_fricas_server && spad_socket == NULL)
428 fprintf(stderr, "(HyperDoc) Error opening FriCAS server. Retrying ...\n");
429 else
430 i = 11;
431 }
432 if (! spad_socket) {
433 fprintf(stderr, "(HyperDoc) Couldn't connect to FriCAS server!\n");
434 if (!is_fricas_server)
435 MenuServerOpened = 0;
436 else {
437 fprintf(stderr, "(HyperDoc) Couldn't connect to FriCAS server!\n");
438 exit(-1);
439 }
440 }
441 else {
442
443 /*
444 * Do the same thing for the SessionServer
445 */
446
447 for (i = 0, session_server = NULL; i < 2 && session_server == NULL
448 ; i++) {
449 session_server =
450 connect_to_local_server(SessionServer, MenuServer,
451 wait_time);
452 if (is_fricas_server && session_server == NULL) {
453 fprintf(stderr,
454 "(HyperDoc) Error opening SessionServer, Retrying ...\n");
455 }
456 else
457 i = 11;
458 }
459 if (session_server == NULL) {
460 fprintf(stderr, "(HyperDoc) Connection attempt to session manager timed out.\n");
461 if (is_fricas_server) {
462 fprintf(stderr,
463 "(HyperDoc) Server unable to connect to session server\n");
464 exit(-1);
465 }
466 else {
467 MenuServerOpened = 0;
468 }
469 }
470 }
471 }
472 }
473