[C++,Python] 316 BBS閲覧アプリの製作 その2 スレッドタイトルの取得 Python編

[M1 Mac, MacOS Ventura 13.3.1, Python 3.10.4]

スレッドタイトルとスレッドIDを取得するPythonスクリプトを書きました。

次はこのスクリプトをC++へ変換したいです。難しくなるようであればモジュール化します。

機能はPythonで下書きしてC++へ変換あるいはモジュール化、GUIはFLTK(C++)でコーディングしていきます。

import requests
import re
from bs4 import BeautifulSoup

# URLからHTMLファイルを取り込む
url = 'スレッドタイトル表示URL(HTMLファイル)'
response = requests.get(url)
response.encoding = response.apparent_encoding
html = response.text

# BeautifulSoupを使用してHTMLを解析する
soup = BeautifulSoup(html, 'html.parser')

# <small id="trad">タグで囲まれた部分の内容を取得する
trad_tags = soup.find_all('small', id='trad')

thread_list = []
for trad_tag in trad_tags:
    content = trad_tag.get_text()

    # <a>タグのhref属性の値を正規表現で取得する
    pattern = r'<a\s+href=[\'"]([^\'"]+)[\'"]'
    href = re.findall(pattern, str(trad_tag))

    # contentをaタグごとに分割してリストにする
    content_list = re.split(r'<a\s+href=[\'"][^\'"]+[\'"]', str(trad_tag))
    
    print(f"hrefの要素数: {len(href)}")
    print(f"content_listの要素数: {len(content_list)}")

    # 辞書型データのリストを作成する
    for i in range(len(href)):
        thread_list.append({'href': (href[i])[:-4], 'content': (content_list[i+1].strip().replace("</a>","").replace("</small>",""))[1:]})

# リストの内容を出力する
for thread in thread_list:
    print(thread['href'])
    print(thread['content'])

[C++,Python] 315 BBS閲覧アプリの製作 その1 DATファイルの保存

[M1 Mac, MacOS Ventura 13.3.1, clang 14.0.3]

とあるBBSのDATファイルへのアクセスが可能になったようなので、早速遊んでみることにしました。

とりあえずDATファイルをダウンロードしてみます。PythonスクリプトをChatGPTに変換してもらったコードがそのまま使えました。

DATファイルの文字コードがシフトJISですから、Macの場合はUTF-8に変換する必要がありますね。

#include <iostream>
#include <fstream>
#include <curl/curl.h>

size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) {
    std::ofstream* file = static_cast<std::ofstream*>(userp);
    file->write(static_cast<char*>(contents), size * nmemb);
    return size * nmemb;
}

int main() {
    std::string url = "DATファイルのurl";
    std::string filename = "保存先DATファイルのパス";

    CURL* curl = curl_easy_init();
    if (curl) {
        std::ofstream file(filename, std::ios::binary);
        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &file);
        CURLcode res = curl_easy_perform(curl);
        if (res != CURLE_OK) {
            std::cerr << "Error: " << curl_easy_strerror(res) << std::endl;
        }
        curl_easy_cleanup(curl);
    } else {
        std::cerr << "Failed to initialize curl" << std::endl;
    }

    return 0;
}

[C++] 314 画像加工アプリ チャンネル数取得 RGBA

[M1 Mac, MacOS Ventura 13.3.1, clang 14.0.3]

画像加工アプリにpngのチャンネル数を取得する機能を追加しました。libpngを使います。

RGBAであれば4、アルファチャンネルのないRGBであれば3になります。

unsigned int width;
unsigned int height;
unsigned int res_x;
unsigned int res_y;
unsigned int readSize;
unsigned int channel;

std::array<int,5> getInfoPNG(const char* filename){
	fi = fopen(filename, "rb");
	readSize = fread(signature, 1, SIGNATURE_NUM, fi);

	png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	info = png_create_info_struct(png);

	png_init_io(png, fi);
	png_set_sig_bytes(png, readSize);
	png_read_png(png, info, PNG_TRANSFORM_PACKING | PNG_TRANSFORM_STRIP_16, NULL);
	
	width = png_get_image_width(png, info);
  	height = png_get_image_height(png, info);
	res_x = png_get_x_pixels_per_inch(png,info);
	res_y = png_get_y_pixels_per_inch(png,info);
	channel = png_get_channels(png, info);

	png_destroy_read_struct(&png, &info, NULL);
  	fclose(fi);

	return {(int)width,(int)height,(int)res_x,(int)res_y, (int)channel};
}

[C++] 313 Makefileでのライブラリ設定 MacOS

[M1 Mac, MacOS Ventura 13.3.1, clang 14.0.3]

Linuxはどうなっているのか分かりませんが、MacOSでのライブラリ設定は結構ややこしいです。

ライブラリパスを.bash_profileでDYLD_LIBRARY_PATHとして設定しておかないとビルドはできても実行はできません。

仕組みがよく分からないまま放置していましたが、ようやく明確にできました。

デフォルトのライブラリパスである/usr/local/libなどに配置すれば今回のような設定は不要です。他のライブラリとは分けて管理したかったためライブラリパスを追加した次第です。

# D2XXライブラリの場合
# /usr/local/D2XX/libにはlibftd2xx.aとlibftd2xx.dylibを配置

# includeパス(-I)
INCLUDE = -I/usr/local/D2XX/include

# ライブラリ(-l) 動的ライブラリ優先
LIBS = -lftd2xx
# 静的ライブラリのフルパス(実行ファイルに取り込まれる、ライブラリパス不要)
# LIBS = /usr/local/D2XX/lib/libftd2xx.a
# 動的ライブラリのフルパスは使えない

# ライブラリパス(-L) .bash_profileでDYLD_LIBRARY_PATHとしての設定も必須
LIBPATH = -L/usr/local/D2XX/lib

includeパスは.bash_profileでも設定できる。

# D2XX
export CPLUS_INCLUDE_PATH=$CPLUS_INCLUDE_PATH:/usr/local/D2XX/include

export DYLD_LIBRARY_PATH="/usr/local/D2XX/lib:$DYLD_LIBRARY_PATH"

DYLD_LIBRARY_PATHを設定していない場合の実行時エラーは以下の通り。echo $DYLD_LIBRARY_PATHでは.bash_profileで設定したライブラリパスしか確認できない。デフォルトの確認方法は不明。

~ $ test ; exit;
dyld[17390]: Library not loaded: libftd2xx.dylib
  Referenced from: <E59057E2-6B27-3B0F-9FD2-A568CC6B0F5D> test
  Reason: tried: '/opt/homebrew/Cellar/exiv2/0.27.5_1/lib/libftd2xx.dylib' (no such file), '/libftd2xx.dylib' (no such file), 'libftd2xx.dylib' (no such file), 
'/System/Volumes/Preboot/Cryptexes/OSlibftd2xx.dylib' (no such file), 
'libftd2xx.dylib' (no such file), '/usr/local/lib/libftd2xx.dylib' (no such file), 
'/usr/lib/libftd2xx.dylib' (no such file, not in dyld cache), 
'/opt/homebrew/Cellar/exiv2/0.27.5_1/lib/libftd2xx.dylib' (no such file), 
'/libftd2xx.dylib' (no such file), '/Users/xxx/libftd2xx.dylib' (no such file),
 '/System/Volumes/Preboot/Cryptexes/OS/Users/xxx/libftd2xx.dylib' (no such file), 
'/Users/xxx/libftd2xx.dylib' (no such file), '/usr/local/lib/libftd2xx.dylib' (no such file), 
'/usr/lib/libftd2xx.dylib' (no such file, not in dyld cache)
Abort trap: 6
logout

[C++] 312 FTDI FT-XシリーズをBit Bangモードで使う MacOS

[M1 Mac, MacOS Ventura 13.3.1, clang 14.0.3]

FTDIの技術資料にあるサンプルコードをApple Silicon Macで動くようにしました。いつものように非IDE環境です。

AN_373 Bit-Bang Modes for the FT-X Series

D2XXドライバをダウンロードして、適当な所に配置します。今回は/usr/localディレクトリにしました。

Windows用のコードをApple Siliconにて非IDE環境で使えるようにする、といった類いの作業は自分なりの手法を確立させているので、比較的はかどります。やっていて楽しい作業です。今回はCocoaフレームワークとIOKitフレームワークのビルドオプションへの追加が肝でした。

FT231Xを使ってAVRマイコンに書き込みできるのか検証中です。

ただ、Bit Bangの解説資料ではあるもののフル機能を使えるわけではないような気がします。

// #include <Windows.h> 元はWindows用
#include <stdio.h>
#include <stdint.h>
#include "ftd2xx.h"

FT_STATUS ftStatus;
FT_HANDLE ftHandle;
DWORD w_data_len = 3; //write 3 bytes
DWORD data_written; // number of bytes written
UCHAR Mask = 0x0F;  //00001111 Set D7-D4 input, D3-D0 output [input (0) and output (1)]
UCHAR Mode = 0x04;  //0x04 = synchronous bit-bang
DWORD RxBytes; //number of bytes to be read from the device
DWORD BytesReceived; //number of bytes read from the device
uint8_t RxBuffer[8]; //buffer to receive data from FT-X device
uint8_t data_out[8]; //buffer for data to be sent to FT-X device
unsigned int i;

int main() 
{
    ftStatus = FT_Open(0, &ftHandle);
    ftStatus |= FT_SetUSBParameters(ftHandle, 4096, 4096); // Set USB transfer sizes
    ftStatus |= FT_SetChars(ftHandle, false, 0, false, 0); // Disable event characters
    ftStatus |= FT_SetTimeouts(ftHandle, 5000, 5000); // Set read/write timeouts to 5 sec
    ftStatus |= FT_SetLatencyTimer(ftHandle, 16); // Latency timer at default 16ms
    ftStatus |= FT_SetFlowControl(ftHandle, FT_FLOW_NONE, 0x11, 0x13);
    ftStatus |= FT_SetBaudRate(ftHandle, 62500); //bit rate is x16 this value = 1M

<以下略>
# コンパイラ設定
COMPILER = clang++
DEBUG = -g

# オプション設定
CPPFLAGS = -std=c++20
LDFLAGS = -lc++ -framework Cocoa -framework IOKit

# includeパス(-I)
INCLUDE = -I./include \
-I/usr/local/D2XX

# ライブラリ(-l)
LIBRARY_l = /usr/local/D2XX/build/libftd2xx.a

# ライブラリパス(-L)
LIBRARY_L = -L/usr/local/lib

# ソースファイル
SRCDIR = ./src
SRCS = $(shell find $(SRCDIR) -type f)

# オブジェクトファイル
OBJDIR = ./obj
OBJS = $(addprefix $(OBJDIR), $(patsubst ./src/%.cpp,/%.o,$(SRCS)))

# 実行ファイル
TARGETDIR = ./bin
TARGET = test

# cppファイルからoファイル作成 $<:依存ファイル
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
	$(COMPILER) $(CPPFLAGS) $(INCLUDE) $(DEBUG) -o $@ -c $<

# oファイルから実行ファイル作成
$(TARGET):$(OBJS)
	$(COMPILER) -o $(TARGETDIR)/$@ $(OBJS) $(LIBRARY_l) $(LIBRARY_L) $(LDFLAGS)

# コンパイル&ビルド
.PHONY:all
all: clean $(OBJS) $(TARGET)

# oファイル・実行ファイル削除
.PHONY:clean
clean:
	rm -rf $(OBJS) $(TARGETDIR)/$(TARGET) $(TARGET).app

[C++] 311 インクルードパスの確認方法 #include_nextトラブル

[M1 Mac, Ventura 13.3.1, clang 13.0.0]

MacOSをMontereyからVenturaに上げるとコンパイル時に以下のエラーが出るようになりました。

fatal error: 'stdio.h' file not found
#include_next <stdio.h>

Command Line Toolsを入れ直してもダメでXcodeを削除したりしているといつの間にか正常になりました。Xcodeを解決後に再インストールしても問題ありませんでした。MacOSをバージョンアップするたびにこの種のトラブルが必ず起こるので困ったものです。

rm -rf /Library/Developer/CommandLineTools
xcode-select --install

ところで#include_nextはインクルードパスにある別の同名ヘッダファイルを読み込む指示です。インクルードパスは以下のコマンドで確認できます。

clang++ -x c++ -v -E /dev/null
$ clang++ -x c++ -v -E /dev/null
Apple clang version 14.0.3 (clang-1403.0.22.14.1)
Target: arm64-apple-darwin22.4.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
 "/Library/Developer/CommandLineTools/usr/bin/clang" -cc1 -triple arm64-apple-macosx13.0.0 -Wundef-prefix=TARGET_OS_ -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -Werror=implicit-function-declaration -E -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name null -mrelocation-model pic -pic-level 2 -mframe-pointer=non-leaf -fno-strict-return -ffp-contract=on -fno-rounding-math -funwind-tables=1 -fobjc-msgsend-selector-stubs -target-sdk-version=13.3 -fvisibility-inlines-hidden-static-local-var -target-cpu apple-m1 -target-feature +v8.5a -target-feature +crc -target-feature +lse -target-feature +rdm -target-feature +crypto -target-feature +dotprod -target-feature +fp-armv8 -target-feature +neon -target-feature +fp16fml -target-feature +ras -target-feature +rcpc -target-feature +zcm -target-feature +zcz -target-feature +fullfp16 -target-feature +sm4 -target-feature +sha3 -target-feature +sha2 -target-feature +aes -target-abi darwinpcs -fallow-half-arguments-and-returns -debugger-tuning=lldb -target-linker-version 857.1 -v -fcoverage-compilation-dir=/Users/user -resource-dir /Library/Developer/CommandLineTools/usr/lib/clang/14.0.3 -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -I/usr/local/include -stdlib=libc++ -internal-isystem /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1 -internal-isystem /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/local/include -internal-isystem /Library/Developer/CommandLineTools/usr/lib/clang/14.0.3/include -internal-externc-isystem /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include -internal-externc-isystem /Library/Developer/CommandLineTools/usr/include -Wno-reorder-init-list -Wno-implicit-int-float-conversion -Wno-c99-designator -Wno-final-dtor-non-final-class -Wno-extra-semi-stmt -Wno-misleading-indentation -Wno-quoted-include-in-framework-header -Wno-implicit-fallthrough -Wno-enum-enum-conversion -Wno-enum-float-conversion -Wno-elaborated-enum-base -Wno-reserved-identifier -Wno-gnu-folding-constant -fdeprecated-macro -fdebug-compilation-dir=/Users/user -ferror-limit 19 -stack-protector 1 -fstack-check -mdarwin-stkchk-strong-link -fblocks -fencode-extended-block-signature -fregister-global-dtors-with-atexit -fgnuc-version=4.2.1 -fno-cxx-modules -no-opaque-pointers -fcxx-exceptions -fexceptions -fmax-type-align=16 -fcommon -fcolor-diagnostics -clang-vendor-feature=+disableNonDependentMemberExprInCurrentInstantiation -fno-odr-hash-protocols -clang-vendor-feature=+enableAggressiveVLAFolding -clang-vendor-feature=+revert09abecef7bbf -clang-vendor-feature=+thisNoAlignAttr -clang-vendor-feature=+thisNoNullAttr -mllvm -disable-aligned-alloc-awareness=1 -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o - -x c++ /dev/null
clang -cc1 version 14.0.3 (clang-1403.0.22.14.1) default target arm64-apple-darwin22.4.0
ignoring nonexistent directory "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/local/include"
ignoring nonexistent directory "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/Library/Frameworks"
#include "..." search starts here:
#include <...> search starts here:
 /usr/local/include
 /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1
 /Library/Developer/CommandLineTools/usr/lib/clang/14.0.3/include
 /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include
 /Library/Developer/CommandLineTools/usr/include
 /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks (framework directory)
End of search list.
# 1 "/dev/null"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 428 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "/dev/null" 2
$ clang++ -x c++ -v -E /dev/null
Apple clang version 14.0.3 (clang-1403.0.22.14.1)
Target: arm64-apple-darwin22.4.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
 "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang" -cc1 -triple arm64-apple-macosx13.0.0 -Wundef-prefix=TARGET_OS_ -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -Werror=implicit-function-declaration -E -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name null -mrelocation-model pic -pic-level 2 -mframe-pointer=non-leaf -fno-strict-return -ffp-contract=on -fno-rounding-math -funwind-tables=1 -fobjc-msgsend-selector-stubs -target-sdk-version=13.3 -fvisibility-inlines-hidden-static-local-var -target-cpu apple-m1 -target-feature +v8.5a -target-feature +crc -target-feature +lse -target-feature +rdm -target-feature +crypto -target-feature +dotprod -target-feature +fp-armv8 -target-feature +neon -target-feature +fp16fml -target-feature +ras -target-feature +rcpc -target-feature +zcm -target-feature +zcz -target-feature +fullfp16 -target-feature +sm4 -target-feature +sha3 -target-feature +sha2 -target-feature +aes -target-abi darwinpcs -fallow-half-arguments-and-returns -debugger-tuning=lldb -target-linker-version 857.1 -v -fcoverage-compilation-dir=/Volumes/DATA_m1/code/cpp/projects/SFTPAssist -resource-dir /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/14.0.3 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk -I/usr/local/include -stdlib=libc++ -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/v1 -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/local/include -internal-isystem /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/14.0.3/include -internal-externc-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include -internal-externc-isystem /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -Wno-reorder-init-list -Wno-implicit-int-float-conversion -Wno-c99-designator -Wno-final-dtor-non-final-class -Wno-extra-semi-stmt -Wno-misleading-indentation -Wno-quoted-include-in-framework-header -Wno-implicit-fallthrough -Wno-enum-enum-conversion -Wno-enum-float-conversion -Wno-elaborated-enum-base -Wno-reserved-identifier -Wno-gnu-folding-constant -fdeprecated-macro -fdebug-compilation-dir=/Volumes/DATA_m1/code/cpp/projects/SFTPAssist -ferror-limit 19 -stack-protector 1 -fstack-check -mdarwin-stkchk-strong-link -fblocks -fencode-extended-block-signature -fregister-global-dtors-with-atexit -fgnuc-version=4.2.1 -fno-cxx-modules -no-opaque-pointers -fcxx-exceptions -fexceptions -fmax-type-align=16 -fcommon -fcolor-diagnostics -clang-vendor-feature=+disableNonDependentMemberExprInCurrentInstantiation -fno-odr-hash-protocols -clang-vendor-feature=+enableAggressiveVLAFolding -clang-vendor-feature=+revert09abecef7bbf -clang-vendor-feature=+thisNoAlignAttr -clang-vendor-feature=+thisNoNullAttr -mllvm -disable-aligned-alloc-awareness=1 -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o - -x c++ /dev/null
clang -cc1 version 14.0.3 (clang-1403.0.22.14.1) default target arm64-apple-darwin22.4.0
ignoring nonexistent directory "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/local/include"
ignoring nonexistent directory "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/Library/Frameworks"
#include "..." search starts here:
#include <...> search starts here:
 /usr/local/include
 /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/v1
 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/14.0.3/include
 /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include
 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include
 /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks (framework directory)
End of search list.
# 1 "/dev/null"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 428 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "/dev/null" 2

今回のトラブルで、私のような非IDE派はCommand Line Toolsさえあればプログラミングできる、つまりXcodeがなくても問題ないということを再確認しました。Xcodeは20GB超えの重量アプリですから、ストレージ不足になったら真っ先に削除するようにします。

[C++] 310 FLTK : 長整数型を引数とするcallback関数 その2

[M1 Mac, Ventura 13.3.1, clang 13.0.0, FLTK 1.3.8, NO IDE]

callback関数の引数に長整数を使うことで第1引数の動作関数に引数として追加できます。

任意の長整数により動作関数の内容を条件分けできます。例えばFileChooserで選んだファイルパスの表示先を変えることが出来たりします。

使用頻度は高くないですが、たまに使おうとすると殆ど忘れてしまっているので再度記事にしておきます。構造がややこしくて共同開発であれば現場を混乱させそうな内容です。

久しぶりにC++のコードを書きましたが、だいぶPythonになじんでいたので調子が出ないです。

// fileFcBtn
fileFcBtn = new Fl_Button(245,108,30,20,"...");
fileFcBtn->color(fl_rgb_color(112,128,144));
fileFcBtn->labelcolor(fl_rgb_color(255,239,213));
fileFcBtn->labelsize(14);
fileFcBtn->callback(FileChooserCB,1); // 長整数1を渡す

// toFcBtn
toFcBtn = new Fl_Button(245,143,30,20,"...");
toFcBtn->color(fl_rgb_color(112,128,144));
toFcBtn->labelcolor(fl_rgb_color(255,239,213));
toFcBtn->labelsize(14);
toFcBtn->callback(FileChooserCB,2); // 長整数2を渡す
void FileChooserCB(Fl_Widget*, long num) {
    int fc;
    string appdir = "/";
    int onoff_dir = dir_rbtn->value();

    if (onoff_dir == 1){
        fc = 4; // FileChooser::DIRECTORY
    } else {
        fc = 0; // FileChooser::SINGLE
    }

    int x_win = window->x_root();
    int y_win = window->y_root();
    cout<<"x_win "<< x_win <<" y_win "<< y_win <<endl;

    chooser = new FileChooser(appdir.c_str(), 
                        "*.*",
                        fc,
                        "File/Dir Chooser",490,380, num
                        );
    
    chooser->resize(x_win+85,y_win+50,490,380);
    chooser->set_modal();
    chooser->Fl_Window::show();

    while(chooser->Fl_Window::shown()){
        Fl::wait();
    }
}
FileChooser::FileChooser(const char *d, const char *p, 
int t, const char *title,int w,int h, long num)
	:Fl_Window(w,h,title),Fl_File_Chooser(d,p,t,title){

<中略>

btnOK = new Fl_Return_Button(313, 345, 85, 25, "OK");
		if (num==1){
			btnOK->callback((Fl_Callback*)btnOKCB);
		} else {
			btnOK->callback((Fl_Callback*)btnOKCB2);
		}
void btnOKCB(Fl_Return_Button*, void*)
{
	const char* file = inputFileName->value();

	file_input->value("");
	file_input->value(file);
	chooser->Fl_Window::hide();
}

void btnOKCB2(Fl_Return_Button*, void*)
{
	const char* file = inputFileName->value();

	to_input->value("");
	to_input->value(file);
	chooser->Fl_Window::hide();
}
FileChooser
FileChooser選択パスの表示先がFILE/DIR欄に固定されていてTO欄が使えていない
修正後はボタン別に表示先を変えられるようになった
類似記事

[C++] 309 ファイルの生成日時を文字列にする

[M1 Mac, Monterey 12.6.3, clang 13.0.0, ChatGPT API(gpt-3.5-turbo), NO IDE]

ChatGPTに作ってもらいました。何度かトライしてようやく成功です。

最初の回答を修正させてハマったので、全く別の方法を考えさせました。

一見単純なコードですが、stat構造体を知らないと書けません。

ところでAIの情報を毎日チェックしていますが、ChatGPTの優秀さが際立つばかりといった印象です。

AI開発停止運動とやらは、OpenAI始め先行開発群に追いつけそうもない焦りの現れでしょうか。

MDファイルをJSONに変換して生成日時をファイル名に追加
#include <sys/stat.h>

string getCreationTime(const char* filePath) {
    struct stat attr;
    if (stat(filePath, &attr) == -1) {
        return "";
    }

    char buffer[16];
    strftime(buffer, sizeof(buffer), "%y%m%d_%H%M%S", localtime(&attr.st_birthtimespec.tv_sec));

    return buffer;
}

[C++] 308 FLTK : ChatGPTアプリの製作 その35 md→json変換 その2

[M1 Mac, Monterey 12.6.3, clang 13.0.0, FLTK 1.3.8, ChatGPT API(gpt-3.5-turbo), NO IDE]

昨日ChatGPTに書いてもらったコードを叩き台にして手を入れ主要な部分を作成しました。

細かいところで色々ややこしかったので、coutデバッグの痕跡を残したままアップしておきます。前半のwhile文はこちらの意図が伝わってなかったのか大分修正しました。後半のfor文が完璧だったのはさすがです。

あとはmdファイルの生成日時をファイル名の先頭に付けたら完成になります。

これでiPadやスマートフォンでのやりとりもChatGPTアプリで閲覧できるようになります。

変換jsonファイルの内容確認
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <sstream>
#include <nlohmann/json.hpp>

using namespace std;
using json = nlohmann::json;

int main() {
    ifstream ifs("test.md");
    string line;
    vector<string> user_messages;
    vector<string> assistant_messages;
    bool is_user = false;
    string assistant_msg;
    string user_msg;

    cout << "初期化通過" << endl;

    while (getline(ifs, line)) {
        cout << "while通過" << endl;

        if (line.empty()) {
            if (is_user) {
                is_user = false;
            }
            cout << "empty通過" << endl;
        } else if (line[0] == '>') { // user
            if (assistant_msg != ""){
                assistant_messages.push_back(assistant_msg);
                cout << "assistantベクター追加" << endl;
                assistant_msg = "";
            }

            is_user = true;
            cout << "user : " << line.substr(2) << endl;
            string user_msg = line.substr(2) + "\n";
            user_messages.push_back(user_msg);
        } else {
            if (is_user) {
                cout << "user2行目以降 : " << line << endl;
                user_msg += line + "\n";
                cout << "user文字列追加" << endl;

            } else {
                if (user_msg != ""){
                    user_messages.push_back(user_msg);
                    cout << "userベクター追加" << endl;
                    user_msg = "";
                }

                cout << "assistant : " << line << endl;
                assistant_msg += line + "\n";
                cout << "assistant文字列追加" << endl;
            }
        }
    }
    assistant_messages.push_back(assistant_msg);
    cout << "assistantベクター最終追加" << endl;

    cout << "getline通過" << endl;

    json root;
    json messages = json::array();
    for (int i = 0; i < user_messages.size(); i++) {
        json message;
        message["content"] = user_messages[i];
        message["role"] = "user";
        messages.push_back(message);
        message["content"] = assistant_messages[i];
        message["role"] = "assistant";
        messages.push_back(message);
    }
    root["messages"] = messages;
    root["model"] = "gpt-3.5-turbo";
    root["temperature"] = 0.0;

    ofstream ofs("output.json");
    ofs << root.dump(4);

    return 0;
}

[C++] 307 FLTK : ChatGPTアプリの製作 その34 md→json変換

[M1 Mac, Monterey 12.6.3, clang 13.0.0, FLTK 1.3.8, ChatGPT API(gpt-3.5-turbo), NO IDE]

iPadでChatGPTを使う場合は公式Webを使います。そこでのやりとりはWebラッパーでmdファイルとしてダウンロードします。

そのmdファイルを自製ChatGPTアプリでjsonファイルに変換できるよう開発を進めています。

最初はRustで製作されたWebラッパーを改変してjsonとしてダウンロードできるようにしようかとも考えたんですが、Rustで書くとJavaのヌルポ攻勢と同様の例外処理対応に追われるのが目に見えているので、やめておくことにしました。

取りあえずChatGPTに叩き台のコードを書いてもらいました。

ところでGPT-4のwaitlistに登録して2週間が経とうとしていますが、まだAPIで使えません。やはり重課金ユーザー優先ということでしょう。当方かなり使ったつもりでもまだ供与された18ドルに遠く及ばない2.8ドルです。

RWKVなど有望なLLMが話題に上がっていて、いよいよローカルChat Botの実現が見えてきました。今のところRTX3080位ないと厳しいらしく、どうするか考えています。

ただTwitterを見る限りキャッチアップしているのは画像生成AI界隈の方ばかりで、その分野に全く興味がない者としてそろそろ潮時とも思えます。プログラマ系の方々は水面下に潜った感がありますね。そりゃTwitterばかり見てたらコードもろくに書けません。

ChatGPTアプリ製作開始から26日経過し、平常モードに戻るタイミングかもしれません。

Q:
以下のコードをC++で書いて下さい。
mdファイルをjsonファイルに変換する。
1.mdファイル
不等号の行はrole:userのcontent
改行コードが2回続き、次の行はrole:assistantのcontent
2.jsonファイル
keyはmessages, model, temperatureの3つ。
modelのvalueはgpt-3.5-turbo
temperatureのvalueは0.0
jsonの例は以下の通り
{
“messages”: [
{
“content”: “”,
“role”: “system”
},
{
“content”: “FLTKのプログラムがFl_Buttonを自動クリックするコードを書いて下さい”,
“role”: “user”
},
{
“content”: “以下は、FLTKのプログラムでFl_Buttonを自動クリックするコードの例です。\n\nc++\n#include <FL/Fl.H>\n#include <FL/Fl_Window.H>\n#include <FL/Fl_Button.H>\n\nint main(int argc, char **argv) {\n Fl_Window *window = new Fl_Window(200, 200, \"Auto Click\");\n Fl_Button *button = new Fl_Button(50, 50, 100, 50, \"Click Me\");\n\n // 自動クリックする\n button->do_callback();\n\n window->end();\n window->show(argc, argv);\n return Fl::run();\n}\n\n\nこの例では、Fl_Buttonオブジェクトのdo_callback()メソッドを呼び出すことで、ボタンを自動的にクリックしています。このメソッドは、ボタンがクリックされたときに呼び出されるコールバック関数を実行します。”,
“role”: “assistant”
},
{
“content”: “これまでの質問回答の内容から15文字程度で日本語タイトルを考えて下さい。英単語が混ざってもかまいません。”,
“role”: “user”
},
{
“content”: “FLTKで自動クリックする方法”,
“role”: “assistant”
}
],
“model”: “gpt-3.5-turbo”,
“temperature”: 0.0
}

A:
以下がC++でのコード例になります。

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <nlohmann/json.hpp>

using json = nlohmann::json;

int main() {
    // mdファイルを読み込む
    std::ifstream ifs("1.md");
    std::string md((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());

    // mdファイルを改行コードで分割する
    std::vector<std::string> lines;
    std::string line;
    std::istringstream iss(md);
    while (std::getline(iss, line)) {
        lines.push_back(line);
    }

    // jsonオブジェクトを作成する
    json j;
    j["messages"] = json::array();
    j["model"] = "gpt-3.5-turbo";
    j["temperature"] = 0.0;

    // mdファイルの内容をjsonオブジェクトに追加する
    std::string role = "user";
    for (const auto& line : lines) {
        if (line.empty()) {
            role = "assistant";
            continue;
        }
        j["messages"].push_back({
            {"content", line},
            {"role", role}
        });
    }

    // jsonファイルに書き込む
    std::ofstream ofs("2.json");
    ofs << j.dump(4) << std::endl;

    return 0;
}

このコードでは、まずmdファイルを読み込み、改行コードで分割して各行を処理します。次に、jsonオブジェクトを作成し、mdファイルの内容をjsonオブジェクトに追加します。最後に、jsonファイルに書き込みます。