MacOSXにGnu indentをインストール

はじめに

MacOSX標準のindentコマンドに、K&Rスタイルがないよー

とあるオープンソースのプロジェクトのソースコードを、ローカルのMacBookにチェックアウトしてしばらく眺めていたところ、スペースやらインデントやらが非常に適当な見づらいソースコードがあったため、indentコマンドでソースコードをフォーマットしてやれ!!と思ったのが、気づいたきっかけ。

前提

ローカルの環境

  • UTF8
  • タブ幅は4
  • タブはスペースに変換しない

調査

MacOSX標準でインストールされているindentコマンドは、manを見る限りBSD由来のものでオプションにK&Rスタイルが用意されていないことがわかった。

$ man indent
INDENT(1)                 BSD General Commands Manual                INDENT(1)

NAME
     indent -- indent and format C program source

SYNOPSIS
     indent [input_file [output_file]] [-bacc | -nbacc] [-bad | -nbad] [-bap | -nbap] [-bbb | -nbbb] [-bc | -nbc] [-bl] [-br] [-cn]
            [-cdn] [-cdb | -ncdb] [-ce | -nce] [-cin] [-clin] [-dn] [-din] [-fc1 | -nfc1] [-in] [-ip | -nip] [-ln] [-lcn]
            [-lp | -nlp] [-npro] [-pcs | -npcs] [-psl | -npsl] [-sc | -nsc] [-sob | -nsob] [-st] [-troff] [-v | -nv]
(...)
HISTORY
     The indent command appeared in 4.2BSD.

BUGS
     indent has even more switches than ls(1).

     A common mistake that often causes grief is typing:

           indent *.c

     to the shell in an attempt to indent all the C programs in a directory.  This is probably a bug, not a feature.

BSD                              June 29, 2004                             BSD

何となく、MacPortsでindentを探してみる

$ port search indent
indent @2.2.10 (devel)
    C language source code formatting program
$ port info indent
indent @2.2.10 (devel)
Variants:             universal

Description:          GNU indent changes the appearance of a C program by inserting or deleting whitespace according to a plethora of options. Some
                      canned styles of formatting are supported as well. GNU indent is a descendant of BSD indent. GNU indent does NOT work for C++,
                      only C.
Homepage:             http://www.gnu.org/software/indent/

Library Dependencies: gettext, libiconv
Platforms:            darwin
License:              unknown
Maintainers:          nomaintainer@macports.org

インストール

Gnu indentなら間違いなくK&Rスタイルは用意されているはずと思ってインストール

port install indent

インストールされたものがどこにあるかは下記のコマンドで確認できる

$ port contents indent
Port indent contains:
  /opt/local/bin/gnuindent
  /opt/local/bin/gnutexinfo2man
  /opt/local/share/doc/indent/indent.html
  /opt/local/share/info/indent.info
  /opt/local/share/locale/ca/LC_MESSAGES/indent.mo
  /opt/local/share/locale/da/LC_MESSAGES/indent.mo
  /opt/local/share/locale/de/LC_MESSAGES/indent.mo
  /opt/local/share/locale/eo/LC_MESSAGES/indent.mo
  /opt/local/share/locale/et/LC_MESSAGES/indent.mo
  /opt/local/share/locale/fi/LC_MESSAGES/indent.mo
  /opt/local/share/locale/fr/LC_MESSAGES/indent.mo
  /opt/local/share/locale/gl/LC_MESSAGES/indent.mo
  /opt/local/share/locale/hu/LC_MESSAGES/indent.mo
  /opt/local/share/locale/it/LC_MESSAGES/indent.mo
  /opt/local/share/locale/ja/LC_MESSAGES/indent.mo
  /opt/local/share/locale/ko/LC_MESSAGES/indent.mo
  /opt/local/share/locale/nl/LC_MESSAGES/indent.mo
  /opt/local/share/locale/pl/LC_MESSAGES/indent.mo
  /opt/local/share/locale/pt_BR/LC_MESSAGES/indent.mo
  /opt/local/share/locale/ru/LC_MESSAGES/indent.mo
  /opt/local/share/locale/sk/LC_MESSAGES/indent.mo
  /opt/local/share/locale/sv/LC_MESSAGES/indent.mo
  /opt/local/share/locale/tr/LC_MESSAGES/indent.mo
  /opt/local/share/locale/zh_TW.Big5/LC_MESSAGES/indent.mo
  /opt/local/share/man/man1/gnuindent.1.gz

MacPortsでインストールされたコマンドはgnuindentなので、manでオプションを確認してみる

$ man gnuindent
INDENT(1L)                                                                                                                 INDENT(1L)

NAME
       indent - changes the appearance of a C program by inserting or deleting whitespace.

SYNOPSIS
       indent [options] [input-files]

       indent [options] [single-input-file] [-o output-file]

       indent --version
(...)
       -ipn, --parameter-indentationn
           Indent parameter types in old-style function definitions by n spaces.
           See  INDENTATION.

       -kr, --k-and-r-style                       #<= 目的のオプションはこれ
           Use Kernighan & Ritchie coding style.
           See  COMMON STYLES.

       -ln, --line-lengthn
           Set maximum line length for non-comment lines to n.
           See  BREAKING LONG LINES.
(...)

試す

下記にこれはひどいというソースコードを用意してみました。

#include <stdio.h>
#include <stdlib.h>

typedef enum {
	SUN,
	MON,
	TUE,
WED,
	THU,
FRI,
SAT
	} Week_t;


typedef struct {
	int year;
int month;
	int day;
 Week_t w;
}   Date_t;


void setdate(Date_t * dt, int y, int m,int d) {
	dt->year=y, dt->month = m, dt->day =d;
}

Week_t dayofweek(int y, int m,int d) {
	if(m <3) {
		y--;
m+=12;
}
	return (Week_t)((y + y/4-y/100+y/400+(13*m+8)/5+d)%7);
}

int main(int argc,char** argv) {
	int i =0;
	Date_t dt[3];
	int ymd[][3] = {
		{2010,1,1,},
	{1999,12,31,},
{2004,8,1,},
	};

	char wstr[][12] = {
	"Sunday","Monday","Tuesday",
	"Wednesday", "Thursday", "Friday",
"Saturday",
	};

	for (i=0; i<3;i++) setdate(&dt[i], ymd[i][0], ymd[i][1], ymd[i][2]);
	for(i=0;i<3;i++) 
	dt[i].w =dayofweek(dt[i].year,dt[i].month, dt[i].day);


	i=0;
	do {
	printf("It's %s (%d.%d.%d).\n", wstr[dt[i].w], dt[i].year, dt[i].month,dt[i].day);
	i++;
} while (i<3);
	return EXIT_SUCCESS;
}

こんなひどいソースコードを、Gnu indentはいとも簡単に読みやすくフォーマットしてくれます。

K&Rスタイルにフォーマット
$ gnuindent -kr -ts4 hoge.c    #<= K&Rスタイルで、タブ幅4を指定
#include <stdio.h>
#include <stdlib.h>

typedef enum {
	SUN,
	MON,
	TUE,
	WED,
	THU,
	FRI,
	SAT
} Week_t;


typedef struct {
	int year;
	int month;
	int day;
	Week_t w;
} Date_t;


void setdate(Date_t * dt, int y, int m, int d)
{
	dt->year = y, dt->month = m, dt->day = d;
}

Week_t dayofweek(int y, int m, int d)
{
	if (m < 3) {
		y--;
		m += 12;
	}
	return (Week_t) ((y + y / 4 - y / 100 + y / 400 + (13 * m + 8) / 5 +
					  d) % 7);
}

int main(int argc, char **argv)
{
	int i = 0;
	Date_t dt[3];
	int ymd[][3] = {
		{2010, 1, 1,},
		{1999, 12, 31,},
		{2004, 8, 1,},
	};

	char wstr[][12] = {
		"Sunday", "Monday", "Tuesday",
		"Wednesday", "Thursday", "Friday",
		"Saturday",
	};

	for (i = 0; i < 3; i++)
		setdate(&dt[i], ymd[i][0], ymd[i][1], ymd[i][2]);
	for (i = 0; i < 3; i++)
		dt[i].w = dayofweek(dt[i].year, dt[i].month, dt[i].day);


	i = 0;
	do {
		printf("It's %s (%d.%d.%d).\n", wstr[dt[i].w], dt[i].year,
			   dt[i].month, dt[i].day);
		i++;
	} while (i < 3);
	return EXIT_SUCCESS;
}

自分でコードをできるだけ素早く書きたいという時でも、indentコマンドが威力を発揮します。