[Swift] 01 自製ヘルスケアapp / 製作着手

[Mac mini M1, MacOS Monterey 12.3.1, XCode 13.2.1]

Swiftの学習に着手しました。まずは各種ヘルスケアデータの取得方法を学んでいきます。

最初は欲しいコーディング情報が見当たらず右往左往していましたが、わかりやすい日本語サイトが見つかってからは比較的スムーズにBuild&Runできました。

Swiftの印象はポインタのないC++といったところです。難易度はJava以上、C++以下と予想します。構造体データとかC言語の知識がないと苦戦しそうです。

Python, Java, C++と学んできた私にはちょうどいい感じです。

参考サイト

[C++] 49 FLTK : findコマンド生成アプリ/ 大文字小文字区別なし

[M1 Mac, Big Sur 11.6.5, FLTK 1.3.8]

大文字小文字の区別なくgrep検索できるようにしました。オプション –ignore-caseをつけるだけです。なぜか -iではうまくできませんでした。

<該当箇所のみ>
if (onoff_grep == 1){
    const char* grep_char = grep_input->value();
    if (onoff_Aa == 0){
        cmd << "grep --ignore-case -r " << string(grep_char) << " " << string(dir_char);
        std::cout << cmd.str() << endl;
        system((cmd.str()).c_str());
    }else{
        cmd << "grep -r " << string(grep_char) << " " << string(dir_char);
        std::cout << cmd.str() << endl;
        system((cmd.str()).c_str());
    }
    // 件数表示
    cmd << " | wc -l";
    std::cout << cmd.str() << endl;
    system((cmd.str()).c_str());
}

[C++] 47 FLTK : findコマンド生成アプリ/ grep機能

[M1 Mac, Big Sur 11.6.5, FLTK 1.3.8]

最後の仕上げとしてgrep機能(テキスト内文字列検索)を追加しました。

findコマンドと区別するためにgrepの上に長い横線を引きたいのですが、どうもうまくできません。

たかが線を簡単に描画させてくれないFLTK、恐るべしです。JavaのSwingと比較して時間的開発コストは体感的に5〜10倍位といったところでしょうか。気長に取り組まないといらだちを鎮められないですね。線を描くのは基本ですからいずれできるようにします。

アプリの機能も充実し、これからヘビーユースすることになりそうです。

[C++] 46 FLTK : findコマンド生成アプリ/ Fl_Choice

[M1 Mac, Big Sur 11.6.5, FLTK 1.3.8]

Fl_Choiceを使ってプルダウンメニューを作成しました。

ネットにあるFl_Choiceのコード例は小難しいばかりで要領を得ませんでしたが、自分で意味を考えながら書くと内容が単純だからかシンプルな表現になりました。

外観をスッキリさせたいのでボタンへのpngファイルの埋め込みは見送りました。あとはgrep機能を追加して完成にするつもりです。

<関連部分のみ抜粋>
Fl_Menu_Item pulldown[] = {
  {"and"},
  {"or"},
  {"not"}
};

if (onoff_free == 1){
   string choices[3] = {"-and","-or","-not"};
   int choice_num = choice->value();
   string choice_str = choices[choice_num];

   cmd << choice_str << " " ;
   std::cout << cmd.str() << endl;

   const char* free_char = free_input->value();
   string free_str = string(free_char);

   cmd << free_str << " " ;
   std::cout << cmd.str() << endl;
}

<main関数内> 変数freeは既に存在するのでfree2とした
// Free
// free_rbtn
free_rbtn = new Fl_Round_Button(40,115,20,20,nullptr);
// free_label
free2 = new Fl_Box(58,120,26,12,"Free");
free2->labelcolor(fl_rgb_color(234,237,247));
free2->align(Fl_Align(FL_ALIGN_INSIDE|FL_ALIGN_LEFT));
// free_choice
choice = new Fl_Choice(95, 115, 50, 20,nullptr);
choice->menu(pulldown);

[C++] 45 FLTK : findコマンド生成アプリ/機能追加

もう少し完成度を高めるべくGUIをデザインしてみました。

検索条件(自由記述)、各項目クリアボタンの追加です。検索条件の”and/or/not”をプルダウンメニューで選択できるようにし、ゴミ箱のpngファイルをボタンに組み込みます。いずれもFLTKで実装するのは初めてです。

骨組みができてからのこういった作業がプレッシャーもなくのんびり進められるので一番楽しい時間かもしれません。

[C++] 44 FLTK : findコマンド生成アプリ/sudo追加

[M1 Mac, Big Sur 11.6.5, FLTK 1.3.8]

検索時にアクセス拒否されたディレクトリ内も検索したい時のためにsudoをコマンドに追加できるようにしました。なんてことはない内容なのでコードは省略します。

GUIへの標準出力表示実装は難航していますが、コンソール版(GUIとのハイブリッド)で事足りるためこれで基本機能は実装完了になりそうです。

[C++] 43 ld: duplicate symbols for architecture arm64への対処

ケースバイケースですが、今回はヘッダファイルの変数にstatic修飾子を付けるとシンボルの重複が解消されて直りました。

#ifndef STDDISPLAY_H
#define STDDISPLAY_H

#include <FL/Fl_Text_Display.H>

static Fl_Text_Display *G_disp[3];
static Fl_Text_Buffer *G_buff[3];
static int G_outfd[3];
static pid_t G_pids[3];  

void start_child(int);
void data_ready(int, void*);
void close_cb(Fl_Widget*, void*);

#endif

[C++] 41 FLTK : findコマンド生成アプリ/コンソール版完成

[M1 Mac, Big Sur 11.6.5, FLTK 1.3.8]

findコマンド生成アプリのコンソール版が完成しました。わずか878KBの超軽量ツールです。

仕上げは標準出力のGUIへの反映になりますが、すんなり実装できればありがたいです。

ところで私のコードの書き方は、C/C++界隈ではメジャーらしいK&RスタイルではなくJavaスタイルです。情報密度と可読性を優先しているので、1行1前カッコは禁止がマイルールです。後カッコはブロックの終わりが分かりやすいため、1行表示しています。

void execute_cb(Fl_Widget*, void*){
    stringstream cmd;
    stringstream pre;
    const char* dir;

    onoff_from = from_rbtn->value(); 
    onoff_to = to_rbtn->value();
    onoff_name = name_rbtn->value();
    dir = dir_input->value();

    cmd << "cd " << string(dir) << " && " << "find `pwd` -type file ";

    if (onoff_from == 1){
        const char* from_char = from_input->value();
        string from_str = string(from_char);

        std::cout << "from_str " << from_str << endl;
        string day = from_str.substr(6);
        string month = from_str.substr(4, 2);
        string year = from_str.substr(0, 4);

        int days = GetDays(stoi(year), stoi(month), stoi(day));
        int predays = days - 1;

        std::cout << "days " << days << endl;
        std::cout << "predays " << predays << endl;
        std::cout << day << " " << month << " " << year <<endl;

        preDate = { 0, 0, 0, stoi(day) -1, stoi(month)-1, stoi(year)};
        preDate_t = std::mktime(&preDate);
        preDate2 = localtime(&preDate_t);

        int pre_y = preDate2->tm_year;
        int pre_m = preDate2->tm_mon + 1;
        int pre_d = preDate2->tm_mday;

        std::cout << "pre_y pre_m pre_d " << pre_y << " " << pre_m << " " << pre_d <<endl;

        int day2 = GetDay(pre_y, pre_m, pre_d, predays);

        std::cout << "day2 " << day2 <<endl;

        pre << pre_y;
        pre << setw(2) << setfill('0') << pre_m;
        pre << setw(2) << setfill('0') << day2;
        
        std::cout << pre.str() << endl;
        
        cmd << "-newerct '" << pre.str() << " 23:59' ";
        std::cout << cmd.str() << endl;
    }
    if (onoff_to == 1){
        const char* to_char = to_input->value();
        string to_str = string(to_char);

        cmd << "! -newerct '" << to_str << " 23:59' " ;
        std::cout << cmd.str() << endl;
    }
    if (onoff_name == 1){
        const char* name_char = name_input->value();
        string name_str = string(name_char);

        cmd << "-name '*" << name_str << "*' " ;
    }

    cmd << "! -name '*DS_Store*'" ;
    std::cout << cmd.str() << endl;
    system((cmd.str()).c_str());

    // 件数表示
    cmd << " | wc -l";
    std::cout << cmd.str() << endl;
    system((cmd.str()).c_str());
}

[C++] 40 FLTK : findコマンド生成アプリ/前日の取得 日付シリアル値

[M1 Mac, Big Sur 11.6.5, FLTK 1.3.8]

前回の続きです。

西暦1年1月1日からの経過日数をシリアル値とし、前回のケースであれば入力日前日のシリアル値に一致するまで架空の2月31日からデクリメントするという手法を取りました。月またぎ、年またぎ、うるう年に対応しています。

シリアル値を算出する関数はネットにありました。デクリメントで実在日を探し出すのは私のアイデアです。ちなみにExcelのシリアル値の起点は1900年1月1日です

こよみは本当にややこしいです。あまり関わりたくないですね。0時0分、たった1分間の作成ファイルが漏れないようにする工数としては割に合わないです。

// 日付シリアル値を算出する関数(西暦1年1月1日を0とする)
int GetDays(int y, int m, int d)
{
  if (m <= 2) // 1・2月は前年の13・14月
  {
    --y;
    m += 12;
  }
  int dy = 365 * (y - 1); // 経過年数×365日
  int c = y / 100;
  int dl = (y >> 2) - c + (c >> 2); // うるう年分
  int dm = (m * 979 - 1033) >> 5; // 1月1日からm月1日までの日数
  return dy + dl + dm + d - 1;
}

// デクリメントで実在する日を探索する関数
int GetDay(int y,int m, int d, int x){
    for (d; d >0; d--){
        int pre_day_dec = GetDays(y, m, d);
        std::cout << "d " << d << " pre_day_dec " << pre_day_dec <<endl;
        if (x == pre_day_dec){
            return d;
        }
    }
}

void execute_cb(Fl_Widget*, void*) {
    stringstream cmd;
    stringstream pre;
    const char* dir = dir_input->value();
    const char* from_char = from_input->value();
    string from_str = string(from_char);

    std::cout << "from_str " << from_str << endl;
    string day = from_str.substr(6);
    string month = from_str.substr(4, 2);
    string year = from_str.substr(0, 4);

    int days = GetDays(stoi(year), stoi(month), stoi(day));
    int predays = days - 1;

    std::cout << "days " << days << endl;
    std::cout << "predays " << predays << endl;
    std::cout << day << " " << month << " " << year <<endl;

    preDate = { 0, 0, 0, stoi(day) -1, stoi(month) -1, stoi(year)};
    preDate_t = std::mktime(&preDate);
    preDate2 = localtime(&preDate_t);

    int pre_y = preDate2->tm_year;
    int pre_m = preDate2->tm_mon +1;
    int pre_d = preDate2->tm_mday;

    std::cout << "pre_y pre_m pre_d " << pre_y << " " << pre_m << " " << pre_d <<endl;

    int day2 = GetDay(pre_y, pre_m, pre_d, predays);

    std::cout << "day2 " << day2 <<endl;

    pre << pre_y;
    pre << setw(2) << setfill('0') << pre_m;
    pre << setw(2) << setfill('0') << day2;
    
    std::cout << pre.str() << endl;
    
    cmd << "cd " << string(dir) << " && " << "find `pwd` -type file -newerct '" << pre.str() << " 23:59' ! -name '*DS_Store*'";
    std::cout << cmd.str() << endl;

    system((cmd.str()).c_str());
}

参考サイト