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