OSDN Git Service

The argument specification changed.
authorShinichiro Nakamura <shinta.main.jp@gmail.com>
Mon, 30 Apr 2012 00:01:08 +0000 (09:01 +0900)
committerShinichiro Nakamura <shinta.main.jp@gmail.com>
Mon, 30 Apr 2012 00:01:08 +0000 (09:01 +0900)
src/Makefile
src/kz_h8write.c
src/mot.c
src/mot.h
src/optparse.c [new file with mode: 0644]
src/optparse.h [new file with mode: 0644]

index 6af95c8..2fcc8ba 100644 (file)
@@ -1,5 +1,5 @@
 TARGET1=kz_h8write
-SRCS1=kz_h8write.c serial_linux.c mot.c
+SRCS1=kz_h8write.c serial_linux.c mot.c optparse.c
 
 TARGET2=motdump
 SRCS2=motdump.c mot.c
index e2c483a..61be76f 100644 (file)
 #include <stdlib.h>
 #include <stdint.h>
 #include "serial.h"
-#include "kz_h8write.h"
 #include "mot.h"
+#include "optparse.h"
+#include "kz_h8write.h"
 
 /**
- * @brief デバッグモードフラグ。
- * @details 0:デバッグモードオフ、1:デバッグモードオン。
+ * @brief プログラム終了用マクロ。
+ * @details このマクロはシリアルポートのオープン成功後の処理に用いる。
+ * @param CODE シェルに返すコード番号。
  */
-#define DEBUG 0
+#define PROGEXIT(CODE) serial_close(serial); exit(CODE)
 
 /**
  * @brief シリアルタイムアウト時間。
  */
 #define SERIAL_TIMEOUT_MS 500
 
-SERIAL *serial;
-unsigned char memory_image[0x100000 + 0x100];
-unsigned int memory_lastaddr = 0;
+/**
+ * @brief ユーザオプション構造体。
+ */
+typedef struct {
+    char cpu_name[BUFSIZ];      /**< CPU名。 */
+    int cpu_freq;               /**< CPU周波数。 */
+    char mot_file[BUFSIZ];      /**< MOTファイル名。NULLなら標準入力。 */
+    char serial_port[BUFSIZ];   /**< シリアルポート名。 */
+    int version;                /**< バージョンフラグ。 */
+    int help;                   /**< ヘルプフラグ。 */
+    int debug;                  /**< デバッグフラグ。 */
+    int error;                  /**< オプション指定エラー検出フラグ。 */
+} user_option_t;
+
+#define USER_OPTION_INITIALIZER \
+{ \
+    .cpu_name = "\0", \
+    .cpu_freq = 20, \
+    .mot_file = "\0", \
+    .serial_port = "\0", \
+    .version = 0, \
+    .help = 0, \
+    .debug = 0, \
+    .error = 0, \
+}
+
+#define USER_OPTION_CPU_NAME(P)     ((P)->cpu_name)
+#define USER_OPTION_CPU_FREQ(P)     ((P)->cpu_freq)
+#define USER_OPTION_MOT_FILE(P)     ((P)->mot_file)
+#define USER_OPTION_SERIAL_PORT(P)  ((P)->serial_port)
+#define USER_OPTION_VERSION(P)      ((P)->version)
+#define USER_OPTION_HELP(P)         ((P)->help)
+#define USER_OPTION_DEBUG(P)        ((P)->debug)
+#define USER_OPTION_ERROR(P)        ((P)->error)
+
+static SERIAL *serial;
+static unsigned char memory_image[0x100000 + 0x100];
+static unsigned int memory_lastaddr = 0;
 
 int com_getc(void);
 int com_putc(unsigned char c);
@@ -553,12 +590,41 @@ enum ErrorCode program(void)
     return NoError;
 }
 
-/**
- * @brief プログラム終了用マクロ。
- * @details このマクロはシリアルポートのオープン成功後の処理に用いる。
- * @param CODE シェルに返すコード番号。
- */
-#define PROGEXIT(CODE) serial_close(serial); exit(CODE)
+int optparse_callback(const char option, const char *argument, void *extobj)
+{
+    user_option_t *user_option = (user_option_t *)extobj;
+
+    printf("option=%c, argument=%s\n", option, argument);
+
+    /*
+     * USER_OPTION_MOT_FILE()とUSER_OPTION_SERIAL_PORT()は別に取得する。
+     */
+    switch (option) {
+        case '3':
+            strcpy(USER_OPTION_CPU_NAME(user_option), "3");
+            strcat(USER_OPTION_CPU_NAME(user_option), argument);
+            break;
+        case 'F':
+        case 'f':
+            if (sscanf(argument, "%i", &USER_OPTION_CPU_FREQ(user_option)) != 1) {
+                USER_OPTION_ERROR(user_option) = 1;
+            }
+            break;
+        case 'V':
+        case 'v':
+            USER_OPTION_VERSION(user_option) = 1;
+            break;
+        case 'H':
+        case 'h':
+            USER_OPTION_HELP(user_option) = 1;
+            break;
+        case 'D':
+        case 'd':
+            USER_OPTION_DEBUG(user_option) = 1;
+            break;
+    }
+    return 0;
+}
 
 /**
  * @brief エントリーポイント。
@@ -570,60 +636,101 @@ int main(int argc, char **argv)
 {
     enum ErrorCode ec;
     uint32_t devcode;
-    char *motfile;
-    int clock;
-    char *interface;
+    user_option_t user_option = USER_OPTION_INITIALIZER;
 
+    /*
+     * バナーを表示する。
+     */
     fprintf(stderr, "=================================================\n");
     fprintf(stderr, " H8/3069F Flash Writer for KOZOS (Version %d.%d.%d)\n",
             VERSION_MAJOR,
             VERSION_MINOR,
             VERSION_RELEASE);
-    fprintf(stderr, " Copyright(C) 2011 Shinichiro Nakamura \n");
+    fprintf(stderr, " Copyright(C) 2011-2012 Shinichiro Nakamura\n");
     fprintf(stderr, "=================================================\n");
 
-    if (argc != 4) {
-        fprintf(stderr, "%s [mot file] [clock] [interface]\n", argv[0]);
+    /*
+     * オプションのデフォルト値を設定する。
+     */
+    strcpy(USER_OPTION_CPU_NAME(&user_option), "3069");
+    USER_OPTION_CPU_FREQ(&user_option)    = 20;
+    strcpy(USER_OPTION_MOT_FILE(&user_option), "");
+    strcpy(USER_OPTION_SERIAL_PORT(&user_option), "");
+    USER_OPTION_VERSION(&user_option)     = 0;
+    USER_OPTION_HELP(&user_option)        = 0;
+    USER_OPTION_DEBUG(&user_option)       = 0;
+    USER_OPTION_ERROR(&user_option)       = 0;
+
+    /*
+     * 文字ベースでオプションを解析する。
+     */
+    optparse_char(argc, argv, &user_option, optparse_callback);
+
+    /*
+     * オプションの指定に誤りがある場合には、使い方を表示して終了する。
+     */
+    if ((argc < 3) || USER_OPTION_ERROR(&user_option)
+            || USER_OPTION_VERSION(&user_option) || USER_OPTION_HELP(&user_option)) {
+        fprintf(stderr, "%s [options...] [mot file] [interface]\n", argv[0]);
+        fprintf(stderr, "\n");
+        fprintf(stderr, " Target CPU        : -3069         (Default:3069)\n");
+        fprintf(stderr, " Target Frequency  : -f[20 | 25]   (Default:20)\n");
+        fprintf(stderr, " Version           : -v\n");
+        fprintf(stderr, " Help              : -h\n");
+        fprintf(stderr, " Debug             : -d\n");
         exit(1);
     }
 
     /*
-     * パラメータを受け取る。
+     * 与えられた引数の最後の二つは、それぞれMOTファイルとシリアルポート名であるという仮定。
+     */
+    strcpy(USER_OPTION_MOT_FILE(&user_option), argv[argc - 2]);
+    strcpy(USER_OPTION_SERIAL_PORT(&user_option), argv[argc - 1]);
+
+    /*
+     * デバッグ用の出力。
+     */
+    if (USER_OPTION_DEBUG(&user_option)) {
+        fprintf(stderr, "Target CPU       : %s\n", USER_OPTION_CPU_NAME(&user_option));
+        fprintf(stderr, "Target Frequency : %d\n", USER_OPTION_CPU_FREQ(&user_option));
+        fprintf(stderr, "MOT File         : %s\n", USER_OPTION_MOT_FILE(&user_option));
+        fprintf(stderr, "Seiral Port      : %s\n", USER_OPTION_SERIAL_PORT(&user_option));
+    }
+
+    /*
+     * 与えられたオプションを検証する。
      */
-    motfile = argv[1];
-    if (sscanf(argv[2], "%d", &clock) != 1) {
-        fprintf(stderr, "Invalid clock number found.\n");
+    if (strcmp(USER_OPTION_CPU_NAME(&user_option), "3069") != 0) {
+        /*
+         * 3069F以外はエラーとする。
+         * 3069F以外で検証するつもりは今のところないから対象外とする。
+         * プロトコルが同じなら書き込めるだろう。
+         */
+        fprintf(stderr, "Unsupported CPU name found.\n");
+        exit(1);
+    }
+    if ((USER_OPTION_CPU_FREQ(&user_option) != 20) && (USER_OPTION_CPU_FREQ(&user_option) != 25)) {
+        /*
+         * 20MHzでもなく、25MHzでもなければエラー。
+         */
+        fprintf(stderr, "Unsupported CPU frequency value found.\n");
         exit(1);
     }
-    interface = argv[3];
 
     /*
      * motファイルを読み込む。
      */
     mot_t mot;
     mot.cb_data = mot_callback;
-    if (mot_read(motfile, &mot) != 0) {
+    if (mot_read(USER_OPTION_MOT_FILE(&user_option), &mot) != 0) {
         fprintf(stderr, "file read error\n");
         exit(1);
     }
 
-#if (DEBUG==1)
-    /*
-     * ダンプしてチェック。
-     */
-    for (unsigned int i = 0; i < memory_lastaddr; i++) {
-        if ((i % 16) == 0) {
-            fprintf(stderr, "\n0x%04X :", i);
-        }
-        fprintf(stderr, " %02X", memory_image[i]);
-    }
-    fprintf(stderr, "\n");
-#endif
-
     /*
      * シリアルポートをオープンする。
      */
-    serial = serial_open(interface, SerialBaud19200);
+    serial = serial_open(USER_OPTION_SERIAL_PORT(&user_option), SerialBaud19200);
     if (serial == NULL) {
         fprintf(stderr, "com port open error\n");
         exit(1);
@@ -653,9 +760,9 @@ int main(int argc, char **argv)
              * リトライした結果として成功した事を知りたい時にのみ
              * 表示を有効にすると良い。
              */
-#if (DEBUG==1)
-            fprintf(stderr, "Bitrate sequence failed.\n");
-#endif
+            if (USER_OPTION_DEBUG(&user_option)) {
+                fprintf(stderr, "Bitrate sequence failed.\n");
+            }
         }
     }
     if (ec != NoError) {
@@ -707,7 +814,7 @@ int main(int argc, char **argv)
     /*
      * 新ビットレート選択を実行する。
      */
-    ec = select_bitrate(19200, clock);
+    ec = select_bitrate(19200, USER_OPTION_CPU_FREQ(&user_option));
     if (ec != NoError) {
         fprintf(stderr, "Select bitrate failed. (code=0x%02x)\n", (int)ec);
         PROGEXIT(1);
index d1a4b4a..84c8445 100644 (file)
--- a/src/mot.c
+++ b/src/mot.c
@@ -235,21 +235,34 @@ static int parse_record(mot_t *p, const char *txt)
 
 /**
  * @brief motファイルを読み込む。
- * @param filename ファイル名。
+ *
+ * @param filename ファイル名。(NULLを与えると標準入力を入力とする。)
  * @param p mot構造体。(コールバック関数などの情報を参照する。)
+ *
  * @retval 0 成功
  * @retval 0以外 エラー番号。
  */
 int mot_read(const char *filename, mot_t *p)
 {
     char buf[BUFSIZ];
+    FILE *fp = NULL;
 
-    /*
-     * ファイルをオープンする。
-     */
-    FILE *fp = fopen(filename, "r");
-    if (fp == NULL) {
-        return -1;
+    if (filename == NULL) {
+        /*
+         * 標準入力を入力用ファイルとして用いる。
+         */
+        fp = stdin;
+        if (fp == NULL) {
+            return -1;
+        }
+    } else {
+        /*
+         * ファイルをオープンする。
+         */
+        fp = fopen(filename, "r");
+        if (fp == NULL) {
+            return -1;
+        }
     }
 
     /*
index 079bf22..eb4bacd 100644 (file)
--- a/src/mot.h
+++ b/src/mot.h
@@ -46,6 +46,15 @@ typedef struct {
 extern "C" {
 #endif
 
+/**
+ * @brief motファイルを読み込む。
+ *
+ * @param filename ファイル名。(NULLを与えると標準入力を入力とする。)
+ * @param p mot構造体。(コールバック関数などの情報を参照する。)
+ *
+ * @retval 0 成功
+ * @retval 0以外 エラー番号。
+ */
 int mot_read(const char *filename, mot_t *p);
 
 #ifdef __cplusplus
diff --git a/src/optparse.c b/src/optparse.c
new file mode 100644 (file)
index 0000000..864cc77
--- /dev/null
@@ -0,0 +1,159 @@
+/**
+ * @file optparse.c
+ * @author Shinichiro Nakamura
+ * @brief オプション解析モジュールの実装。
+ */
+
+/*
+ * ===============================================================
+ *  Option parse library
+ *  Version 0.0.1
+ * ===============================================================
+ * Copyright (c) 2012 Shinichiro Nakamura
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ * ===============================================================
+ */
+
+#include <string.h>
+#include "optparse.h"
+
+int optparse_char(
+        int argc,
+        char **argv,
+        void *extobj,
+        int (*callback)(
+            const char option, const char *argument, void *extobj))
+{
+    for (int i = 1; i < argc;) {
+        int r = 0;
+        int c = 0;
+        if (argv[i][0] == '-') {
+            /*
+             * 与えられた文字列は引数である。
+             */
+            if (strlen(argv[i]) > 2) {
+                /*
+                 * 同じ箇所にアーギュメントが指定されている。
+                 */
+                r = callback(argv[i][1], &argv[i][2], extobj);
+                c = 1;
+            } else {
+                if ((i + 1) < argc) {
+                    /*
+                     * まだ続きがありそうだ。
+                     * 先を見ておこう。
+                     */
+                    if (argv[i + 1][0] == '-') {
+                        /*
+                         * その引数にアーギュメントはない。
+                         */
+                        r = callback(argv[i][1], "", extobj);
+                        c = 1;
+                    } else {
+                        /*
+                         * その引数にアーギュメントがある。
+                         */
+                        r = callback(argv[i][1], argv[i + 1], extobj);
+                        c = 2;
+                    }
+                } else {
+                    /*
+                     * もう先がない。
+                     * ということはアーギュメントはない。
+                     */
+                    r = callback(argv[i][1], "", extobj);
+                    c = 1;
+                }
+            }
+        } else {
+            /*
+             * 与えられた文字列はオプションでない
+             * 単独アーギュメントである。
+             */
+            r = callback('\x00', &argv[i][0], extobj);
+            c = 1;
+        }
+        i += c;
+        if (r != 0) {
+            break;
+        }
+    }
+    return 0;
+}
+
+int optparse_text(
+        int argc,
+        char **argv,
+        void *extobj,
+        int (*callback)(
+            const char *option, const char *argument, void *extobj))
+{
+    for (int i = 1; i < argc;) {
+        int r = 0;
+        int c = 0;
+        if (argv[i][0] == '-') {
+            /*
+             * 与えられた文字列は引数である。
+             */
+            if ((i + 1) < argc) {
+                /*
+                 * まだ続きがありそうだ。
+                 * 先を見ておこう。
+                 */
+                if (argv[i + 1][0] == '-') {
+                    /*
+                     * その引数にアーギュメントはない。
+                     */
+                    r = callback(&argv[i][1], "", extobj);
+                    c = 1;
+                } else {
+                    /*
+                     * その引数にアーギュメントがある。
+                     */
+                    r = callback(&argv[i][1], argv[i + 1], extobj);
+                    c = 2;
+                }
+            } else {
+                /*
+                 * もう先がない。
+                 * ということはアーギュメントはない。
+                 */
+                r = callback(&argv[i][1], "", extobj);
+                c = 1;
+            }
+        } else {
+            /*
+             * 与えられた文字列はオプションでない
+             * 単独アーギュメントである。
+             */
+            r = callback("", &argv[i][0], extobj);
+            c = 1;
+        }
+        i += c;
+        if (r != 0) {
+            break;
+        }
+    }
+    return 0;
+}
+
diff --git a/src/optparse.h b/src/optparse.h
new file mode 100644 (file)
index 0000000..db35299
--- /dev/null
@@ -0,0 +1,55 @@
+/**
+ * @file optparse.h
+ * @author Shinichiro Nakamura
+ * @brief オプション解析モジュールの定義。
+ */
+
+/*
+ * ===============================================================
+ *  Option parse library
+ *  Version 0.0.1
+ * ===============================================================
+ * Copyright (c) 2012 Shinichiro Nakamura
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ * ===============================================================
+ */
+
+#ifndef OPTPARSE_H
+#define OPTPARSE_H
+
+int optparse_char(
+        int argc,
+        char **argv,
+        void *extobj,
+        int (*callback)(
+            const char option, const char *argument, void *extobj));
+
+int optparse_text(
+        int argc,
+        char **argv,
+        void *extobj,
+        int (*callback)(
+            const char *option, const char *argument, void *extobj));
+
+#endif
+