Beispiel #1
0
int getop(char s[])
{
	int i, c, next;

	while ((s[0] = c = get_ch()) == ' ' || c == '\t')
		;	/* 我写代码时,还检查了回车,但是不应该检查回车,其是有效字符 */
	s[1] = '\0';
	if (is_loweralpha(c))	/* 判断是否是变量,变量名只有一个小写字母 */
		return 'a';
	if (!is_digit(c) && c != '.' && c != '-')
		return c;
	i = 0;
	if (c == '-') {	/* collect negative sign */
		if (!is_digit(next = get_ch()) && next != '.') {
			unget_ch(next);
			return c;
		}
		s[++i] = c = next;
	}
	if (is_digit(c))
		while (is_digit(s[++i] = c = get_ch()))
			;
	if (c == '.')	/* collect fraction part */
		while (is_digit(s[++i] = c = get_ch()))
			;
	s[i] = '\0';
	if (c != EOF)
		unget_ch(c);
	return '0';
}
Beispiel #2
0
static int  post_preproc(
    char * out
)
/*
 * Convert digraphs and double '\\' of the second byte of SJIS (BIGFIVE or
 * ISO2022_JP).
 * Note: Output of -K option embeds macro informations into comments.
 * scan_token() does not recognize comment and parses it as '/', '*', etc.
 */
{
#if ! HAVE_DIGRAPHS
    int     di_count = 0;
#endif
    int     token_type;
    int     c;
    char *  str;
    char *  cp = out;

    unget_string( out, NULL);
    while ((c = get_ch()) != '\n') {    /* Not to read over to next line    */
        if (char_type[ c] & HSP) {
            *cp++ = c;
            continue;
        }
        str = cp;
        token_type = scan_token( c, &cp, out_wend);
        switch (token_type) {
#if ! MBCHAR_IS_ESCAPE_FREE
        case WSTR   :
        case WCHR   :
            str++;                          /* Skip prefix 'L'      */
            /* Fall through */
        case STR    :
        case CHR    :
            if (bsl_need_escape)
                cp = esc_mbchar( str, cp);
            break;
#endif  /* ! MBCHAR_IS_ESCAPE_FREE  */
#if ! HAVE_DIGRAPHS
        case OPE    :
            if (mcpp_mode == STD && (openum & OP_DIGRAPH)) {
                cp = conv_a_digraph( cp);   /* Convert a digraph    */
                di_count++;
            }
            break;
#endif
        }
    }
    *cp++ = '\n';
    *cp = EOS;
#if ! HAVE_DIGRAPHS
    if (mcpp_mode == STD && di_count && (warn_level & 16))
        cwarn( "%.0s%ld digraph(s) converted"           /* _W16_    */
                , NULL, (long) di_count, NULL);
#endif
    return  0;
}
Beispiel #3
0
static void devide_line(
    char * out                      /* 'out' is 'output' in actual  */
)
/*
 * Devide a too long line into output lines shorter than NWORK.
 * This routine is called from putout().
 */
{
    FILEINFO *  file;
    char *  save;
    char *  wp;
    int     c;

    file = unget_string( out, NULL);        /* To re-read the line  */
    wp = out_ptr = out;

    while ((c = get_ch()), file == infile) {
        if (char_type[ c] & HSP) {
            if (keep_spaces || out == out_ptr
                    || (char_type[ *(out_ptr - 1) & UCHARMAX] & HSP)) {
                *out_ptr++ = c;
                wp++;
            }
            continue;
        }
        scan_token( c, &wp, out_wend);          /* Read a token     */
        if (NWORK-2 < wp - out_ptr) {           /* Too long a token */
            cfatal( "Too long token %s", out_ptr, 0L, NULL);        /* _F_  */
        } else if (out_end <= wp) {             /* Too long line    */
            if (mcpp_debug & MACRO_CALL) {      /* -K option        */
                /* Other than GCC or Visual C   */
                /* scan_token() scans a comment as sequence of some */
                /* tokens such as '/', '*', ..., '*', '/', since it */
                /* does not expect comment.                         */
                save = out_ptr;
                while ((save = strrchr( save, '/')) != NULL) {
                    if (*(save - 1) == '*') {   /* '*' '/' sequence */
                        out_ptr = save + 1;     /* Devide at the end*/
                        break;                  /*      of a comment*/
                    }
                }
            }
            save = save_string( out_ptr);       /* Save the token   */
            *out_ptr++ = '\n';                  /* Append newline   */
            *out_ptr = EOS;
            put_a_line( out);           /* Putout the former tokens */
            wp = out_ptr = stpcpy( out, save);      /* Restore the token    */
            free( save);
        } else {                            /* Still in size        */
            out_ptr = wp;                   /* Advance the pointer  */
        }
    }

    unget_ch();                 /* Push back the source character   */
    put_a_line( out);                   /* Putout the last tokens   */
    sharp( NULL, 0);                        /* Correct line number  */
}
Beispiel #4
0
int get_op(char s[]) {
	int i, c;

	while ((s[0] = c = get_ch()) == ' ' || c == '\t')
		;
	s[1] = '\0';
	if (!isdigit(c) && c != '.' && c != '-')
		return c;
	i = 0;
	if (isdigit(c) || c == '-')
		while (isdigit(s[++i] = c = get_ch()))
			;
	if (c == '.')
		while (isdigit(s[++i] = c = get_ch()))
			;
	s[i] = '\0';
	if (c != EOF)
		unget_ch(c);
	return NUMBER;
}
Beispiel #5
0
static void put_seq(
    char *  begin,                  /* Sequence already in buffer   */
    char *  seq                     /* Sequence to be read          */
)
/*
 * Put out the failed sequence as it is.
 */
{
    FILEINFO *  file = infile;
    int     c;

    cerror( "Operand of _Pragma() is not a string literal"  /* _E_  */
            , NULL, 0L, NULL);
    while (c = get_ch(), file == infile)
        *seq++ = c;
    unget_ch();
    out_ptr = seq;
    putout( begin);
}
Beispiel #6
0
static inline int32_t get_len(char end) {
  char ch;
  int32_t len = 0;
  
  for (;;) {
    ch = get_ch();
    if (ch == end)
      break;
    if ((ch < '0') || (ch > '9'))
      die_format();
    if (len > 429496720) {
      errno = ENOMEM;
      die_write();
    }
    len = len * 10 + (ch - '0');
  }
  
  return len;
}
Beispiel #7
0
static void do_pragma_op( void)
/*
 * Execute the _Pragma() operator contained in an expanded macro.
 * Note: _Pragma() operator is also implemented as a special macro.  Therefore
 *      it is always searched as a macro.
 * There might be more than one _Pragma() in a expanded macro and those may be
 *      surrounded by other token sequences.
 * Since all the macros have been expanded completely, any name identical to
 *      macro should not be re-expanded.
 * However, a macro in the string argument of _Pragma() may be expanded by
 *      do_pragma() after de_stringize(), if EXPAND_PRAGMA == TRUE.
 */
{
    FILEINFO *  file;
    DEFBUF *    defp;
    int     prev = output < out_ptr;        /* There is a previous sequence */
    int     token_type;
    char *  cp1, * cp2;
    int     c;

    file = unget_string( out_ptr, NULL);
    while (c = get_ch(), file == infile) {
        if (char_type[ c] & HSP) {
            *out_ptr++ = c;
            continue;
        }
        if (scan_token( c, (cp1 = out_ptr, &cp1), out_wend)
                    == NAM && (defp = is_macro( &cp1)) != NULL
                && defp->nargs == DEF_PRAGMA) {     /* _Pragma() operator   */
            if (prev) {
                putout( output);    /* Putout the previous sequence */
                cp1 = stpcpy( output, "pragma ");   /* From top of buffer   */
            }
            /* is_macro() already read over possible spaces after _Pragma   */
            *cp1++ = get_ch();                              /* '('  */
            while (char_type[ c = get_ch()] & HSP)
                *cp1++ = c;
            if (((token_type = scan_token( c, (cp2 = cp1, &cp1), out_wend))
                    != STR && token_type != WSTR)) {
                /* Not a string literal */
                put_seq( output, cp1);
                return;
            }
            workp = de_stringize( cp2, work_buf);
            while (char_type[ c = get_ch()] & HSP)
                *cp1++ = c;
            if (c != ')') {         /* More than a string literal   */
                unget_ch();
                put_seq( output, cp1);
                return;
            }
            strcpy( workp, "\n");       /* Terminate with <newline> */
            unget_string( work_buf, NULL);
            do_pragma();                /* Do the #pragma "line"    */
            infile->bptr += strlen( infile->bptr);      /* Clear sequence   */
            cp1 = out_ptr = output;     /* From the top of buffer   */
            prev = FALSE;
        } else {                        /* Not pragma sequence      */
            out_ptr = cp1;
            prev = TRUE;
        }
    }
    unget_ch();
    if (prev)
        putout( output);
}
Beispiel #8
0
static void mcpp_main( void)
/*
 * Main process for mcpp -- copies tokens from the current input stream
 * (main file or included file) to the output file.
 */
{
    int     c;                      /* Current character            */
    char *  wp;                     /* Temporary pointer            */
    DEFBUF *    defp;               /* Macro definition             */
    int     line_top;       /* Is in the line top, possibly spaces  */
    LINE_COL    line_col;   /* Location of macro call in source     */

    keep_comments = option_flags.c && !no_output;
    keep_spaces = option_flags.k;       /* Will be turned off if !compiling */
    line_col.col = line_col.line = 0L;

    /*
     * This loop is started "from the top" at the beginning of each line.
     * 'wrong_line' is set TRUE in many places if it is necessary to write
     * a #line record.  (But we don't write them when expanding macros.)
     *
     * 'newlines' variable counts the number of blank lines that have been
     * skipped over.  These are then either output via #line records or
     * by outputting explicit blank lines.
     * 'newlines' will be cleared on end of an included file by get_ch().
     */
    while (1) {                             /* For the whole input  */
        newlines = 0;                       /* Count empty lines    */

        while (1) {                         /* For each line, ...   */
            out_ptr = output;               /* Top of the line buf  */
            c = get_ch();
            if (src_col)
                break;  /* There is a residual tokens on the line   */
            while (char_type[ c] & HSP) {   /* ' ' or '\t'          */
                if (c != COM_SEP)
                    *out_ptr++ = c; /* Retain line top white spaces */
                                    /* Else skip 0-length comment   */
                c = get_ch();
            }
            if (c == '#') {                 /* Is 1st non-space '#' */
                directive();                /* Do a #directive      */
            } else if (mcpp_mode == STD && option_flags.dig && c == '%') {
                    /* In POST_STD digraphs are already converted   */
                if (get_ch() == ':') {      /* '%:' i.e. '#'        */
                    directive();            /* Do a #directive      */
                } else {
                    unget_ch();
                    if (! compiling) {
                        skip_nl();
                        newlines++;
                    } else {
                        break;
                    }
                }
            } else if (c == CHAR_EOF) {     /* End of input         */
                break;
            } else if (! compiling) {       /* #ifdef false?        */
                skip_nl();                  /* Skip to newline      */
                newlines++;                 /* Count it, too.       */
            } else if (in_asm && ! no_output) { /* In #asm block    */
                put_asm();                  /* Put out as it is     */
            } else if (c == '\n') {         /* Blank line           */
                if (keep_comments)
                    mcpp_fputc( '\n', OUT); /* May flush comments   */
                else
                    newlines++;             /* Wait for a token     */
            } else {
                break;                      /* Actual token         */
            }
        }

        if (c == CHAR_EOF)                  /* Exit process at      */
            break;                          /*   end of input       */

        /*
         * If the loop didn't terminate because of end of file, we
         * know there is a token to compile.  First, clean up after
         * absorbing newlines.  newlines has the number we skipped.
         */
        if (no_output) {
            wrong_line = FALSE;
        } else {
            if (wrong_line || newlines > 10) {
                sharp( NULL, 0);            /* Output # line number */
                if (keep_spaces && src_col) {
                    while (src_col--)       /* Adjust columns       */
                        mcpp_fputc( ' ', OUT);
                    src_col = 0;
                }
            } else {                        /* If just a few, stuff */
                while (newlines-- > 0)      /* them out ourselves   */
                    mcpp_fputc('\n', OUT);
            }
        }

        /*
         * Process each token on this line.
         */
        line_top = TRUE;
        while (c != '\n' && c != CHAR_EOF) {    /* For the whole line   */
            /*
             * has_pragma is set to TRUE so as to execute _Pragma() operator
             * when the psuedo macro _Pragma() is found.
             */
            int     has_pragma;

            if ((mcpp_debug & MACRO_CALL) && ! in_directive) {
                line_col.line = src_line;       /* Location in source   */
                line_col.col = infile->bptr - infile->buffer - 1;
            }
            if (scan_token( c, (wp = out_ptr, &wp), out_wend) == NAM
                    && (defp = is_macro( &wp)) != NULL) {   /* A macro  */
                wp = expand_macro( defp, out_ptr, out_wend, line_col
                        , & has_pragma);    /* Expand it completely */
                if (line_top) {     /* The first token is a macro   */
                    char *  tp = out_ptr;
                    while (char_type[ *tp & UCHARMAX] & HSP)
                        tp++;           /* Remove excessive spaces  */
                    memmove( out_ptr, tp, strlen( tp) + 1);
                    wp -= (tp - out_ptr);
                }
                if (has_pragma) {           /* Found _Pramga()      */
                    do_pragma_op();         /* Do _Pragma() operator*/
                    out_ptr = output;       /* Do the rest of line  */
                    wrong_line = TRUE;      /* Line-num out of sync */
                } else {
                    out_ptr = wp;
                }
                if (keep_spaces && wrong_line && infile
                        && *(infile->bptr) != '\n' && *(infile->bptr) != EOS) {
                    src_col = infile->bptr - infile->buffer;
                    /* Remember the current colums  */
                    break;                  /* Do sharp() now       */
                }
            } else {                        /* Not a macro call     */
                out_ptr = wp;               /* Advance the place    */
                if (wrong_line)             /* is_macro() swallowed */
                    break;                  /*      the newline     */
            }
            while (char_type[ c = get_ch()] & HSP) {    /* Horizontal space */
                if (c != COM_SEP)           /* Skip 0-length comment*/
                    *out_ptr++ = c;
            }
            line_top = FALSE;               /* Read over some token */
        }                                   /* Loop for line        */

        putout( output);                    /* Output the line      */
    }                                       /* Continue until EOF   */
}
Beispiel #9
0
int main(int argc, char **argv) {
    modulation mod = AM;
    int genwav = 0;
    int test = 0;
    int chat = 0;
    static struct option long_options[] = {
        {"modulation",  required_argument, 0, 'm'},
        {"genwav",  no_argument,       0, 'g'},
        {"test",  no_argument,       0, 't'},
        {"chat",  no_argument,       0, 'c'},
        {0, 0, 0, 0}
    };
    int c;
    int option_index = 0;
    do {
        c = getopt_long (argc, argv, "m:gt",
                         long_options, &option_index);
        switch (c) {
        case 0:
            break;
        case 'm':
            if (strcmp(optarg, "AM") == 0) {
                mod = AM;
                break;
            }
            if (strcmp(optarg, "FM") == 0) {
                mod = FM;
                break;
            }
            fprintf(stderr, "Error: Invalid modulation\n");
            return 1;
        case 't':
            test = 1;
            break;
        case 'g':
            genwav = 1;
            break;
        case 'c':
            chat = 1;
            break;
        case -1:
            break;
        default:
            return 1;
            break;
        }
    } while (c != -1);
    if (!(test || chat || genwav)) {
        fprintf(stderr, "Error: You must suply an action\n");
        return 1;
    }


    int *vbuf;
    frame *msg;
    int i;

    if (genwav || test) {
        vbuf = get_fdata(PING_STR, strlen(PING_STR), mod);
        if (chk_wav_data(vbuf, &msg, mod))
            printf("Info: PCM data is ok.\n");
        else {
            fprintf(stderr, "Error: PCM data can not be read\n");
            for (i = 0; i < FRAME_SIZE; i++)
                fprintf(stderr, "%hhx", ((char *) msg)[i]);
            fprintf(stderr, "\n");
        }
    }
    if (genwav) {
        FILE *am = fopen("am.wav", "w");
        if (am == NULL) {
            printf("could not open files\n");
            exit(1);
        }
        write_wav(am, FRAME_BUFFER, vbuf);
        printf("Info: WAV ready\n");
    }

    if (!chat) return 0;

    char *mg  = (char *) malloc(65536);
    int j;
    pa_simple *ch = get_ch();
    pa_simple *pl = get_pl();
    int err = 0;
    int *buf = (int *) malloc(sizeof(int) * SAMPLE_BUFFER);
    sbf = (int *) calloc(sizeof(int), FRAME_BUFFER);
    int *pbf;
    fd_set set;
    int rv;
    struct timeval tv;

    printf("Info: Starting soundwave chat.\n");
    while (1) {
        if (pa_simple_read(ch, buf, sizeof(int) * SAMPLE_BUFFER, &err))
            fprintf(stderr, "Error: %s\n", pa_strerror(err));
        //filter_frq(buf, SAMPLE_BUFFER);
        mmpush(sbf, FRAME_BUFFER * sizeof(int), buf, SAMPLE_BUFFER * sizeof(int));
        msg = get_msg(sbf, mod);
        if (chk_frm(msg)) {
            printf("M: %.*s", 61, msg->data);
            flushfb();
        }
        free(msg);
        FD_ZERO(&set);
        FD_SET(STDIN_FILENO, &set);
        tv.tv_sec = 0;
        tv.tv_usec = 0;
        rv = select(STDIN_FILENO + 1, &set, NULL, NULL, &tv);
        if ((rv != 0) && (rv != -1)) {
            rv = read(STDIN_FILENO, mg, 65536);
            for (i = 0; i < rv; i += 61) {
                j = ((i + 61) <= rv) ? 61 : (rv - i);
                pbf = get_fdata(mg + i, j, mod);
                if (pa_simple_write(pl, pbf, FRAME_BUFFER * sizeof(int), &err))
                    printf("error: %s\n", pa_strerror(err));
                free(pbf);
            }
        }
        fflush(stdin);
        fflush(stdout);
        fflush(stderr);
    }
    printf("\n");
    pa_simple_free(ch);
    pa_simple_free(pl);
    return 0;
}
Beispiel #10
0
int main(int argc, char **argv, char **envp) {
  char ch;
  struct cdbmake cm;
  array_t data = ARRAY_INIT(1);
  int32_t dlen;
  int fd;
  uint32_t i;
  array_t key = ARRAY_INIT(1);
  int32_t klen;
  char *path;
  char *tmp;
  
  if (!*argv || !*++argv)
    usage();
  path = *argv;
  
  if (!*++argv)
    usage();
  tmp = *argv;
  
  /* Create the temporary file and start the cdb creation process with it. */
  fd = open("test.cdb", O_CREAT | O_TRUNC | O_WRONLY, 0644);
  if (fd == -1)
    strerr_die4sys(111, FATAL, "unable to create ", tmp, ": ");
  if (cdbmake_start(&cm, fd) == -1)
    strerr_die2sys(111, FATAL, "cdbmake initialization failed: ");
    
  for (;;) {
    /* Skip over new lines and require the first character to be '+'. */
    ch = get_ch();
    if (ch == '\n')
      break;
    if (ch != '+')
      die_format();
      
    /* Read the key length. */
    klen = get_len(',');
    if (klen == -1)
      die_format();
      
    /* Read the data length. */
    dlen = get_len(':');
    if (dlen == -1)
      die_format();
      
    /* Truncate the key array and load it with the key from the cdb record. */
    array_trunc(&key);
    for (i = 0; i < klen; i++) {
      ch = get_ch();
      array_append(&key, &ch, 1);
    }
    
    /* Verify the separator is ->. */
    if ((get_ch() != '-') || (get_ch() != '>'))
      die_format();
      
    /* Truncate the data array and load it with the data from the cdb record. */
    array_trunc(&data);
    for (i = 0; i < dlen; i++) {
      ch = get_ch();
      array_append(&data, &ch, 1);
    }
    
    /* The line is valid, so add it to the cdb file and check that it ends with
     * a new line. */
    if (cdbmake_add(&cm, array_start(&key), klen, array_start(&data), dlen) == -1)
      die_write();
    if (get_ch() != '\n')
      die_format();
  }
  
  /* Finish the cdb file, sync it to disk, close it, and finally rename it to
   * the target path. */
  if (cdbmake_finish(&cm) == -1)
    die_write();
  if (fsync(fd) == -1)
    die_write();
  if (close(fd) == -1)
    die_write();
  if (rename(tmp, path) == -1)
    strerr_die6sys(111, FATAL, "unable to rename ", tmp, " to ", path, ": ");
    
  _exit(0);
}
int EditAttributes (FILES *f) {

  char  *buf;
  USHORT len = (vio.col * 7) * 2,curpos = 0;
  char   nattr = (1 << 4) | (7 | 8);
  char   sattr = 8;
  int    ret = 0,x,key;
  BOOL   okay = TRUE;
  char   attrs[5] = "----";

  if(!f)
    return -1;
  buf = malloc(len);
  if(!buf)
    return -1;

  ThreadMsg(" ");

  VioReadCellStr(buf,&len,(vio.row / 2) - 1,0,0);

  VioWrtCharStrAtt("ÚÄ Attributes: Ä¿",17,(vio.row / 2) - 1,
                   34,&nattr,0);
  VioWrtCharStrAtt("³ Readonly: [ ] ³",17,vio.row / 2,
                   34,&nattr,0);
  VioWrtCharStrAtt("³ Hidden:   [ ] ³",17,(vio.row / 2) + 1,
                   34,&nattr,0);
  VioWrtCharStrAtt("³ System:   [ ] ³",17,(vio.row / 2) + 2,
                   34,&nattr,0);
  VioWrtCharStrAtt("³ Archived: [ ] ³",17,(vio.row / 2) + 3,
                   34,&nattr,0);
  VioWrtCharStrAtt("ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ",17,(vio.row / 2) + 4,
                   34,&nattr,0);
  VioWrtNAttr(&sattr,1,vio.row / 2,51,0);
  VioWrtNAttr(&sattr,1,(vio.row / 2) + 1,51,0);
  VioWrtNAttr(&sattr,1,(vio.row / 2) + 2,51,0);
  VioWrtNAttr(&sattr,1,(vio.row / 2) + 3,51,0);
  VioWrtNAttr(&sattr,1,(vio.row / 2) + 4,51,0);
  VioWrtNAttr(&sattr,16,(vio.row / 2) + 5,36,0);
  if(f->attrFile & FILE_READONLY)
    attrs[0] = 'x';
  if(f->attrFile & FILE_HIDDEN)
    attrs[1] = 'x';
  if(f->attrFile & FILE_SYSTEM)
    attrs[2] = 'x';
  if(f->attrFile & FILE_ARCHIVED)
    attrs[3] = 'x';
  for(x = 0;x < 4;x++)
    VioWrtCharStr(attrs + x,1,x + (vio.row / 2),47,0);
  VioSetCurPos(curpos + (vio.row / 2),47,0);
  ShowCursor(FALSE);
  while(okay) {
    VioWrtCharStr(attrs + curpos,1,curpos + (vio.row / 2),47,0);
    VioSetCurPos(curpos + (vio.row / 2),47,0);
    key = get_ch(-1);
    switch(key) {
      case 256:
        break;

      case 45 | 256:
      case 61 | 256:
      case '\x1b':  /* abort */
        okay = FALSE;
        ret = -1;
        break;

      case '\r':      /* process */
        okay = FALSE;
        {
          FILESTATUS3 fs3;

          if(!DosQueryPathInfo(f->filename,FIL_STANDARD,&fs3,sizeof(fs3))) {
            fs3.attrFile &= (~FILE_DIRECTORY);
            if(attrs[0] == 'x')
              fs3.attrFile |= FILE_READONLY;
            else
              fs3.attrFile &= (~FILE_READONLY);
            if(attrs[1] == 'x')
              fs3.attrFile |= FILE_HIDDEN;
            else
              fs3.attrFile &= (~FILE_HIDDEN);
            if(attrs[2] == 'x')
              fs3.attrFile |= FILE_SYSTEM;
            else
              fs3.attrFile &= (~FILE_SYSTEM);
            if(attrs[3] == 'x')
              fs3.attrFile |= FILE_ARCHIVED;
            else
              fs3.attrFile &= (~FILE_ARCHIVED);
            if(DosSetPathInfo(f->filename,FIL_STANDARD,&fs3,sizeof(fs3),
                              DSPI_WRTTHRU))
              DosBeep(50,100);
            else
              ret = 1;
          }
          else
            DosBeep(50,100);
        }
        break;

      case 72 | 256:  /* up */
        curpos--;
        if(curpos > 3)
          curpos = 3;
        break;

      case 'x':
      case 'X':
      case '+':
        attrs[curpos] = 'x';
        break;

      case '-':
        attrs[curpos] = '-';
        break;

      case ' ':       /* toggle */
        attrs[curpos] = (attrs[curpos] == 'x') ? '-' : 'x';
        VioWrtCharStr(attrs + curpos,1,curpos + (vio.row / 2),47,0);
        /* intentional fallthru */
      case 80 | 256:  /* down */
        curpos++;
        if(curpos > 3)
          curpos = 0;
        break;
    }
  }

  ShowCursor(TRUE);
  VioWrtCellStr(buf,len,(vio.row / 2) - 1,0,0);
  free(buf);
  SetupConsole();
  ThreadMsg(NULL);
  return ret;
}
int EnterLine (char *buf,ULONG len,USHORT y,char *filename,
               char **choices,int numc,int start) {

  ULONG         pos = 0,c,nm,numchars = 0,tpos,wl;
  APIRET        rc;
  int           key,attr = ((7 << 4) << 8) | ' ',ret = 0;
  BOOL          okay = TRUE,insert = TRUE,lasttab = FALSE;
  char         *sav,*k = NULL,*p;
  static char   keybuf[1026];
  USHORT        t;
  FILEFINDBUF3  fb3;
  HDIR          hdir = HDIR_CREATE;

  wl = 0;

  sav = malloc(vio.col * 2);
  if(!sav) {
    DosBeep(50,100);
    *buf = 0;
    return -1;
  }

  ThreadMsg(" ");

  t = vio.col * 2;
  VioReadCellStr(sav,&t,y,0,0);
  VioWrtNCell((char *)&attr,vio.col,y,0,0);
  ShowCursor(FALSE);
  VioSetCurPos(y,0,0);

  for(c = 0;c < len - 1;c++) {          /* find end of default string */
    if(!buf[c])
      break;
  }
  pos = c;
  for(;c < len - 1;c++)                 /* space-pad remainder of buf */
    buf[c] = ' ';

  while(okay) {
    /* assure buffer is null terminated (cluck, cluck) */
    buf[len - 1] = 0;

    /* assure pos hasn't gone past our limit */
    if(pos > len - 1)
      pos = len - 1;

    /* set left side of entry field */
    if(pos < wl)
      wl = pos;
    if(pos >= wl + vio.col)
      wl = (pos - vio.col) + 1;

    /* set cursor position */
    VioSetCurPos(y,pos - wl,0);

    /* display buf */
    tpos = min(vio.col,len - wl); /* max length of displayable text */
    VioWrtCharStr(buf + wl,tpos,y,0,0); /* show text */
    if(tpos < vio.col)                  /* space-pad? */
      VioWrtNChar(" ",vio.col - tpos,y,tpos,0);

    if(k && *k)   /* "macros" waiting to be entered? */
      key = *k++; /* yep, skip keyboard input */
    else {        /* nope, go to the keyboard */
      k = NULL;   /* clear macro pointer */
      key = get_ch(-1);
    }

    switch(key) {
      case 256:       /* shiftstate changed -- ignore */
        break;

      case '\r':      /* accept input */
        okay = FALSE;
        break;

      case 45 | 256:
      case 61 | 256:
      case '\x1b':    /* Escape -- exit editor */
        memset(buf,' ',len - 1);
        buf[len - 1] = 0;
        okay = FALSE;
        ret = -1;
        break;

      case '\b':
        if(pos) {
          pos--;
          memmove(buf + pos,buf + (pos + 1),len - (pos + 1));
          buf[len - 2] = ' ';
        }
        lasttab = FALSE;
        break;

      case 25:          /* ctrl+y -- clear input */
        VioWrtNCell((char *)&attr,vio.col,y,0,0);
        memset(buf,' ',len - 1);
        buf[len - 1] = 0;
        wl = pos = 0;
        lasttab = FALSE;
        break;

      case 59 | 256:    /* F1 -- insert directory */
        k = directory;
        lasttab = FALSE;
        break;

      case 60 | 256:    /* F2 -- insert filename */
        if(filename)
          k = filename;
        lasttab = FALSE;
        break;

      case 62 | 256:    /* F4 -- insert target */
        k = target;
        lasttab = FALSE;
        break;

      case 15:          /* shift+tab */
        if(hdir != (HDIR)HDIR_CREATE) {
          DosFindClose(hdir);
          hdir = HDIR_CREATE;
          lasttab = FALSE;
        }
        /* intentional fallthru */
      case 9:           /* tab -- auto-complete */
        if(!pos || pos >= len - 1)
          break;
        if(lasttab && numchars) {
          lasttab = FALSE;
          for(tpos = 0;tpos < numchars;tpos++)
            keybuf[tpos] = '\b';
          keybuf[tpos++] = '\01';
          keybuf[tpos] = 0;
          numchars = 0;
          k = keybuf;
          break;
        }
        else {
          if(hdir != (HDIR)HDIR_CREATE)
            DosFindClose(hdir);
          hdir = HDIR_CREATE;
        }
        /* intentional fallthru */
      case 1:           /* cheat! */
        k = NULL;
        if(!pos || pos >= len - 1)
          break;
        tpos = pos - 1;
        while(tpos && buf[tpos] != ' ')
          tpos--;
        if(buf[tpos] == ' ')
          tpos++;
        strcpy(keybuf,buf + tpos);
        tpos = 0;
        while(keybuf[tpos] && keybuf[tpos] != ' ')
          tpos++;
        keybuf[tpos] = 0;
        lstrip(rstrip(keybuf));
        if(*keybuf) {
          strcat(keybuf,"*");
          nm = 1;
          if(hdir == (HDIR)HDIR_CREATE)
            rc = DosFindFirst(keybuf,
                              &hdir,
                              FILE_NORMAL    | FILE_HIDDEN   | FILE_SYSTEM |
                              FILE_DIRECTORY | FILE_ARCHIVED | FILE_READONLY,
                              &fb3,
                              sizeof(fb3),
                              &nm,
                              FIL_STANDARD);
          else
            rc = DosFindNext(hdir,&fb3,sizeof(fb3),&nm);
          if(!rc) {
            while((fb3.attrFile & FILE_DIRECTORY) &&
                  (*fb3.achName == '.' && (!fb3.achName[1] ||
                                           (fb3.achName[1] == '.' &&
                                            !fb3.achName[2])))) {
              nm = 1;
              if(DosFindNext(hdir,&fb3,sizeof(fb3),&nm)) {
                DosFindClose(hdir);
                hdir = HDIR_CREATE;
                *fb3.achName = 0;
                break;
              }
            }
            if(*fb3.achName) {
              keybuf[strlen(keybuf) - 1] = 0;
              p = strchr(keybuf,'\\');
              if(p)
                p++;
              else
                p = keybuf;
              tpos = 0;
              while(*p && fb3.achName[tpos] &&
                    toupper(*p) == toupper(fb3.achName[tpos])) {
                p++;
                tpos++;
              }
              if(fb3.achName[tpos]) {
                strcpy(keybuf,fb3.achName + tpos);
                numchars = strlen(keybuf);
                lasttab = TRUE;
                k = keybuf;
              }
              else if(hdir != (HDIR)HDIR_CREATE) {
                DosFindClose(hdir);
                hdir = HDIR_CREATE;
              }
            }
          }
          else if(hdir != (HDIR)HDIR_CREATE) {
            DosBeep(50,50);
            DosFindClose(hdir);
            hdir = HDIR_CREATE;
          }
        }
        break;

      case 83 | 256:    /* delete */
        memmove(buf + pos,buf + (pos + 1),len - (pos + 1));
        buf[len - 2] = ' ';
        lasttab = FALSE;
        break;

      case 82 | 256:    /* insert */
        insert = (insert) ? FALSE : TRUE;
        break;

      case 71 | 256:    /* home */
        wl = pos = 0;
        lasttab = FALSE;
        break;

      case 79 | 256:    /* end */
        pos = len - 2;
        while(pos && buf[pos] == ' ')
          pos--;
        if(pos && buf[pos] != ' ')
          pos++;
        lasttab = FALSE;
        break;

      case 75 | 256:    /* left */
        if(pos)
          pos--;
        lasttab = FALSE;
        break;

      case 77 | 256:    /* right */
        if(pos < len - 1)
          pos++;
        lasttab = FALSE;
        break;

      case 72 | 256:    /* up */
        lasttab = FALSE;
        if(choices) {
          if(choices[start]) {
            VioWrtNCell((char *)&attr,vio.col,y,0,0);
            memset(buf,' ',len - 1);
            buf[len - 1] = 0;
            wl = pos = 0;
            k = choices[start];
            start++;
            while(start < numc && !choices[start])
              start++;
            if(start > (numc - 1))
              start = 0;
            if(!choices[start]) {
              while(start < numc && !choices[start])
                start++;
            }
            if(start > (numc - 1))
              start = 0;
          }
        }
        break;

      case 80 | 256:    /* down */
        lasttab = FALSE;
        if(choices) {
          if(choices[start]) {
            VioWrtNCell((char *)&attr,vio.col,y,0,0);
            memset(buf,' ',len - 1);
            buf[len - 1] = 0;
            wl = pos = 0;
            k = choices[start];
            start--;
            while(start >= 0 && !choices[start])
              start--;
            if(start < 0)
              start = numc - 1;
            if(!choices[start]) {
              while(start >= 0 && !choices[start])
                start--;
            }
            if(start < 0)
              start = numc - 1;
          }
        }
        break;

      case 115 | 256:   /* ctrl+left */
        while(pos && buf[pos] == ' ')
          pos--;
        while(pos && buf[pos] != ' ')
          pos--;
        lasttab = FALSE;
        break;

      case 116 | 256:   /* ctrl + right */
        while(pos < len - 1 && buf[pos] == ' ')
          pos++;
        while(pos < len - 1 && buf[pos] != ' ')
          pos++;
        lasttab = FALSE;
        break;

      default:
        if(pos < len - 1 && !(key & 256) && !iscntrl(key)) {
          if(insert) {
            if(pos < len - 2) {
              memmove(buf + (pos + 1),buf + pos,len - (pos + 2));
              buf[len - 2] = ' ';
            }
            buf[pos] = (char)key;
          }
          else
            buf[pos] = (char)key;
          pos++;
        }
        else if(pos >= len - 1)
          DosBeep(250,25);
        break;
    }
  }

  if(hdir != (HDIR)HDIR_CREATE)
    DosFindClose(hdir);

  ShowCursor(TRUE);
  VioWrtCellStr(sav,vio.col * 2,y,0,0);
  free(sav);
  SetupConsole();

  ThreadMsg(NULL);

  buf[len - 1] = 0;
  lstrip(rstrip(buf));
  return (ret) ? ret : strlen(buf);
}
int SimpleInput (char *title,char *text,ULONG beep,ULONG dur,ULONG wait,
                 int *responses) {

  char  *buf;
  int    xlen,key = 0,x;
  USHORT len = (vio.col * 7) * 2,start,mlen,cell;
  char   sattr = 8;
  BOOL   okay = TRUE;

  if(!title)
    title = "";
  if(!text)
    return key;
  xlen = min(max(strlen(title),strlen(text)),vio.col - 6);
  mlen = xlen + 6;
  start = (vio.col - xlen) / 2;

  buf = malloc(len);
  if(buf) {
    /* save screen under */
    VioReadCellStr(buf,&len,(vio.row / 2) - 2,0,0);
    /* draw borders */
    /* first, bright white left and top */
    cell = ((((7 | 8) << 4) | 7) << 8) | ' ';
    VioWrtNCell((char *)&cell,mlen,(vio.row / 2) - 2,start,0);
    VioWrtNCell((char *)&cell,1,(vio.row / 2) - 1,start,0);
    VioWrtNCell((char *)&cell,1,(vio.row / 2),start,0);
    VioWrtNCell((char *)&cell,1,(vio.row / 2) + 1,start,0);
    VioWrtNCell((char *)&cell,1,(vio.row / 2) + 2,start,0);
    VioWrtNCell((char *)&cell,1,(vio.row / 2) + 3,start,0);
    /* now dark grey right and bottom */
    cell = (((8 << 4) | 7) << 8) | ' ';
    VioWrtNCell((char *)&cell,1,(vio.row / 2) - 1,start + (mlen - 1),0);
    VioWrtNCell((char *)&cell,1,(vio.row / 2),start + (mlen - 1),0);
    VioWrtNCell((char *)&cell,1,(vio.row / 2) + 1,start + (mlen - 1),0);
    VioWrtNCell((char *)&cell,1,(vio.row / 2) + 2,start + (mlen - 1),0);
    VioWrtNCell((char *)&cell,mlen - 1,(vio.row / 2) + 3,start + 1,0);
    /* fill title area with light grey foreground, red background */
    cell = (((7 << 4) | 4) << 8) | ' ';
    VioWrtNCell((char *)&cell,mlen - 2,(vio.row / 2) - 1,start + 1,0);
    /* fill text area with light grey foreground, black background */
    cell = (((7 << 4) | 0) << 8) | ' ';
    VioWrtNCell((char *)&cell,mlen - 4,(vio.row / 2) + 1,start + 2,0);
    /* make interior border -- first white on light grey */
    cell = (((7 << 4) | (7 | 8)) << 8) | 'Ú';
    VioWrtNCell((char *)&cell,1,(vio.row / 2),start + 1,0);
    cell = (((7 << 4) | (7 | 8)) << 8) | '¿';
    VioWrtNCell((char *)&cell,1,(vio.row / 2),start + (mlen - 2),0);
    cell = (((7 << 4) | (7 | 8)) << 8) | 'Ä';
    VioWrtNCell((char *)&cell,mlen - 4,(vio.row / 2),start + 2,0);
    cell = (((7 << 4) | (7 | 8)) << 8) | '³';
    VioWrtNCell((char *)&cell,1,(vio.row / 2) + 1,start + 1,0);
    cell = (((7 << 4) | (7 | 8)) << 8) | 'À';
    VioWrtNCell((char *)&cell,1,(vio.row / 2) + 2,start + 1,0);
    /* now dark grey on light grey */
    cell = (((7 << 4) | 8) << 8) | 'Ä';
    VioWrtNCell((char *)&cell,mlen - 4,(vio.row / 2) + 2,start + 2,0);
    cell = (((7 << 4) | 8) << 8) | 'Ù';
    VioWrtNCell((char *)&cell,1,(vio.row / 2) + 2,start + (mlen - 2),0);
    cell = (((7 << 4) | 8) << 8) | '³';
    VioWrtNCell((char *)&cell,1,(vio.row / 2) + 1,start + (mlen - 2),0);

    /* insert title */
    VioWrtCharStr(title,
                  min(xlen,strlen(title)),
                  (vio.row / 2) - 1,
                  (start + (mlen / 2)) - (min(xlen,strlen(title)) / 2),
                  0);
    /* insert text */
    VioWrtCharStr(text,
                  min(xlen,strlen(text)),
                  (vio.row / 2) + 1,
                  (start + (mlen / 2)) - (min(xlen,strlen(text)) / 2),
                  0);
    /* draw shadow */
    VioWrtNAttr(&sattr,1,(vio.row / 2) - 1,start + mlen,0);
    VioWrtNAttr(&sattr,1,(vio.row / 2),start + mlen,0);
    VioWrtNAttr(&sattr,1,(vio.row / 2) + 1,start + mlen,0);
    VioWrtNAttr(&sattr,1,(vio.row / 2) + 2,start + mlen,0);
    VioWrtNAttr(&sattr,1,(vio.row / 2) + 3,start + mlen,0);
    VioWrtNAttr(&sattr,mlen,(vio.row / 2) + 4,start + 1,0);
    VioSetCurPos((vio.row / 2) + 1,start + (mlen - 3),0);
    if(responses)
      ShowCursor(FALSE);
    if(beep)
      DosBeep(beep,dur);
    if(!responses)
      DosSleep(wait);
    else {
      KbdFlushBuffer(0);
      while(okay) {
        key = get_ch(-1);
        if(!*responses)
          break;
        for(x = 0;responses[x];x++) {
          if(key == responses[x]) {
            okay = FALSE;
            break;
          }
        }
      }
    }
    ShowCursor(TRUE);
    VioWrtCellStr(buf,len,(vio.row / 2) - 2,0,0);
    free(buf);
    KbdFlushBuffer(0);
    ThreadMsg(NULL);
  }
  return key;
}