極めて美しいのは、93行以降のnotice_promptの並びです。字下げが見事なまでにきれいに戻っ ていき、その中にエラーメッセージ表示のための関数notice_promptが限りなく美しいハーモニー を保って配置されています。ネストも9段あり、見とれてしまう「究極の美」です。
美しい次下げということは、ふつうなら理解しやすく喜ばしいのですが、これは違います。
リスト12−1 オリジナルプログラム 究極の美(字下げ) |
1 int file_copyfile( filed, files, job, page, comment ) 2 PBYTE filed; /* 複写先ファイル名 */ 3 PBYTE files; /* 複写元ファイル名 */ 4 PBYTE job; /* 複写先JOB名 */ 5 PBYTE page; /* 複写先頁番号 */ 6 PBYTE comment; /* 複写先コメント */ 7 { 8 int ret; 9 int fhs, fhd; 10 int size, rsize, wsize; 11 PBYTE buff; 12 int pos; 13 SYS_PAGE_HEAD head; 14 BASE_INFO destbase; 15 16 fhd = open( filed, O_RDONLY ); 17 if ( fhd != -1 ) 18 { 19 close( fhd ); 20 ret = notice_prompt( master_menu_panel, NULL, 21 NOTICE_MESSAGE_STRINGS, 22 SYS_MESSAGE_SAVE_OWRITE1, 23 SYS_MESSAGE_SAVE_OWRITE2, 24 NULL, 25 NOTICE_BUTTON_YES, SYS_TEXT_YES, 26 NOTICE_BUTTON_NO, SYS_TEXT_NO, 27 NULL ); 28 if ( ret != NOTICE_YES ) 29 return -2; 30 } 31 ret = NORMAL; 32 fhs = open( files, O_RDONLY ); 33 if ( fhs != -1 ) 34 { 35 fhd = open( filed, O_CREAT | O_TRUNC | O_WRONLY, 00660 ); 36 if ( fhd != -1 ) 37 { 38 size = KB_SIZE; 39 buff = malloc( size ); 40 if ( buff != NULL ) 41 { 42 for( rsize = read( fhs, buff, size ); rsize != 0 && rsize != -1; 43 rsize = read( fhs, buff, size ) ) 44 { 45 wsize = write( fhd, buff, rsize ); 46 if ( wsize != rsize ) 47 { 48 notice_prompt( master_menu_panel, NULL, 49 NOTICE_MESSAGE_STRINGS, 50 SYS_MESSAGE_FILEWRITE, 51 SYS_MESSAGE_FILECOPYE, 52 NULL, 53 NOTICE_BUTTON_YES, SYS_TEXT_CHECK, 54 NULL ); 55 ret = ERROR; 56 break; 57 } 58 } 59 if ( rsize == -1 ) 60 { 61 notice_prompt( master_menu_panel, NULL, 62 NOTICE_MESSAGE_STRINGS, 63 SYS_MESSAGE_FILEREAD, 64 SYS_MESSAGE_FILECOPYE, 65 NULL, 66 NOTICE_BUTTON_YES, SYS_TEXT_CHECK, 67 NULL ); 68 ret = ERROR; 69 } 70 free( buff ); 71 if ( ret == NORMAL ) 72 { 73 pos = lseek( fhs, 0, SEEK_SET ); 74 if ( pos == 0 ) 75 { 76 size = read( fhs, &head, sizeof( SYS_PAGE_HEAD ) ); 77 if ( size == sizeof( SYS_PAGE_HEAD ) ) 78 { 79 if ( lseek( fhs, head.base_pos, SEEK_SET ) == 80 head.base_pos && 81 lseek( fhd, head.base_pos, SEEK_SET ) == 82 head.base_pos ) 83 { 84 size = read( fhs, &destbase, head.base_size ); 85 if ( size == head.base_size ) 86 { 87 strncpy( destbase.job_name, job, JOBNAME_LEN ); 88 strncpy( destbase.page_no, page, PAGENO_LEN ); 89 strncpy( destbase.comment, comment,COMMENT_LEN); 90 size = write( fhd, &destbase,head.base_size); 91 if ( size != head.base_size ) 92 { 93 notice_prompt( master_menu_panel, NULL, 94 NOTICE_MESSAGE_STRINGS, 95 SYS_MESSAGE_FILEWRITE, 96 SYS_MESSAGE_FILECOPYE, 97 NULL, 98 NOTICE_BUTTON_YES, 99 SYS_TEXT_CHECK, 100 NULL ); 101 ret = ERROR; 102 } 103 } 104 else 105 { 106 notice_prompt( master_menu_panel, NULL, 107 NOTICE_MESSAGE_STRINGS, 108 SYS_MESSAGE_FILEREAD, 109 SYS_MESSAGE_FILECOPYE, 110 NULL, 111 NOTICE_BUTTON_YES, 112 SYS_TEXT_CHECK, 113 NULL ); 114 ret = ERROR; 115 } 116 } 117 else 118 { 119 notice_prompt( master_menu_panel, NULL, 120 NOTICE_MESSAGE_STRINGS, 121 SYS_MESSAGE_FILEWRITE, 122 SYS_MESSAGE_FILECOPYE, 123 NULL, 124 NOTICE_BUTTON_YES, SYS_TEXT_CHECK, 125 NULL ); 126 ret = ERROR; 127 } 128 } 129 else 130 { 131 notice_prompt( master_menu_panel, NULL, 132 NOTICE_MESSAGE_STRINGS, 133 SYS_MESSAGE_FILEREAD, 134 SYS_MESSAGE_FILECOPYE, 135 NULL, 136 NOTICE_BUTTON_YES, SYS_TEXT_CHECK, 137 NULL ); 138 ret = ERROR; 139 } 140 } 141 else 142 { 143 notice_prompt( master_menu_panel, NULL, 144 NOTICE_MESSAGE_STRINGS, 145 SYS_MESSAGE_FILEREAD, 146 SYS_MESSAGE_FILECOPYE, 147 NULL, 148 NOTICE_BUTTON_YES, SYS_TEXT_CHECK, 149 NULL ); 150 ret = ERROR; 151 } 152 } 153 } 154 else 155 { 156 notice_prompt( master_menu_panel, NULL, 157 NOTICE_MESSAGE_STRINGS, 158 SYS_MESSAGE_FILEMEM, 159 SYS_MESSAGE_FILECOPYE, 160 NULL, 161 NOTICE_BUTTON_YES, SYS_TEXT_CHECK, 162 NULL ); 163 ret = ERROR; 164 } 165 close( fhs ); 166 if ( close( fhd ) == -1 ) 167 { 168 notice_prompt( master_menu_panel, NULL, 169 NOTICE_MESSAGE_STRINGS, 170 SYS_MESSAGE_FILEWRITE, 171 SYS_MESSAGE_FILECOPYE, 172 NULL, 173 NOTICE_BUTTON_YES, SYS_TEXT_CHECK, 174 NULL ); 175 ret = ERROR; 176 } 177 if ( ret == ERROR ) 178 unlink( filed ); 179 } 180 else 181 { 182 close( fhs ); 183 notice_prompt( master_menu_panel, NULL, 184 NOTICE_MESSAGE_STRINGS, 185 SYS_MESSAGE_FILEOPEND, 186 SYS_MESSAGE_FILECOPYE, 187 NULL, 188 NOTICE_BUTTON_YES, SYS_TEXT_CHECK, 189 NULL ); 190 ret = ERROR; 191 } 192 } 193 else 194 { 195 notice_prompt( master_menu_panel, NULL, 196 NOTICE_MESSAGE_STRINGS, 197 SYS_MESSAGE_FILEOPENS, 198 SYS_MESSAGE_FILECOPYE, 199 NULL, 200 NOTICE_BUTTON_YES, SYS_TEXT_CHECK, 201 NULL ); 202 ret = ERROR; 203 } 204 205 return ret; 206 } |
では今回の最初の問題です。どのnotice_promptがどのifに対応しているか調べてください。 notice_promptは全部で12個あり、if文は14個あるので、2つのif文にはnotice_promptは対応 しません。この対応は強力なエディタの利用者には容易ですが、リストを見ただけでは全く分かり ません。リストの拡大コピーを取り、定規で対応をつけてください。
ブロックを示す波括弧 { } が癖のある書き方なので難しいでしょう。記事を書く以上、私も調 べましたが、これはとても面倒な作業でしたので結果に自信が持てません。対応を調べ、その離れ 具合を「距離」で示しました。
表12−1 条件判定位置とエラー処理部分の距離 |
条件判定位置 エラー処理位置 if notice_prompt 距離(行) 17 20 3 33 193 160 36 180 144 40 156 116 46 48 2 59 61 2 71 74 143 69 77 131 54 79 119 40 85 106 21 91 93 2 166 168 2 177 |
if文は流れを2つに分けるという、プログラムの読みやすさを著しく損なう性質をもっています。 したがって、if文のネストが深くなれば、流れはどんどん枝分かれし、深いネストを抱えたif文は elseまでの距離が何ページも先になってしまいます。
要するに、if文をネストした場合、elseまでの距離が長くなってしまい、プログラムの流れが読 めなくなるのです。「この部分はどのifと対応しているんだっけ?」というようなものは、どんな に美しかろうと、プログラムとしての価値などまったくありません。ソースリストが、字下げで凸 凹することこそC言語らしいなどと思って説明しているような本もあるようなので注意しましょう。
たとえ「スバゲッティー」や「ざるそば」みたいなプログラムでなくても、この「距離」が長く なると難解なプログラムになってしまうのです。
リスト12−1の正常処理の最後の文は、関数の最後の205行のreturn文です。では、その直前 はどこを通過したでしょう。すぐに答えられたら、あなたはこのプログラムを書いた人と同様の天 才で、どんな苛酷な、誰もが悲鳴を上げたくなるようなプログラムにも耐えられるでしょう。
では、この関数の正常処理のときの経路を示しましょう。以下の数字は行を示します。
16〜17,31〜46,70〜91,165〜178,205リストのこの部分にマーカーで色をつけてみると、何と訳の分からない経路をたどっているかが しっかりと分かるでしょう。とくに、205行の直前が165〜178行というのは分かりづらいはずです。