File:  [Coherent Logic Development] / freem / src / init.c
Revision 1.8: download - view: text, annotated - select for diffs
Mon Mar 24 04:44:55 2025 UTC (8 days, 19 hours ago) by snw
Branches: MAIN
CVS tags: v0-62-3, HEAD
Don't call ttyname on OS/2

/*
 *   $Id: init.c,v 1.8 2025/03/24 04:44:55 snw Exp $
 *    FreeM initialization 
 *
 *  
 *   Author: Serena Willis <snw@coherent-logic.com>
 *    Copyright (C) 1998 MUG Deutschland
 *    Copyright (C) 2020, 2025 Coherent Logic Development LLC
 *
 *
 *   This file is part of FreeM.
 *
 *   FreeM is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU Affero Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   FreeM is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU Affero Public License for more details.
 *
 *   You should have received a copy of the GNU Affero Public License
 *   along with FreeM.  If not, see <https://www.gnu.org/licenses/>.
 *
 *   $Log: init.c,v $
 *   Revision 1.8  2025/03/24 04:44:55  snw
 *   Don't call ttyname on OS/2
 *
 *   Revision 1.7  2025/03/24 04:05:36  snw
 *   Replace crlf with frm_crlf to avoid symbol conflict with readline on OS/2
 *
 *   Revision 1.6  2025/03/09 19:14:25  snw
 *   First phase of REUSE compliance and header reformat
 *
 *
 * SPDX-FileCopyrightText:  (C) 2025 Coherent Logic Development LLC
 * SPDX-License-Identifier: AGPL-3.0-or-later
 **/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <time.h>
#include <errno.h>
#include <sys/ioctl.h>

#if !defined(__APPLE__) && !defined(__gnu_hurd__) && !defined(EMSCRIPTEN)
# if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__AMIGA)
#  include <termios.h>
#  if !defined(__AMIGA)
#   define TCGETA TIOCGETA
#   define TCSETA TIOCSETA
#  endif
#  define termio termios
# else
#  if !defined(MSDOS)
#    include <termio.h>
#  endif
# endif
#else
# include <termios.h>
#endif

#include "config.h"

#if defined(HAVE_MWAPI_MOTIF)
# include <Xm/Xm.h>
#endif

#include "mpsdef.h"
#include "transact.h"
#include "namespace.h"
#include "events.h"
#include "mdebug.h"
#include "shmmgr.h"
#include "locktab.h"
#include "jobtab.h"
#include "datatypes.h"
#include "objects.h"

#ifdef HAVE_LIBREADLINE
#  if defined(HAVE_READLINE_READLINE_H)
#    include <readline/readline.h>
#  elif defined(HAVE_READLINE_H)
#    include <readline.h>
#  else /* !defined(HAVE_READLINE_H) */
extern char *readline ();
#  endif /* !defined(HAVE_READLINE_H) */
char *cmdline = NULL;
#else /* !defined(HAVE_READLINE_READLINE_H) */
  /* no readline */
#endif /* HAVE_LIBREADLINE */

#ifdef HAVE_READLINE_HISTORY
#  if defined(HAVE_READLINE_HISTORY_H)
#    include <readline/history.h>
#  elif defined(HAVE_HISTORY_H)
#    include <history.h>
#  else /* !defined(HAVE_HISTORY_H) */
extern void add_history ();
extern int write_history ();
extern int read_history ();
#  endif /* defined(HAVE_READLINE_HISTORY_H) */
  /* no history */
#endif /* HAVE_READLINE_HISTORY */

#if defined(HAVE_WIRINGPI_H)
# include <wiringPi.h>
#endif

#if !defined(PATH_MAX) && defined(_SCO_DS)
# define PATH_MAX 4096
#endif

#if !defined(PATH_MAX) && defined(__gnu_hurd__)
# define PATH_MAX 1024
#endif

#if !defined(PATH_MAX) && defined(__sun__)
# include <limits.h>
#endif

#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
# include <sys/syslimits.h>
#endif

#define SHMKEY 0x990120
#define SHMSIZ 1048576

void init_process(void);
void init_devtable(void);
void init_signals(void);
void init_timezone(void);
void init_freem_path(void);

#if defined(HAVE_LIBREADLINE)
void init_readline(void);
#endif

void init_execution_context(void);
void init_io(void);
void init_random_number(void);
void init_ztrap(void);
void init_ssvn(void);
void init_terminal(void);
void init_estack(void);

void init_mwapi(void);

short init (char *namespace_name) 
{
    short retval;
    
    init_process ();
    init_devtable ();
    init_signals ();
    init_freem_path ();
    init_timezone ();

#if defined(HAVE_LIBREADLINE)
    init_readline ();
#endif    

    init_execution_context ();

    if (run_daemon == FALSE) {
        init_io ();
    }
    
    init_random_number ();
    init_ztrap ();

    retval = shm_init (shm_init_size);

    if (retval == SHMS_GET_ERR) {
        fprintf (stderr, "init:  error initializing shared memory [errno %d]\r\n", errno);
        exit (1);
    }

    symtab_init ();
    tp_init ();
    
    set_namespace (namespace_name, FALSE);

    if (first_process) {
        fprintf (stderr, "init:  we are the first process in the environment (pid %d)\r\n", pid);
    }

    if (first_process) fprintf (stderr, "init:  initializing job table\r\n");
    jobtab_init ();

    if (first_process) fprintf (stderr, "init:  adding job to job table\r\n");
    job_init (FALSE);

    if (first_process) fprintf (stderr, "init:  initializing structured system variables\r\n");
    init_ssvn ();

    if (first_process) fprintf (stderr, "init:  initializing terminal\r\n");
    init_terminal ();

    if (first_process) fprintf (stderr, "init:  initializing asynchronous events\r\n");
    evt_init ();

    if (first_process) fprintf (stderr, "init:  initializing debugger\r\n");
    dbg_init ();    

    if (first_process) fprintf (stderr, "init:  initializing error stack\r\n");
    init_estack();
    
    etrap[0] = EOL;
    ecode[0] = EOL;
    estack = 0;

    init_mwapi();
    
    if (merr () == OK) {
        return TRUE;
    }

    return FALSE;
}

void init_process (void)
{
    pid = getpid ();            /* get $J = process ID */
    umask (0);              /* protection bits mask to full rights */
    snprintf (fp_conversion, 9, "%%.%df\201", DBL_DIG);

    if (fp_mode) {
        zprecise = DBL_DIG;
    }
    else {
        zprecise = 100;
    }
}

void init_devtable (void)
{
    register int i;
    register int j;

    for (j = 0; j <= MAXDEV; j++) { /* init. translation tables */
        
        for (i = 0; i < 256; i++) {
            G0I[j][i] = (char) i;
            G0O[j][i] = (char) i;
            G1I[j][i] = (char) i;
            G1O[j][i] = (char) i;
        }
        
        G0I[j][UNSIGN (EOL)] = NUL;
        G0O[j][UNSIGN (EOL)] = NUL;
        G1I[j][UNSIGN (EOL)] = NUL;
        G1O[j][UNSIGN (EOL)] = NUL;
        G0I[j][UNSIGN (DELIM)] = NUL;
        G0O[j][UNSIGN (DELIM)] = NUL;
        G1I[j][UNSIGN (DELIM)] = NUL;
        G1O[j][UNSIGN (DELIM)] = NUL;
        G0I[j][256] = EOL;
        G0O[j][256] = EOL;
        G1I[j][256] = EOL;
        G1O[j][256] = EOL;
    
    }

    #ifdef SCO
        #ifndef HACK_NOXLATE
            G0I[HOME][245] = 64;
            G0O[HOME][64] = 245;        /* Paragraph */
            G0I[HOME][142] = 91;
            G0O[HOME][91] = 142;        /* A umlaut */
            G0I[HOME][153] = 92;
            G0O[HOME][92] = 153;        /* O umlaut */
            G0I[HOME][154] = 93;
            G0O[HOME][93] = 154;        /* U umlaut */
            G0I[HOME][132] = 123;
            G0O[HOME][123] = 132;       /* a umlaut */
            G0I[HOME][148] = 124;
            G0O[HOME][124] = 148;       /* o umlaut */
            G0I[HOME][129] = 125;
            G0O[HOME][125] = 129;       /* u umlaut */
            G0I[HOME][225] = 126;
            G0O[HOME][126] = 225;       /* sharp s  */
        #endif/*HACK_NOXLATE*/

        /* DEC Special graphics                             */
        G1I[HOME][254] = 96;
        G1O[HOME][96] = 254;        /* diamond  */
        G1I[HOME][176] = 97;
        G1O[HOME][97] = 176;        /* checker board */
        G1I[HOME][241] = 99;
        G1O[HOME][99] = 241;        /* FF */
        G1I[HOME][242] = 100;
        G1O[HOME][100] = 242;       /* CR */
        G1I[HOME][243] = 101;
        G1O[HOME][101] = 243;       /* LF */
        G1I[HOME][248] = 102;
        G1O[HOME][102] = 248;       /* degree sign */
        G1I[HOME][241] = 103;
        G1O[HOME][103] = 241;       /* plus minus */
        G1I[HOME][244] = 104;
        G1O[HOME][104] = 244;       /* NL */
        G1I[HOME][251] = 105;
        G1O[HOME][105] = 251;       /* VT */
        G1I[HOME][217] = 106;
        G1O[HOME][106] = 217;       /* lower right corner */
        G1I[HOME][191] = 107;
        G1O[HOME][107] = 191;       /* upper right corner */
        G1I[HOME][218] = 108;
        G1O[HOME][108] = 218;       /* upper left corner */
        G1I[HOME][192] = 109;
        G1O[HOME][109] = 192;       /* lower left corner */
        G1I[HOME][197] = 110;
        G1O[HOME][110] = 197;       /* cross */
        G1I[HOME][200] = 111;
        G1O[HOME][111] = 200;       /* linescan 5 */
        G1I[HOME][201] = 112;
        G1O[HOME][112] = 201;       /* linescan 4 */
        G1I[HOME][196] = 113;
        G1O[HOME][113] = 196;       /* linescan 3 */
        G1I[HOME][202] = 114;
        G1O[HOME][114] = 202;       /* linescan 2 */
        G1I[HOME][203] = 115;
        G1O[HOME][115] = 203;       /* linescan 1 */
        G1I[HOME][195] = 116;
        G1O[HOME][116] = 195;       /* left  junction */
        G1I[HOME][180] = 117;
        G1O[HOME][117] = 180;       /* right junction */
        G1I[HOME][193] = 118;
        G1O[HOME][118] = 193;       /* lower junction */
        G1I[HOME][194] = 119;
        G1O[HOME][119] = 194;       /* upper junction */
        G1I[HOME][179] = 120;
        G1O[HOME][120] = 179;       /* vertival bar */
        G1I[HOME][243] = 121;
        G1O[HOME][121] = 243;       /* lower equals */
        G1I[HOME][242] = 122;
        G1O[HOME][122] = 242;       /* greater equals */
        G1I[HOME][227] = 123;
        G1O[HOME][123] = 227;       /* pi */
        G1I[HOME][246] = 124;
        G1O[HOME][124] = 246;       /* not equals */
        G1I[HOME][128] = 125;
        G1O[HOME][125] = 128;       /* euro sign */
        G1I[HOME][250] = 126;
        G1O[HOME][126] = 250;       /* centered dot */
    #endif /* SCO */
}

void init_signals (void)
{
    sig_init ();
}

void init_timezone (void)
{
   
    struct tm lt;
    struct tm gt;

    unsigned long gmt;
    unsigned long lmt;

    long clock;

#ifdef __CYGWIN__

    tzset ();                        /* may be required in order   */
                                     /* to guarantee _timezone set */
#else

    clock = time (0L);
    lt = *localtime (&clock);
    gt = *gmtime (&clock);

    /* This is awkward but I think it is portable: steve_morris */
    gmt = gt.tm_year * 365;
    gmt = (gmt + gt.tm_yday) * 24;
    gmt = (gmt + gt.tm_hour) * 60;
    gmt = (gmt + gt.tm_min);

    lmt = lt.tm_year * 365;
    lmt = (lmt + lt.tm_yday) * 24;
    lmt = (lmt + lt.tm_hour) * 60;
    lmt = (lmt + lt.tm_min);

    FreeM_timezone = (gmt - lmt) * 60;
    tzoffset = -FreeM_timezone;
    
#endif /* __CYGWIN__ */
    

}

void init_freem_path (void)
{

    if((freem_path = malloc(PATH_MAX + 1)) == NULL) {
        fprintf(stderr, "Can't allocate freem_path. Exiting.");

        exit(1);
    }

    freem_path[0] = NUL;

    /* check where I'm being executed from */
#ifdef __linux__
    readlink ("/proc/self/exe", freem_path, PATH_MAX);
#endif
#ifdef __FreeBSD__
    readlink ("/proc/curproc/file", freem_path, PATH_MAX);
#endif
#ifdef __sun
    readlink ("/proc/self/path/a.out", freem_path, PATH_MAX);
#endif

    if(freem_path[0] == NUL) {
        /* we don't know where we came from */
    }

    getcwd (curdir, PATHLEN);
    stcnv_c2m (curdir);
    
}

#if defined(HAVE_LIBREADLINE)
void init_readline (void)
{
    uid_t uid = geteuid ();
    struct passwd *pw = getpwuid (uid);
    char *pw_buf;

    pw_buf = (char *) calloc (strlen(pw->pw_dir) + 1, sizeof(char));
    strcpy (pw_buf, pw->pw_dir);

    snprintf (history_file, 256, "%s/.freem_history", pw_buf);

    free (pw_buf);

    using_history ();
    read_history (history_file);
}
#endif    

void init_execution_context (void)
{
    register int i;

    obj_init ();
    
    merr_clear ();
    
    codptr = code;
    code[0] = EOL;          /* init code_pointer */
    partition = calloc ((unsigned) (PSIZE + 2), 1);

    if (partition == NULL) exit (2);            /* could not allocate stuff...     */

    for (i = 0; i < MAXNO_OF_RBUF; i++) {
        rbuf_flags[i].standard = standard;
    }

    for (i = 0; i < NESTLEVLS; i++) {
        extr_types[i] = DT_STRING;
    }
    
    symlen = PSIZE;
    s = &partition[PSIZE] - 256;    /* pointer to symlen_offset        */
    argptr = partition;         /* pointer to beg of tmp-storage   */

    svntable = calloc ((unsigned) (UDFSVSIZ + 1), 1);
    if (svntable == NULL) exit (2);         /* could not allocate stuff...     */
    
    svnlen = UDFSVSIZ;          /* begin of udf_svn_table         */
    buff = calloc ((unsigned) NO_OF_RBUF * (unsigned) PSIZE0, 1);   /* routine buffer pool          */
    if (buff == NULL) exit (2);         /* could not allocate stuff...     */

    
    newstack = calloc ((unsigned) NSIZE, 1); 
    if (newstack == NULL) exit (2);         /* could not allocate stuff...     */

    #ifdef DEBUG_NEWPTR
        printf("Allocating newptr stack...\r\n");
    #endif

    newptr = newstack;
    newlimit = newstack + NSIZE - 1024;
    

    namstck = calloc ((unsigned) NESTLEVLS * 13, 1);
    if (namstck == NULL) exit (2);          /* could not allocate stuff...     */

    *namstck = EOL;
    *(namstck + 1) = EOL;
    namptr = namstck;           /* routine name stack pointer       */
    framstck = calloc ((unsigned) NESTLEVLS * 256, 1);
    if (framstck == NULL) exit (2);         /* could not allocate stuff...     */

    *framstck = EOL;
    *(framstck + 1) = EOL;
    dofrmptr = framstck;        /* DO_frame stack pointer           */
    cmdstack = calloc ((unsigned) NESTLEVLS * 256, 1);
    if (cmdstack == NULL) exit (2);         /* could not allocate stuff...     */

    cmdptr = cmdstack;          /* command stack */

    rouend = rouins = rouptr = buff;
    roucur = buff + (NO_OF_RBUF * PSIZE0 + 1);
    *rouptr = EOL;
    *(rouptr + 1) = EOL;
    *(rouptr + 2) = EOL;

    err_suppl[0] = EOL; /* empty out supplemental error info */
}

void init_estack (void)
{
    stcpy (merr_stack[0].PLACE, "xecline()\201");
}

#if defined(HAVE_MWAPI_MOTIF)
void init_mwapi (void)
{
    /*
    if (getenv("DISPLAY") != NULL) {
        gtk_init (0, NULL);
    }
    */
    //TODO: init Motif/libXt
}
#else
void init_mwapi (void)
{
    return;
}
#endif

void init_io (void)
{
    register int i;

    /* initialize screen */
    setbuf (stdin, NULL);      /* no input buffering */
    glvnflag.all = 0L;
    stcpy (buff, "\201");
    writeHOME (buff);
    sq_modes[0] = '+';
    for (i = 0; i <= MAXDEV; ug_buf[i++][0] = EOL); /* init read-buffers */

    frm_crlf[HOME] = frm_filter;

    if (hardcopy) zbreakon = ENABLE;        /* enable CTRL/B */

    set_io (MUMPS);         /* set i/o parameters */

#if !defined(__AMIGA) && !defined(__OS2__)
    if (ttyname (HOME)) {       /* for $IO of HOME */
        strcpy (dev[HOME], ttyname (HOME));
        dev[HOME][strlen (dev[HOME])] = EOL;
    } 
    else {
        dev[HOME][0] = EOL;     /* ...we are in a pipe */
    }
#else
#if defined(__AMIGA)
    strcpy (dev[HOME], "CONSOLE:");
#else
#if defined(__OS2__)
    strcpy (dev[HOME], "CON:");
#endif
#endif
#endif    

    /* init function keys */
    for (i = 0; i < 44; zfunkey[i++][0] = EOL);
}

void init_random_number (void)
{

    srand (time (NULL));

    if ((nrandom = time (0L) * getpid ()) < 0) {
        nrandom = (-nrandom);
    }

}

void init_ztrap (void)
{

    if (frm_filter) { 
        ztrap[0][0] = EOL;      /* no default ztrap for filters */
    }
    else if (startuprou[0] == '^') {
        stcpy (ztrap[0], startuprou);
    }
    else {
        stcpy (ztrap[0], "^%SYSINIT\201");
    }

    /* $ZT to be xecuted on startup */
    
    stcpy (ztrap[NESTLEVLS + 1], ztrap[0]); /* DSM V.2 error trapping */

}

void init_ssvn(void)
{
    ssvn_job_update ();
    ssvn_display_update ();
    ssvn_routine_update ();
    ssvn_library_update ();
    if (first_process) ssvn_system_update ();
}

void init_terminal(void)
{
    xpos[HOME] = 80;
    ypos[HOME] = 24;
}

void reset_terminal(void)
{
    struct termio tpara;

    ioctl (0, TCGETA, &tpara);

    tpara.c_lflag |= (ECHO | ICANON);	/* enable echo/no cbreak mode */
    tpara.c_iflag |= ICRNL;		/* cr-lf mapping */
    tpara.c_oflag |= ONLCR;		/* cr-lf mapping */
    tpara.c_cc[VMIN] = EOT;
    tpara.c_cc[VTIME] = -1;

    ioctl (0, TCSETA, &tpara);
}

void cleanup (void)
{
    char k_buf[256];
    int ch;

    /* remove this job's entry from ^$JOB SSVN */
    snprintf (k_buf, 255, "^$JOB\202%d\201", pid);
    symtab_shm (kill_sym, k_buf, " \201");
    
    reset_terminal ();

    if (tp_level > 0) {

        if (direct_mode == TRUE) {
            fprintf (stderr, "UNCOMMITTED TRANSACTIONS EXIST:\n\n");
            tp_tdump ();
            set_io (UNIX);
            fprintf (stderr, "\nWould you like to c)ommit or r)ollback the above transactions and their operations? ($TLEVEL = %d) ", tp_level);

            for (;;) {
                ch = fgetc (stdin);

                if (ch == 'c' || ch == 'C') {
                    while (tp_level > 0) tp_tcommit ();

                    fprintf (stderr, "\n\nTransactions have been committed.\n");

                    break;
                }
                else if (ch == 'r' || ch == 'R') {
                    tp_trollback (tp_level);

                    fprintf (stderr, "\n\nTransactions have been rolled back.\n");

                    break;
                }
                else {
                    fprintf (stderr, "\n\nInvalid input '%c'. Must choose c)ommit or r)ollback.\n", ch);
                }
            }
        }
        else {
            fprintf (stderr, "Uncommitted transactions exist. Rolling back.\n");
            tp_trollback (tp_level);
        }
    }

#if defined(HAVE_LIBREADLINE)
    write_history (history_file);
#endif

    locktab_unlock_all ();    
    job_remove (pid);

    shm_exit ();

    if (run_daemon == TRUE) {

        if (pid_fd != -1) {
            lockf (pid_fd, F_ULOCK, 0);
            close (pid_fd);
        }

        if (pid_file_path != NULL) {
            unlink (pid_file_path);
        }

    }
        
    
    
    free (buff);            /* free previously allocated space */
    free (svntable);
    if (partition) free (partition);
    if (apartition) free (apartition);

   
    free (newstack);
    
    
    if (v22size) free (v22ali);    
    
    return;
}                   /* end of cleanup */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>