返回列表 发帖

choice.exe高仿版

本帖最后由 happy886rr 于 2016-12-6 16:21 编辑

[2016/12/06]修复一处设计错误。

由于微软的choice.exe无法实现小于1秒的延时,遂用C语言高仿了choice.exe,功能、性能与微软原版毫无差别,但支持0.0几秒延迟,需要的可以自行编译下面的源码。
/*
CONSOLE KEY TOOL, COPYRIGHT@2016~2018 BY HAPPY
High imitation CHOICE.EXE
VERSION 1.0
*/
#include <stdio.h>
#include <Windows.h>
#include <conio.h>
#include <time.h>
#define HELP_INFORMATION "\
  CHOICE [/C choices] [/N] [/CS] [/T timeout /D choice] [/M text]\n\n\
  Description:\n\
     This tool allows users to select one item from a list \n\
     of choices and returns the index of the selected choice.\n\n\
  Parameter List:\n\
     /C    choices       Specifies the list of choices to be created.\n\
                         Default list is \"YN\".\n\n\
     /N                  Hides the list of choices in the prompt.\n\
                         The message before the prompt is displayed\n\
                         and the choices are still enabled.\n\n\
     /CS                 Enables case-sensitive choices to be selected.\n\
                         By default, the utility is case-insensitive.\n\n\
     /T    timeout       The number of seconds to pause before a default \n\
                         choice is made. Acceptable values are from 0.000 to \n\
                         9999... If 0 is specified, there will be no pause \n\
                         and the default choice is selected.\n\n\
     /D    choice        Specifies the default choice after nnnn seconds.\n\
                         Character must be in the set of choices specified\n\
                         by /C option and must also specify nnnn with /T.\n\n\
     /M    text          Specifies the message to be displayed before \n\
                         the prompt. If not specified, the utility \n\
                         displays only a prompt.\n\n\
     /?                  Displays this help message.\n\n\
     NOTE:\n\
     The ERRORLEVEL environment variable is set to the index of the\n\
     key that was selected from the set of choices. The first choice\n\
     listed returns a value of 1, the second a value of 2, and so on.\n\
     If the user presses a key that is not a valid choice, the tool \n\
     sounds a warning beep. If tool detects an error condition,\n\
     it returns an ERRORLEVEL value of 255. If the user presses \n\
     CTRL+BREAK or CTRL+C, the tool returns an ERRORLEVEL value\n\
     of 0. When you use ERRORLEVEL parameters in a batch program, list\n\
     them in decreasing order.\n\n\
  Examples:\n\
     CHOICE /?\n\
     CHOICE /C YNC /M \"Press Y for Yes, N for No or C for Cancel.\"\n\
     CHOICE /T 10 /C ync /CS /D y \n\
     CHOICE /C ab /M \"Select a for option 1 and b for option 2.\"\n\
     CHOICE /C ab /N /M \"Select a for option 1 and b for option 2.\"\n"
/***************功能函数群***************/
//帮助信息
void HelpInfomation(int code)
{
    fputs(HELP_INFORMATION, stdout);
    exit(code);
}
//核心函数
int ChoiceCore(const unsigned char FLAG, char* list, char* text, clock_t timeout, unsigned char deft)
{
    unsigned char KEY_V;
    char* p;
    //选择列表为空则退出
    if(list==NULL)
    {
        fputs("Missing choice list\n", stdout);
        exit(255);
    }
    //警告/T开关和/D开关必须同时指定,或同时未指定
    if((((FLAG&0x04)>>2)^((FLAG&0x08)>>3))==0x01)
    {
        fputs("The /T swith and /D swith must be specified at the same time,\nType \"CHOICE /?\" for usage.\n", stdout);
        exit(255);
    }
    //显示/M开关之后的消息
    if(text!=NULL)
    {
        fputs(text, stdout);
        fputc( ' ', stdout);
    }
    //如未开启CS开关,则将选择列表转为大写
    if((FLAG&0x01) ==0x00)
    {
        list=strupr(list);
        deft=('a'<=deft && deft<='z')?deft-32:deft;
    }
    //如未开启N开关,则显示/M之后的消息
    if((FLAG&0x02) ==0x00)
    {
        p=(char*)list;
        fputc('[', stdout);
        fputc( *p, stdout);
        while( *(++p) !='\0')
        {
            fputc(',', stdout);
            fputc( *p, stdout);
        }
        fputs("]?", stdout);
    }
    clock_t start=clock();
    do
    {
        if(kbhit())
        {
            KEY_V=getch();
            p=(char*)list;
            while(*p!='\0')
            {
                if(
                    ((FLAG&0x01)==0x00 && (*p==KEY_V-32)) ||
                    (*p ==KEY_V)
                )
                {
                    fputc(  *p, stdout);
                    fputc('\n', stdout);
                    return p-list+1;
                }
                p++;
            }
        }
        //缓解CPU占用
        Sleep(1);
    }
    while(clock()-start <timeout || timeout==-255);
    //超时则抛出/D开关指定的默认选项
    fputc(deft, stdout);
    fputc('\n', stdout);
    p=(char*)list;
    while(*p!='\0'){
        if(*p==deft){break;}
        p++;
    }
    if(*p=='\0'){return 255;}
    return p-list+1;
}
/*************MAIN主函数入口*************/
int main(int argc, char** argv)
{
    unsigned char FLAG=0;
    unsigned char deft='Y';
    clock_t timeout=(clock_t)(-255);
    char* list="YN";
    char* text=NULL;
    int i=0;
    while(++i<argc)
    {
        if(argv[i][0]!='/')
        {
            continue;
        }
        else if(argv[i][1]=='?')
        {
            //显示帮助消息
            HelpInfomation(255);
        }
        else if(
            (argv[i][1]=='C'||argv[i][1]=='c') &&
            (argv[i][2]=='S'||argv[i][2]=='s')
        )
        {
            //区分大写小
            FLAG|=0x01;
            continue;
        }
        else if(argv[i][1]=='N'||argv[i][1]=='n')
        {
            //隐藏选项列表
            FLAG|=0x02;
            continue;
        }
        else if(i+1 >=argc ||argv[i+1][1]=='/')
        {
            fputs("Missing parameters\n", stdout);
            return 255;
        }
        switch(argv[i][1])
        {
            //从选择列表选择一项并返回选项索引
        case 'C':
        case 'c':
            list=argv[i+1];
            break;
            //做出默认选择之前,暂停的秒数
        case 'T':
        case 't':
            timeout=(clock_t)(atof(argv[i+1])*1000);
            FLAG|=0x04;
            break;
            //在等待...秒之后指定默认选项
        case 'D':
        case 'd':
            deft=(unsigned char)argv[i+1][0];
            FLAG|=0x08;
            break;
            //指定提示之前要显示的消息
        case 'M':
        case 'm':
            text=argv[i+1];
            break;
            //错误反馈
        default:
            fputs("Error option\n", stdout);
            return 255;
        }
        i++;
    }
    //调用核心函数
    return ChoiceCore(FLAG, list, text, timeout, deft);
}COPY
使用说明:
-----------------------------------------------------------------------------
CHOICE [/C choices] [/N] [/CS] [/T timeout /D choice] [/M text]
-----------------------------------------------------------------------------
参数列表:
   /C    choices        "YN"
   /N                  在提示符中隐藏选项列表。提示前面的消息得到显示,
                       选项依旧处于启用状态。
   /CS                 允许选择分大小写的选项。在默认情况下,这个工具
                       是不分大小写的。
   /T    timeout       做出默认选择之前,暂停的秒数。可接受的值是从0.000
                       到 9999...。如果指定了 0,就不会有暂停,默认选项
                       会得到选择。
   /D    choice        在 nnnn 秒之后指定默认选项。字符必须在用 /C 选
                       项指定的一组选择中; 同时,必须用 /T 指定 nnnn。
   /M    text          指定提示之前要显示的消息。如果没有指定,工具只
                       显示提示。
   /?                  显示此帮助消息。
-----------------------------------------------------------------------------COPY
2

评分人数

可以出个跟ms-dos的choice语法一样的
新手上路!

TOP

返回列表