K&R演習[1-21]

課題

ブランクの列を同じスペーシングをお粉う最小の数のタブおよびブランクで置き換えるプログラムentabを書け。

回答

#include <stdio.h>
#include <string.h>

typedef unsigned long int u8;
const int TAB_WIDTH = 8;        // タブ幅
void detab(u8 n, char *rslt);
void entab(char *str, char c, u8 *space_pos, u8 *cnt_space, u8 *cnt_str, u8 *cnt_org);

/**
 * @fn      Main
 * @brief
 * @param
 * @return
 * @detail
 */
int main(void)
{
    int c;
    u8 cnt_org = 0, cnt_str = 0, space_pos = 0, cnt_space;
    char str[1000];

    while ((c = getchar()) != EOF) {        // 改行まで入力を取得する
        switch (c) {
            case ' ':                       // 空白なら
                entab(str, c, &space_pos, &cnt_space, &cnt_str, &cnt_org);
                break;

            case '\n':                      // 改行なら
                str[cnt_str++] = '\n';      // コピーする
                str[cnt_str]   = '\0';      // 終端とする
                printf("%s", str);          // 印字する
                
                {
                    int i;
                    for (i = 0; i <= cnt_str; i++) {
                        printf("%2d:%c(0x%x)\n", i, str[i], str[i]);
                    }
                }

                // 次に備えて初期化
                cnt_org = 0;
                cnt_str = 0;    
                break;

            // タブ、改行以外の文字
            default:
                str[cnt_str++] = c;
                break;
        }
        cnt_org++;
    }
}

/**
 *  @fn     entab
 *  @breif  スペースだけを受け取る前提で、それをタブとスペースに置き換える
 *  @param  space_pos = スペース発見位置
            cnt_space = スペース連続回数
            cnt_str   = strの格納位置
            cnt_org   = 入力文字の計測回数
 *  @return
 *  @detail
 */

void entab(char *str, char c, u8 *space_pos, u8 *cnt_space, u8 *cnt_str, u8 *cnt_org)
{
    if (*space_pos == 0) {      // スペース未発見なら
        *space_pos = *cnt_org;  // スペース発見位置を記録
    }
    if ((++(*cnt_space) >= 2) &&    // スペースが連続しており
        (((*cnt_org + 1) % TAB_WIDTH) == 0)) {  // タブストップまで達していたら
        str[*space_pos] = '\t';                 // タブを記録
        memset(str + *space_pos + 1, ' ', TAB_WIDTH - *space_pos - 1);  // 次のタブストップまでは空白にする
        *cnt_str = *cnt_org;
    } else {
        str[(*cnt_str)++] = c;
    }


}

実行内容

uy      ew

実行結果

uy           ew
 0:u(0x75)
 1:y(0x79)
 2:     (0x9)
 3: (0x20)
 4: (0x20)
 5: (0x20)
 6: (0x20)
 7: (0x20)
 8:e(0x65)
 9:w(0x77)
10:
(0xa)
11: