[C++] 67 アプリ画像ファイルの有効パス その2 : 作業ディレクトリ変更

[M1 Mac, Big Sur 11.6.7, clang 13.0.0, no IDE]

実行ファイルのあるところに作業ディレクトリを変更して相対パスが使えないか検証しました。

実行ファイルのディレクトリの文字列を作成するために文字列分割関数と文字列分割/再結合関数を作りました。これらは後日ライブラリにする予定です。

検証の方は成功しました。手間は掛かりますが、作業ディレクトリを実行ファイルのディレクトリに変更することで相対パスでの画像ファイルの使用は実行ファイル、appファイル共に可能になります。

#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_PNG_Image.H>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <vector>

using std::string; using std::vector;
using std::cout; using std::endl;

Fl_Window* window;
Fl_Box* picturebox;
Fl_PNG_Image* pngimage;  

// 文字列を文字列delで分割しリスト化する関数
vector<string> split(string str, char del) {
    int first = 0;
    int last = str.find_first_of(del);
    vector<string> result;
 
    while (first < str.size()) {
        string subStr(str, first, last - first);
        result.push_back(subStr);
 
        first = last + 1;
        last = str.find_first_of(del, first);
 
        if (last == string::npos) {
            last = str.size();
        }
    }
    return result;
}
// 分割リストのstart番目からend番目までの要素を再結合する関数
string splitjoin(string str, char del, int start, int end){
    string result2;
    vector<string> list = split(str, del);

    vector<string> list2;
    for (int i = 0; i < list.size(); i++){
        if (end < 0){
            end += list.size();
        }
        if (i >= start && i <= end) {
            list2.push_back(list[i]);
        }
    }
    for (int i = 0; i< list2.size(); i++){
        result2.append(list[i] + del);
    }
    return result2;
}

int main(int argc, char **argv) {
    // 変更前の作業ディレクトリ確認
    char tmp[256];
    getcwd(tmp, 256);
    cout << "Current working directory: " << tmp << endl;

    // 実行ファイルのパスを出力
    cout << argv[0] << endl;

    // パスをスラッシュで分割しリストにする
    vector<string> l = split(argv[0], '/');

    // リストの内容確認
    int i = 0;
    for (const auto &item : l) {
        cout << i << " " << item << "; ";
        i++;
    }
    cout << endl;

    // リストの0番目から-2番目(最後から2番目)までの文字列を結合して新ディレクトリ作成
    string new_path = splitjoin(argv[0], '/', 0, -2);
    cout << new_path << endl;
    
    // 作業ディレクトリを変更
    int rtn = chdir(new_path.c_str());
    cout << rtn << endl ;

    // 変更後の作業ディレクトリ確認
    getcwd(tmp, 256);
    cout << "Current working directory: " << tmp << endl;

    Fl::set_font(FL_HELVETICA, "Osaka");
    window = new Fl_Window(100,100,360,220,"PLAIN");
    window->color(fl_rgb_color(131,204,210));

    pngimage = new Fl_PNG_Image("star.png");
    picturebox = new Fl_Box(20, 20, 120, 120);
    picturebox->box(FL_UP_BOX);
    picturebox->image(pngimage); 
    picturebox->redraw();  
    window->add(picturebox);

    window->end();
    window->show(argc, argv);
    
    return Fl::run();
}
Current working directory: /Users/[ユーザID]
/Volumes/DATA_m1/code/cpp/projects/plainPNG/bin/plain
0 ; 1 Volumes; 2 DATA_m1; 3 code; 4 cpp; 5 projects; 6 plainPNG; 7 bin; 8 plain; 
/Volumes/DATA_m1/code/cpp/projects/plainPNG/bin/
0
Current working directory: /Volumes/DATA_m1/code/cpp/projects/plainPNG/bin