* AMemFile
-(by [[K]], 2024.09.02)

** (0)
-ファイルをファイルハンドル経由でアクセスせずに、全部メモリ上に読み込んで自由にアクセスしたらプログラムが簡単になるんじゃないかと考えました。ファイル内のテキストの任意の部分を char * で指し示すことができるようになります。
-ファイルサイズに合わせてメモリサイズを自動調整する機能を持っていて、それを利用して単に自動伸長型の配列として使うこともできます。
--(例)[[a24_acpp0]]の、includedでこの機能を使っています。

** (1) ver.1.20 [2024.09.20] (147行)
-AMemFile : 必要な情報を集めた構造体。
-AMemFile *AMemFile_newSiz(int flags, int siz): 中身が空っぽのAMemFileを作成。
--flags: AMemFile_Err=エラー処理をライブラリ任せにはしない, AMemFile_Text=テキストモード
--siz: 初期バッファサイズ。0を指定してはいけない。普通は16以上を指定。
-AMemFile *AMemFile_new(int flags): siz=64KBでAMemFile_newSiz()する。
-void AMemFile_close(AMemFile *mp)
-int AMemFile_write(AMemFile *mp, const char *s, int n)
-int AMemFile_toReadMode(AMemFile *mp): もうwriteは使わないことを前提に末尾に16バイトの0x00を追加して、サイズを切り詰め、メモリを節約します。
--追加された0x00は本体データであるp0~pには含まれません。多くの場合追加の0x00は1バイトで十分そうな気がしますが、まあ余裕を見て16バイトにしました。
-int AMemFile_load(AMemFile *mp, const char *path):下請け
-int AMemFile_save(AMemFile *mp, const char *path):下請け
-void AMemFile_eraseCr(AMemFile *mp):下請け
-AMemFile *AMemFile_open(int flags, const char *path)
-int AMemFile_saveClose(AMemFile *mp, const char *path)
-[補足説明]
--テキストモードを指定してAMemFile_open()すると、読み込み直後にAMemFile_eraseCr()します。またAMemFile_save時には"wt"でfopenします。それ以外の差異はありません。
--たとえテキストモードでもload時は"rt"で読み込んだりはしません。なぜならLinuxなどでは"rt"でfopenしても(Windowsから持ってきたファイルの)'\r'が消えないからです。だからOSにかかわらず"rb"で読み取って、AMemFile_eraseCr()で消します。

 AClass(AMemFile) {
     AInt bufSiz, flags;
     char *p0, *p, *p1;
     AM *m;
 };
 
 AStatic AMap11 *AMemFile_dbgNam = 0;
 AInlineStatic void AMemFile_dbgSetNam(AMemFile *w, const char *n) { aDbgSetNam(&AMemFile_dbgNam, w, n); }
 AInlineStatic void AMemFile_dbgDelNam(AMemFile *w) { aDbgDelNam(&AMemFile_dbgNam, w); }
 AStatic void AMemFile_err(AMemFile *w, const char *fnc, const char *f,...) { va_list ap; va_start(ap, f); aClassErr(&AMemFile_dbgNam, w, fnc, f, ap); va_end(ap); }
 
 #define AMemFile_Text    8
 
 AStatic void AMemFile_dst(AMemFile *mp)
 {
     if (mp != 0) {
         AM_fre(mp->m, mp->p0, mp->bufSiz);
         AM_fre(mp->m, mp, sizeof (AMemFile));
         #if (ADbgLv >= 1)
             AMemFile_dbgDelNam(mp);
         #endif
     }
 }
 
 AStatic AMemFile *AMemFile_newSiz(int flags, AM *m, AInt siz)
 {
     AMemFile *mp = AM_alc(m, 4, sizeof (AMemFile));
     if (mp == 0) {
 outOfMemory:
         if ((flags & 4) == 0) aErrExit("AMemFile_new: out of memory");
         return 0;
     }
     mp->p0 = AM_alc(m, 4, siz);
     if (mp->p0 == 0) { AM_fre(m, mp, sizeof (AMemFile)); goto outOfMemory; }
     mp->bufSiz = siz;
     mp->flags = flags;
     mp->p = mp->p0;
     mp->p1 = mp->p0 + siz;
     mp->m = m;
     if ((flags & 1) != 0) AM_arp(m, AMemFile_dst, mp, 0, 0);
     return mp;
 }
 
 AInlineStatic AMemFile *AMemFile_new(int flags, AM *m) { return AMemFile_newSiz(flags, m, 64 * 1024); }
 
 AStatic int AMemFile_write(AMemFile *mp, int flags, const char *s, AInt n)
 {
 retry:
     if (n <= 0) return 0;
     if (mp->p + n <= mp->p1) {
         memcpy(mp->p, s, n);
         mp->p += n;
         return 0;
     }
     if (mp->bufSiz * 2 <= mp->bufSiz) AMemFile_err(mp, "AMemFile_write", "error: siz=%d", (int) mp->bufSiz);
     char *p = AM_rlc(mp->m, flags & 6, mp->p0, mp->bufSiz, mp->bufSiz * 2);
     if (p == 0) return 1;
     AInt i = mp->p - mp->p0;
     mp->bufSiz *= 2;
     mp->p0 = p;
     mp->p = p + i;
     mp->p1 = mp->p0 + mp->bufSiz;
     goto retry;
 }
 
 AStatic int AMemFile_toReadMode(AMemFile *mp, int flags)
 {
     static char s[16];
     AInt i = AMemFile_write(mp, flags, s, 16);
     if (i != 0) return 1;
     i = mp->p - mp->p0;
     char *p0 = AM_rlc(mp->m, flags & 4, mp->p0, mp->bufSiz, i);
     if (p0 == 0) return 1;
     mp->p0 = p0;
     mp->p = mp->p0 + (i - 16);
     mp->p1 = mp->p0 + i;
     mp->bufSiz = i;
     return 0;
 }
 
 AStatic int AMemFile_load(AMemFile *mp, int flags, AM *m, FILE *fp)
 {
     AInt siz = 1024 * 1024, i;
     char *t = AM_alc(m, flags & 4, siz);
     if (t == 0) return 1;
     do {
         i = fread(t, 1, siz, fp);
         if (AMemFile_write(mp, flags, t, i) != 0) {
             AM_fre(m, t, siz);
             return 1;
         }
     } while (i >= siz); // 実際には i > siz になることはない.
     AM_fre(m, t, siz);
     return 0;
 }
 
 AStatic int AMemFile_save(AMemFile *mp, int flags, const char *path)
 {
     const char *mod = "wb";
     if ((mp->flags & AMemFile_Text) != 0) { mod = "wt"; }
     FILE *fp = fopen(path, mod);
     if (fp == 0) {
         if ((flags & 4) == 0) AMemFile_err(mp, "AMemFile_save", "fopen error: %s", path);
         return 1;
     }
     AInt i = fwrite(mp->p0, 1, mp->p - mp->p0, fp);
     fclose(fp);
     if (i < mp->p - mp->p0) {
         if ((flags & 4) == 0) AMemFile_err(mp, "AMemFile_save", "fwrite error: %s", path);
         return 1;
     }
     return 0;
 }
 
 AStatic void AMemFile_eraseCr(AMemFile *mp)
 {
     char *p = mp->p0, *q = p, *p1 = mp->p;
     for (; p < p1; p++) {
         if (*p != '\r') { *q++ = *p; }
     }
     mp->p = q;
 }
 
 AStatic AMemFile *AMemFile_open(int flags, AM *m, const char *path)
 {
     AMemFile *mp = AMemFile_new(flags, m);
     if (mp == 0) return 0;
     FILE *fp = fopen(path, "rb");
     if (fp == 0) {
         if ((flags & 4) == 0) AMemFile_err(mp, "AMemFile_open", "fopen error: %s", path);
         if ((flags & 1) == 0) AMemFile_dst(mp);
         return 0;
     }
     if (AMemFile_load(mp, flags, m, fp) != 0) { fclose(fp); if ((flags & 1) == 0) AMemFile_dst(mp); return 0; }
     fclose(fp);
     if ((flags & AMemFile_Text) != 0) { AMemFile_eraseCr(mp); }
     if (AMemFile_toReadMode(mp, flags) != 0) { if ((flags & 1) == 0) AMemFile_dst(mp); return 0; }
     return mp;
 }
 
 AStatic int AMemFile_saveDst(AMemFile *mp, int flags, const char *path)
 {
     int i = AMemFile_save(mp, flags, path);
     if (i != 0) { return i; }
     if ((flags & 1) == 0) AMemFile_dst(mp);
     return 0;
 }

** (2) よく使うサンプルコード

 char *aSkpLf(const char *s, const char *s1)
 // 次の行の先頭を得る.
 {
     while (s < s1 && *s != '\n') s++;
     if (s < s1 && *s == '\n') s++;
     return (char *) s;
 }
 
 char *aSkpSpc(const char *s, const char *s1)
 {
     while (s < s1 && (*s == ' ' || *s == '\t')) s++;
     return (char *) s;
 }
 
 int main()
 {
     AMemFile *mp = AMemFile_open(AMemFile_Text + 1, am0, "file.txt");
     char *p, *p1, *p2 = mp->p1;
     for (p = mp->p0; p < (p1 = aSkpLf(p, p2)); p = p1) {
         // これで [p,p1) で1行ずつ処理できる.
         ...
     }
     AM_dst(am0);
     return 0;
 }

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS