往年のアスキーネットに似た操作系のパソコン通信のホストプログラム「mmm(トライエム)」のtalkルームの内容をテキストで取り出したくて解析して、プログラムも作ってみた。
mmmのTALKディレクトリにはルームの使用状況を表すROOMS.DATと、ルーム番号に応じてR1.USR〜R1500.USRの座席状況と、R1.IDX〜R1500.IDXの発言内容を格納したファイルが存在する。使用していないルーム番号のUSRファイル、IDXファイルは存在しない。
ROOMS.DATは1500バイト固定のファイルで、ルーム番号に対応したバイト位置が00なら未使用、01なら使用中を示している。
USRファイルは1レコード31バイトのファイルで、各レコードの最初の1バイト目が次に続く文字列の長さを、2バイト目から8バイト分が文字列、10バイト目から4バイト分がFAT形式の日時、14バイト目が次に続く文字列の長さ、15バイト目から16バイト分が文字列、31バイト目がフラグとなっている。
1レコード目は、最初の文字列がルームの状況(Open、Closed、Locked)を表しており、続いてルームの状況が更新された日時、2つ目の文字列やフラグは未使用となっている。
2レコード目以降はルーム内に座席のあるユーザーを示しており、最初の文字列がユーザーIDを、続いてユーザーが最後に入室した日時、2つ目の文字列がハンドル名を表し、フラグは座席がある場合は1、無い場合が0、ノック中である場合は2が加えられ、リーダーである場合は4が加えられる。
ちなみにFAT形式での日付は2バイトで、上位7ビット分が1980年からの年、次の4ビット分が月、下位5ビット分が日を表す。時間も2バイトで、上位5ビット分が時、次の6ビット分が分、下位5ビット分が2秒ごとの秒を表す。
以下、LSI-C86試食版で作ったUSRファイル及びIDXファイルのテキスト化表示プログラムのソース。いつものごとく標準関数しか使ってないので、SLザウルスとかでも動くと思う。使い方はUSRファイルもしくはIDXファイルを指定して起動するだけ。
#include <stdio.h> #include <string.h> int strcpyn(char *sd,char *ss,int sl,int lm) { int i; i=0; while(i<sl && i<lm && sl<=lm) { sd[i]=ss[i]; i++; } sd[i]='\0'; } int main(int argc,char *argv[]) { FILE *fp; unsigned char buf[94]; char idx[9],msg[81]; int dy,dm,dd,th,tm,ts,bs,ms; if(argc!=2) { printf("usage: TALKTXT filename\n",argv[0]); return(1); } fp=fopen(argv[1],"rb"); if(fp==NULL) { printf("'%s' is not open.\n",argv[1]); return(1); } if(strstr(argv[1],".IDX")!=NULL) { bs=94; ms=80; } else { bs=31; ms=16; } while(fread(buf,1,bs,fp)==bs) { strcpyn(idx,buf+1,buf[0],8); ts=(buf[9] & 0x1f)*2; tm=((buf[10] & 0x07) << 3)+((buf[9] & 0xe0) >> 5); th=(buf[10] & 0xf8) >> 3; dd=buf[11] & 0x1f; dm=((buf[12] & 0x01) << 3)+((buf[11] & 0xe0) >> 5); dy=1980+((buf[12] & 0xfe) >> 1); strcpyn(msg,buf+14,buf[13],ms); printf("%3d %-8s %02d/%02d/%02d %02d:%02d:%02d %3d ",buf[0],idx,dy,dm,dd,th,tm,ts,buf[13]); if(bs==94) { printf("%s\n",msg); } else { printf("%-16s %3d\n",msg,buf[30]); } } fclose(fp); return(0); }