MacOSXにGnu 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コマンドが威力を発揮します。