/*1Copyright (C) 1991-2002, The Numerical Algorithms Group Ltd.2All rights reserved.3Copyright (C) 2007-2010, Gabriel Dos Reis.4All rights reserved.56Redistribution and use in source and binary forms, with or without7modification, are permitted provided that the following conditions are8met:910- Redistributions of source code must retain the above copyright11notice, this list of conditions and the following disclaimer.1213- Redistributions in binary form must reproduce the above copyright14notice, this list of conditions and the following disclaimer in15the documentation and/or other materials provided with the16distribution.1718- Neither the name of The Numerical Algorithms Group Ltd. nor the19names of its contributors may be used to endorse or promote products20derived from this software without specific prior written permission.2122THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS23IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED24TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A25PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER26OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,27EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,28PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR29PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF30LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING31NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS32SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.33*/3435/*36* This is the main module of the HyperDoc program. It contains the main37* routine which initializes all the X stuff, and the tables. Then it passes38* control over to the main event loop.39*/4041/* #define DEBUG 1 */4243/* Include all the needed include files */4445#include <sys/types.h>46#include <sys/signal.h>47#include <sys/wait.h>48#include <setjmp.h>49#include <X11/cursorfont.h>50#include <stdlib.h>51#include <locale.h>5253#include "debug.h"54#include "cfuns.h"55#include "sockio.h"56#include "hyper.h"57#include "lex.h"58#include "keyin.h"59#include "initx.h"60#include "event.h"61#include "hyper.h"62#include "bsdsignal.h"63#include "sockio.h"64#include "parse.h"6566using namespace OpenAxiom;6768static void init_hash();69static void make_server_connections();70static void check_arguments();71static void init_hash();72static void make_server_connections();73static void check_arguments();7475/*76* Here is a flag used to tell me whether I made a good connection to the77* menu server. Needed so I don't send spad commands when I should not78*/7980int MenuServerOpened = 1;8182/* include icon bitmap data */8384#define BITMAPDEPTH 18586/* X11 display and screen variables */8788Display *gXDisplay;89int gXScreenNumber;9091/*92* Information about the top level HyperDoc window93*/9495HDWindow *gWindow = NULL; /* the current window */96HDWindow *gParentWindow =NULL; /* the parent window. The one that appears97* when you first start HyperDoc */9899HashTable gSessionHashTable; /* hash table of HD windows */100HashTable init_page_hash; /* initial hash table of HD pages */101HashTable init_macro_hash; /* initial hash table of HD macros */102HashTable init_patch_hash; /* initial hash table of HD patches */103104/* The various Cursors we use */105106Cursor gNormalCursor; /* The normal mouse cursor */107Cursor gActiveCursor; /* The cursor in active regions */108Cursor gBusyCursor; /* The clock cursor for when I am busy */109110111HashTable gFileHashTable; /* hash table of HyperDoc files */112HashTable gImageHashTable; /* hash table for images */113114115/* Some things needed for Handling interupts properly */116117int gIsEndOfOutput; /* set to true when spad has finished output */118int received_window_request = 0;/* true iff Spad wants a pop-up */119int in_next_event = 0; /* true when in XNextEvent */120int make_input_file = 0; /* true when making input files from ht */121int make_patch_files = 0; /* true when making patch files from ht */122int gmake_record_file= 0; /* true when making record files from ht */123int gverify_record_file = 0; /* true when verifying record files from ht */124int gverify_dates = 0; /* true when we want hypertex to verify ht.db dates */125126openaxiom_sio *session_server; /* socket connecting to session manager */127128int gIsAxiomServer = 0; /* true iff HyperDoc is acting as a */129/* an Axiom server */130131int kill_spad = 0; /* kill spad when finished with paste file */132133int gSwitch_to_mono=0; /* will be set to 1 if at any time we don't have134enough colours for the images. We will know this135when read_pixmap_file returns -1. We will use this136when deciding what to do in case of \inputimage */137138int gTtFontIs850=0; /* a flag that tells us if the Tt font is a IBM pagecode 850139font and hence supports the graphics chars140set when the TtFont is opened*/141142/*143* Global copies of the command line arguments, so they never have to be144* passed as parameters. This is also so any child process starting up also145* has the same values.146*/147148int gArgc;149char **gArgv;150151char **input_file_list;152int input_file_count;153154/*155* SIGUSR2 is raised by the spadbuf program when it is done with the current156* command157*/158159void160sigusr2_handler(int sig)161{162gIsEndOfOutput = 1;163return ;164}165166void167sigcld_handler(int sig)168{169170/* why were we waiting after the child had already died ??171because we don't want zombies */172173int x;174wait(&x);175176}177178extern jmp_buf env;179180181/* Clean up spad sockets on exit */182void183clean_socket(void )184{185char name[256];186187make_server_name(name, MenuServerName);188unlink(name);189}190191/*192* initialize hash tables, signal handlers and windows, then call the main193* event handling loop194*/195196int197main(int argc, char **argv)198{199using namespace OpenAxiom;200int ret_status;201202/* Initialize some global values */203/* fprintf(stderr,"hyper:main:entered\n");*/204oa_setenv("LC_ALL", "C");205setlocale(LC_ALL, "");206gArgc = argc;207gArgv = argv;208gIsEndOfOutput = 1;209210/* fprintf(stderr,"hyper:main:calling check_arguments\n");*/211check_arguments();212/* fprintf(stderr,"hyper:main:returned check_arguments\n");*/213214/*215* initialize the hash tables for the files and the windows and images216*/217/* fprintf(stderr,"hyper:main:calling init_hash\n");*/218init_hash();219/* fprintf(stderr,"hyper:main:returned init_hash\n");*/220221/*222* initialize the parser keyword hash table223*/224/* fprintf(stderr,"hyper:main:calling parser_init\n");*/225parser_init();226/* fprintf(stderr,"hyper:main:returned parser_init\n");*/227228/* fprintf(stderr,"hyper:main:calling read_ht_db\n");*/229read_ht_db(&init_page_hash, &init_macro_hash, &init_patch_hash);230/* fprintf(stderr,"hyper:main:returned read_ht_db\n");*/231232/*233* Now initialize x. This includes opening the display, setting the234* screen and display global values, and also gets all the fonts and235* colors we will need.236*/237238if (!make_input_file && !gmake_record_file && !gverify_record_file) {239/* fprintf(stderr,"hyper:main:calling initializeWindowSystem\n");*/240initializeWindowSystem();241/* fprintf(stderr,"hyper:main:returned initializeWindowSystem\n");*/242243/*244* Initialize some of the global values used by the input string245* routines246*/247/* fprintf(stderr,"hyper:main:calling init_keyin\n");*/248init_keyin();249/* fprintf(stderr,"hyper:main:returned init_keyin\n");*/250251/*252* regardless of what else happened, we should always pop up an253* initial window.254*/255256/* fprintf(stderr,"hyper:main:calling init_top_window\n");*/257ret_status = init_top_window("RootPage");258/* fprintf(stderr,"hyper:main:returned init_top_window\n");*/259gParentWindow = gWindow;260if (ret_status == -1) {261fprintf(stderr,262"(HyperDoc) Could not find RootPage for top-level window.\n");263exit(-1);264}265266/*267* Tell it how to handle the user defined signals I may get268*/269bsdSignal(SIGUSR2, sigusr2_handler,RestartSystemCalls);270bsdSignal(SIGUSR1, SIG_IGN,RestartSystemCalls);271bsdSignal(OPENAXIOM_SIGCHLD, sigcld_handler,RestartSystemCalls);272bsdSignal(SIGINT, SIG_IGN,RestartSystemCalls);273274/*275* Now go to the main event loop. I will never return, so just end276* the main routine after that277*/278279/*280* make an input file if requested281*/282}283else {284285/*286* Try to establish all the socket connections I need. If I am an287* gIsAxiomServer and the routine fails, it will exit for me288*/289/* fprintf(stderr,"hyper:main:in else case\n");*/290/* fprintf(stderr,"hyper:main:calling make_server_connections\n");*/291make_server_connections();292/* fprintf(stderr,"hyper:main:returned make_server_connections\n");*/293294295if (make_input_file) ht2_input();296if (gmake_record_file) make_record();297if (gverify_record_file) verify_record();298exit(0);299}300301/*302* Try to establish all the socket connections I need. If I am an303* gIsAxiomServer and the routine fails, it will exit for me304*/305/* fprintf(stderr,"hyper:main:calling make_server_connections\n");*/306make_server_connections();307/* fprintf(stderr,"hyper:main:returned make_server_connections\n");*/308309310/* fprintf(stderr,"hyper:main:calling mainEventLoop\n");*/311mainEventLoop();312/* fprintf(stderr,"hyper:main:returned mainEventLoop\n");*/313314return 0;315}316317/*318* Initializes the hash table for Files, and Windows319*/320321static void322init_hash()323{324hash_init(&gFileHashTable,325FileHashSize,326(EqualFunction)string_equal,327(HashcodeFunction) string_hash);328hash_init(&gSessionHashTable,329SessionHashSize,330(EqualFunction) window_equal,331(HashcodeFunction) window_code);332hash_init(&gImageHashTable,333ImageHashSize,334(EqualFunction) string_equal,335(HashcodeFunction) string_hash);336}337338/* initialize the HyperDoc page hierarchy data structures */339340void341init_page_structs(HDWindow *w)342{343int i;344345w->fMemoStackIndex = 0;346for (i = 0; i < MaxMemoDepth; i++) {347w->fMemoStack[i] = NULL;348w->fDownLinkStackTop[i] = 0;349}350w->fDownLinkStackIndex = 0;351for (i = 0; i < MaxDownlinkDepth; i++)352w->fDownLinkStack[i] = NULL;353}354355static void356check_arguments()357{358int i;359360/*361* Now check the command line arguments, to see if I am supposed to be a362* server or not363*/364for (i = 1; i < gArgc; i++) {365if (gArgv[i][0] == '-')366switch (gArgv[i][1]) {367case 'p':368gverify_dates=1;369break;370case 's':371if (!MenuServerOpened) {372fprintf(stderr, "(HyperDoc) Server already in use.\n");373exit(-1);374}375gIsAxiomServer = 1;376break;377case 'i':378if (gArgv[i][2] == 'p')379make_patch_files = 1;380make_input_file = 1;381input_file_list = gArgv + i + 1;382input_file_count = gArgc - i - 1;383break;384case 'k':385kill_spad = 1;386break;387case 'r':388if (gArgv[i][2] == 'm')389gmake_record_file=1;390else if (gArgv[i][2] == 'v')391gverify_record_file=1;392else393fprintf(stderr, "(HyperDoc) v or m must follow -r\n");394input_file_list = gArgv + i + 1;395input_file_count = gArgc - i - 1;396break;397default:398fprintf(stderr, "(HyperDoc) Unexpected Command Line Argument %s\n", gArgv[i]);399fprintf(stderr, " Usage: hypertex [-s]\n");400break;401}402}403}404405static void406make_server_connections()407{408int i, wait_time;409410/*411* Try to open the menuserver socket, if I can not, then set a flag412*/413414if (open_server(MenuServerName) == -2) {415fprintf(stderr, "(HyperDoc) Warning: Not connected to OpenAxiom Server!\n");416MenuServerOpened = 0;417} else {418atexit(&clean_socket);419MenuServerOpened = 1;420}421422423/*424* If I have opened the MenuServer socket, then I should also try to open425* the SpadServer socket, so I can send stuff right to SPAD.426*/427428if (MenuServerOpened) {429430/*431* If I am a ht server, then I should not continue on unless I432* establish some sort of connection433*/434435/*436* Modified on 11/20 so that it prints an error message every ten for437* ten tries at opeing the socket. If it fails all ten times, it438* gives up and exits.439*/440441if (!gIsAxiomServer)442wait_time = 2;443else444wait_time = 1000;445446for (i = 0, spad_socket = NULL; i < 2 && spad_socket == NULL; i++) {447spad_socket = connect_to_local_server(SpadServer,448MenuServer, wait_time);449if (gIsAxiomServer && spad_socket == NULL)450fprintf(stderr, "(HyperDoc) Error opening OpenAxiom server. Retrying ...\n");451else452i = 11;453}454if (! spad_socket) {455fprintf(stderr, "(HyperDoc) Couldn't connect to OpenAxiom server!\n");456if (!gIsAxiomServer)457MenuServerOpened = 0;458else {459fprintf(stderr, "(HyperDoc) Couldn't connect to OpenAxiom server!\n");460exit(-1);461}462}463else {464465/*466* Do the same thing for the SessionServer467*/468469for (i = 0, session_server = NULL; i < 2 && session_server == NULL470; i++) {471session_server =472connect_to_local_server(SessionServer, MenuServer,473wait_time);474if (gIsAxiomServer && session_server == NULL) {475fprintf(stderr,476"(HyperDoc) Error opening SessionServer, Retrying ...\n");477}478else479i = 11;480}481if (session_server == NULL) {482fprintf(stderr, "(HyperDoc) Connection attempt to session manager timed out.\n");483if (gIsAxiomServer) {484fprintf(stderr,485"(HyperDoc) Server unable to connect to session server\n");486exit(-1);487}488else {489MenuServerOpened = 0;490}491}492}493}494}495496497