source: lab.git/Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Console.c @ a1bae3e

trunk
Last change on this file since a1bae3e was a1bae3e, checked in by mitty <mitty@…>, 12 years ago
  • copy vendor drop to trunk

git-svn-id: https://lab.mitty.jp/svn/lab/trunk@147 7d2118f6-f56c-43e7-95a2-4bb3031d96e7

  • Property mode set to 100644
File size: 46.6 KB
Line 
1// SoftEther UT-VPN SourceCode
2//
3// Copyright (C) 2004-2010 SoftEther Corporation.
4// Copyright (C) 2004-2010 University of Tsukuba, Japan.
5// Copyright (C) 2003-2010 Daiyuu Nobori.
6// All Rights Reserved.
7//
8// http://utvpn.tsukuba.ac.jp/
9//
10// This program is free software; you can redistribute it and/or
11// modify it under the terms of the GNU General Public License
12// version 2 as published by the Free Software Foundation.
13//
14// This program is distributed in the hope that it will be useful,
15// but WITHOUT ANY WARRANTY; without even the implied warranty of
16// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17// GNU General Public License for more details.
18//
19// You should have received a copy of the GNU General Public License version 2
20// along with this program; if not, write to the Free Software
21// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22//
23// このファイルは GPL バージョン 2 ライセンスで公開されています。
24// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
25// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
26// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
27// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
28//
29// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
30// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
31// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
32// ホストされています。
33// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
34// および、試験または研究のために利用が行われることを想定して配布
35// しています。
36// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
37// あります。
38// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
39// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
40// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
41// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
42// に組み込みさせていただきます。
43//
44// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
45// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
46//
47// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
48// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
49// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
50// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
51// ください。
52//
53// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
54// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
55// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
56// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
57// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
58// 公益保護にご協力いただきますようお願い申し上げます。
59//
60// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
61// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
62// を保護するための努力を行います。
63//
64// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
65// 日本国内の脆弱性情報届出受付公的機関:
66//         独立行政法人 情報処理推進機構
67//         http://www.ipa.go.jp/security/vuln/report/
68//
69// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
70// 連絡先: http://www.softether.co.jp/jp/contact/
71
72// -----------------------------------------------
73// [ChangeLog]
74// 2010.05.20
75//  新規リリース by SoftEther
76// -----------------------------------------------
77
78// Console.c
79// コンソール サービス
80
81#include "CedarPch.h"
82
83
84// コマンドのヘルプを表示する
85void PrintCmdHelp(CONSOLE *c, char *cmd_name, TOKEN_LIST *param_list)
86{
87    wchar_t tmp[MAX_SIZE];
88    wchar_t *buf;
89    UINT buf_size;
90    wchar_t *description, *args, *help;
91    UNI_TOKEN_LIST *t;
92    UINT width;
93    UINT i;
94    char *space;
95    // 引数チェック
96    if (c == NULL || cmd_name == NULL || param_list == NULL)
97    {
98        return;
99    }
100
101    width = GetConsoleWidth(c) - 2;
102
103    buf_size = sizeof(wchar_t) * (width + 32);
104    buf = Malloc(buf_size);
105
106    GetCommandHelpStr(cmd_name, &description, &args, &help);
107
108    space = MakeCharArray(' ', 2);
109
110    // タイトル
111    UniFormat(tmp, sizeof(tmp), _UU("CMD_HELP_TITLE"), cmd_name);
112    c->Write(c, tmp);
113    c->Write(c, L"");
114
115    // 目的
116    c->Write(c, _UU("CMD_HELP_DESCRIPTION"));
117    t = SeparateStringByWidth(description, width - 2);
118    for (i = 0;i < t->NumTokens;i++)
119    {
120        UniFormat(buf, buf_size, L"%S%s", space, t->Token[i]);
121        c->Write(c, buf);
122    }
123    UniFreeToken(t);
124    c->Write(c, L"");
125
126    // 説明
127    c->Write(c, _UU("CMD_HELP_HELP"));
128    t = SeparateStringByWidth(help, width - 2);
129    for (i = 0;i < t->NumTokens;i++)
130    {
131        UniFormat(buf, buf_size, L"%S%s", space, t->Token[i]);
132        c->Write(c, buf);
133    }
134    UniFreeToken(t);
135    c->Write(c, L"");
136
137    // 使用方法
138    c->Write(c, _UU("CMD_HELP_USAGE"));
139    t = SeparateStringByWidth(args, width - 2);
140    for (i = 0;i < t->NumTokens;i++)
141    {
142        UniFormat(buf, buf_size, L"%S%s", space, t->Token[i]);
143        c->Write(c, buf);
144    }
145    UniFreeToken(t);
146
147    // 引数
148    if (param_list->NumTokens >= 1)
149    {
150        c->Write(c, L"");
151        c->Write(c, _UU("CMD_HELP_ARGS"));
152        PrintCandidateHelp(c, cmd_name, param_list, 2);
153    }
154
155    Free(space);
156
157    Free(buf);
158}
159
160// SafeStr であるかどうかの評価
161bool CmdEvalSafe(CONSOLE *c, wchar_t *str, void *param)
162{
163    wchar_t *p = (param == NULL) ? _UU("CMD_EVAL_SAFE") : (wchar_t *)param;
164
165    if (IsSafeUniStr(str))
166    {
167        return true;
168    }
169
170    c->Write(c, p);
171
172    return false;
173}
174
175// 文字列入力プロンプト
176wchar_t *CmdPrompt(CONSOLE *c, void *param)
177{
178    wchar_t *p = (param == NULL) ? _UU("CMD_PROMPT") : (wchar_t *)param;
179
180    return c->ReadLine(c, p, true);
181}
182
183// 指定されたファイルが存在するかどうか評価
184bool CmdEvalIsFile(CONSOLE *c, wchar_t *str, void *param)
185{
186    char tmp[MAX_PATH];
187    // 引数チェック
188    if (c == NULL || str == NULL)
189    {
190        return false;
191    }
192
193    UniToStr(tmp, sizeof(tmp), str);
194
195    if (IsEmptyStr(tmp))
196    {
197        c->Write(c, _UU("CMD_FILE_NAME_EMPTY"));
198        return false;
199    }
200
201    if (IsFileExists(tmp) == false)
202    {
203        wchar_t tmp2[MAX_SIZE];
204
205        UniFormat(tmp2, sizeof(tmp2), _UU("CMD_FILE_NOT_FOUND"), tmp);
206        c->Write(c, tmp2);
207
208        return false;
209    }
210
211    return true;
212}
213
214// 整数の評価
215bool CmdEvalInt1(CONSOLE *c, wchar_t *str, void *param)
216{
217    wchar_t *p = (param == NULL) ? _UU("CMD_EVAL_INT") : (wchar_t *)param;
218
219    if (UniToInt(str) == 0)
220    {
221        c->Write(c, p);
222
223        return false;
224    }
225
226    return true;
227}
228
229// 空白を指定できないパラメータの評価
230bool CmdEvalNotEmpty(CONSOLE *c, wchar_t *str, void *param)
231{
232    wchar_t *p = (param == NULL) ? _UU("CMD_EVAL_NOT_EMPTY") : (wchar_t *)param;
233
234    if (UniIsEmptyStr(str) == false)
235    {
236        return true;
237    }
238
239    c->Write(c, p);
240
241    return false;
242}
243
244// パラメータの最小 / 最大値評価関数
245bool CmdEvalMinMax(CONSOLE *c, wchar_t *str, void *param)
246{
247    CMD_EVAL_MIN_MAX *e;
248    wchar_t *tag;
249    UINT v;
250    // 引数チェック
251    if (param == NULL)
252    {
253        return false;
254    }
255
256    e = (CMD_EVAL_MIN_MAX *)param;
257
258    if (e->StrName == NULL)
259    {
260        tag = _UU("CMD_EVAL_MIN_MAX");
261    }
262    else
263    {
264        tag = _UU(e->StrName);
265    }
266
267    v = UniToInt(str);
268
269    if (v >= e->MinValue && v <= e->MaxValue)
270    {
271        return true;
272    }
273    else
274    {
275        wchar_t tmp[MAX_SIZE];
276
277        UniFormat(tmp, sizeof(tmp), tag, e->MinValue, e->MaxValue);
278        c->Write(c, tmp);
279
280        return false;
281    }
282}
283
284// コマンドのヘルプ文字列を取得する
285void GetCommandHelpStr(char *command_name, wchar_t **description, wchar_t **args, wchar_t **help)
286{
287    char tmp1[128], tmp2[128], tmp3[128];
288
289    Format(tmp1, sizeof(tmp1), "CMD_%s", command_name);
290    Format(tmp2, sizeof(tmp2), "CMD_%s_ARGS", command_name);
291    Format(tmp3, sizeof(tmp3), "CMD_%s_HELP", command_name);
292
293    if (description != NULL)
294    {
295        *description = _UU(tmp1);
296        if (UniIsEmptyStr(*description))
297        {
298            *description = _UU("CMD_UNKNOWM");
299        }
300    }
301
302    if (args != NULL)
303    {
304        *args = _UU(tmp2);
305        if (UniIsEmptyStr(*args))
306        {
307            *args = _UU("CMD_UNKNOWN_ARGS");
308        }
309    }
310
311    if (help != NULL)
312    {
313        *help = _UU(tmp3);
314        if (UniIsEmptyStr(*help))
315        {
316            *help = _UU("CMD_UNKNOWN_HELP");
317        }
318    }
319}
320
321// パラメータのヘルプ文字列を取得する
322void GetCommandParamHelpStr(char *command_name, char *param_name, wchar_t **description)
323{
324    char tmp[160];
325    if (description == NULL)
326    {
327        return;
328    }
329
330    Format(tmp, sizeof(tmp), "CMD_%s_%s", command_name, param_name);
331
332    *description = _UU(tmp);
333
334    if (UniIsEmptyStr(*description))
335    {
336        *description = _UU("CMD_UNKNOWN_PARAM");
337    }
338}
339
340// 文字列比較関数
341int CompareCandidateStr(void *p1, void *p2)
342{
343    char *s1, *s2;
344    if (p1 == NULL || p2 == NULL)
345    {
346        return 0;
347    }
348    s1 = *(char **)p1;
349    s2 = *(char **)p2;
350    if (s1 == NULL || s2 == NULL)
351    {
352        return 0;
353    }
354
355    if (s1[0] == '[' && s2[0] != '[')
356    {
357        return -1;
358    }
359    else if (s2[0] == '[' && s1[0] != '[')
360    {
361        return 1;
362    }
363
364    return StrCmp(s1, s2);
365}
366
367// 候補一覧のヘルプを表示する
368void PrintCandidateHelp(CONSOLE *c, char *cmd_name, TOKEN_LIST *candidate_list, UINT left_space)
369{
370    UINT console_width;
371    UINT max_keyword_width;
372    LIST *o;
373    UINT i;
374    wchar_t *tmpbuf;
375    UINT tmpbuf_size;
376    char *left_space_array;
377    char *max_space_array;
378    // 引数チェック
379    if (c == NULL || candidate_list == NULL)
380    {
381        return;
382    }
383
384    // 画面の横幅の取得
385    console_width = GetConsoleWidth(c) - 1;
386
387    tmpbuf_size = sizeof(wchar_t) * (console_width + 32);
388    tmpbuf = Malloc(tmpbuf_size);
389
390    left_space_array = MakeCharArray(' ', left_space);
391
392    // コマンド名はソートしてリスト化する
393    // パラメータ名はソートしない
394    o = NewListFast(cmd_name == NULL ? CompareCandidateStr : NULL);
395
396    max_keyword_width = 0;
397
398    for (i = 0;i < candidate_list->NumTokens;i++)
399    {
400        UINT keyword_width;
401
402        // 各キーワードの横幅を取得する
403        Insert(o, candidate_list->Token[i]);
404
405        keyword_width = StrWidth(candidate_list->Token[i]);
406        if (cmd_name != NULL)
407        {
408            if (candidate_list->Token[i][0] != '[')
409            {
410                keyword_width += 1;
411            }
412            else
413            {
414                keyword_width -= 2;
415            }
416        }
417
418        max_keyword_width = MAX(max_keyword_width, keyword_width);
419    }
420
421    max_space_array = MakeCharArray(' ', max_keyword_width);
422
423    // 候補を表示する
424    for (i = 0;i < LIST_NUM(o);i++)
425    {
426        char tmp[128];
427        char *name = LIST_DATA(o, i);
428        UNI_TOKEN_LIST *t;
429        wchar_t *help;
430        UINT j;
431        UINT keyword_start_width = left_space;
432        UINT descript_start_width = left_space + max_keyword_width + 1;
433        UINT descript_width;
434        char *space;
435
436        if (console_width >= (descript_start_width + 5))
437        {
438            descript_width = console_width - descript_start_width - 3;
439        }
440        else
441        {
442            descript_width = 2;
443        }
444
445        // 名前を生成する
446        if (cmd_name != NULL && name[0] != '[')
447        {
448            // パラメータの場合は先頭に "/" を付ける
449            Format(tmp, sizeof(tmp), "/%s", name);
450        }
451        else
452        {
453            // コマンド名の場合はそのままの文字を使用する
454            if (cmd_name == NULL)
455            {
456                StrCpy(tmp, sizeof(tmp), name);
457            }
458            else
459            {
460                StrCpy(tmp, sizeof(tmp), name + 1);
461                if (StrLen(tmp) >= 1)
462                {
463                    tmp[StrLen(tmp) - 1] = 0;
464                }
465            }
466        }
467
468        // ヘルプ文字を取得する
469        if (cmd_name == NULL)
470        {
471            GetCommandHelpStr(name, &help, NULL, NULL);
472        }
473        else
474        {
475            GetCommandParamHelpStr(cmd_name, name, &help);
476        }
477
478        space = MakeCharArray(' ', max_keyword_width - StrWidth(name) - (cmd_name == NULL ? 0 : (name[0] != '[' ? 1 : -2)));
479
480        t = SeparateStringByWidth(help, descript_width);
481
482        for (j = 0;j < t->NumTokens;j++)
483        {
484            if (j == 0)
485            {
486                UniFormat(tmpbuf, tmpbuf_size, L"%S%S%S - %s",
487                    left_space_array, tmp, space, t->Token[j]);
488            }
489            else
490            {
491                UniFormat(tmpbuf, tmpbuf_size, L"%S%S   %s",
492                    left_space_array, max_space_array, t->Token[j]);
493            }
494
495            c->Write(c, tmpbuf);
496        }
497
498        Free(space);
499
500        UniFreeToken(t);
501    }
502
503    ReleaseList(o);
504
505    Free(max_space_array);
506    Free(tmpbuf);
507    Free(left_space_array);
508}
509
510// 文字列を指定された横幅で分割する
511UNI_TOKEN_LIST *SeparateStringByWidth(wchar_t *str, UINT width)
512{
513    UINT wp;
514    wchar_t *tmp;
515    UINT len, i;
516    LIST *o;
517    UNI_TOKEN_LIST *ret;
518    // 引数チェック
519    if (str == NULL)
520    {
521        return UniNullToken();
522    }
523    if (width == 0)
524    {
525        width = 1;
526    }
527
528    o = NewListFast(NULL);
529
530    len = UniStrLen(str);
531    tmp = ZeroMalloc(sizeof(wchar_t) * (len + 32));
532    wp = 0;
533
534    for (i = 0;i < (len + 1);i++)
535    {
536        wchar_t c = str[i];
537
538        switch (c)
539        {
540        case 0:
541        case L'\r':
542        case L'\n':
543            if (c == L'\r')
544            {
545                if (str[i + 1] == L'\n')
546                {
547                    i++;
548                }
549            }
550
551            tmp[wp++] = 0;
552            wp = 0;
553
554            Insert(o, UniCopyStr(tmp));
555            break;
556
557        default:
558            tmp[wp++] = c;
559            tmp[wp] = 0;
560            if (UniStrWidth(tmp) >= width)
561            {
562                tmp[wp++] = 0;
563                wp = 0;
564
565                Insert(o, UniCopyStr(tmp));
566            }
567            break;
568        }
569    }
570
571    if (LIST_NUM(o) == 0)
572    {
573        Insert(o, CopyUniStr(L""));
574    }
575
576    ret = ZeroMalloc(sizeof(UNI_TOKEN_LIST));
577    ret->NumTokens = LIST_NUM(o);
578    ret->Token = ZeroMalloc(sizeof(wchar_t *) * ret->NumTokens);
579
580    for (i = 0;i < LIST_NUM(o);i++)
581    {
582        wchar_t *s = LIST_DATA(o, i);
583
584        ret->Token[i] = s;
585    }
586
587    ReleaseList(o);
588    Free(tmp);
589
590    return ret;
591}
592
593// 指定した文字列が help を示すかどうかをチェック
594bool IsHelpStr(char *str)
595{
596    // 引数チェック
597    if (str == NULL)
598    {
599        return false;
600    }
601
602    if (StrCmpi(str, "help") == 0 || StrCmpi(str, "?") == 0 ||
603        StrCmpi(str, "man") == 0 || StrCmpi(str, "/man") == 0 ||
604        StrCmpi(str, "-man") == 0 || StrCmpi(str, "--man") == 0 ||
605        StrCmpi(str, "/help") == 0 || StrCmpi(str, "/?") == 0 ||
606        StrCmpi(str, "-help") == 0 || StrCmpi(str, "-?") == 0 ||
607        StrCmpi(str, "/h") == 0 || StrCmpi(str, "--help") == 0 ||
608        StrCmpi(str, "--?") == 0)
609    {
610        return true;
611    }
612
613    return false;
614}
615
616// コマンドの実行
617bool DispatchNextCmd(CONSOLE *c, char *prompt, CMD cmd[], UINT num_cmd, void *param)
618{
619    return DispatchNextCmdEx(c, NULL, prompt, cmd, num_cmd, param);
620}
621bool DispatchNextCmdEx(CONSOLE *c, wchar_t *exec_command, char *prompt, CMD cmd[], UINT num_cmd, void *param)
622{
623    wchar_t *str;
624    wchar_t *tmp;
625    char *cmd_name;
626    bool b_exit = false;
627    wchar_t *cmd_param;
628    UINT ret = ERR_NO_ERROR;
629    TOKEN_LIST *t;
630    TOKEN_LIST *candidate;
631    bool no_end_crlf = false;
632    UINT i;
633    // 引数チェック
634    if (c == NULL || (num_cmd >= 1 && cmd == NULL))
635    {
636        return false;
637    }
638
639    if (exec_command == NULL)
640    {
641        // プロンプトを表示
642RETRY:
643        tmp = CopyStrToUni(prompt);
644        str = c->ReadLine(c, tmp, false);
645        Free(tmp);
646
647        if (str != NULL && IsEmptyUniStr(str))
648        {
649            Free(str);
650            goto RETRY;
651        }
652    }
653    else
654    {
655        wchar_t tmp[MAX_SIZE];
656        // exec_command を使用
657        if (UniStartWith(exec_command, L"utvpncmd") == false)
658        {
659            if (prompt != NULL)
660            {
661                if (c->ConsoleType != CONSOLE_CSV)
662                {
663                    UniFormat(tmp, sizeof(tmp), L"%S%s", prompt, exec_command);
664                    c->Write(c, tmp);
665                }
666            }
667        }
668        str = CopyUniStr(exec_command);
669    }
670
671    if (str == NULL)
672    {
673        // ユーザーキャンセル
674        return false;
675    }
676
677    UniTrimCrlf(str);
678    UniTrim(str);
679
680    if (UniIsEmptyStr(str))
681    {
682        // 何もしない
683        Free(str);
684        return true;
685    }
686
687    // コマンド名とパラメータに分ける
688    if (SeparateCommandAndParam(str, &cmd_name, &cmd_param) == false)
689    {
690        // 何もしない
691        Free(str);
692        return true;
693    }
694
695    if (StrLen(cmd_name) >= 2 && cmd_name[0] == '?' && cmd_name[1] != '?')
696    {
697        char tmp[MAX_SIZE];
698        wchar_t *s;
699
700        StrCpy(tmp, sizeof(tmp), cmd_name + 1);
701        StrCpy(cmd_name, 0, tmp);
702
703        s = UniCopyStr(L"/?");
704        Free(cmd_param);
705
706        cmd_param = s;
707    }
708
709    if (StrLen(cmd_name) >= 2 && EndWith(cmd_name, "?") && cmd_name[StrLen(cmd_name) - 2] != '?')
710    {
711        wchar_t *s;
712
713        cmd_name[StrLen(cmd_name) - 1] = 0;
714
715        s = UniCopyStr(L"/?");
716        Free(cmd_param);
717
718        cmd_param = s;
719    }
720
721    // コマンドの候補を取得する
722    t = ZeroMalloc(sizeof(TOKEN_LIST));
723    t->NumTokens = num_cmd;
724    t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
725    for (i = 0;i < t->NumTokens;i++)
726    {
727        t->Token[i] = CopyStr(cmd[i].Name);
728    }
729
730    if (IsHelpStr(cmd_name))
731    {
732        if (UniIsEmptyStr(cmd_param))
733        {
734            wchar_t tmp[MAX_SIZE];
735
736            // 使用できるコマンド一覧を表示する
737            UniFormat(tmp, sizeof(tmp), _UU("CMD_HELP_1"), t->NumTokens);
738            c->Write(c, tmp);
739
740            PrintCandidateHelp(c, NULL, t, 1);
741
742            c->Write(c, L"");
743            c->Write(c, _UU("CMD_HELP_2"));
744        }
745        else
746        {
747            char *cmd_name;
748
749            // 指定したコマンドのヘルプを表示する
750            if (SeparateCommandAndParam(cmd_param, &cmd_name, NULL))
751            {
752                bool b = true;
753
754                if (IsHelpStr(cmd_name))
755                {
756                    b = false;
757                }
758
759                if (b)
760                {
761                    wchar_t str[MAX_SIZE];
762
763                    UniFormat(str, sizeof(str), L"%S /help", cmd_name);
764                    DispatchNextCmdEx(c, str, NULL, cmd, num_cmd, param);
765                    no_end_crlf = true;
766                }
767
768                Free(cmd_name);
769            }
770        }
771    }
772    else if (StrCmpi(cmd_name, "exit") == 0 || StrCmpi(cmd_name, "quit") == 0)
773    {
774        // 終了
775        b_exit = true;
776    }
777    else
778    {
779        candidate = GetRealnameCandidate(cmd_name, t);
780
781        if (candidate == NULL || candidate->NumTokens == 0)
782        {
783            wchar_t tmp[MAX_SIZE];
784
785            // 候補無し
786            UniFormat(tmp, sizeof(tmp), _UU("CON_UNKNOWN_CMD"), cmd_name);
787            c->Write(c, tmp);
788
789            c->RetCode = ERR_BAD_COMMAND_OR_PARAM;
790        }
791        else if (candidate->NumTokens >= 2)
792        {
793            wchar_t tmp[MAX_SIZE];
794
795            // 候補が複数ある
796            UniFormat(tmp, sizeof(tmp), _UU("CON_AMBIGIOUS_CMD"), cmd_name);
797            c->Write(c, tmp);
798            c->Write(c, _UU("CON_AMBIGIOUS_CMD_1"));
799            PrintCandidateHelp(c, NULL, candidate, 1);
800            c->Write(c, _UU("CON_AMBIGIOUS_CMD_2"));
801
802            c->RetCode = ERR_BAD_COMMAND_OR_PARAM;
803        }
804        else
805        {
806            char *real_cmd_name;
807            UINT i;
808
809            // 1 つに定まった
810            real_cmd_name = candidate->Token[0];
811
812            for (i = 0;i < num_cmd;i++)
813            {
814                if (StrCmpi(cmd[i].Name, real_cmd_name) == 0)
815                {
816                    if (cmd[i].Proc != NULL)
817                    {
818                        // CSV モードでなければコマンドの説明を表示する
819                        if(c->ConsoleType != CONSOLE_CSV)
820                        {
821                            wchar_t tmp[256];
822                            wchar_t *note;
823
824                            GetCommandHelpStr(cmd[i].Name, &note, NULL, NULL);
825                            UniFormat(tmp, sizeof(tmp), _UU("CMD_EXEC_MSG_NAME"), cmd[i].Name, note);
826                            c->Write(c, tmp);
827                        }
828
829                        // コマンドのプロシージャを呼び出す
830                        ret = cmd[i].Proc(c, cmd[i].Name, cmd_param, param);
831
832                        if (ret == INFINITE)
833                        {
834                            // 終了コマンド
835                            b_exit = true;
836                        }
837                        else
838                        {
839                            c->RetCode = ret;
840                        }
841                    }
842                }
843            }
844        }
845
846        FreeToken(candidate);
847    }
848
849    FreeToken(t);
850    Free(str);
851    Free(cmd_name);
852    Free(cmd_param);
853
854    if (no_end_crlf == false)
855    {
856        //c->Write(c, L"");
857    }
858
859    if (b_exit)
860    {
861        return false;
862    }
863
864    return true;
865}
866
867// 現在のコンソールの横幅を取得する
868UINT GetConsoleWidth(CONSOLE *c)
869{
870    UINT size;
871
872    size = c->GetWidth(c);
873
874    if (size == 0)
875    {
876        size = 80;
877    }
878
879    if (size < 32)
880    {
881        size = 32;
882    }
883
884    if (size > 65536)
885    {
886        size = 65535;
887    }
888
889    return size;
890}
891
892// コマンドラインをコマンドとパラメータの 2 つに分離する
893bool SeparateCommandAndParam(wchar_t *src, char **cmd, wchar_t **param)
894{
895    UINT i, len, wp;
896    wchar_t *tmp;
897    wchar_t *src_tmp;
898    // 引数チェック
899    if (src == NULL)
900    {
901        return false;
902    }
903    if (cmd != NULL)
904    {
905        *cmd = NULL;
906    }
907    if (param != NULL)
908    {
909        *param = NULL;
910    }
911
912    src_tmp = UniCopyStr(src);
913    UniTrimCrlf(src_tmp);
914    UniTrim(src_tmp);
915
916    len = UniStrLen(src_tmp);
917    tmp = Malloc(sizeof(wchar_t) * (len + 32));
918    wp = 0;
919
920    for (i = 0;i < (len + 1);i++)
921    {
922        wchar_t c = src_tmp[i];
923
924        switch (c)
925        {
926        case 0:
927        case L' ':
928        case L'\t':
929            tmp[wp] = 0;
930            if (UniIsEmptyStr(tmp))
931            {
932                Free(tmp);
933                Free(src_tmp);
934                return false;
935            }
936            if (cmd != NULL)
937            {
938                *cmd = CopyUniToStr(tmp);
939                Trim(*cmd);
940            }
941            goto ESCAPE;
942
943        default:
944            tmp[wp++] = c;
945            break;
946        }
947    }
948
949ESCAPE:
950    if (param != NULL)
951    {
952        *param = CopyUniStr(&src_tmp[wp]);
953        UniTrim(*param);
954    }
955
956    Free(tmp);
957    Free(src_tmp);
958
959    return true;
960}
961
962// ユーザーが指定したコマンド名の省略形に一致する実在するコマンドの一覧の候補を取得する
963TOKEN_LIST *GetRealnameCandidate(char *input_name, TOKEN_LIST *real_name_list)
964{
965    TOKEN_LIST *ret;
966    LIST *o;
967    UINT i;
968    bool ok = false;
969    // 引数チェック
970    if (input_name == NULL || real_name_list == NULL)
971    {
972        return NullToken();
973    }
974
975    o = NewListFast(NULL);
976
977    for (i = 0;i < real_name_list->NumTokens;i++)
978    {
979        char *name = real_name_list->Token[i];
980
981        // まず最優先で完全一致するものを検索する
982        if (StrCmpi(name, input_name) == 0)
983        {
984            Insert(o, name);
985            ok = true;
986            break;
987        }
988    }
989
990    if (ok == false)
991    {
992        // 完全一致するコマンドが無い場合、省略形コマンドとして一致するかどうかチェックする
993        for (i = 0;i < real_name_list->NumTokens;i++)
994        {
995            char *name = real_name_list->Token[i];
996
997            if (IsOmissionName(input_name, name) || IsNameInRealName(input_name, name))
998            {
999                // 省略形を発見した
1000                Insert(o, name);
1001                ok = true;
1002            }
1003        }
1004    }
1005
1006    if (ok)
1007    {
1008        // 1 つ以上の候補が見つかった
1009        ret = ListToTokenList(o);
1010    }
1011    else
1012    {
1013        ret = NullToken();
1014    }
1015
1016    ReleaseList(o);
1017
1018    return ret;
1019}
1020
1021// ユーザーが指定したコマンドが既存のコマンドの省略形かどうかチェックする
1022bool IsOmissionName(char *input_name, char *real_name)
1023{
1024    char oname[128];
1025    // 引数チェック
1026    if (input_name == NULL || real_name == NULL)
1027    {
1028        return false;
1029    }
1030
1031    if (IsAllUpperStr(real_name))
1032    {
1033        // すべて大文字のコマンドは省略形をとらない
1034        return false;
1035    }
1036
1037    GetOmissionName(oname, sizeof(oname), real_name);
1038
1039    if (IsEmptyStr(oname))
1040    {
1041        return false;
1042    }
1043
1044    if (StartWith(oname, input_name))
1045    {
1046        // 例: AccountSecureCertSet の oname は ascs だが
1047        //     ユーザーが asc と入力した場合は true を返す
1048        return true;
1049    }
1050
1051    if (StartWith(input_name, oname))
1052    {
1053        // 例: AccountConnect と
1054        //     AccountCreate の 2 つのコマンドが実在する際、
1055        //     ユーザーが "aconnect" と入力すると、
1056        //     AccountConnect のみ true になるようにする
1057
1058        if (EndWith(real_name, &input_name[StrLen(oname)]))
1059        {
1060            return true;
1061        }
1062    }
1063
1064    return false;
1065}
1066
1067// 指定したコマンド名の省略名を取得する
1068void GetOmissionName(char *dst, UINT size, char *src)
1069{
1070    UINT i, len;
1071    // 引数チェック
1072    if (dst == NULL || src == NULL)
1073    {
1074        return;
1075    }
1076
1077    StrCpy(dst, size, "");
1078    len = StrLen(src);
1079
1080    for (i = 0;i < len;i++)
1081    {
1082        char c = src[i];
1083
1084        if ((c >= '0' && c <= '9') ||
1085            (c >= 'A' && c <= 'Z'))
1086        {
1087            char tmp[2];
1088            tmp[0] = c;
1089            tmp[1] = 0;
1090
1091            StrCat(dst, size, tmp);
1092        }
1093    }
1094}
1095
1096// ユーザーが指定したコマンドが既存のコマンドに一致するかどうかチェックする
1097bool IsNameInRealName(char *input_name, char *real_name)
1098{
1099    // 引数チェック
1100    if (input_name == NULL || real_name == NULL)
1101    {
1102        return false;
1103    }
1104
1105    if (StartWith(real_name, input_name))
1106    {
1107        return true;
1108    }
1109
1110    return false;
1111}
1112
1113// コマンドリストをパースする
1114LIST *ParseCommandList(CONSOLE *c, char *cmd_name, wchar_t *command, PARAM param[], UINT num_param)
1115{
1116    UINT i;
1117    LIST *o;
1118    bool ok = true;
1119    TOKEN_LIST *param_list;
1120    TOKEN_LIST *real_name_list;
1121    bool help_mode = false;
1122    wchar_t *tmp;
1123    // 引数チェック
1124    if (c == NULL || command == NULL || (num_param >= 1 && param == NULL) || cmd_name == NULL)
1125    {
1126        return NULL;
1127    }
1128
1129    // 初期化
1130    for (i = 0;i < num_param;i++)
1131    {
1132        if (IsEmptyStr(param[i].Name) == false)
1133        {
1134            if (param[i].Name[0] == '[')
1135            {
1136                param[i].Tmp = "";
1137            }
1138            else
1139            {
1140                param[i].Tmp = NULL;
1141            }
1142        }
1143        else
1144        {
1145            param[i].Tmp = "";
1146        }
1147    }
1148
1149    real_name_list = ZeroMalloc(sizeof(TOKEN_LIST));
1150    real_name_list->NumTokens = num_param;
1151    real_name_list->Token = ZeroMalloc(sizeof(char *) * real_name_list->NumTokens);
1152
1153    for (i = 0;i < real_name_list->NumTokens;i++)
1154    {
1155        real_name_list->Token[i] = CopyStr(param[i].Name);
1156    }
1157
1158    // ユーザーが指定したパラメータ名のリストを生成する
1159    param_list = GetCommandNameList(command);
1160
1161    for (i = 0;i < param_list->NumTokens;i++)
1162    {
1163        char *s = param_list->Token[i];
1164
1165        if (StrCmpi(s, "help") == 0 || StrCmpi(s, "?") == 0)
1166        {
1167            help_mode = true;
1168            break;
1169        }
1170    }
1171
1172    tmp = ParseCommand(command, L"");
1173    if (tmp != NULL)
1174    {
1175        if (UniStrCmpi(tmp, L"?") == 0)
1176        {
1177            help_mode = true;
1178        }
1179        Free(tmp);
1180    }
1181
1182    if (help_mode)
1183    {
1184        // ヘルプを表示
1185        PrintCmdHelp(c, cmd_name, real_name_list);
1186        FreeToken(param_list);
1187        FreeToken(real_name_list);
1188        return NULL;
1189    }
1190
1191    for (i = 0;i < param_list->NumTokens;i++)
1192    {
1193        // ユーザーが指定したすべてのパラメータ名について対応するコマンドを取得する
1194        TOKEN_LIST *candidate = GetRealnameCandidate(param_list->Token[i], real_name_list);
1195
1196        if (candidate != NULL && candidate->NumTokens >= 1)
1197        {
1198            if (candidate->NumTokens >= 2)
1199            {
1200                wchar_t tmp[MAX_SIZE];
1201
1202                // 2 つ以上の候補がある
1203                UniFormat(tmp, sizeof(tmp), _UU("CON_AMBIGIOUS_PARAM"), param_list->Token[i]);
1204                c->Write(c, tmp);
1205                UniFormat(tmp, sizeof(tmp), _UU("CON_AMBIGIOUS_PARAM_1"), cmd_name);
1206                c->Write(c, tmp);
1207
1208                PrintCandidateHelp(c, cmd_name, candidate, 1);
1209
1210                c->Write(c, _UU("CON_AMBIGIOUS_PARAM_2"));
1211
1212                ok = false;
1213            }
1214            else
1215            {
1216                UINT j;
1217                char *real_name = candidate->Token[0];
1218
1219                // 候補が 1 つだけしか無い
1220                for (j = 0;j < num_param;j++)
1221                {
1222                    if (StrCmpi(param[j].Name, real_name) == 0)
1223                    {
1224                        param[j].Tmp = param_list->Token[i];
1225                    }
1226                }
1227            }
1228        }
1229        else
1230        {
1231            wchar_t tmp[MAX_SIZE];
1232
1233            // 候補無し
1234            UniFormat(tmp, sizeof(tmp), _UU("CON_INVALID_PARAM"), param_list->Token[i], cmd_name, cmd_name);
1235            c->Write(c, tmp);
1236
1237            ok = false;
1238        }
1239
1240        FreeToken(candidate);
1241    }
1242
1243    if (ok == false)
1244    {
1245        FreeToken(param_list);
1246        FreeToken(real_name_list);
1247
1248        return NULL;
1249    }
1250
1251    // リストの作成
1252    o = NewParamValueList();
1253
1254    // パラメータ一覧に指定された名前のすべてのパラメータを読み込む
1255    for (i = 0;i < num_param;i++)
1256    {
1257        bool prompt_input_value = false;
1258        PARAM *p = &param[i];
1259
1260        if (p->Tmp != NULL || p->PromptProc != NULL)
1261        {
1262            wchar_t *name = CopyStrToUni(p->Name);
1263            wchar_t *tmp;
1264            wchar_t *str;
1265
1266            if (p->Tmp != NULL)
1267            {
1268                tmp = CopyStrToUni(p->Tmp);
1269            }
1270            else
1271            {
1272                tmp = CopyStrToUni(p->Name);
1273            }
1274
1275            str = ParseCommand(command, tmp);
1276            Free(tmp);
1277            if (str != NULL)
1278            {
1279                wchar_t *unistr;
1280                bool ret;
1281EVAL_VALUE:
1282                // 読み込みに成功した
1283                unistr = str;
1284
1285                if (p->EvalProc != NULL)
1286                {
1287                    // EvalProc が指定されている場合は値を評価する
1288                    ret = p->EvalProc(c, unistr, p->EvalProcParam);
1289                }
1290                else
1291                {
1292                    // EvalProc が指定されていない場合はどのような値でも受け付ける
1293                    ret = true;
1294                }
1295
1296                if (ret == false)
1297                {
1298                    // 指定した値は不正である
1299                    if (p->PromptProc == NULL)
1300                    {
1301                        // キャンセル
1302                        ok = false;
1303                        Free(name);
1304                        Free(str);
1305                        break;
1306                    }
1307                    else
1308                    {
1309                        // もう一度入力させる
1310                        Free(str);
1311                        str = NULL;
1312                        goto SHOW_PROMPT;
1313                    }
1314                }
1315                else
1316                {
1317                    PARAM_VALUE *v;
1318                    // 読み込み完了したのでリストに追加する
1319                    v = ZeroMalloc(sizeof(PARAM_VALUE));
1320                    v->Name = CopyStr(p->Name);
1321                    v->StrValue = CopyUniToStr(str);
1322                    v->UniStrValue = CopyUniStr(str);
1323                    v->IntValue = ToInt(v->StrValue);
1324                    Insert(o, v);
1325                }
1326            }
1327            else
1328            {
1329                // 読み込みに失敗した。指定されたパラメータが指定されていない
1330                if (p->PromptProc != NULL)
1331                {
1332                    wchar_t *tmp;
1333SHOW_PROMPT:
1334                    // 必須パラメータであるのでプロンプトを表示する
1335                    tmp = p->PromptProc(c, p->PromptProcParam);
1336                    if (tmp == NULL)
1337                    {
1338                        // ユーザーがキャンセルした
1339                        ok = false;
1340                        Free(str);
1341                        Free(name);
1342                        break;
1343                    }
1344                    else
1345                    {
1346                        // ユーザーが入力した
1347                        c->Write(c, L"");
1348                        str = tmp;
1349                        prompt_input_value = true;
1350                        goto EVAL_VALUE;
1351                    }
1352                }
1353            }
1354
1355            Free(str);
1356            Free(name);
1357        }
1358    }
1359
1360    FreeToken(param_list);
1361    FreeToken(real_name_list);
1362
1363    if (ok)
1364    {
1365        return o;
1366    }
1367    else
1368    {
1369        FreeParamValueList(o);
1370        return NULL;
1371    }
1372}
1373
1374// [はい] か [いいえ] の取得
1375bool GetParamYes(LIST *o, char *name)
1376{
1377    char *s;
1378    char tmp[64];
1379    // 引数チェック
1380    if (o == NULL)
1381    {
1382        return false;
1383    }
1384
1385    s = GetParamStr(o, name);
1386    if (s == NULL)
1387    {
1388        return false;
1389    }
1390
1391    StrCpy(tmp, sizeof(tmp), s);
1392    Trim(tmp);
1393
1394    if (StartWith(tmp, "y"))
1395    {
1396        return true;
1397    }
1398
1399    if (StartWith(tmp, "t"))
1400    {
1401        return true;
1402    }
1403
1404    if (ToInt(tmp) != 0)
1405    {
1406        return true;
1407    }
1408
1409    return false;
1410}
1411
1412// パラメータ値 Int の取得
1413UINT GetParamInt(LIST *o, char *name)
1414{
1415    PARAM_VALUE *v;
1416    // 引数チェック
1417    if (o == NULL)
1418    {
1419        return 0;
1420    }
1421
1422    v = FindParamValue(o, name);
1423    if (v == NULL)
1424    {
1425        return 0;
1426    }
1427    else
1428    {
1429        return v->IntValue;
1430    }
1431}
1432
1433// パラメータ値 Unicode 文字列の取得
1434wchar_t *GetParamUniStr(LIST *o, char *name)
1435{
1436    PARAM_VALUE *v;
1437    // 引数チェック
1438    if (o == NULL)
1439    {
1440        return NULL;
1441    }
1442
1443    v = FindParamValue(o, name);
1444    if (v == NULL)
1445    {
1446        return NULL;
1447    }
1448    else
1449    {
1450        return v->UniStrValue;
1451    }
1452}
1453
1454// パラメータ値文字列の所得
1455char *GetParamStr(LIST *o, char *name)
1456{
1457    PARAM_VALUE *v;
1458    // 引数チェック
1459    if (o == NULL)
1460    {
1461        return NULL;
1462    }
1463
1464    v = FindParamValue(o, name);
1465    if (v == NULL)
1466    {
1467        return NULL;
1468    }
1469    else
1470    {
1471        return v->StrValue;
1472    }
1473}
1474
1475// パラメータ値の取得
1476PARAM_VALUE *FindParamValue(LIST *o, char *name)
1477{
1478    PARAM_VALUE t, *ret;
1479    // 引数チェック
1480    if (o == NULL)
1481    {
1482        return NULL;
1483    }
1484    if (name == NULL)
1485    {
1486        name = "";
1487    }
1488
1489    Zero(&t, sizeof(t));
1490    t.Name = name;
1491
1492    ret = Search(o, &t);
1493
1494    return ret;
1495}
1496
1497// パラメータ値リストの解放
1498void FreeParamValueList(LIST *o)
1499{
1500    UINT i;
1501    // 引数チェック
1502    if (o == NULL)
1503    {
1504        return;
1505    }
1506
1507    for (i = 0;i < LIST_NUM(o);i++)
1508    {
1509        PARAM_VALUE *v = LIST_DATA(o, i);
1510
1511        Free(v->StrValue);
1512        Free(v->UniStrValue);
1513        Free(v->Name);
1514        Free(v);
1515    }
1516
1517    ReleaseList(o);
1518}
1519
1520// パラメータ値リストソート関数
1521int CmpParamValue(void *p1, void *p2)
1522{
1523    PARAM_VALUE *v1, *v2;
1524    if (p1 == NULL || p2 == NULL)
1525    {
1526        return 0;
1527    }
1528    v1 = *(PARAM_VALUE **)p1;
1529    v2 = *(PARAM_VALUE **)p2;
1530    if (v1 == NULL || v2 == NULL)
1531    {
1532        return 0;
1533    }
1534
1535    if (IsEmptyStr(v1->Name) && IsEmptyStr(v2->Name))
1536    {
1537        return 0;
1538    }
1539    return StrCmpi(v1->Name, v2->Name);
1540}
1541
1542// パラメータ値リストの生成
1543LIST *NewParamValueList()
1544{
1545    return NewListFast(CmpParamValue);
1546}
1547
1548// 入力されたコマンドに含まれていたパラメータ名のリストを取得する
1549TOKEN_LIST *GetCommandNameList(wchar_t *str)
1550{
1551    TOKEN_LIST *t;
1552    // 引数チェック
1553    if (str == NULL)
1554    {
1555        return NullToken();
1556    }
1557
1558    Free(ParseCommandEx(str, L"dummy_str", &t));
1559
1560    return t;
1561}
1562
1563// 指定した名前で始まるコマンドを取得する
1564wchar_t *ParseCommand(wchar_t *str, wchar_t *name)
1565{
1566    return ParseCommandEx(str, name, NULL);
1567}
1568wchar_t *ParseCommandEx(wchar_t *str, wchar_t *name, TOKEN_LIST **param_list)
1569{
1570    UNI_TOKEN_LIST *t;
1571    UINT i;
1572    wchar_t *tmp;
1573    wchar_t *ret = NULL;
1574    LIST *o;
1575    // 引数チェック
1576    if (str == NULL)
1577    {
1578        return NULL;
1579    }
1580    if (name != NULL && UniIsEmptyStr(name))
1581    {
1582        name = NULL;
1583    }
1584
1585    o = NULL;
1586    if (param_list != NULL)
1587    {
1588        o = NewListFast(CompareStr);
1589    }
1590
1591    tmp = CopyUniStr(str);
1592    UniTrim(tmp);
1593
1594    i = UniSearchStrEx(tmp, L"/CMD ", 0, false);
1595
1596    // このあたりは急いで実装したのでコードがあまり美しくない。
1597    if (i != INFINITE && i >= 1 && tmp[i - 1] == L'/')
1598    {
1599        i = INFINITE;
1600    }
1601    if (i == INFINITE)
1602    {
1603        i = UniSearchStrEx(tmp, L"/CMD\t", 0, false);
1604        if (i != INFINITE && i >= 1 && tmp[i - 1] == L'/')
1605        {
1606            i = INFINITE;
1607        }
1608    }
1609    if (i == INFINITE)
1610    {
1611        i = UniSearchStrEx(tmp, L"/CMD:", 0, false);
1612        if (i != INFINITE && i >= 1 && tmp[i - 1] == L'/')
1613        {
1614            i = INFINITE;
1615        }
1616    }
1617    if (i == INFINITE)
1618    {
1619        i = UniSearchStrEx(tmp, L"/CMD=", 0, false);
1620        if (i != INFINITE && i >= 1 && tmp[i - 1] == L'/')
1621        {
1622            i = INFINITE;
1623        }
1624    }
1625    if (i == INFINITE)
1626    {
1627        i = UniSearchStrEx(tmp, L"-CMD ", 0, false);
1628        if (i != INFINITE && i >= 1 && tmp[i - 1] == L'-')
1629        {
1630            i = INFINITE;
1631        }
1632    }
1633    if (i == INFINITE)
1634    {
1635        i = UniSearchStrEx(tmp, L"-CMD\t", 0, false);
1636        if (i != INFINITE && i >= 1 && tmp[i - 1] == L'-')
1637        {
1638            i = INFINITE;
1639        }
1640    }
1641    if (i == INFINITE)
1642    {
1643        i = UniSearchStrEx(tmp, L"-CMD:", 0, false);
1644        if (i != INFINITE && i >= 1 && tmp[i - 1] == L'-')
1645        {
1646            i = INFINITE;
1647        }
1648    }
1649    if (i == INFINITE)
1650    {
1651        i = UniSearchStrEx(tmp, L"-CMD=", 0, false);
1652        if (i != INFINITE && i >= 1 && tmp[i - 1] == L'-')
1653        {
1654            i = INFINITE;
1655        }
1656    }
1657
1658    if (i != INFINITE)
1659    {
1660        char *s = CopyStr("CMD");
1661        if (InsertStr(o, s) == false)
1662        {
1663            Free(s);
1664        }
1665        if (UniStrCmpi(name, L"CMD") == 0)
1666        {
1667            ret = CopyUniStr(&str[i + 5]);
1668            UniTrim(ret);
1669        }
1670        else
1671        {
1672            tmp[i] = 0;
1673        }
1674    }
1675
1676    if (ret == NULL)
1677    {
1678        t = UniParseCmdLine(tmp);
1679
1680        if (t != NULL)
1681        {
1682            for (i = 0;i < t->NumTokens;i++)
1683            {
1684                wchar_t *token = t->Token[i];
1685
1686                if ((token[0] == L'-' && token[1] != L'-') ||
1687                    (UniStrCmpi(token, L"--help") == 0) ||
1688                    (token[0] == L'/' && token[1] != L'/'))
1689                {
1690                    UINT i;
1691
1692                    // 名前付き引数
1693                    // コロン文字があるかどうか調べる
1694
1695                    if (UniStrCmpi(token, L"--help") == 0)
1696                    {
1697                        token++;
1698                    }
1699
1700                    i = UniSearchStrEx(token, L":", 0, false);
1701                    if (i == INFINITE)
1702                    {
1703                        i = UniSearchStrEx(token, L"=", 0, false);
1704                    }
1705                    if (i != INFINITE)
1706                    {
1707                        wchar_t *tmp;
1708                        char *a;
1709
1710                        // コロン文字がある
1711                        tmp = CopyUniStr(token);
1712                        tmp[i] = 0;
1713
1714                        a = CopyUniToStr(&tmp[1]);
1715                        if (InsertStr(o, a) == false)
1716                        {
1717                            Free(a);
1718                        }
1719
1720                        if (UniStrCmpi(name, &tmp[1]) == 0)
1721                        {
1722                            if (ret == NULL)
1723                            {
1724                                // 内容
1725                                ret = UniCopyStr(&token[i + 1]);
1726                            }
1727                        }
1728
1729                        Free(tmp);
1730                    }
1731                    else
1732                    {
1733                        // コロン文字が無い
1734                        char *a;
1735
1736                        a = CopyUniToStr(&token[1]);
1737                        if (InsertStr(o, a) == false)
1738                        {
1739                            Free(a);
1740                        }
1741
1742                        if (UniStrCmpi(name, &token[1]) == 0)
1743                        {
1744                            if (ret == NULL)
1745                            {
1746                                // 空文字
1747                                ret = UniCopyStr(L"");
1748                            }
1749                        }
1750                    }
1751                }
1752                else
1753                {
1754                    // 名前無し引数
1755                    if (name == NULL)
1756                    {
1757                        if (ret == NULL)
1758                        {
1759                            if (token[0] == L'-' && token[1] == L'-')
1760                            {
1761                                ret = UniCopyStr(&token[1]);
1762                            }
1763                            else if (token[0] == L'/' && token[1] == L'/')
1764                            {
1765                                ret = UniCopyStr(&token[1]);
1766                            }
1767                            else
1768                            {
1769                                ret = UniCopyStr(token);
1770                            }
1771                        }
1772                    }
1773                }
1774            }
1775
1776            UniFreeToken(t);
1777        }
1778    }
1779
1780    Free(tmp);
1781
1782    if (o != NULL)
1783    {
1784        TOKEN_LIST *t = ZeroMalloc(sizeof(TOKEN_LIST));
1785        UINT i;
1786
1787        t->NumTokens = LIST_NUM(o);
1788        t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
1789
1790        for (i = 0;i < t->NumTokens;i++)
1791        {
1792            t->Token[i] = LIST_DATA(o, i);
1793        }
1794
1795        ReleaseList(o);
1796
1797        *param_list = t;
1798    }
1799
1800    if (UniStrCmpi(ret, L"none") == 0 || UniStrCmpi(ret, L"null") == 0)
1801    {
1802        // none と null は予約語である
1803        ret[0] = 0;
1804    }
1805
1806    return ret;
1807}
1808char *ParseCommandA(wchar_t *str, char *name)
1809{
1810    wchar_t *tmp1, *tmp2;
1811    char *ret;
1812    // 引数チェック
1813    if (str == NULL)
1814    {
1815        return NULL;
1816    }
1817
1818    if (name != NULL)
1819    {
1820        tmp1 = CopyStrToUni(name);
1821    }
1822    else
1823    {
1824        tmp1 = NULL;
1825    }
1826
1827    tmp2 = ParseCommand(str, tmp1);
1828
1829    if (tmp2 == NULL)
1830    {
1831        ret = NULL;
1832    }
1833    else
1834    {
1835        ret = CopyUniToStr(tmp2);
1836        Free(tmp2);
1837    }
1838
1839    Free(tmp1);
1840
1841    return ret;
1842}
1843
1844// パスワードプロンプト
1845bool PasswordPrompt(char *password, UINT size)
1846{
1847    UINT wp;
1848    bool escape = false;
1849    void *console;
1850    // 引数チェック
1851    if (password == NULL || size <= 1)
1852    {
1853        if (size >= 1)
1854        {
1855            password[0] = 0;
1856        }
1857        return false;
1858    }
1859
1860    wp = 0;
1861
1862    Zero(password, size);
1863
1864    console = SetConsoleRaw();
1865
1866    while (true)
1867    {
1868        int c;
1869
1870#ifdef  OS_WIN32
1871        c = getch();
1872#else   // OS_WIN32
1873        c = getc(stdin);
1874#endif  // OS_WIN32
1875
1876        if (c >= 0x20 && c <= 0x7E)
1877        {
1878            // 文字
1879            if ((wp + 1) < size)
1880            {
1881                password[wp++] = (char)c;
1882                putc('*', stdout);
1883            }
1884        }
1885        else if (c == 0x03)
1886        {
1887            // 強制終了
1888            exit(0);
1889        }
1890        else if (c == 0x04 || c == 0x1a || c == 0x0D || c==0x0A)
1891        {
1892            // 終了
1893            if (c == 0x04 || c == 0x1a)
1894            {
1895                escape = true;
1896            }
1897            break;
1898        }
1899        else if (c == 0xE0)
1900        {
1901            // もう 1 文字読む
1902            c = getch();
1903            if (c == 0x4B || c == 0x53)
1904            {
1905                // バックスペース
1906                goto BACKSPACE;
1907            }
1908        }
1909        else if (c == 0x08)
1910        {
1911BACKSPACE:
1912            // バックスペース
1913            if (wp >= 1)
1914            {
1915                password[--wp] = 0;
1916                putc(0x08, stdout);
1917                putc(' ', stdout);
1918                putc(0x08, stdout);
1919            }
1920        }
1921    }
1922    Print("\n");
1923
1924    RestoreConsole(console);
1925
1926    return (escape ? false : true);
1927}
1928
1929// プロンプトを表示
1930wchar_t *Prompt(wchar_t *prompt_str)
1931{
1932    wchar_t *ret = NULL;
1933    wchar_t *tmp = NULL;
1934    // 引数チェック
1935    if (prompt_str == NULL)
1936    {
1937        prompt_str = L"";
1938    }
1939
1940#ifdef  OS_WIN32
1941    UniPrint(L"%s", prompt_str);
1942    tmp = Malloc(MAX_PROMPT_STRSIZE);
1943    if (fgetws(tmp, MAX_PROMPT_STRSIZE - 1, stdin) != NULL)
1944    {
1945        bool escape = false;
1946        UINT i, len;
1947
1948        len = UniStrLen(tmp);
1949        for (i = 0;i < len;i++)
1950        {
1951            if (tmp[i] == 0x04 || tmp[i] == 0x1A)
1952            {
1953                escape = true;
1954                break;
1955            }
1956        }
1957
1958        if (escape == false)
1959        {
1960            UniTrimCrlf(tmp);
1961
1962            ret = UniCopyStr(tmp);
1963        }
1964    }
1965    Free(tmp);
1966#else   // OS_WIN32
1967    {
1968        char *prompt = CopyUniToStr(prompt_str);
1969        char *s = readline(prompt);
1970        Free(prompt);
1971
1972        if (s != NULL)
1973        {
1974            TrimCrlf(s);
1975            Trim(s);
1976
1977            if (IsEmptyStr(s) == false)
1978            {
1979                add_history(s);
1980            }
1981
1982            ret = CopyStrToUni(s);
1983
1984            free(s);
1985        }
1986    }
1987#endif  // OS_WIN32
1988
1989    if (ret == NULL)
1990    {
1991        Print("\n");
1992    }
1993
1994    return ret;
1995}
1996char *PromptA(wchar_t *prompt_str)
1997{
1998    wchar_t *str = Prompt(prompt_str);
1999
2000    if (str == NULL)
2001    {
2002        return NULL;
2003    }
2004    else
2005    {
2006        char *ret = CopyUniToStr(str);
2007
2008        Free(str);
2009        return ret;
2010    }
2011}
2012
2013// コンソールを Raw モードにする
2014void *SetConsoleRaw()
2015{
2016#ifdef  OS_UNIX
2017    struct termios t, *ret;
2018
2019    Zero(&t, sizeof(t));
2020    if (tcgetattr(0, &t) != 0)
2021    {
2022        // 失敗
2023        return NULL;
2024    }
2025
2026    // 現在の設定をコピー
2027    ret = Clone(&t, sizeof(t));
2028
2029    // 設定を変更
2030    t.c_lflag &= (~ICANON);
2031    t.c_lflag &= (~ECHO);
2032    t.c_cc[VTIME] = 0;
2033    t.c_cc[VMIN] = 1;
2034    tcsetattr(0, TCSANOW, &t);
2035
2036    return ret;
2037#else   // OS_UNIX
2038    return Malloc(0);
2039#endif  // OS_UNIX
2040}
2041
2042// コンソールのモードを復帰する
2043void RestoreConsole(void *p)
2044{
2045#ifdef  OS_UNIX
2046    struct termios *t;
2047    // 引数チェック
2048    if (p == NULL)
2049    {
2050        return;
2051    }
2052
2053    t = (struct termios *)p;
2054
2055    // 設定を復帰する
2056    tcsetattr(0, TCSANOW, t);
2057
2058    Free(t);
2059#else   // OS_UNIX
2060    if (p != NULL)
2061    {
2062        Free(p);
2063    }
2064#endif  // OS_UNIX
2065}
2066
2067////////////////////////////
2068// ローカルコンソール関数
2069
2070// 新しいローカルコンソールの作成
2071CONSOLE *NewLocalConsole(wchar_t *infile, wchar_t *outfile)
2072{
2073    IO *in_io = NULL, *out_io = NULL;
2074    CONSOLE *c = ZeroMalloc(sizeof(CONSOLE));
2075    LOCAL_CONSOLE_PARAM *p;
2076    UINT old_size = 0;
2077
2078#ifdef  OS_WIN32
2079    if (MsGetConsoleWidth() == 80)
2080    {
2081        //old_size = MsSetConsoleWidth(WIN32_DEFAULT_CONSOLE_WIDTH);
2082    }
2083#endif  // OS_WIN32
2084
2085    c->ConsoleType = CONSOLE_LOCAL;
2086    c->Free = ConsoleLocalFree;
2087    c->ReadLine = ConsoleLocalReadLine;
2088    c->ReadPassword = ConsoleLocalReadPassword;
2089    c->Write = ConsoleLocalWrite;
2090    c->GetWidth = ConsoleLocalGetWidth;
2091
2092    if (UniIsEmptyStr(infile) == false)
2093    {
2094        // 入力ファイルが指定されている
2095        in_io = FileOpenW(infile, false);
2096        if (in_io == NULL)
2097        {
2098            wchar_t tmp[MAX_SIZE];
2099
2100            UniFormat(tmp, sizeof(tmp), _UU("CON_INFILE_ERROR"), infile);
2101            c->Write(c, tmp);
2102            Free(c);
2103            return NULL;
2104        }
2105        else
2106        {
2107            wchar_t tmp[MAX_SIZE];
2108
2109            UniFormat(tmp, sizeof(tmp), _UU("CON_INFILE_START"), infile);
2110            c->Write(c, tmp);
2111        }
2112    }
2113
2114    if (UniIsEmptyStr(outfile) == false)
2115    {
2116        // 出力ファイルが指定されている
2117        out_io = FileCreateW(outfile);
2118        if (out_io == NULL)
2119        {
2120            wchar_t tmp[MAX_SIZE];
2121
2122            UniFormat(tmp, sizeof(tmp), _UU("CON_OUTFILE_ERROR"), outfile);
2123            c->Write(c, tmp);
2124            Free(c);
2125
2126            if (in_io != NULL)
2127            {
2128                FileClose(in_io);
2129            }
2130            return NULL;
2131        }
2132        else
2133        {
2134            wchar_t tmp[MAX_SIZE];
2135
2136            UniFormat(tmp, sizeof(tmp), _UU("CON_OUTFILE_START"), outfile);
2137            c->Write(c, tmp);
2138        }
2139    }
2140
2141    p = ZeroMalloc(sizeof(LOCAL_CONSOLE_PARAM));
2142    c->Param = p;
2143
2144    p->InFile = in_io;
2145    p->OutFile = out_io;
2146    p->Win32_OldConsoleWidth = old_size;
2147
2148    if (in_io != NULL)
2149    {
2150        UINT size;
2151        void *buf;
2152
2153        size = FileSize(in_io);
2154        buf = ZeroMalloc(size + 1);
2155        FileRead(in_io, buf, size);
2156
2157        p->InBuf = NewBuf();
2158        WriteBuf(p->InBuf, buf, size);
2159        Free(buf);
2160
2161        p->InBuf->Current = 0;
2162    }
2163
2164    return c;
2165}
2166
2167// コンソール解放
2168void ConsoleLocalFree(CONSOLE *c)
2169{
2170    LOCAL_CONSOLE_PARAM *p;
2171    // 引数チェック
2172    if (c == NULL)
2173    {
2174        return;
2175    }
2176
2177    p = (LOCAL_CONSOLE_PARAM *)c->Param;
2178
2179#ifdef  OS_WIN32
2180    if (p->Win32_OldConsoleWidth != 0)
2181    {
2182        MsSetConsoleWidth(p->Win32_OldConsoleWidth);
2183    }
2184#endif  // OS_WIN32
2185
2186    if (p != NULL)
2187    {
2188        if (p->InFile != NULL)
2189        {
2190            FileClose(p->InFile);
2191            FreeBuf(p->InBuf);
2192        }
2193
2194        if (p->OutFile != NULL)
2195        {
2196            FileClose(p->OutFile);
2197        }
2198
2199        Free(p);
2200    }
2201
2202    // メモリ解放
2203    Free(c);
2204}
2205
2206// 画面の横幅を取得
2207UINT ConsoleLocalGetWidth(CONSOLE *c)
2208{
2209    UINT ret = 0;
2210    // 引数チェック
2211    if (c == NULL)
2212    {
2213        return 0;
2214    }
2215
2216#ifdef  OS_WIN32
2217    ret = MsGetConsoleWidth();
2218#else   // OS_WIN32
2219    {
2220        struct winsize t;
2221
2222        Zero(&t, sizeof(t));
2223
2224        if (ioctl(1, TIOCGWINSZ, &t) == 0)
2225        {
2226            ret = t.ws_col;
2227        }
2228    }
2229#endif  // OS_WIN32
2230
2231    return ret;
2232}
2233
2234// コンソールから 1 行読み込む
2235wchar_t *ConsoleLocalReadLine(CONSOLE *c, wchar_t *prompt, bool nofile)
2236{
2237    wchar_t *ret;
2238    LOCAL_CONSOLE_PARAM *p;
2239    // 引数チェック
2240    if (c == NULL)
2241    {
2242        return NULL;
2243    }
2244    p = (LOCAL_CONSOLE_PARAM *)c->Param;
2245    if (prompt == NULL)
2246    {
2247        prompt = L">";
2248    }
2249
2250    ConsoleWriteOutFile(c, prompt, false);
2251
2252    if (nofile == false && p->InBuf != NULL)
2253    {
2254        // ファイルから次の行を読み込む
2255        ret = ConsoleReadNextFromInFile(c);
2256
2257        if (ret != NULL)
2258        {
2259            // 擬似プロンプトを表示する
2260            UniPrint(L"%s", prompt);
2261
2262            // 画面に描画する
2263            UniPrint(L"%s\n", ret);
2264        }
2265    }
2266    else
2267    {
2268        // 画面から次の行を読み込む
2269        ret = Prompt(prompt);
2270    }
2271
2272    if (ret != NULL)
2273    {
2274        ConsoleWriteOutFile(c, ret, true);
2275    }
2276    else
2277    {
2278        ConsoleWriteOutFile(c, _UU("CON_USER_CANCEL"), true);
2279    }
2280
2281    return ret;
2282}
2283
2284// コンソールからパスワードを読み込む
2285char *ConsoleLocalReadPassword(CONSOLE *c, wchar_t *prompt)
2286{
2287    char tmp[64];
2288    // 引数チェック
2289    if (c == NULL)
2290    {
2291        return NULL;
2292    }
2293    if (prompt == NULL)
2294    {
2295        prompt = L"Password>";
2296    }
2297
2298    UniPrint(L"%s", prompt);
2299    ConsoleWriteOutFile(c, prompt, false);
2300
2301    if (PasswordPrompt(tmp, sizeof(tmp)))
2302    {
2303        ConsoleWriteOutFile(c, L"********", true);
2304        return CopyStr(tmp);
2305    }
2306    else
2307    {
2308        ConsoleWriteOutFile(c, _UU("CON_USER_CANCEL"), true);
2309        return NULL;
2310    }
2311}
2312
2313// コンソールに文字列を表示する
2314bool ConsoleLocalWrite(CONSOLE *c, wchar_t *str)
2315{
2316    // 引数チェック
2317    if (c == NULL || str == NULL)
2318    {
2319        return false;
2320    }
2321
2322    UniPrint(L"%s%s", str, (UniEndWith(str, L"\n") ? L"" : L"\n"));
2323
2324    ConsoleWriteOutFile(c, str, true);
2325
2326    return true;
2327}
2328
2329// 入力ファイルから次の 1 行を読み込む
2330wchar_t *ConsoleReadNextFromInFile(CONSOLE *c)
2331{
2332    LOCAL_CONSOLE_PARAM *p;
2333    char *str;
2334    // 引数チェック
2335    if (c == NULL)
2336    {
2337        return NULL;
2338    }
2339
2340    p = (LOCAL_CONSOLE_PARAM *)c->Param;
2341
2342    if (p->InBuf == NULL)
2343    {
2344        return NULL;
2345    }
2346
2347    while (true)
2348    {
2349        str = CfgReadNextLine(p->InBuf);
2350
2351        if (str == NULL)
2352        {
2353            return NULL;
2354        }
2355
2356        Trim(str);
2357
2358        if (IsEmptyStr(str) == false)
2359        {
2360            UINT size;
2361            wchar_t *ret;
2362
2363            size = CalcUtf8ToUni((BYTE *)str, StrLen(str));
2364            ret = ZeroMalloc(size + 32);
2365            Utf8ToUni(ret, size, (BYTE *)str, StrLen(str));
2366
2367            Free(str);
2368
2369            return ret;
2370        }
2371
2372        Free(str);
2373    }
2374}
2375
2376// 出力ファイルが指定されている場合は書き出す
2377void ConsoleWriteOutFile(CONSOLE *c, wchar_t *str, bool add_last_crlf)
2378{
2379    LOCAL_CONSOLE_PARAM *p;
2380    // 引数チェック
2381    if (c == NULL || str == NULL)
2382    {
2383        return;
2384    }
2385
2386    p = (LOCAL_CONSOLE_PARAM *)c->Param;
2387
2388    if (p != NULL && p->OutFile != NULL)
2389    {
2390        wchar_t *tmp = UniNormalizeCrlf(str);
2391        UINT utf8_size;
2392        UCHAR *utf8;
2393
2394        utf8_size = CalcUniToUtf8(tmp);
2395        utf8 = ZeroMalloc(utf8_size + 1);
2396        UniToUtf8(utf8, utf8_size + 1, tmp);
2397
2398        FileWrite(p->OutFile, utf8, utf8_size);
2399
2400        if (UniEndWith(str, L"\n") == false && add_last_crlf)
2401        {
2402            char *crlf = "\r\n";
2403            FileWrite(p->OutFile, "\r\n", StrLen(crlf));
2404        }
2405
2406        Free(utf8);
2407        Free(tmp);
2408    }
2409
2410}
2411
Note: See TracBrowser for help on using the repository browser.