/* main.c
 *
 * Amiga UnixWindows main startup code and select loop
 *
 * Copyright (c) 1993,1994 by Ezra Story.  All rights reserved.  Permission to
 * copy this program is given provided that the copy is not sold and that
 * this copyright notice is included.
 */
static char rcsid[] = "$Id: main.c 1.5 1994/06/11 19:29:04 Ezra_Story Exp $";

#include "config.h"
#include <sys/types.h>
#include <sys/file.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <pwd.h>
#include <signal.h>
#include <errno.h>
#ifdef STRING
#include <string.h>
#else
#include <strings.h>
#endif
#ifdef SYSSELECT
#include <sys/select.h>
#endif
#include <stdio.h>

#include "lists.h"
#include "mydefs.h"


proto struct selmask        selmask[2];          /* select() masks */
proto fildes_t              nfds;                /* num of fds */
proto fildes_t              cout;                /* stdout */
proto fildes_t              cin;                 /* stdin  */
proto int                   metaon;
proto int                   bps;                 /* bps rate */
proto int                   micPerChar;
proto int                   charPerSec;
proto int                   wnoutsz;             /* max window size */
proto done();
proto cwait();

extern int  opterr;
extern char *optarg;

int bps = 19200;
int micPerChar = 520; /* 19200 */
int charPerSec = 1920;
int metaon = 0;
int errflag;
int wnoutsz = 64;
fildes_t nfds, cout, cin;
struct selmask selmask[2];

#ifndef FNDELAY
#define FNDELAY O_NDELAY
#endif

main(argc, argv)
char **argv;
{
        int c;

        /* a little logo */
        puts("AmigaUW (release 4) by Ezra Story (c) 1993, 1994");

        /* are we already here? */
        if (getenv("AMUW"))
                {
                fprintf(stderr, "%s is already running\n", *argv);
                exit(1);
                }
#ifndef NOPUTENV
        putenv("AMUW=00");
#endif

        /* get arguments */
        opterr = 0;
        while ((c=getopt(argc, argv, "w:hb:m")) != EOF)
            switch (c)
                {
                case 'w':
                    wnoutsz = atoi(optarg);
                    if (wnoutsz > WINOUTSZ) wnoutsz = WINOUTSZ;
                    if (wnoutsz < 6) wnoutsz = 6;
                    break;

                case 'b':
                    bps = atoi(optarg);
                    if (bps == 0)
                        bps = 19200;
                    else
                        {
                        charPerSec = bps / 10;
                        micPerChar = 1000000 / charPerSec;
                        }
                    break;

                case 'm':
                    metaon = 1;
                    break;

                default:
                    errflag = 1;
                    break;
                }

        if (errflag)
            {
            fprintf(stderr, "Usage: \"%s [-mb(rate)w(win size)]\"\n", *argv);
            fprintf(stderr,"    -m   8-bit capable output\n");
            fprintf(stderr,"    -b   Output BPS rate (def. 19200)\n");
            fprintf(stderr,"    -w   Largest output window size (def. 64)\n");
            exit(1);
            }

        puts("Starting...");

        /* Init file descriptor data */
        InitFD();
        FD_SET(0, &selmask[0].sm_rd);
        cin = 0;
        cout = 1;
        (void)fcntl(0,F_SETFL, FNDELAY);

        /* Init window structs */
        InitWindows();

        /* setup signal handlers */
        (void)signal(SIGHUP, (int)done);       /* quit on hangup */
        (void)signal(SIGINT, (int)SIG_IGN);    /* ignore interrupt */
        (void)signal(SIGQUIT, (int)SIG_IGN);   /* ignore quits */
        (void)signal(SIGTERM, (int)done);      /* quit on terminate */
        (void)signal(SIGTSTP, (int)SIG_IGN);   /* ignore stop */
#ifdef SYSV
        (void)signal(SIGCLD, (int)cwait);
#else
        (void)signal(SIGCHLD, (int)cwait);     /* collect dead children */
#endif

        /* setup raw tty */
        TtyRaw();

        /* send startup code */
        p_Startup();

        /* main select() loop */
        while (1)
            {
            selmask[1] = selmask[0];
            if (select(nfds, &selmask[1].sm_rd, &selmask[1].sm_wt,
                &selmask[1].sm_ex, (struct timeval *)0) < 0)
                {
                if (errno == EINTR) continue;
                done(1,"select");
                }

            /* stdin? */
            if (FD_ISSET(0, &selmask[1].sm_rd)) p_ProcessInput();

            /* check windows in priority order */
            CheckWindows();
            }
}


done(s,e)
int s;
char *e;
{
        if (e) perror(e);

        p_Exit();
        CloseFD();
        TtyRestore();
        exit(s);
}

cwait()
{
        register int pid;
#ifdef STRUCTWAIT
        union wait status;
#else
        int status;
#endif
#ifndef SYSV
        struct rusage rusage;

        /*
         * Collect dead children.  Restart any children that have stopped.
         */
        while ((pid=wait3(&status, WNOHANG|WUNTRACED, &rusage)) > 0)
                if (WIFSTOPPED(status))
                        (void)kill(pid, SIGCONT);
#else
        while ((pid=waitpid(-1,&status, WNOHANG|WUNTRACED)) > 0)
                if (WIFSTOPPED(status))
                        (void)kill(pid,SIGCONT);
#endif
}

InitFD()
{
        register fildes_t fd;
#ifndef NODTABLE
        nfds = getdtablesize();
        if (nfds > FD_SETSIZE)
#endif
            nfds = FD_SETSIZE;
        if (nfds > 128) nfds = 128;

        for (fd=3; fd < nfds; fd++)
            {
            (void)close(fd);
            }
        FD_ZERO(&selmask[0].sm_rd);
        FD_ZERO(&selmask[0].sm_wt);
        FD_ZERO(&selmask[0].sm_ex);
}

CloseFD()
{
        register fildes_t fd;

        for (fd=3; fd < nfds; fd++)
                (void)close(fd);
}

