/* 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 #include #if HAS_STDLIB_H #include /* normal case */ #endif #ifdef MACINTOSH # include "StandardFile.h" /* added for ThinkC 7 */ # ifdef THINK_C # include # 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 #include 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 #endif #ifdef UNIX #include #include #include "cmtio.h" #ifdef _IBMR2 #define NBBY 8 #define OPEN_MAX 2000 #endif #include #endif #ifdef linux #include /* for FD_ZERO / FD_SET */ #endif extern int debug; #ifdef NYQUIST /* get definitions for stdputstr, etc. */ #include "xlisp.h" #endif /**************************************************************************** * * routines private to this module * ****************************************************************************/ int GetReadFileName(); int GetWriteFileName(); #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(); /**************************************************************************** * * 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 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 = fopen(fileopen_name, 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 = 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 = 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 vsprintf, 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 USE_VSPRINTF #ifdef DOTS_FOR_ARGS /* define with ... in arg list and use vsprintf to get temp1 */ public void gprintf(long where, char *format, ...) { char temp1[GPRINTF_MESSAGE_LEN]; #ifdef AMIGA char temp2[GPRINTF_MESSAGE_LEN]; #endif va_list ap; va_start(ap, format); vsprintf(temp1, format, ap); va_end(ap); #else /* !DOTS_FOR_ARGS */ /* define with va_alist and use vsprintf 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); vsprintf(temp1, format, pvar); va_end(pvar); #endif /* DOTS_FOR_ARGS */ #else /* !USE_VSPRINTF */ #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 vsprintf */ 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 vsprintf */ 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 */ sprintf(temp1, format, args); #endif /* USE_VSPRINTF */ /* * 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(c) 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 /* UNIX_MACH */ #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 /* UNIX_MACH */ } #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() { 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(file_limit.rlim_max+1, &readfds, 0, 0, NULL); #endif /* !UNIX_MACH */ #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