first - みる会図書館


検索対象: 月刊 C MAGAZINE 1990年1月号
12件見つかりました。

1. 月刊 C MAGAZINE 1990年1月号

以上の点を踏まえた上て、 ,fat. c(List3) の プログラムについて説明していこう。 MS-DOS て、は , ファイルを処理するとき ます最初にディレクトリエントリをサーチ し , その中に登録されている開始 FAT の番 号を得る。このとき開始 FAT 番号は変換後 の値が格納されている。この変換後の値を 変換前の値に一度変換してから FAT 領域を サーチする。この変換の式は以下のとおり て、あり ,search fat( ) 関数て、 FAT に関する すべての抽出が行われている。 Fig. 5 て、も確 認してほしい。なお , この式の余りはすべ / * 12 ビット FAT 場合 * / fat entry = ( number/2 ) て切り捨てとする。 [ 表 4 ] FAT 登録の確認 List 3 259 : { に正常に書き込ま 0002H-FFEFH FFFOH-FFF6H FFF8H-FFFFH 002H-FEFH FFOH-FF6H FF8H-FFFH 205 : 206 : 207 : 208 : 210 : 211 : 212 : 213 : 214 : 2 1 6 : 2 1 7 : 幻 8 : 219 : 220 : 221 : 222 : 223 : 224 : 225 : 226 : 227 : 228 : 229 : 230 : 231 : 232 : 233 : 234 : 235 : 236 : 237 : 238 : 239 : 240 : 241 : 242 : 243 : 244 : SEARCH_FAT() FUNCTION 209 : unsigned char *buff = FAT 領域の先頭を指すポインタ : ディレクトリエントリに登録されている F A T int number int search_fat(unsigned char *buff. int number) int fat-entry; i nt f i rst : int second: int third; / * F A T 領域の先頭からの番号 / * 上記の番号の最初のパイト / * 2 番目のバイト / 本 3 番目のバイト (nunber/2)*3; fat _entry ″ F A T 領域からの位置を求める * / first ニ * (buff 十 fat_entry + + ) : second = *(buff 十 fat_entry 十十 ) : ニ *(buff 十 fat_entry+ + ) : th ird first = first + ( (second くく 8 ) & 0X0f00 ) : (third くく 4 ) + (second 〉 > 4 ) : third if(number & 0X000D / * 第 1 バイト / * 第 2 バイト / 本第 3 パイト return(third) : ″奇数ならば第 3 パイトを返す else return (first) : な偶数ならば第 1 バイトを返す FCB_WILD() FUNCTION int fcb_wild(char ⅱ d. FCB *fcb) lnregs. X. aX : 0X2900 : 245 : 246 : 247 : 248 : 249 : 250 : 251 : 252 : 253 : 254 : 255 : 256 : 257 : 258 : 260 : 261 : 262 : 263 : 264 : 265 : 266 : 267 : 268 : 269 : 270 : 271 : 272 : 273 : 274 : 275 : 276 : 277 : 278 : 279 : 280 : 281 : 282 : 283 : (unsigned int)wild; lnregs. X. SI (unsigned int) fcb; inregs. X. di intdos (&inregs. &outregs) : return(outregs. h. (l) : FIND_FIRST ( ) FUNCTION int find_first(FCB *fcb) / * ffh=directory entry not exsit * / / * OOh-directory entry exsit returi( (int)outregs. h. 引 ) : intdos(&inregs. &outregs) : inregs. X. dX (unsigned int)fcb; ニ 0x 1 1 : inregs. h. ah SET_DTA() FUNCTION void set_dta(DIR_ENTRY *fcb_entry) / 事 return is nothing . becuse NO flag * / intdos(&inregs, &outregs) : inregs. X. dX (unsigned int) fcb entry; 0xla; inregs. h. ah 上記のようにして求めた値をさらに加工 し , その先頭アドレスを返す。そしてその malloc( ) 関数を用いてヒープ領域に確保 最初に FAT 領域の容量を調べ , その値を FAT 領域の先頭を読み込む方法は , まず 関数を参考にして作成してみるとよいだろ の抽出は非常に簡単なのて、 , search fat() プログラムを参照してほしい。 16 ビット FAT 断する必要がある。詳細な内容については , まり次の表 4 に明記されている値を調べて判 ものかどうかを調べなければならない。つ 必要がある。それには FAT の登録が正規の 終的に search fat( ) 関数の返す値を調べる イト , そして第 3 バイトを求める。次に , 最 して目的の FAT て、ある , 第 1 バイト , 第 2 バ 1 2 ピット FAT 1 6 ビット FAT 説 未使用コード 空きクラスタ 明 OOOH OO 1 H F F 7 H OOOOH OOOI H FFF7H 次のクラスタを示す 予約 不良クラスタ 最後のクラスタ 先頭アドレスの位置から absread ( ) 関数を使 って実際に FAT 領域をそのままコピーする ように読み込むのて、ある。 fatsize ( ) 関数と fat_read( ) 関数がその作業を行う関数てあ る。完全なプログラムは , fat. c (List3) を見 てもらいたい。ファイル名から FAT 番号を 取得する方法については FCB を用いてい また 12 / 16 ビット FAT の識別は , 最大クラ スタが 4087 以降て、あれば 16 ビット FAT て、あ り , そうてなければ 12 ビット FAT ( 表 4 ) て、あ る。次の等式を参考にされるとわかりやす Max Cluster Number / * 12 ビット FAT * / 4087 M a x C 1 u s t e r N u m b e r いだろう。 / * 16 ビット FAT * / 4087 ファイルがフロッヒ。 ティレクトリ領域 62 CMAGAZINE 19 1

2. 月刊 C MAGAZINE 1990年1月号

木構造は構造体 TREE 型を基に構築しま す。 TREE 型は 3 つのメンバ (node, first, second ) をもっています。メンバ node は , 23 : } : 29 : } : dcl_ID, dcl_PTR, 、フ type-spec このノードの意味を示し , 9 : typedef struct tree { DCLNODE : enum 言の木構造 List 6 ダミー ( dcl dcl_ARRAY dcl_FUNC, dcl_NONE, dcl DUMMY, node : *second; *first; node ; *first; node : node; *third; *second : *first; DUMMY ) , 識別子 ( dcl ID ) , 空 ( dcl NONE), ポインタ (dcl PTR), 関数 ( dcl FUNC), 配列 ( dcl ARRAY) のいずれかの 値がセットされます。メンバ first と second / * array * / / * function * / / * pointer * / / * empty * / i dent i f i er * / / * dummy * / 1 : typedef struct struct struct 26 : 25 : 24 : 22 : 20 : 17 : 16 : 13 : 8 : 6 : 5 : 4 : 3 : 2 : DCLNODE struct struct struct TREE; treel int t ree2 int struct tree3 int struct struct tree tree tree tree tree TREE が宣言の木構造を表すための構造体て、ある。 struct treel, struct tree2, struct tree3 は , ヒープ領域確保に使うダミーの型てある メンバが含まれているが , これは実際には使わない 注☆前号の付録ディスクに収録の cmdef. h ては , TREE 型に third とし List 7 宣言のアクション ( cm. y より抜粋 ) 1 : 2 : 3 : 4 : 5 : 6 : 7 : 8 : 9 : 10 : 13 : 20 : 22 : 23 : 24 : 25 : 26 : declaration spec SC Iist3(dcl_DUMMY, type_spec declarator_list sc ー type- : INT ー CHAR $ 1 , $ 1 , $ 1 , $ 2 ) (void *)NU し L) ・ { $ $ = list3(dcl_DUMMY, { $ $ = TYPE_CHAR; } { $ $ ニ TYPE_INTEGER; } 15 : declarator_l ist dec larator ー dec larator-l i st declarator ー Iist3(dcl_DUMMY, declarator = append ( $ 1 , ⅱ st3 (dcl NU しい・ DUMMY, $ 3. NU しい) ・ は , このノードの子へのポインタて、す。 TR 刊 E 型の意味の詳細は後ほど説明します。 宣言の木構造をつくる関数は , listl, list2, 1ist3 の 3 つがあります。それぞれ , 子がないノード , 子がひとつのノード , 子 がふたつのノードをつくり , っくり出した ノードへのポインタを返します。 言の木構造をつくる Cm コンパイラて、は , 宣言のアクションて、 木構造を組み立て , それをたどりながら変 数や関数をシンボルテープルに登録します。 そこて、 , まずはじめは木構造を組み立てる ところから見ていきましよう。 cm. Y から , 宣言の部分のみを抜き出したものが List7 て、 す。これらのアクションは , みな listl ~ list 5 関数を呼び出して , 宣言の木構造を組み立 てています。 宣言のアクションて、つくり出されるノー ドの種類は , Fig. 2 のとおりて、す。 ( a ) の識 別子は , 名前を表す文字列へのポインタを もっています。 ( b ) の空は , 抽象宣言子 ( キ ャストを定義するのに使う ) の定義て、使われ るものて、す。 (c) のポインタは , 子としてポ イントされるものをもっています。 (d) の関 数は , 関数が返すもの ( 左の子 ) とパラメー タのリスト ( 右の子 ) をもっています。 , て、斜線は NULL , つまり木構造の終端を示 します。 (e) の配列は , 配列されるもの ( 表 の 31 行目の規則 スにとりかかる前の状態て、す。ここて、 ,List7 木を組み立てていきます。まず , ①がパー の①から⑤まて、 , 順にリデュースしながら , 例として , * a( ) を取り上げましよう。 Fig. 3 組み立てる過程を実際に見てみましよう。 こて、宣言をパースしながら , 木構造を す。 るもの ) と , その配列の要素数をもっていま 現が変て、すが , 要するに配列の要素にあた す。このとき , 32 行目のアクション て、リデュースが行われ , ②の状態になりま declarator2 工 DENTIFIER 70 CMAGAZINE ・ * ・ declarator { $ $ - Iist2(dcI_PTR, declarator2 19 1

3. 月刊 C MAGAZINE 1990年1月号

List 1 花 O 言語プロシェクトの イン一みレータ。 0 0 j ニ dir->level + 1 : 391 : 392 : 393 : 394 : 395 : if ( y > ニ 23 ) { 396 : for ( i 397 : = 23 ミ i く一 printf( Xs*n", crtCi] ) ; 398 : 399 : 400 : y0 = yO ー y + 22 : 401 : 402 : 403 : / * ディレクトリ選択 * / 404 : XX = x; YY = y; do { 405 : if ( xx ! = 0 ) { 406 : strnchg( &(crt[yy] [ xx * 25 ー 12 ] ) , 407 : 408 : if ( yy ! : y ) ( 409 : locate( 1. YO + yy ) : 410 : printf( ” Xs", crt[yy] ) : 411 : 412 : if ( y0 + y ← 0 ) ( 413 : for ( : yO + y ← 0 ; y0 + + ) { 414 : rollup(); 415 : printf( ” Xs*n ” crt[-y0] ) : 416 : clearline( 24 ) : 417 : 418 : 419 : 420 : 421 : 422 : 423 : 424 : 425 : 426 : 427 : 428 : 429 : 430 : 431 : 432 : 433 : 434 : 435 : 436 : 437 : 438 : 439 : 440 : 441 : 442 : 443 : 444 : 445 : 446. 447 : main( int ac, Char **av ) 448 : int 449 : char path[80J; / * パス名 * / 450 : / * ドライブ移動の有無 1 : 有 0 : 無り 451 : int chg, / * 表示行数 * / 452 : line, 453 : 454 : -disable(); 455 : 456 : / * 入力チェック & ディレクトリの直接移動り chg = chk-args( ac, av ) : 457 : 458 : 459 : / * 初期設定 * / 460 : (struct Dir * ) malloc( sizeof( struct Dir ) ) : first = dir 461 : 462 : first->next first; 463 : first->level = ℃ : 464 : 465 : / * ディレクトリ構造の読みだしり strcpy( path, wild ) ; 466 : find( 1 , path ) ; / * パスの第 1 レベルの検索 * / 467 : 468 : print f ( " サブディレクトリは存在しません . *n" ) ; 469 : return( 1 ) ; 470 : 471 : findrest( path ) : / * パスの第 2 レベル以降 , DEPTH レベルまでの検索り 472 : 473 : 474 : / * 表示バッファ設定 & 表示 * / line = mk-crt(); 475 : cursor( OFF ) : 476 : 477 : C010 「 ( 7 ) : for ( i = 0 : i く line & & i く 23 ; i + + ) ( 478 : printf( ” Xs*n ” , crt[i] ) : 479 : 480 : 481 : 482 : ″ディレクトリの移動り select( chg, line ) : 483 : 484 : 485 : / 本後処理り cursor( ON ) ; 486 : enable(); 487 : 488 クロスリ ) し〉ス ー表 り編十 ・ 1 0 0 C010r ( 16 ) : else ( strnchg( &(crt[y)[x*25-12]), locate( 1 , YO + y ) : printf( ” Xs}n ” XX } while ( ( rtn : move( &x, &y, line ) ) C010r ( 7 ) : locate( 1 , YO + line ) : if ( rtn = get—path( x, y, path ) ; chdir( path ) ; else ( printf( ” *nCanceIed. ” ) : return( rtn ) : 関数系図 ” 43 ” , 高品質のドキュメンテーションを簡単に実現する、 新世代のプロジェクト指向プログラムノトです。 CPAD はこれまで C 言語による開発でソフトハウ スカ脳んでいた、開発時の工数短縮及び複数 人数 ( るプロジェクト管理を容易に致します。ま た、既存のソースリストの仕様書を自動作成しま すので、管理体制を容易に画一化することが可 能となり、また、プログラマーの余分な負担を軽減 する事ができます。 機能 0 ソースの解析、援学習ツヲレて ①プログラマーの熟練度の違いを吸収。 2 カーニハン & リッチーの書式にソースをリフォーム。 BPAD 仕様に準する出力機能。 ( 自動出力印刷例参照 ) ④全ソースリストを公開。 ( オプション ) 豊富な出力機能。 ( 自動出力印刷例参照 ) C 言語開発支援ツール シーバッド Ver.1.5 CPAD 標準価格 ( 税込み価格 ) ・・・¥ 65 , 000 ( 対応版 ) ¥ 85 , 000 ( その他対応版 ) 対応機種、大幅に拡張。広かる CPAD の世界。 NEC PC ー 98 、富士通 FM 日、 沖 if800 」日 M PC / A 丁・ 55 、松下 技術的なこ質問・こ相談に電話でお答えします ソフトウェアインフォメーションセンター ) - 3 〒 5 田大阪市浪速区日本橋東 3 丁目 2- のオオッカ商事 本社 . 〒 7 聞高松市西内町 5-14 ワンホイントフロクラミンク講座 133

4. 月刊 C MAGAZINE 1990年1月号

MS - DOS プログラミング入門 List 4 (char *)&fcb + sizeof(FCB) fcb. c 2 : 3 : 4 : 5 : 6 : 7 : 8 : 9 : 10 : 12 : 13 : 14 : 16 : 1 7 : 20 : 21 : 22 : 23 : 24 : 25 : 26 : 28 : 29 : 30 : 32 : 33 : 34 : 35 : 36 : 37 : 38 : 39 : 40 : 41 : 42 : 43 : 44 : 45 : 46 : 47 : 48 : 49 : 50 : Prog ramned by Dated Vers i on Purposed #include く stdio. h> A. Akitu 1989-1 ト 01 P C B を用いてファイルの検素及び表示を 行なうプログラムです 88 : 91 : 92 : 93 : 95 : 96 : 98 : 99 : 0 : 1 : 2 : 103 : 104 : 105 : 106 : 107 : 108 : 109 : IIO: 1 ll : 112 : 1 15 : 116 : 118 : 1 19 : 120 : 121 : 122 : 123 : 124 : 125 126 : 127 : 128 : 129 : 130 : 131 132 : 133 : 134 : 135 : 136 : 137 : 138 : 139 : 140 : 141 : 142 : 143: 144: 145 : } 146: 147 : 148 : 149 : 150 : 15 い 152 : 153 : 154 : 155 : 156 : 157 : 158 : 159 160 : 161 : 162 : 163 : 164 : 165 : 168 : 169 : 170 : 89 : void fcb-print(DIR-ENTRY *fcb-entry) strncpy(). fcb_entry->filetype. f[8] ニ 0 ・ : strncpy(). fcb_entry->filenane. char f [ 16 ]. e[6]: 8 ) : 3 ) : # i ncl ude # i nc lude 15 : #include く dos. h> ty pedef struct く string. h 〉 く process. h> _FCB { drive; filenane[8] : fiIetype[3] : relative_record; current ー record : reserved[8] : tine, date; file_size: record_size; current_block; printf( ” Xs printf("Xs printf("X8u printf("Yn") : fcb-entry->file-size) : Char Char Char int int long int i nt char Char ー ong printf("X2d-X02d-X02d printf("X02d:X02d . ((fcb_entry->date 〉 > 9 ) & Ox7F) 十 80 / * year / ネ nonth * / ″ day . ((fcb_entry->time . ((fcb_entry->time 〉 ) (l) & OxlF) . ( fcb_entry- 〉 date & 0xlF) ) : . ((fcb_entry->date 〉 > 5 ) & 0x0F) / * hour ” 5 ) & 0x3F) ) : if( fcb_entry- 〉 attrib & FA_RDON し Y ) printf()R つ : / 事 Read_only : 0X01F * / ) printf("A"); ″ Archive = 0X20F り if( fcb_entry- 〉 attrib & FA_ARCH } FCB; / * PCB 用の構造体 * / 31 : typedef struct -DIR_ENTRY { Char Char Char Char Char int int int long d r i ve : fiIename[8] : filetype[3] : attrib; reserved[10] : t i ne : date; start_cluster; file_size: } DIR_ENTRY; / * 読み込む側の構造体 * / union REGS inregs. outregs; MAIN() FUNCTION VOid main(int argc, char *argv[] ) fcb_entry: DIR_ENTRY FCB fcb : 52 : 53 : 54 : 55 : 56 : 59 : 60 : 62 : 63 : 64 : 65 : 66 : 68 : 69 : 70 : 72 : 73 : 74 : 77 : 80 : 82 : 83 : 84 : 85 : 86 : VO i d int int int VO i d Char fcb_print(DlR_ENTRY * ) : fcb wild(char *. FCB * ) : find_first(FCB * ) : find_next(FCB の : set-fat(DlR_ENTRY * ) : *Ptr; if(argc ! = 2 ) printf("argument error !Yn" ex i t ( 1 ) : lnitialize of FCB * / for (ptr (char *)&fcb : *Ptr = ptr く : 0xff) if( find_first(&fcb) set_fat(&fcb_entry) : fcb_wild(argv[l] . &fcb): printf("file not find fcb-print(&fcb_entry) : ex i t ( l) : : pt 「十十 ) FCB_WILD() FUNCTION int fcb_wild(char ⅱ d. FCB *fcb) return(outregs. h. (l) : intdos(&inregs, &outregs) : inregs. X. di (unsigned int) fcb; lnregs. X. SI (unsigned int)wild; inregs. x. ax = 0X2900 : FIND_FIRST() FUNCTION int find_first(FCB *fcb) intdos(&inregs. &outregs) ; inregs. X. dX (unsigned int) fcb; inregs. h. ah = OXII; return( (int)outregs. h. 引 ) : / * 00h=directory entry exsit / 事 ffh=directory entry not exsit * / FIND_NEXT() FUNCTION int find-next(FCB *fcb) intdos(&inregs. &outregs) : inregs. X. dX (unsigned int) fcb; inregs. h. ah 0x 12 : / * ffh=directory entry not exsit * / return( (int)outregs. h. ) : ″ OOh=directory entry exsit SET_FAT() FUNCTION i ntdos ( & i nregs. &outregs) : inregs. x. dx : (unsigned int) fcb-entry: inregs. h. ah = Ox1a: 166 : void set_fat(DIR-ENTRY *fcb-entry) while( find_next(&fcb) fcb-print(&fcb-entry) : ! : 0xff てきなかったのて、 , UNIX/XENIX が使用し ていたファイルハンドル方式を採用した。 また , このことは MS-DOS を UNIX 互換に近 づけるためのひとつの手段てもあった。内 部的には , FCB を使ってはいるものの , ユ ーザインタフェイスは , ファイルハンドル 処理になっている。 C 言語て、 FCB を使うとき に構造体を定義したが , ファイルハンドル て、も同様に専用の構造体を定義しなければ ならない。通常 C 言語てはヘッダファイルの 中て定義されているのて , 単にそのヘッダ ファイル , つまり stdio. h をインクルードす ればよいだけて、ある。 TurboC< は , ファイルハンドルをファイル ファイルをすべて定義づけることになる。 格納する。以後はこの構造体の情報がその は , その結果を定義してある FILE 構造体に ファイルハンドルを行うファンクション C プログラマのための MS ー DOS プログラミング入門 65

5. 月刊 C MAGAZINE 1990年1月号

List 1 圓 : 101 : 102 : 103 : 104 : 105 : 106 : 107 : 108 : 109 : 110 : 111 : 112 : 113 : 114 : 115 : 116 : 117 : 118 : 119 : 120 : 121 : 122 : 123. 124 : 127 : ( 128 : 129 : 130 : 131 : 132 : 133 : 134 : 135 : 136 : 137 : 138 : 139 : 140 : 141 : 142 : 143 : 144 : 145 : 146 : 147 : 148 : 149 : 150 : 151 : 152 : 153 : 154 : 155 : 156 : 157 : 158 : 161 162 : 163 : 164 : 165 : 166 : 167 : 168 : 169 : 170 : 171 : 172 : 173 : 174 : 175. 176 : 178 : 179 : { 180 : 181 : 182 : 183 : 184 : 185 : 186 : 187 : 188 : 189 : 190 : 191 : 192 : 193 : 194 : 195 : 1 if ( *(DTA. name) ! : d2 ニ (struct Dir の malloc( sizeof( struct Dir & & (DTA. attr&0xl の ! : 0 ) ( d2->name : strdup( DTA. name dir = d2; dir->next ニ d2; d2->br d2- 〉 level d2->next : dir->next; level; SW i tch case 0 : break ; case 1 : dir- 〉 br break; default: dl ニ dl dl- 〉 br dir->br break : ->next : return( n - n0 ) ; 125 : / * ファイル検索制御部 * / 126 : void findrest( char *path ) char parent[DEPTH] [ 80 ] ; int level, 11 , nn; strcpy( parent[O], yen ) ; for ( level ニ 1 ; level く DEPTH; d i 「 first—>next ; while ( dir ! = first ) { if ( 11 - 11 = dir->level level + + キーあるいは十圄を押します。 ListI てはなるべく前回作成した関数をそ のまま使用て、きるように配慮しましたが , 一部仕様が変更している関数などもありま すのて , 注意してください。今回は , プロ グラムが長くなってしまいましたのて , 解 説が短くなってしまいましたが , リスト中 に , どのような内容を行っているのかの概 要だけはコメントとして記入しましたのて , さほど読みづらくはないと思います。以下 にほかのプログラムてもそのまま使えそう な関数と , 使えそうなアイデアを含んだ関 数を以下に示します。 : 現在の画面のカーソル位置 int x, y; : get POS( &x,&y ) ; get pos : カーソルの位置を検出する 制限される。 りも長い場合は sl の長さに る。 s2 の長さのほうが sl よ 文字を文字列 s2 て、置き換え : 文字列 sl の先頭から最高 n int n ; char * s1, * s2 : strnchg( SI, s2, n ) ; ( 置換て、はない ) strnchg : 文字列の入れ換えをします 使用法 内 谷 strcpy( parent[O], yen ) : if ( dir->level > 0 ) if ( dir->level level ) ( strcpy( path, parentCl 1 ] ) ; strcat( path, dir- 〉 name ) ; strcat( path, wi ld ) : ー dir- 〉 level; dir->level if ( nn - = find( level + 1 , path ) : else ( strcpy( parent[ll + 1], strcat( parent[ll + 1], strcat( parent[ll + 1], dir = dir->next; 159 : / * 文字列の置き換え ( 上書き ) 160 : void strnchg( char 本 sl , char *S2, int parent[ll] ) : dir—>name ) : yen ) : n ) + DTA. drv - 1 ) : 使用法 内容 内容 使用法 mk crt を検出し , 変数 x ( 横軸 ) ( 縦軸 ) に値を返す。 , Y int lenl, len2, i : lenl = strlen( sl ) ; len2 = strlen( s2 ) ; if ( lenl > = n ) lenl for ( i : 0 : i く lenl ; if ( i く len2 ) ( sl[i] = else { sl[i] = s2[i]; ・構造体 dir から画面イメー の形に整形する : mk crt( ) ; シ n : i 十十 177 : な表示用データ作成り int mk—crt( void ) int 1 , J' char SPCC6][3] ; 1 ine ニ 0 : x : 0 : X : dir first->next; for ( j crt[line) CMAXWIDTH] = ' \ 0 ' : crt[line][j] : for ( j = 3 : j く MAXWIDTH; sprintf( crt[line], strnchg( &(crtCline][j*25-21]), strnchg( &(crtCline][j*25-14]), ” \ xlb [ 32m ” , 5 ) ; ” \ xlb [ 37m ” , 5 ) : strnchg( &(crtCline][j*25-21]), ” \ xlb [ 37m ” , 5 ) : for ( i 0 ; i く n; i + + , dir ニ dir->next ) ( ・構造体 dir からディレクトリ 構造を画面イメージの形に 整形する。画面イメージに は , 木構造を表す枝とその 色を変えるためのエスケー プシーケンスを含んていま す。このエスケープシーケ ンスを前述の関数 strnc れ g て書き換えることによって , 画面上のカーソルを移動さ せているようにみせていま す。 ワンポイントプログラミング講座 131

6. 月刊 C MAGAZINE 1990年1月号

List 1 まチェンジティレクトリ コマンド乍成 2 : / 事拡張チェンジディレクトリコマンド c d e C Magag i ne. NO. 4 by Tetsu. U 6 : #include く stdio. h> 7 : #include く stdlib. h> 8 : #include く conio. h> 9 : #include く string. h> 10 : #include く direct. h> 11 : #include く dos. h 〉 12 : #include く C . H > 13 : / 事 M S ー C V e r 5 . 1 のとき 14 : #define MSC5 dir—first() -dos—findfirst(path, 0x3f, (struct find-t *)&DTA) 15 : #define dir—next() dos—findnext((struct find—t *)&DTA) 16 : #define 17 : 18 : 19 : #define MAXLINE 30 20 : #define MAXWIDTH 134 21 : #define DEPTH 5 22 : 23 : struct Dta ( 24 : char drv; char fille 「 [ 2 の : 25 : 26 : char attr; unsigned time; 28 : uns i gned date ; 29 : long Size; char name[13] : 30 : 31 : ) DTA; 32 : 33 : struct Dir { int level : 34 : 35 : int br; 36 : Char •name : struct Dir *next; 38 : ) *dir, *first; 39 : 40 : int れ = 0 : 41 : char crt[MAXLINE][MAXWIDTH + 1] ; 42 : static char yen[] branchC4][3] 43 : 44 : 45 : / 事使用法事 / 46 : void usage( void ) pr intf( ”拡張チェンジディレクトリコマンド c d e ” ) : 48 : printf( ” > c d e [ [A : ] d i 「 e c t r y ] *n" ) ; 49 : exit( 1 ) ; 50 : 52 : 53 : / 事引き数チェック & 引き数のディレクトリへ移動り 54 : int chk—args( int ac, char 事事 a ) d ” 1 , d Ⅳ 2 ; ″ドライプ番号り 56 : unsigned 面 : / 事使用可能なドライブ数り 58 : 59 : d ” 1 = む v2 = 0 ・ if ( ac - 60 : return( 0 ) : else if ( ac 63 : if ( : -dos-getdrive( &drvl ) ; 65 : (int ) ( toupper( av [ 1 蔓匠 ) ー 66 : drv2 _dos_setdrive( drv2, &dn ) : 68 : if ( chdir( av[l] ) = 0 ) ( 69 : exi t( 0 ) ; 70 : return( (drvl ! : drv2) ? 1 72 : 73 : else if ( ac > 3 ) { usage() : 75 : 76 : 78 : 79 : / 事ディレクトリ内のファイルの検索事 / 80 : int find( int level, char *path ) struct Dir 事 dl , 事 d2 : 83 : int nO; 85 : dl = dir; 86 : n0 : n; dir_first(); & & ( DTA. at い & 0X1 の ! ニ 0 ) ( if ( *(DTÅ. name) ! = ' 88 : d2 = (struct Dir の malloc( sizeof( struct Dir ) ) : 89 : d2->name = strdup( DTA. name ) : 90 : d2->leveI : le 1 : d2->br : 2 : 93 : d2->next : dir->next; dir->next : d2; 94 : dir : d2; 96 : n 十 = 1 : while ( dir-next() 98 : それては , これらの関数を使ってディレ クトリを移動するユーティリティを作成し てみましよう。一般的な方法てすと , MS- DOS のコマンドと同じになってしまいま す。ここては連載第 2 回の「ディレクトリ構 造読み出しプログラム」をひな形として , 任意のディレクトリへメニュー形式て移動 てきるようなユーティリティを目標にしま す。 また , FD べースてはないてしようが , 40 M や 80M 以上の容量をもつハードディスク ては , ディレクトリ構造も複雑になり 1 画面 24 行のなかに入りきらない場合が出てきそ うてす。そこて , 前回の「 more プログラム」 を参考にしてください。 more プログラムを 参考にすることによってディレクトリを見 つけしだい画面に表示するのてはなく , メ モリ上て加工してから表示することがてき るようになります。 [ 外部仕様 ] ・コマンド名 CDE (Change Directry Excelent) ・機能 : ディレクトリの移動を行う ・入力形式 : cde [ [ ドライプ : ] ノヾス ] ・使用法 . ① cdeu カレントドライプのディレクトリを表 示し , 現在のカレントにカーソルを表 示する。 ② cde ドライプ名 指定ドライプのディレクトリ構造を表 示し , カーソルをカレントに表示する。 ③ cde パス名 指定パスへ移動する。パス名は絶対指 定ても相対指定ても可。指定パスが存 在しない場合は , 指定ドライプあるい はカレントドライプのディレクトリ構 造を表示する。 いずれの場合もディレクトリ構造が表示 されたら , カーソル移動キーて移動先のデ ィレクトリを選択し , リターンキーて決定 します。キャンセルしたい場合は , ー 130 CMAGAZINE 19 1

7. 月刊 C MAGAZINE 1990年1月号

の内部を詳解 0 ポインタ」をつくると②になります。今度 は , ノードが tc FUNC なのて、 , 「②の型 ( = TYPE CHAR へのポインタ ) を返す関数」を つくると③になります。ここて、 , 木構造の ノードは tc 工 D なのて、 , シンポルテープルに 登録すると , 最終的に④のようになります。 この作業を実際に行うのが , glodecl, paramdecl, locdecl, abstdecl の 4 つの関 数て、す。このうち locdecl を List11 に示しま す。ここては for 文 ( 8 行目 ) て、 , ループしな がら木構造をたぐっていきます。そして , そのノードによって必要な処理に分岐しま す。 dcl 工 D の場合 ( 10 ~ 25 行目 ) には , 結果 をシンボルテープルに登録して , そのエン トリへのポインタをリターンします。また , このとき , あらかじめローカルシンボ、ルテ ープルをサーチして , すて、にその変数が定 義ずみて、あるかどうかをチェックします ( 12 ~ 16 行目 ) 。また , Cm て、は関数をローカ ルに宣言することはて、きませんのて、 , それ もチェックします ( 17 ~ 21 行目 ) 。これらの チェックの結果 , OK だったらローカルシン ボ、ルテープルに登録します ( 22 ~ 25 行目 ) 。 dcl PTR, dcl FUNC, dcl ARRAY は , それぞれ tc POINTER, tc FUNC TION, tc ARRAY の型をつくります。ま こて、は宣言て、禁止されている組み合 わせを使っていないかをチェックします。 たとえば , 「関数の配列」「配列を返す関数」 「関数を返す関数」などの組み合わせは許さ れていないのて , もしあれば工ラーにしな ければなりません。 declare. c て、定義されている関数 ( 外部から 参照されるもの。表 6 ) は , すべて cm. y から 起動されます。 cm. y の文法定義のうち , も っとも外側のレベルの部分を抜粋したもの が List12 て、す。このリストて、下線を引いた部 分が , 宣言を処理する関数への呼び出して、 す。 今回は , レキシカルアナライザ , 木構造 を扱うルーチン , シンポルテープル , 宣言 の処理を説明しました。次回からは , コー ド生成を始めます。 76 CMAGAZINE 19 1 List 1 1 type = reg し 0CType (tc-FUNCT10N, type) : tree->first; tree Case dcI-ARRAY: if (isFunction(type)) { error("array Of function is not allowed") : return NULL; tp = regLocType (tc-ARRAY, type) : (int)tree->second; ((struct array *)tp)->size = type = tp : tree : tree->first; Defau は : bug("locdecl") : 4 ・ - -0 0 ー 8 0 1 より朝っ 0 -4 ・ LO ー 8 宣言処理の呼び出し ( cm. y より抜粋 ) 1 2 List 2 : 3 : 4 : 5 : 6 : 7 : 8 : 9 : 12 : extern_def 13 : func_def ー EXTERN func_def ー declaration { globalDataDecI($1, 0 ) ー EXTERN declaration { gIobaIDataDecl ( $ 2. 1 ) 20 : 22 : func_def type-spec dec larator 23 : { funcDef()1 $ 2 ) : 24 : 25 : initFunc : 26 : cont し abel = break し abel func-body 28 : { funcend ( ) : 29 : 30 : endFunc : fIushStr() : } 31 : 32 : declarator { funcDef(TYPE INTEGER, (I) : 33 : 34 : initFunc : break し abel = 0 : 35 : cont し abel initStr() 36 : 37 : func-body { funcend() : 38 : 39 : endFunc : fIushStr() : } 40 : 42 : 43 : func -b0dY ・ { ・ declaration-list 44 : { funchead() ・ 45 : 46 : 47 : 48 : 49 : declaration_l ist : / * empty * / 50 : ー declaration_l ist declaration { yyerrok; 52 : localDataDecl ( $ 2 ) 53 : ー declaration-l ist error 54 : 55 : 下線を引いた部分が declare. c 内の関数への呼び出し extern def file extern_def { yyerrok; } error error func_body file error fi le error func-body initStr(); }

8. 月刊 C MAGAZINE 1990年1月号

コンヾイラ の内部を詳解 TYPE 構造体は使いません ( Fig. 5 ( a ) ) 。 (b) 配列の要素数て、す。型は , 構造体 TYPE へ 実際に型がどのように表現されるかを考え は char へのポインタて、す。 (c) は , 「 [fchar のポインタて、表現されますが , int 型と char てみましよう。いろいろな型について , そ へのポインタ』を返す関数」て、す。また ( d ) 型はそれぞれ特別な値 ( TYPE CHAR と の型テープルて、の表現をまとめたのが Fig. 5 は , 「「 char を返す関数』へのポインタ」て、 て、す。まず , int と char はそれぞれ定数 TYPE TYPE INTEGER) て、表現します。 す。 (c) と (d) の違いに注目してください。 ちょっと話がややこしくなりましたのて、 , CHAR と TYPE INTEGER て、表現され , また同様に ( e ) は「「 char のポインタ』の配 言とクラス 列」 , ( f ) は「『 char の配列』へのポインタ」と なります 0 List 9 / * f00 ニ SC_G し OBA し int f00 : / * bar = SC_EXTERN 2 : extern func ニ SC_EXTERN 3 : Char 4 : 5 : main(int argc, char **argv) ニ SC_GLOBA し ma ー n ニ SC_PARAM 6 : argc, argv = SC_LOCAL 8 : C 9 : bar; int func ( ) : 宣言の処理 さて , 宣言の木構造のつくり方とシンポ ルテープルの仕組みを説明し終わりました。 最後に , 宣言の木構造をもとに , 変数や関 数をシンボルテープルに登録しなければな りません。これらの関数は declare. c て、定義 されていますが , これらのうち , ほかのフ ァイルから参照する関数の一覧を表 6 に示し ます。 宣言の木構造を元に型テープルに型をつ くり出すのは glodecl ( グローバル宣言 ) , paramdecl( ノヾラメータ宣言 ) , locdecl( ロ 宀二・ ) abstdecl ( 抽象宣言子 ) の 4 つ カノレ . 目 . ロ , の関数て、す。これらの関数は , 木構造をた ぐりながら , その宣言が表す型を型テープ ルの中に構築します。先ほど Fig. 3 て、取り上 げた * a( ) という宣言子を例にとって考えて みましよう。 Fig. 6 は左側が宣言を表す木構造 , 右側が 型テープルの内容を表しています。これか ら処理する宣言は次のものて、す。 char * a( ) ; まず①は最初の状態て、 , 木構造は Fig. 3 て っくり上げたものて、す。また , 型は TYPE CHAR て、す。ここて、 , 木構造の最初のノー ドは tc PTR なのて、 , 「 TYPE CHAR への [ 表 6 ] 宣言を処理する関係 ( decla 「 e. c ) 目的 関数 グローノヾル変数の定義 globalDataDecI 関数の定義 funcDef ( バラメータの宣言を含む ) 関数の開始時のコード出力 funchead 関数の終了時のコード出力 funcend ローカル変数の定義 localDataDecl 抽象宣言子の処理 abstdecl Char func(c) : 構造体 TYPE 型 ( 型テープル ) の定義 ( cmdef. h ) FUNCTION } tc_POINTER, tc ARRAY, tc- 10 List 1 : typedef enum TCLASS; 2 : 3 : 4 : typedef struct type TC し ASS 5 : tc : 6 : struct type i nt 7 : S ー ze ; TYPE; 9 : 11 : #def i ne TYPE_CHAR TYPE_INTEGER 12 : #define *father; (TYPE*) 1 (TYPE*)2 locdecl 関数 1 1 List 1 : / * locdecl process local variable declaration TREE *tree) 2 : private SYMTB し *locdecI(TYPE *type, TYPE 4 : *tp; SYMTB し *s; 5 : 6 : Char *name; 7 : for C ・ 8 : switch (tree->node) { 9 : Case dcl_ID: ニ saveLocId((char *)tree->first) : name searchLoc(name)) ! ニ NUL し ) { if ((s error2("Iocal variable ・ % s ・ is declared twice. name) : return NU しし : if (isFunction(type)) { error2(" '%s ・ function cannot declared locally" name) : 19 : return NU しし 20 : regLocId(name) : 22 : S ニ SC_LOCA し : 23 : s—>class 24 : type : s->type 25 : return s; 26 : Case dc I_PTR: type = regLocType(tc-POINTER, type) : tree->first; 28 : tree 29 : Case dc I_FUNC: if (isArray(type)) { 30 : not allowed") : error ("function returns array iS return NU しし : 32 : 33 : yacc による C コンバイラブログラミング 75

9. 月刊 C MAGAZINE 1990年1月号

MS - DOS プログラミング入門 List 3 1 3 : * / # i nc lude く d i 「 . h> fat. C A. Akitu 1989-10-01 F A T 工ントリを調べて、その F A T のつながりを TURBOC のみ さらに実際のセクタも表示している。 たどりながら表示するプログラムです。 f i ー e S i ze : record_size; current_block; fiIetype[3] : filename[8] : d 「 i ve : 103 : 104 : 105 : 106 : 107 : 108 : 109 : 110 : 1 12 : 113 : 1 14 : 115 : 1 16 : 1 17 : 1 18 : 1 19 : 120 : 122 : 123 : 124 : 125 : 126 : 127 : 128 : 129 : 130 : 131 : 132 : 133 : 134 : 135 : 136 : 137 : 138 : ロ 9 : 140 : 141 : 142 : 143 : 144 : 145 : 146 : 147 : 148 : 149 : 150 : 151 : 152 : 153 : 154 : 155 : 156 : 157 : 158 : 159 : 160 : 16L 162 : 163 : 164 : 5 : 166 : 167 : 168 : 9 : 170 : 171 : 172 : 173 : 174 : 175 : 176 : 177 : 178 : 179 : 180 : 182 : 183 : 184 : 5 : 186 : 187 : 188 : 189 : 190 : 191 : 192 : 193 : 194 : 5 : 四 6 : 8 : 199 : 200 : 201 202 : 203 : 204 : pt 「十十 ) 10 : 14 : 15 : 16 : 17 : 18 : 19 : 20 : 21 : 22 : 23 : 24 : 26 : 28 : 29 : 30 : 32 : 33 : 34 : 35 : 36 : 38 : 39 : 40 : 42 : 43 : 44 : 45 : 46 : 48 : 49 : 50 : 52 : 53 : 54 : 55 : 58 : 59 : 62 : 63 : 65 : 66 : 68 : 69 : 70 : 72 : 73 : 74 : 75 : 77 : 78 : 79 : 82 : 83 : 84 : 85 : 86 : 88 : 90 : 92 : 93 : 94 : 95 : 96 : 97 : 98 : 99 : 100 : 間 1 : 102 : ネ Comp ⅱ ed Prog rammed by Created date Version Purposed # ・ i ncl ude #include #include #include #include #include く stdiO. h> #include <stdlib. h> く string. h> く process. h> long int int Char Char Char typedef struct -FCB く errno. h> く dos. h> く ctype. h> int date: i n t t i ne : } FCB; long Char Char / 本 * ま * ま本本事本本 lnitial ize 0f FCB * 本ま本本ま本 * 本 * * * 本 * * ま本 / for(ptr (char *)&fcb : ptr く (char *)&fcb + sizeof(FCB) printf("file npt find !Yn"): ニ 0xff) if( find_first(&fcb) fcb ⅵ ( a 「 gv [ 1 ]. &fcb): dta(&fcb-entry) : *Ptr - set ex i t ( l) : fcb entry. start_cluster; nunl exit(l): pr i ntf (" D P B が読めません . つ : if( (size : fatsize() ) pr i ntf ( " F A T の読み込みに失敗しました . if( fat-read(buff) ex i t ( l) : pr i ntf ( " メモリが足りません . ! " ) : = NU しし ) : nalloc(size)) if ( (buff ex i t ( l) : reserved[8] : current_record; relative_record; / * F C B 用のファイルを展開するための構造体 * / while(nunl ! ニ 0xfff) count 十十 : numl printf("X03X(XX) ” / * FAT の判定 * / typedef struct -DIR-ENTRY { } DIR_ENTRY;/* 検素後のファイルを格納する為の構造体 * / long f i ー e S i ze : int start_cluster; int date; i n t t i me : Char reserved[10] : char attrib; Char fiIetype[3] : char filename[8] : Char drive; . (numl - 2)*(addr->Sector-CIuster + 1 ) + addr->Start-Data-Sector) : 仙 m l) : printf( ” = % 03XYn ” . numl - search_fat(buff. numl) : struct DPB unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned Struct unsigned Char int Char Char int Char int int int Char int Char Char Char DPB int Drive_number; Unit_Number; Sector_ し ength: Sector_Cluster; Shift_Count; Reserved_Sector; Fat_Number; Number_Dir_Entry : Start_Data_Sector: Max_Cluster_Number; Sector_Fat; far *Device_Header: Media_Descriptor; Change-Disk; far *Next_Dpb; Cur_Dir_Fat; / * ドライプ番号 / * ュニット番号 な 1 セクタ当りのバイト数 な 1 クラスタ当りのセクタ数 / * シフトカウント / * 予約セクタの数 な F A T の数 / F A T 当りのセクタ数 / * 最大クラスタ番号 + 1 / * データ領域の開始セクタ / 本ルートディレクトリの最大数 printf( ” Yntotal count of FAT = XdYn ” . free(buff) : PATSIZE() FUNCTION int fatsize(void) count) : 本 / Start_Rootdir_Sector:/* ルートディレクトリの開始セクタり / * デバイスドライバへのポインタ * / なメディアディスクリプタ / * ディスク交換用のフラグ / * 次の D P B へのポインタ なカレントディレクトリの F A T り / * D P B 用の構造体 . M S ー D 0 S コンパチ * / int fat_read(unsigned char * ) : int fatsize(void) : int search_fat(unsigned char *. int) : int fcb-wild(char *. FCB 事 ) ; int find-first(FCB * ) ; int find-next(FCB * ) : 76 : void set-dta(DIR_ENTRY * ) : struct DPB far *addr: union REGS inregs, outregs; 80 : struct SREGS segregs; HAIN() FUNCTION VOid nain(int argc, char *argv[]) inregs. h. ah = 0X32 : / * カレントドライプ A. 2 ニ B , 3 = C... * / - 0X00 : inregs. h. 引 intdosx(&inregs. &outregs. &segregs) : if( outregs. h. 引 = 0xff ) return (-I) : return(addr->Sector- し ength 事 addr->Sector_Fat) : addr MK_FP(segregs. ds, outregs. x. (x) : e ー se るセクタ数を掛け合わせることによって得られる。 F A T の容量は、 D P B から得られるセクタの長さと 1 F A T がしめ を addr で絶対指定する。 を使用するのでセクメントリードを行なう。セグメントとオフセット スモールメモリモデルでは、 D P B の情報を得るのに f a r ポインタ FAT_READ() FUNCTION int fat_read(unsigned char *buff) addr->Reserved_Sector. buff ) if( absread(getdisk(). addr->Sector_Fat. FCB DIR_ENTRY Char unsigned char *buff: int if(argc ! : 2 ) size, nunl, *ptr; fcb_entry: fcb: count return (-l) : return 1 : / 本 getdisk() / 事 addr->Sector_Pat e ー se - カレントドライプの拾得 1 F A T のセクタ数 / 事 addr->Reserved_Sector : 先頭 P A T セクタ / 本 buff ニ読み込み先のアドレス 本 / 本 / 事 / pri ntf に調べるためのファイルを指定して下さい。 Yn" exit(l): C プログラマのための MS ー DOS プログラミング入門 61

10. 月刊 C MAGAZINE 1990年1月号

三田典玄の 実践 C プログラマ 養成講座 第④回リスト構造 最初の 1 行を読み込んだとき List 4 どの文書工デイタがこの構造と似かよった 構造をもっているといってもいい。そして データベースなどのあらゆるノイマン型コ ンビュータ上のデータも , ほばこれに似た データ構造をもっている。しつこいようだ こういうデータ管理の方法がコンピュ ータ上て、のデータ管理の基本なのて、ある。 そしてこの構造体を使って 1 行分のデータ をファイルから読んて、きて , メモリ上に編 集のために置くときは List3 のようなコーデ イングが必要て、ある。 もちろん , ここて、も工ッセンスだけを書 く。工ラー処理などについてはいっさい考 えていないことをお断わりしておく。 List3 のようなコーディング ( 再度断わって おくが , これはエラーについてはまったく 考えていないのて、 , 絶対にこのままて、使わ ないように / ) て、 , まずェリアの確保をして おく。そしてそれが編集対象のファイルを 読み込むときの最初の 1 行て、あれば , その後 に List4 を加える。 つまり , 最初の 1 行はデータがそれ以前に ないわけだから , PreviousLine ポインタ変 数メンバの値は NULL ( つまり「 0 」 ) て、ある。 よもや説明はいるまい , とは思うが , NULL はマクロとして stdio. h に定義されているの が普通て、ある。また , 構造体の鎖 ( 「チェー ン構造」といういい方もある ) の最初を示す のにグローバル変数としてつくってある FirstLine ポインタ変数に最初の構造体の ありかを示すポインタも代入しておく。 また , ここて、示されている「 NextLine 」メ ンバのことをより一般的には「フォワードチ 工ーン」といい , 「 PreviousLine 」メンノヾの ことは「バックワードチェーン」という。 また , 次の 1 行を読んだとき , その「一〉 1 : 6 : 5 : 4 : 3 : 2 : struct -line *FirstLine, struct 」 ine *Saved い ne; F i rst い ne = p : FirstLine—>PreviousLine Saved い ne = p, (struct -line *)NULL; 1 : Saved い ne->Next い ne List 5 3 : Saved い ne 2 : p->PreviousLine 最初の行と最後の行以外を読み込んだとき = Saved い ne; 最後の行を読み込んだとき 1 : Saved い ne->Next い ne List 6 2 : p->Previous い ne 3 : p->NextLine = Saved し ine ; (struct 」 ine * ) NUL し : PreviousLine 」メンバに入れる値を確保し ておかないと「私の後ろにいるのは誰 ? 」と いうことになってしまうのて、 , 用意として SavedLine というポインタ変数に今回 mal 10C ( ) て、とってきて文書の 1 行のデータを入 れた行管理構造体のポインタ変数の値を代 入しておく。この値は次の行を読みにいっ て , 同様に構造体をつくったときに使うわ けだ。 さて , 2 行目以降 ( すなわち 2 回目以降 , 行 を読んて、きたとき ) は List3 に続いて , 今度は List4 の代わりに List5 のようなコーディング が必要になる。 最初の 1 行て、ひとつ前の行管理構造体の NextLine;tk インタ変数メンバに , 先ほどと ってきた行管理構造体のポインタ値 ( どこに あるかを示している ) を代入する。 そして 2 行目て、今とってきた行管理構造体 には , PrevoiusLineztk インタ変数メンバに ひとつ前の行管理構造体のポインタ値 ( どこ にあるかを示す ) を代入している。 そして 3 行目て次に新しい行管理構造体が て、きたときに備えて現在の行管理構造体の ポインタ値をセープしておく。 さて , こまてくると頭がピーマンにな った ( ふるいなー / 最近は「ウニになった」 というそうて、ある。〔それて、も古い : 編注〕 ) 読者も多いことだろう。なに , たった 3 行て、 ある。 1 日も悩めば , 何をやっているのか , 解析て、きるはずて、ある。やってみよう。 え ? 1 日たったけどわからないって ? 眺 めているだけて、はだめて、すね。ちょっと散 歩にて、もて、かけるほうがいいかもしれませ 読み込んだテータの表示 1 1 : struct 」 ine *p; 2 : for(p = First い ne List 7 96 CMAGAZINE 19 1 : (struct _line * ) N 乢し ! p->Next い (e) printf("XsYn",p-> い neBuffer) :