root/games/phantasia/io.c
/*      $NetBSD: io.c,v 1.14 2009/08/31 08:27:16 dholland Exp $ */

/*
 * io.c - input/output routines for Phantasia
 */

#include <sys/cdefs.h>

#include <ctype.h>
#include <math.h>
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "macros.h"
#include "phantdefs.h"
#include "phantstruct.h"
#include "phantglobs.h"
//#include "pathnames.h"

#undef bool
#include <curses.h>

static void catchalarm(int) __dead;

void
getstring(char *cp, int mx)
{
        char   *inptr;          /* pointer into string for next string */
        int     x, y;           /* original x, y coordinates on screen */
        int     ch;             /* input */

        getyx(stdscr, y, x);    /* get coordinates on screen */
        inptr = cp;
        *inptr = '\0';          /* clear string to start */
        --mx;                   /* reserve room in string for nul terminator */

        do
                /* get characters and process */
        {
                if (Echo)
                        mvaddstr(y, x, cp);     /* print string on screen */
                clrtoeol();     /* clear any data after string */
                refresh();      /* update screen */

                ch = getchar(); /* get character */

                switch (ch) {
                case CH_ERASE:  /* back up one character */
                        if (inptr > cp)
                                --inptr;
                        break;

                case CH_KILL:   /* back up to original location */
                        inptr = cp;
                        break;

                case CH_NEWLINE:        /* terminate string */
                        break;

                case CH_REDRAW:/* redraw screen */
                        clearok(stdscr, TRUE);
                        continue;

                default:        /* put data in string */
                        if (ch >= ' ' || Wizard)
                                /* printing char; put in string */
                                *inptr++ = ch;
                }

                *inptr = '\0';  /* terminate string */
        }
        while (ch != CH_NEWLINE && inptr < cp + mx);
}

void
more(int where)
{
        mvaddstr(where, 0, "-- more --");
        getanswer(" ", FALSE);
}

double
infloat(void)
{
        double  result;         /* return value */

        getstring(Databuf, SZ_DATABUF);
        if (sscanf(Databuf, "%lf", &result) < 1)
                /* no valid number entered */
                result = 0.0;

        return (result);
}

int
inputoption(void)
{
        ++Player.p_age;         /* increase age */

        if (Player.p_ring.ring_type != R_SPOILED)
                /* ring ok */
                return (getanswer("T ", TRUE));
        else
                /* bad ring */
        {
                getanswer(" ", TRUE);
                return ((int) ROLL(0.0, 5.0) + '0');
        }
}

void
interrupt(void)
{
        char    line[81];       /* a place to store data already on screen */
        int     loop;           /* counter */
        int     x, y;           /* coordinates on screen */
        int     ch;             /* input */
        unsigned savealarm;     /* to save alarm value */

#ifdef SYS3
        signal(SIGINT, SIG_IGN);
#endif
#ifdef SYS5
        signal(SIGINT, SIG_IGN);
#endif

        savealarm = alarm(0);   /* turn off any alarms */

        getyx(stdscr, y, x);    /* save cursor location */

        for (loop = 0; loop < 80; ++loop) {     /* save line on screen */
                move(4, loop);
                line[loop] = inch();
        }
        line[80] = '\0';        /* nul terminate */

        if (Player.p_status == S_INBATTLE || Player.p_status == S_MONSTER)
                /* in midst of fighting */
        {
                mvaddstr(4, 0, "Quitting now will automatically kill your character.  Still want to ? ");
                ch = getanswer("NY", FALSE);
                if (ch == 'Y')
                        death("Bailing out");
                /* NOTREACHED */
        } else {
                mvaddstr(4, 0, "Do you really want to quit ? ");
                ch = getanswer("NY", FALSE);
                if (ch == 'Y')
                        leavegame();
                /* NOTREACHED */
        }

        mvaddstr(4, 0, line);   /* restore data on screen */
        move(y, x);             /* restore cursor */
        refresh();

#ifdef SYS3
        signal(SIGINT, interrupt);
#endif
#ifdef SYS5
        signal(SIGINT, interrupt);
#endif

        alarm(savealarm);       /* restore alarm */
}

int
getanswer(const char *choices, phbool def)
{
        int     ch;             /* input */
        volatile int    loop;   /* counter */
        volatile int    oldx, oldy;     /* original coordinates on screen */

        getyx(stdscr, oldy, oldx);
        alarm(0);               /* make sure alarm is off */

        for (loop = 3; loop; --loop)
                /* try for 3 times */
        {
                if (setjmp(Timeoenv) != 0)
                        /* timed out waiting for response */
                {
                        if (def || loop <= 1)
                                /* return default answer */
                                break;
                        else
                                /* prompt, and try again */
                                goto YELL;
                } else
                        /* wait for response */
                {
                        clrtoeol();
                        refresh();
#ifdef BSD41
                        sigset(SIGALRM, catchalarm);
#else
                        signal(SIGALRM, catchalarm);
#endif
                        /* set timeout */
                        if (Timeout)
                                alarm(7);       /* short */
                        else
                                alarm(600);     /* long */

                        ch = getchar();

                        alarm(0);       /* turn off timeout */

                        if (ch < 0)
                                /* caught some signal */
                        {
                                ++loop;
                                continue;
                        } else
                                if (ch == CH_REDRAW)
                                        /* redraw screen */
                                {
                                        clearok(stdscr, TRUE);  /* force clear screen */
                                        ++loop; /* don't count this input */
                                        continue;
                                } else
                                        if (Echo) {
                                                addch(ch);      /* echo character */
                                                refresh();
                                        }
                        if (islower(ch))
                                /* convert to upper case */
                                ch = toupper(ch);

                        if (def || strchr(choices, ch) != NULL)
                                /* valid choice */
                                return (ch);
                        else
                                if (!def && loop > 1)
                                        /* bad choice; prompt, and try again */
                                {
                        YELL:           mvprintw(oldy + 1, 0, "Please choose one of : [%s]\n", choices);
                                        move(oldy, oldx);
                                        clrtoeol();
                                        continue;
                                } else
                                        /* return default answer */
                                        break;
                }
        }

        return (*choices);
}

static void
catchalarm(int dummy __unused)
{
        longjmp(Timeoenv, 1);
}