1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-05-03 17:19:43 +02:00
2021-01-28 01:59:04 -06:00

1298 lines
36 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* userio.c -- handy user interface functions */
/* Copyright 1989 Carnegie Mellon University */
/*****************************************************************************
* Change Log
* Date | Change
*-----------+-----------------------------------------------------------------
* 21-May-86 | Created
* 11-Aug-87 | F.H: Added clear_abort(), stop()
* May-88 | JCD : AMIGA VERSION
* 11-Jun-88 | RBD: disable printing of GDEBUG messages
* 12-Oct-88 | JCD : EXCLUSIVE AMIGA VERSION
* 13-Apr-89 | JCD : New portable version.
* 5-Apr | JDW : Further changes
* 2-Mar-92 | GWL : Little changes to satisfy compiler
* 19-Nov-92 | JDZ : Mach tty io threads
* 28-Apr-03 | DM : portability changes. true->TRUE, false->FALSE
*****************************************************************************/
/* Notes on ascii input:
Input is complicated because different systems have varying input models,
especially with regard to handling ^C. The CMT model handles ^C and ^G as
special characters, and these do not cause software interrupts. Also, the
lowest level of the CMT model does not support line editing: Every character
is acted upon immediately. This has two implications:
(1) CMT must "read ahead" looking for ^C and ^G characters. This is handled
by the check_aborted() procedure, which reads characters into the
type_ahead[] array.
(2) CMT must do its own line editing. This is handled by the ggets() routine.
A number of functions support ascii input, only some of which are visible
to the application programmer. Let's start at the top-level and work down;
each of the following calls the routine below it:
ggets() - gets a string with line editing support. This function is fairly
machine independent, except for some backspace-and-erase control character
code sequences.
ggetchar() - gets a raw character. This function calls wait_ascii()
and echoes it. Note that it may return ABORT_CHAR or BREAK_CHAR.
wait_ascii() - gets a raw character without echo and without character
code translation. wait_ascii() either polls get_ascii() or uses some
kind of system-dependent event waiting. Returns ABORT_CHAR or BREAK_CHAR
immediately if abort_flag has been set, regardless of whether there is
new ascii input.
get_ascii() - checks to see if a character is available. (Using
check_aborted().)
The only dependency here is on the Amiga, we restart input when buffer goes
from full to non-full.
check_aborted() - looks for input by calling ascii_input. If found,
put the input into the type_ahead[] buffer. Returns abort_flag.
ascii_input() - lowest level of input; just gets a character if there is
one. Does conversion from RETURN (\r) to EOL (\n). The Amiga handles
this in-line directly in check_aborted().
Here's a quick summary:
ggets = ggetchar + line editing & string building
ggetchar = wait_ascii + character echo
wait_ascii = get_ascii + wait for character
get_ascii = check_aborted + pull char from buffer
check_aborted = ascii_input + test for ^C,^G + put in buffer
ascii_input = poll for char + CR->EOL conversion
*/
#include "switches.h"
#include <stdio.h>
#include <string.h>
#if HAS_STDLIB_H
#include <stdlib.h> /* normal case */
#endif
#ifdef MACINTOSH
# include "StandardFile.h"
/* added for ThinkC 7 */
# ifdef THINK_C
# include <pascal.h>
# endif
#endif
#ifdef AMIGA
# ifdef AZTEC
# include "functions.h"
# else /* LATTICE */
# include "amiga.h"
# include "stdarg.h"
# endif
# include "intuition/intuition.h"
# include "devices/console.h"
#endif
#include "ctype.h"
#include "stdio.h"
#include "cext.h"
#include "userio.h"
#ifdef MICROSOFT
#include "signal.h"
#endif
#ifdef UNIX_MACH
#include <varargs.h>
#include <midistruct.h>
extern char a_in;
extern int a_in_flag;
extern int i_am_running;
#ifdef RTMach
extern itc_mutex_t a_mutex;
extern itc_condition_t a_cond, a_in_cond;
#define A_LOCK() itc_mutex_lock(&a_mutex)
#define A_UNLOCK() itc_mutex_unlock(&a_mutex)
#else /* RTMach */
extern struct mutex a_mutex;
extern struct condition a_cond, a_in_cond;
#define A_LOCK() mutex_lock(&a_mutex)
#define A_UNLOCK() mutex_unlock(&a_mutex)
#endif /* RTMach */
#endif
#ifdef DOTS_FOR_ARGS
#include <stdarg.h>
#endif
#ifdef UNIX
#include <sys/param.h>
#include <sys/resource.h>
#include "cmtio.h"
#ifdef _IBMR2
#define NBBY 8
#define OPEN_MAX 2000
#endif
#include <sys/select.h>
#endif
#ifdef linux
#include <sys/time.h> /* for FD_ZERO / FD_SET */
#endif
extern int debug;
#ifdef NYQUIST
/* get definitions for stdputstr, etc. */
#include "xlisp.h"
#endif
int IOinputfd; /* input file descriptor (usually 0) */
int IOnochar; /* Value to be returned by IOgetchar()
where there is no input to be had */
/****************************************************************************
*
* routines private to this module
*
****************************************************************************/
int GetReadFileName(void);
int GetWriteFileName(void);
#ifdef MACINTOSH
private void PtoC_StrCopy(char *p1, char *p2);
#endif
#ifdef AMIGA
char ConGetChar();
ConMayGetChar();
private void ConRead();
private void ConPutStr();
private void ConPutChar();
UBYTE ascii_signal();
UBYTE KeybSig();
#endif
/****************************************************************************
*
* variables shared with other modules
*
****************************************************************************/
public int abort_flag; /* control C or control G equivalent */
public int redirect_flag; /* check whether the I/O has been redirected--
Added by Ning Hu Apr.2001*/
/* extern void musicterm(); */ /*DMH: from macmidi.c, to allow abort_check*/
public boolean ascii_input(char *c);
/****************************************************************************
*
* variables private to this module
*
****************************************************************************/
#ifdef AMIGA
struct IntuitionBase *IntuitionBase;
private struct IOStdReq *ConOutReq;
private struct MsgPort *ConOutPort;
private struct IOStdReq *ConInReq;
private struct MsgPort *ConInPort;
private char KeyBuff[16];
private struct Window *Window;
private struct NewWindow NewWindow = {
0,11,640,189,
0,1,
NULL,
SMART_REFRESH | ACTIVATE | WINDOWDRAG | WINDOWDEPTH |
WINDOWSIZING,
NULL,NULL,
(STRPTR) "Carnegie Mellon University MIDI Toolkit for Commodore AMIGA",
NULL,NULL,
100,25,640,200,
WBENCHSCREEN };
#endif
#ifdef MACINTOSH
private OSType io_file_type = 0x3F3F3F3F; /* '????' */
private OSType io_file_creator = 0x3F3F3F3F; /* '????' */
#endif
#define type_ahead_max 100
char type_ahead[100];
int type_ahead_head = 0;
int type_ahead_tail = 0;
int type_ahead_count = 0;
#ifdef DOS
#ifdef BORLAND
int c_break(void)
{
gprintf(TRANS, " BREAK ");
abort_flag = ABORT_LEVEL;
return 1; /* non-zero means do not exit program */
}
#endif
#ifdef MICROSOFT
void c_break(int sig)
{
abort_flag = ABORT_LEVEL;
/* The CTRL+C interrupt must be reset to our handler since
* by default it is reset to the system handler.
*/
signal(SIGINT, c_break); /* assume this succeeds */
}
#endif
#endif
#ifdef MACINTOSH
#ifdef NYQUIST
void FlushOutput (void);
#endif
#endif
/* gflush -- flush output produced by gprintf, etc. */
/**/
void gflush(void)
{
#ifdef MACINTOSH
#ifdef NYQUIST
FlushOutput();
#else
fflush(stdout); /* make sure any prompts or errors have been output */
fflush(STDERR);
#endif /* NYQUIST */
#endif /* MACINTOSH */
#ifdef UNIX
fflush(stdout); /* make sure any prompts or errors have been output */
fflush(STDERR);
#endif
}
/****************************************************************************
* io_init
*
* I added this init function for the AMIGA version.
*
* io_init : opens a window
* and exits if initialisation can not be done properly.
* registers cleanup calls to carefully deallocate resources.
*
* io_init is not amiga specific : the simplest version
* of io_init could be a clear screen statement for example, and a
* printf("Good bye !\n") on exit.
*
* for the Mac, it seems that ascii_input doesn't work unless getchar() is
* called first. I assume this is because getchar() initializes the ability
* of the window to process type-in, so there is probably a way to set this
* directly. If you figure it out, let me know. -RBD
*
*****************************************************************************/
void
io_init()
{
#ifdef AMIGA
int error;
/* Window and console initialisation */
IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",1L);
if (IntuitionBase == NULL) EXIT(1);
cu_register((cu_fn_type) CloseLibrary, IntuitionBase);
ConOutPort = CreatePort("conoutport", 0L);
if (ConOutPort == NULL) EXIT(1);
cu_register((cu_fn_type) DeletePort, ConOutPort);
ConOutReq = CreateStdIO(ConOutPort);
if (ConOutReq == NULL) EXIT(1);
cu_register((cu_fn_type) DeleteStdIO, ConOutReq);
ConInPort = CreatePort("coninport", 0L);
if (ConInPort == NULL) EXIT(1);
cu_register((cu_fn_type) DeletePort, ConInPort);
ConInReq = CreateStdIO(ConInPort);
if (ConInReq == NULL) EXIT(1);
cu_register((cu_fn_type) DeleteStdIO, ConInReq);
Window = OpenWindow(&NewWindow);
if (Window == NULL) EXIT(1);
cu_register((cu_fn_type) CloseWindow, Window);
ConOutReq->io_Data = (APTR)Window;
ConOutReq->io_Length = sizeof(*Window);
error = OpenDevice("console.device", 0L, (struct IORequest *) ConOutReq, 0L);
ConInReq->io_Device = ConOutReq->io_Device;
ConInReq->io_Unit = ConOutReq->io_Unit;
if (error != NULL) EXIT(1);
cu_register((cu_fn_type) CloseDevice, ConOutReq);
ConInReq->io_Command = CMD_READ;
ConInReq->io_Data = (APTR)KeyBuff;
ConInReq->io_Length = 1;
SendIO((struct IORequest *) ConInReq);
#endif
#ifdef UNIX
#ifndef BUFFERED_SYNCHRONOUS_INPUT
IOsetup(0 /* standard input */);
cu_register((cu_fn_type) IOcleanup, NULL);
#endif
#endif
#ifdef MACINTOSH
#ifndef NYQUIST /* don't need this if we're in Nyquist */
char s[100];
printf("Type <return> to start: ");
fgets(s, 100, stdin);
#endif /* NYQUIST */
#endif
#ifdef DOS
#ifdef MICROSOFT
if (signal(SIGINT, c_break) == SIG_ERR) {
gprintf(ERROR, "Couldn't set Ctrl C handler\n");
EXIT(1);
}
#else
#ifdef BORLAND
ctrlbrk(c_break);
#else
... we are in DOS, but neither MICROSOFT nor BORLAND,
please set up a control C handler here...
#endif
#endif
#endif
}
#ifdef MACINTOSH
/****************************************************************************
* abort_check
* Effect:
* exit nicely if the aborted flag is set
****************************************************************************/
public void abort_check()
{
if (abort_flag) clean_exit();
}
/****************************************************************************
* clean_exit
* Effect:
* clean up and exit
****************************************************************************/
public void clean_exit()
{
gprintf(TRANS, "Exiting...\n");
EXIT(1);
}
#ifdef MPW
/****************************************************************************
* cleanup_abort_handler
* Effect:
* shuts down abort watcher
****************************************************************************/
public void cleanup_abort_handler()
{
(void) sigset(SIGINT, SIG_DFL); /* deactivate abort watcher */
}
/****************************************************************************
* init_abort_handler
* Effect:
* starts abort watcher
* aborted flag is set to FALSE
****************************************************************************/
public void init_abort_handler()
{
abort_flag = FALSE;
(void) sigset(SIGINT, abort_watcher); /* activate abort watcher */
}
#endif
#endif
/****************************************************************************
* askbool
* Inputs:
* char *prompt: string to prompt for user input
* int deflt: TRUE or FALSE default
* Returns:
* boolean: TRUE or FALSE as entered by user
* Effect:
* prompts user for yes or no input, returns result
****************************************************************************/
int askbool(prompt, deflt)
char *prompt;
int deflt;
{
#define undefined -1
char defchar; /* the default answer */
char c; /* user input */
char in_string[100];
int result = -1; /* the result: -1 = undefined, 0 = FALSE, 1 = TRUE */
if (deflt) defchar = 'y';
else defchar = 'n';
while (result == undefined) {
gprintf(TRANS, "%s? [%c]: ", prompt, defchar);
ggets(in_string);
c = in_string[0];
if (islower(c)) c = toupper(c);
if (c == 'Y') result = TRUE;
else if (c == 'N') result = FALSE;
else if (c == EOS) result = deflt;
else if (abort_flag) result = deflt;
/* space before Please to separate from user's type-in: */
else gprintf(TRANS, " Please type Y or N.\n");
}
if (abort_flag == BREAK_LEVEL) {
abort_flag = 0;
result = deflt;
gprintf(TRANS, "\n");
}
return result;
}
/****************************************************************************
* fileopen
* Inputs:
* char *deflt: the default file name (e.g. from command line)
* char *extension: default extension
* char *mode: read ("r") or write ("w")
* char *prompt: prompt for user
* Returns:
* opened file pointer
* Effect:
* opens file, prompts for user input if necessary and warns about
* possible confusion. If deflt is a null string or NULL, the user will
* be prompted for a name. The routine loops until a file is opened.
* If the mode is "r", a check is made to see if the file exists
* with and without the extension. If both exist a warning is given.
* For mode "w", a check is made to see if the file will be overwritten.
* The extension is automatically added if the default or user-typed
* file has no "." At the bottom of the loop body, if no file has
* been opened, the user is prompted for another file name.
****************************************************************************/
char fileopen_name[100]; /* name of the opened file */
FILE *fileopen(deflt, extension, mode, prompt)
char *deflt;
char *extension; /* default extension */
char *mode; /* read "r" or write "w" */
char *prompt; /* prompt for user */
{
char extname[100]; /* trial name with extension added */
FILE *fp = NULL; /* file corresponding to filename */
FILE *fpext; /* file corresponding to extname */
char *problem = NULL; /* tells user why he has to try again */
if (!deflt) deflt = ""; /* treat NULL as the empty string */
strcpy(fileopen_name, deflt);
/* keep trying until a good file is found: */
while (fp == NULL) {
/* avoid null file names: */
while (strlen(fileopen_name) == 0) {
#ifndef MACINTOSH
gprintf(TRANS, "%s : ", prompt);
ggets(fileopen_name);
if (abort_flag) {
if (abort_flag == BREAK_LEVEL) {
abort_flag = 0;
/* type return since user didn't... */
gprintf(TRANS, "\n");
}
return NULL;
}
#else /* use Macintosh file dialog */
if (mode[0] == 'r') {
if (!GetReadFileName(fileopen_name)) return NULL;
} else if (mode[0] == 'w') {
if (!(GetWriteFileName(fileopen_name, prompt))) return NULL;
} else {
gprintf(ERROR, "(fileopen) internal error: bad mode\n");
}
#endif /* MACINTOSH */
}
if (mode[0] == 'r') {
strcpy(extname, fileopen_name);
strcat(extname, ".");
strcat(extname, extension);
fp = NULL;
fpext = NULL;
if (ok_to_open(fileopen_name, mode)) {
fp = fopen(fileopen_name, mode);
}
if (ok_to_open(extname, mode)) {
fpext = fopen(extname, mode);
}
if (fp != NULL && fpext != NULL) {
gprintf(TRANS,
"warning: both %s and %s exist. %s will be used.\n",
fileopen_name, extname, fileopen_name);
fclose(fpext);
} else if (fpext != NULL) {
fp = fpext;
strcpy(fileopen_name, extname); /* remember what was opened */
}
if (fp == NULL) problem = "Couldn't find %s.\n";
} else if (mode[0] == 'w') {
boolean added_extension = FALSE;
/* add the extension if there is no '.' in the file name */
if (!strchr(fileopen_name, '.')) {
strcat(fileopen_name, ".");
strcat(fileopen_name, extension);
added_extension = TRUE;
}
if (TRUE
#ifdef MACINTOSH
/* file open dialog already asked user to confirm unless we're
* adding an extension
*/
&& added_extension
#endif
) {
fp = NULL;
if (ok_to_open(fileopen_name, "r"))
fp = fopen(fileopen_name, "r");
if (fp != NULL) {
char question[100];
fclose(fp);
strcpy(question, "OK to overwrite ");
strcat(question, fileopen_name);
if (!askbool(question, FALSE)) {
fp = NULL;
problem = "\n";
goto tryagain;
}
}
}
fp = NULL;
if (ok_to_open(fileopen_name, mode))
fp = fopen(fileopen_name, mode);
if (fp == NULL) problem = "Couldn't create %s.\n";
}
tryagain:
if (fp == NULL) {
gprintf(TRANS, problem, fileopen_name);
gprintf(TRANS,"Try again.\n");
fileopen_name[0] = EOS;
}
}
return fp;
}
#ifdef MACINTOSH
static int GetReadFileName(name)
char *name;
{
static Point p = {100,100};
SFReply loadfile;
SFTypeList mytypes;
mytypes[0] = 0x54455854; /* 'TEXT' */
mytypes[1] = 0x4D696469; /* 'Midi' */
mytypes[2] = 0x3F3F3F3F; /* '????' */
/* could put any filter here (i.e. giofilefileter) */
SFGetFile(p, "\p", NULL, 3, mytypes, 0L, &loadfile);
if (loadfile.good) {
SetVol(0L,loadfile.vRefNum);
PtoC_StrCopy((char *) &loadfile.fName, name);
return(true);
} else return(false);
}
static int GetWriteFileName(fn, str)
char *fn, *str;
{
static Point SFPwhere = { 106, 104 };
unsigned char Pstr[100], Pfn[100];
SFReply reply;
strcpy((char *)Pstr, str);
CtoPstr((char *)Pstr);
strcpy((char *)Pfn, fn);
CtoPstr((char *)Pfn);
SFPutFile(SFPwhere, (ConstStr255Param) Pstr, (ConstStr255Param) Pfn,
0L, &reply);
if (reply.good) {
SetVol (0L,reply.vRefNum);
PtoC_StrCopy((char *) &reply.fName, fn);
return(true);
}
else return(false);
}
void PtoC_StrCopy(p1, p2)
register char *p1, *p2;
/* copies a pascal string from p1 to p2 */
{
register int len;
len = *p1++;
while (--len>=0) *p2++=*p1++;
*p2 = '\0';
}
boolean get_file_info(char *filename, OSType *file_type, OSType *file_creator)
{
short rc; /* toolbox return code */
FInfo fi; /* toolbox file info */
char fn[101]; /* temporary file name */
strcpy(fn, filename);
CtoPstr(fn);
if (rc = GetFInfo((byte*)fn, 0, &fi)) {
gprintf(ERROR, "rc from GetFInfo=%d\n", rc);
gprintf(ERROR, "unable to get file type\n");
*file_type = 0x3F3F3F3F; /* '????' */
*file_creator = 0x3F3F3F3F; /* '????' */
return FALSE;
} else /* set file type & creator */ {
if (debug) gprintf(TRANS, "File Type: '%.4s' File Creator: '%.4s'\n",
&fi.fdType, &fi.fdCreator );
*file_type = fi.fdType;
*file_creator = fi.fdCreator;
}
return TRUE;
}
boolean put_file_info(char *filename, OSType file_type, OSType file_creator)
{
short rc; /* toolbox return code */
FInfo fi; /* toolbox file info */
char fn[101]; /* temporary file name */
if (debug) gprintf(TRANS,"set file %s to become type '%.4s'\n", filename, &file_type);
strcpy(fn, filename);
CtoPstr(fn);
if (rc = GetFInfo((byte*)fn, 0, &fi)) {
gprintf(TRANS, "rc from GetFInfo=%d\n", rc);
gprintf(TRANS, "unable to set file type\n");
} else /* set file type & creator */ {
if (debug) gprintf(TRANS, "File Type: '%.4s' File Creator: '%.4s'\n",
&fi.fdType, &fi.fdCreator );
fi.fdType = file_type;
fi.fdCreator = file_creator;
if (rc=SetFInfo((byte*)fn, 0, &fi)) {
gprintf(TRANS, "rc from SetFInfo=%d\n", rc);
gprintf(TRANS, "unable to set file type\n");
} else if (rc=GetFInfo((byte*)fn, 0, &fi)) {
gprintf(TRANS, "rc from GetFInfo=%d\n", rc);
gprintf(TRANS, "unable to verify file type\n");
} else {
if (debug) gprintf(TRANS, "File Type: '%.4s' File Creator: '%.4s'\n",
&fi.fdType, &fi.fdCreator );
}
}
}
#endif /* MACINTOSH */
#ifdef AMIGA
/***************************************************************
* ascii_signal
*
* Input : none
* Ouput : none
* Return: the signal that will be raised on ascii input
* Effect: none
***************************************************************/
UBYTE ascii_signal()
{
return ConInPort->mp_SigBit;
}
#endif
/* check_aborted -- see if any characters are available, check for ctrl C */
int check_aborted()
{
char in_c;
#ifdef AMIGA
if (GetMsg(ConInPort)) {
in_c = KeyBuff[0];
if (in_c == '\r') in_c = '\n';
#endif
#ifndef AMIGA /* DOS or MACINTOSH or UNIX */
if (type_ahead_count < type_ahead_max && ascii_input(&in_c)) {
#endif
type_ahead[type_ahead_tail] = in_c;
if (in_c == ABORT_CHAR) abort_flag = ABORT_LEVEL;
else if (!abort_flag && in_c == BREAK_CHAR)
abort_flag = BREAK_LEVEL;
/* go ahead and insert anything into buffer, including ^C, ^G: */
type_ahead_count++;
type_ahead_tail++;
if (type_ahead_tail == type_ahead_max) type_ahead_tail = 0;
#ifdef AMIGA
if (type_ahead_count < type_ahead_max) ConRead();
#endif
}
return abort_flag;
}
/****************************************************************************
* readln
* Inputs:
* FILE * fp: File to read from
* Effect:
* Reads and discards characters until a newline is seen
****************************************************************************/
void readln(fp)
register FILE *fp;
{
register int c;
while (((c = getc(fp)) != '\n') && (c != EOF)) ;
}
/****************************************************************************
* gprintf
* Inputs:
* int * handler: pointer to output handler (say, a window)
* or one of {TRANS, ERROR, FATAL, GDEBUG} from userio.h
* char * format: a null-terminated printf style format string
* int arg0 through arg14: a variable number of arguments for printf
* Effect:
* formats and outputs the specified information to an output handler.
* this is a system-independent approach to output. On
* a simple machine, it is like printf. on a more complex machine,
* output is directed to the appropriate window.
* Implementation
* Note that to handle the variable argument list, a number of different
* approaches are implemented. The first part of the implementation selects
* one of 4 ways to build temp1, a formatted string. The 4 ways arise from
* use or non-use of vsnprintf, and use or non-use of ... in the arg list.
* After building temp1, non-Amiga systems write to stdout or stderr,
* whereas AMIGA writes to a special console. Why? Because the Amiga
* needs a new console so we can set up a signal upon character typein.
****************************************************************************/
#ifndef gprintf
#define GPRINTF_MESSAGE_LEN 512
#ifdef HAVE_VSNPRINTF
#ifdef DOTS_FOR_ARGS
/* define with ... in arg list and use vsnprintf to get temp1 */
public void gprintf(long where, const char *format, ...)
{
char temp1[GPRINTF_MESSAGE_LEN];
#ifdef AMIGA
char temp2[GPRINTF_MESSAGE_LEN];
#endif
va_list ap;
va_start(ap, format);
vsnprintf(temp1, GPRINTF_MESSAGE_LEN, format, ap);
va_end(ap);
#else /* !DOTS_FOR_ARGS */
/* define with va_alist and use vsnprintf to get temp1 */
public void gprintf(where, format, va_alist)
long where;
char *format;
va_dcl
{
char temp1[GPRINTF_MESSAGE_LEN];
va_list pvar;
/* this is a syntax error - if you don't have to remove this, */
/* then this whole section of code is unnecessary. */
va_start(pvar);
vsnprintf(temp1, GPRINTF_MESSAGE_LEN, format, pvar);
va_end(pvar);
#endif /* DOTS_FOR_ARGS */
#else /* !HAVE_VSNPRINTF */
#define MAX_GPRINTF_ARGS 10
typedef struct gp_args_struct {
long arg[MAX_GPRINTF_ARGS];
} gp_args_node;
#ifdef DOTS_FOR_ARGS
/* use ... but not vsnprintf */
public void gprintf(long where, char *format, ...)
{
char temp1[GPRINTF_MESSAGE_LEN];
#ifdef AMIGA
char temp2[GPRINTF_MESSAGE_LEN];
#endif
va_list ap;
gp_args_node args;
va_start(ap, format);
args = va_arg(ap, gp_args_node);
va_end(ap);
#else /* !DOTS_FOR_ARGS */
/* don't use ... and don't use vsnprintf */
public void gprintf(where, format, args)
long where;
char *format;
gp_args_node args;
{
char temp1[GPRINTF_MESSAGE_LEN];
#ifdef AMIGA
char temp2[GPRINTF_MESSAGE_LEN];
#endif /* AMIGA*/
#endif /* DOTS_FOR_ARGS */
snprintf(temp1, GPRINTF_MESSAGE_LEN, format, args);
#endif /* HAVE_VSNPRINTF */
/*
* Now we've got formatted output in temp1. Write it out.
*/
#ifdef NYQUIST
switch ((long) where) {
case TRANS:
stdputstr(temp1);
break;
case ERROR:
errputstr(temp1);
break;
case FATAL:
errputstr("FATAL: ");
errputstr(temp1);
break;
case GDEBUG:
errputstr("DEBUG: ");
errputstr(temp1);
break;
default:
errputstr("UNKNOWN: ");
errputstr(temp1);
break;
}
gflush();
#else /* not NYQUIST */
#ifdef AMIGA
switch((long) where) {
case TRANS:
strcpy(temp2, temp1);
break;
case ERROR:
strcpy(temp2, temp1);
break;
case FATAL:
strcpy(temp2, "FATAL: ");
strcat(temp2, temp1);
break;
case GDEBUG:
strcpy(temp2,"DEBUG: ");
strcat(temp2, temp1);
break;
default:
strcpy(temp2, "UNKNOWN: ");
strcat(temp2, temp1);
break;
}
ConOutReq->io_Command = CMD_WRITE;
ConOutReq->io_Data = (APTR)temp2;
ConOutReq->io_Length = -1; /* NULL terminated string */
DoIO((struct IORequest *) ConOutReq);
#else /* not NYQUIST or AMIGA */
switch(where) {
case TRANS:
printf("%s", temp1);
break;
case ERROR:
fprintf(STDERR, "%s", temp1);
break;
case GDEBUG:
fprintf(STDERR, "DEBUG %s", temp1);
break;
case FATAL:
fprintf(STDERR, "FATAL %s", temp1);
break;
default:
fprintf(STDERR, "UNKNOWN %s", temp1);
break;
}
#endif /* AMIGA */
#endif /* NYQUIST */
}
#endif /* ifndef gprintf */
/**************************************************************************
* gputchar
* General putchar
**************************************************************************/
#ifndef gputchar
#ifdef AMIGA
public int gputchar(c)
int c;
{
ConPutChar((char)c);
return(c);
}
#else
public int gputchar(c)
int c;
{
putchar((char)c);
return(c);
}
#endif
#endif /* ifndef gputchar */
/**************************************************************************
* ggetchar
* General getchar
**************************************************************************/
public int ggetchar()
{
#ifdef BUFFERED_SYNCHRONOUS_INPUT
return getchar();
#else
int key = wait_ascii();
if (key != ABORT_CHAR && key != '\b') gputchar((char)key);
return(key);
#endif
}
/**************************************************************************
* ggets
* General gets
**************************************************************************/
#ifndef ggets
public char *ggets(str)
char *str;
{
char *s = str;
int c;
do {
c = ggetchar();
if (c == '\b' /* backspace */) {
if (s != str) {
gputchar('\b');
gputchar((int)' ');
gputchar('\b');
s--;
} else {
#ifdef AMIGA
gputchar((int)0x9b);
gputchar((int)0x43);
#else
/* gputchar((int)' '); */
#endif
gputchar((int)0x07);
}
} else *s++ = (char) c;
} while (c != (int) '\n' && !abort_flag);
*(s-1) = EOS;
if (abort_flag) *str = EOS;
return str;
}
#endif /* ifndef ggets */
/****************************************************************************
* get_ascii
* Returns:
* boolean: TRUE if a character was found
* int * c: pointer to int into which to store the character, if any
* Effect:
* polls (doesn't wait) for an ascii character and says if it got one
* the character is returned in *c.
****************************************************************************/
public boolean get_ascii(c)
char *c;
{
check_aborted(); /* input buffer check */
if (type_ahead_count == 0) return FALSE;
#ifdef AMIGA
/* if the buffer is full, then there is no outstanding read, restart it: */
if (type_ahead_count == type_ahead_max) ConRead();
#endif
type_ahead_count--;
*c = type_ahead[type_ahead_head++];
if (type_ahead_head == type_ahead_max) type_ahead_head = 0;
return TRUE;
}
#ifdef MACINTOSH /** Macintosh direct ascii input**/
public boolean ascii_input(c)
char *c;
{
EventRecord theEvent;
(void) GetNextEvent((keyDownMask | autoKeyMask), &theEvent);
if ((theEvent.what == keyDown) || (theEvent.what == autoKey)) {
*c = theEvent.message & charCodeMask;
if (*c == '\r') *c = '\n';
return(true);
}
else {
return(false);
}
}
#endif
#ifdef WINDOWS
#include "conio.h"
#define kbhit _kbhit
#define getch _getch
#endif
#ifdef DOS
public boolean ascii_input(c)
char *c;
{
if (abort_flag == ABORT_LEVEL) {
*c=ABORT_CHAR;
return((boolean)TRUE);
}
if (kbhit()) { /* If the keyboard was hit */
*c = getch(); /* Don't echo it */
// printf("now break");
if (*c == '\r') *c = '\n';
return((boolean)TRUE);
}
return((boolean)FALSE); /* Keeps Lattice compiler happy */
}
#endif
#ifdef UNIX
public boolean ascii_input(char *c)
{
#ifdef UNIX_MACH
/*
* we can't read from stdin directly, because the ascii
* input thread is already doing so, so instead we'll
* wait for that thread to read a character and then take
* it
*/
boolean ret = FALSE;
A_LOCK();
if (a_in_flag) {
(*c) = a_in;
a_in_flag = 0;
ret = TRUE;
}
A_UNLOCK();
if (ret) {
#ifdef RTMach
itc_condition_signal(&a_cond);
#else /* RTMach */
condition_signal(&a_cond);
#endif /* RTMach */
}
if ((*c) == '\r')
(*c) = '\n';
return(ret);
#else /* __APPLE__ */
#ifndef BUFFERED_SYNCHRONOUS_INPUT
int input = IOgetchar();
if (input != IOnochar) {
*c = input;
if (*c == '\r') *c = '\n';
return TRUE;
}
#endif /* BUFFERED_SYNCHRONOUS_INPUT */
return FALSE;
#endif /* __APPLE__ */
}
#endif
#ifndef AMIGA /*DOS and MAC and UNIX */
public void unget_ascii(char c)
{
if (type_ahead_head == 0) type_ahead_head = type_ahead_max;
type_ahead_head--;
type_ahead[type_ahead_head] = c;
type_ahead_count++;
}
public boolean check_ascii(void)
{
char c;
if(get_ascii(&c)) {
unget_ascii(c);
return TRUE;
}
else return FALSE;
}
#endif
/****************************************************************************
* wait_ascii
* Returns:
* int: character for key pressed
* Effect:
* waits for the user to type a key on the terminal keyboard
* (versus the synthesizer keyboard) and returns the key typed
****************************************************************************/
#ifdef MACINTOSH
public int wait_ascii()
{
char key ; /* key typed */
if (abort_flag == ABORT_LEVEL) return ABORT_CHAR;
if (abort_flag == BREAK_LEVEL) return BREAK_CHAR;
gflush();
while (!get_ascii(&key)) ;
return(key);
}
#endif
#ifdef DOS
public int wait_ascii()
{
char key ; /* key typed */
if (abort_flag == ABORT_LEVEL) return ABORT_CHAR;
if (abort_flag == BREAK_LEVEL) return BREAK_CHAR;
if (!get_ascii(&key)) {
key = _getch(); // block until we get an input
}
/* GWL - check for abort on previos line */
return (int)key;
}
#endif
#ifndef MACINTOSH
#ifndef DOS
public int wait_ascii()
{
#ifdef UNIX /* was defined (UNIX) || defined(ITC) */
#ifndef UNIX_MACH
fd_set readfds;
#endif /* !UNIX_MACH */
#endif
char c;
struct rlimit file_limit;
if (abort_flag == ABORT_LEVEL) return ABORT_CHAR;
if (abort_flag == BREAK_LEVEL) return BREAK_CHAR;
while (!get_ascii(&c)) {
#ifdef AMIGA
WaitPort(ConInPort);
#endif
#ifdef UNIX
fflush(stdout);
#ifdef UNIX_MACH
/*
* we can't select, since another thread is reading
* from stdin, and we don't want to have an input war
* so instead, the ascii input thread will signal
* a_in_cond when it gets input, so we just wait
* for that to happen
*/
A_LOCK();
#ifdef RTMach
itc_condition_wait(&a_in_cond, &a_mutex);
#else /* RTMach */
condition_wait(&a_in_cond, &a_mutex);
#endif /* RTMach */
A_UNLOCK();
#else /* UNIX_MACH */
FD_ZERO(&readfds);
FD_SET(IOinputfd, &readfds);
gflush();
getrlimit(RLIMIT_NOFILE, &file_limit);
select((int) (file_limit.rlim_max+1), &readfds, 0, 0, NULL);
#endif /* !__APPLE__ */
#endif /* ifdef UNIX */
}
return (int) c;
}
#endif
#endif
#ifdef AMIGA
/******************************************************************
AMIGA 2000.
Console IO Functions
JCD 25-Apr-88
*******************************************************************/
UBYTE KeybSig()
{
return ConInPort->mp_SigBit;
}
private void ConPutChar(c)
char c;
{
ConOutReq->io_Command = CMD_WRITE;
ConOutReq->io_Data = (APTR)&c;
ConOutReq->io_Length = 1;
DoIO((struct IORequest *) ConOutReq);
}
private void ConPutStr(str)
char *str;
{
ConOutReq->io_Command = CMD_WRITE;
ConOutReq->io_Data = (APTR)str;
ConOutReq->io_Length = -1;
DoIO((struct IORequest *) ConOutReq);
}
private void ConRead()
{
ConInReq->io_Command = CMD_READ;
ConInReq->io_Data = (APTR)KeyBuff;
ConInReq->io_Length = 1;
SendIO((struct IORequest *) ConInReq);
}
#endif