『Cプログラミング診断室』目次次(第9章 珠玉の力作 文字列処理)

第9章 珠玉の力作

構造体


リスト9−1を見てください。実際のファイルは長いので、1つの関数の部分だけを取り出した ものです。リスト9−2が、DATE型に関する定義部分です。

リスト9−1 オリジナルプログラム 構造体の処理
     1  int         saveall_execute( item, event )
     2  Panel_item  item;       /*アイテムハンドル*/
     3  Event       *event;     /*イベントアドレス*/
     4  {
     5  BYTE        job[JOBNAME_LEN+1];
     6  BYTE        plane[PLANENO_LEN+1];
     7  BYTE        com[COMMENT_LEN+1];
     8  BYTE        term[TERMINAL_LEN+1];
     9  int         i;
    10  Panel       panel;
    11  DATE        old_date;
    12  int         old_term;
    13  
    14  xv_set( base_frame, FRAME_BUSY, TRUE, NULL );
    15  panel = (Panel)xv_get( item, PANEL_PARENT_PANEL );
    16  if ( tr_jobname( saveall_frame, item,
    17                   saveall_job_item, saveall_plane_item,
    18                   job, plane ) != NORMAL )
    19      {
    20      xv_set( base_frame, FRAME_BUSY, FALSE, NULL );
    21      return XV_ERROR;
    22      }
    23  strcpy( com, (char *)xv_get( saveall_com_item, PANEL_VALUE ) );
    24  strcpy( term, (char *)xv_get( saveall_terminal_item, PANEL_LABEL_STRING ) );
    25  
    26  termlist_end( );
    27  xv_set( saveall_frame, XV_SHOW, FALSE, NULL );
    28  command_end( );
    29  
    30  strncpy( base.job_name, job, JOBNAME_LEN );
    31  strncpy( base.plane_no, plane, PLANENO_LEN );
    32  strncpy( base.comment, com, COMMENT_LEN );
    33  old_term = term_no;
    34  term_no = saveall_termno;
    35  
    36  old_date.year[0]    = base.date.year[0];
    37  old_date.year[1]    = base.date.year[1];
    38  old_date.month[0]   = base.date.month[0];
    39  old_date.month[1]   = base.date.month[1];
    40  old_date.day[0]     = base.date.day[0];
    41  old_date.day[1]     = base.date.day[1];
    42  old_date.hour[0]    = base.date.hour[0];
    43  old_date.hour[1]    = base.date.hour[1];
    44  old_date.minute[0]  = base.date.minute[0];
    45  old_date.minute[1]  = base.date.minute[1];
    46  old_date.second[0]  = base.date.second[0];
    47  old_date.second[1]  = base.date.second[1];
    48  get_date( (PDATE)&base.date );
    49  if ( save_rundata( OFF ) == NORMAL )
    50      {
    51      edit = OFF;
    52      if ( savequit == 1)
    53          {
    54          savequit = OFF;
    55          xv_set( base_frame, FRAME_BUSY, FALSE, NULL );
    56          xv_set( base_frame, FRAME_NO_CONFIRM, TRUE, NULL );
    57          xv_destroy_safe( base_frame );
    58          return XV_OK;
    59          }
    60      else if ( savequit == 2 )
    61          {
    62          savequit = OFF;
    63          xv_set( base_frame, FRAME_BUSY, FALSE, NULL );
    64          mainmenu_mode = MAINID_CREATE_CREATE;
    65          create_create( );
    66          }
    67      else if ( savequit == 3 )
    68          {
    69          savequit = OFF;
    70          xv_set( base_frame, FRAME_BUSY, FALSE, NULL );
    71          mainmenu_mode = MAINID_CREATE_FILE;
    72          file_read( );
    73          }
    74      else if ( savequit == 5 )
    75          {
    76          savequit = OFF;
    77          xv_set( base_frame, FRAME_BUSY, FALSE, NULL );
    78          mainmenu_mode = MAINID_CREATE_OUTPUT;
    79          file_output( );
    80          }
    81      }
    82  else
    83      {
    84      term_no = old_term;
    85      base.date.year[0]   = old_date.year[0];
    86      base.date.year[1]   = old_date.year[1];
    87      base.date.month[0]  = old_date.month[0];
    88      base.date.month[1]  = old_date.month[1];
    89      base.date.day[0]    = old_date.day[0];
    90      base.date.day[1]    = old_date.day[1];
    91      base.date.hour[0]   = old_date.hour[0];
    92      base.date.hour[1]   = old_date.hour[1];
    93      base.date.minute[0] = old_date.minute[0];
    94      base.date.minute[1] = old_date.minute[1];
    95      base.date.second[0] = old_date.second[0];
    96      base.date.second[1] = old_date.second[1];
    97      }
    98  xv_set( base_frame, FRAME_BUSY, FALSE, NULL );
    99  return XV_OK;
   100  }

リスト9−2 オリジナルプログラム 構造体の宣言
     1  typedef char            BYTE;           /* 符号付き1バイト */
     2  typedef BYTE            *PBYTE;
     3  typedef unsigned char   UBYTE;          /* 符号無し1バイト */
     4  typedef UBYTE           *PUBYTE;
     5  
     6  
     7  typedef struct  {
     8      UBYTE       year[2];                /* 年 */
     9      UBYTE       month[2];               /* 月 */
    10      UBYTE       day[2];                 /* 日 */
    11      UBYTE       hour[2];                /* 時 */
    12      UBYTE       minute[2];              /* 分 */
    13      UBYTE       second[2];              /* 秒 */
    14      } DATE;
    15  typedef DATE            *PDATE;

まず感じるのは、関数ブロックの中が、字下げ(インデンテーション)されていないことです。 この程度なら字下げされていなくても、関数の開始、終了はすぐ分かりますが、長くなると分かり づらいので、関数の内部は1タブ下げるようにしましょう。

xv_set, xv_getはXViewの関数です。詳しく知りたい方は、Xのマニュアルの第7巻(参考文献) を見てください。

36〜47行は

    36  old_date.year[0]    = base.date.year[0];
    37  old_date.year[1]    = base.date.year[1];
    38  old_date.month[0]   = base.date.month[0];
    39  old_date.month[1]   = base.date.month[1];
    40  old_date.day[0]     = base.date.day[0];
    41  old_date.day[1]     = base.date.day[1];
    42  old_date.hour[0]    = base.date.hour[0];
    43  old_date.hour[1]    = base.date.hour[1];
    44  old_date.minute[0]  = base.date.minute[0];
    45  old_date.minute[1]  = base.date.minute[1];
    46  old_date.second[0]  = base.date.second[0];
    47  old_date.second[1]  = base.date.second[1];
  
85〜96行は
    85      base.date.year[0]   = old_date.year[0];
    86      base.date.year[1]   = old_date.year[1];
    87      base.date.month[0]  = old_date.month[0];
    88      base.date.month[1]  = old_date.month[1];
    89      base.date.day[0]    = old_date.day[0];
    90      base.date.day[1]    = old_date.day[1];
    91      base.date.hour[0]   = old_date.hour[0];
    92      base.date.hour[1]   = old_date.hour[1];
    93      base.date.minute[0] = old_date.minute[0];
    94      base.date.minute[1] = old_date.minute[1];
    95      base.date.second[0] = old_date.second[0];
    96      base.date.second[1] = old_date.second[1];
  

となっています。構造体であるDATE型のbase.date(現データ)を、old_dateに複写しておき、処理 に失敗したとき、old_dateからbase.dateに戻すことで回復処理をしています。でも、1バイト毎 に代入しています。年、月、日、時、分、秒それぞれに2バイトを割り当てているので、結局12個 の代入文をずらーっとというか、だらだらというべきか並べています。=で構造体の代入ができる ことを知らないのでしょうね。それぞれの12行は、

	old_date = base.date;
と
	base.date = old_date;
  
で済みます。

これは単に12行が1行に縮んだだけではありません。これによって、保守性が向上しているので す。たとえば、year[2]がyear[4]に変更になった場合、修正版では何の変更も不要です。オリジナ ルでは、2行追加になります。もし、ミリセカンドを追加したいときでも、修正版では変更不要で す。修正版では、構造体の内部がどのように変化しようとも、一切修正が要りません。

横着(世間ではエレガントとも言う)に書くと、その後も横着できる、サボれることを理解し、 実施しましょう。そのうえ、サボったプログラムは品質が良いのです。「サボリ」はプログラマの とっての最大の「美徳」です。「力」をこめてプログラムを書いたりしたら、プログラムもキーボー ドも痛んでしまうではないですか。

その他には、標準型のcharは嫌いらしく、BYTE, PBYTE,UBYTE,PUBYTEなどで置き換えていますが、 あまり意味はないでしょう。プログラム全体できちんと使っていないのだから、本当に無意味でしょ う。

修正した関数をリスト9−3、DATEの型宣言をリスト9−4に示します。

リスト9−3 修正版 構造体の処理
     1  int         saveall_execute( item, event )
     2    Panel_item  item;     /*アイテムハンドル*/
     3    Event       *event;   /*イベントアドレス*/
     4  {
     5          char        job[JOBNAME_LEN+1];
     6          char        plane[PLANENO_LEN+1];
     7          char        com[COMMENT_LEN+1];
     8          char        term[TERMINAL_LEN+1];
     9          DATE        old_date;
    10          int         old_term;
    11  
    12          xv_set( base_frame, FRAME_BUSY, TRUE, NULL );
    13  
    14          if ( tr_jobname( saveall_frame, item,
    15                           saveall_job_item, saveall_plane_item, job, plane ) != NORMAL )
    16          {
    17              xv_set( base_frame, FRAME_BUSY, FALSE, NULL );
    18              return XV_ERROR;
    19          }
    20  
    21          strcpy( com,  (char *)xv_get( saveall_com_item, PANEL_VALUE ) );
    22          strcpy( term, (char *)xv_get( saveall_terminal_item, PANEL_LABEL_STRING ) );
    23  
    24          termlist_end( );
    25          xv_set( saveall_frame, XV_SHOW, FALSE, NULL );
    26          command_end( );
    27  
    28          strcpy( base.job_name, job );
    29          strcpy( base.plane_no, plane );
    30          strcpy( base.comment, com );
    31          old_term = term_no;
    32          term_no = saveall_termno;
    33          old_date = base.date;
    34  
    35          get_date( (PDATE)&base.date );
    36          if ( save_rundata( OFF ) == NORMAL ) {
    37                  edit = OFF;
    38  
    39                  switch( savequit ) {
    40                    case 1:
    41                          savequit = OFF;
    42                          xv_set( base_frame, FRAME_BUSY, FALSE, NULL );
    43                          xv_set( base_frame, FRAME_NO_CONFIRM, TRUE, NULL );
    44                          xv_destroy_safe( base_frame );
    45                          return XV_OK;
    46                    case 2:
    47                          savequit = OFF;
    48                          xv_set( base_frame, FRAME_BUSY, FALSE, NULL );
    49                          mainmenu_mode = MAINID_CREATE_CREATE;
    50                          create_create( );
    51                          break;
    52                    case 3:
    53                          savequit = OFF;
    54                          xv_set( base_frame, FRAME_BUSY, FALSE, NULL );
    55                          mainmenu_mode = MAINID_CREATE_FILE;
    56                          file_read( );
    57                          break;
    58                    case 5:
    59                          savequit = OFF;
    60                          xv_set( base_frame, FRAME_BUSY, FALSE, NULL );
    61                          mainmenu_mode = MAINID_CREATE_OUTPUT;
    62                          file_output( );
    63                          break;
    64                  }
    65          } else {
    66              term_no = old_term;
    67              base.date = old_date;
    68          }
    69  
    70          xv_set( base_frame, FRAME_BUSY, FALSE, NULL );
    71          return XV_OK;
    72  }

リスト9−4 修正版 構造体の宣言
     1  typedef struct  {
     2      char        year[2];                /* 年 */
     3      char        month[2];               /* 月 */
     4      char        day[2];                 /* 日 */
     5      char        hour[2];                /* 時 */
     6      char        minute[2];              /* 分 */
     7      char        second[2];              /* 秒 */
     8  } DATE;


Copyright1996 Hirofumi Fujiwara. No reproduction or republication without written permission
『Cプログラミング診断室』目次次(第9章 珠玉の力作 文字列処理)