OSDN Git Service

support/genmancfg.sh: 新規追加。
[linuxjm/jm.git] / support / genmancfg.sh
1 #!/bin/bash
2
3 # 概要
4 #   本スクリプトは po4a の cfg ファイルと対応する Makefile を自動生成します。
5 #   これに伴って関連ファイルも自動生成します。処理にあたっては original ディ
6 #   レクトリ配下に original/man[0-9n]/* という、翻訳対象のオリジナル man ページ
7 #   が配置済みであることが必要です。
8 #
9 #   生成ファイル
10 #     po4a{,/man[0-9n]}/<package name>.cfg:
11 #               po4a の cfg ファイル               (上書き生成)
12 #     Makefile: cfg ファイルを処理する Makefile        (上書き生成)
13 #     translation_list.tmp:
14 #               translation_list 相当の初期テンプレートファイル
15 #                                               (上書き生成)
16 #     po4a/add_ja/copyright/man[0-9n]/<manpage name>.[0-9n].txt:
17 #               いわゆる"copyright"ファイル     (上書きはしない)
18 #     def.mk:   パッケージ情報を提供するためのファイル
19 #               非存在時にはエラー終了しテンプレートを生成する。
20 #               テンプレート内容を適切に書き換えて再実行する。
21 #
22 # 使用方法
23 #   翻訳パッケージディレクトリ (jm.git/manual/<package name>) にて実行。
24 #   (manual ディレクトリと同列の support ディレクトリに本スクリプトを配置
25 #    しており、相対パスで本スクリプトを実行することを前提とする)
26 #
27 #   $ cd jm.git/manual/<package name>
28 #   $ ../../support/genmancfg.sh [options]
29 #
30 #   オプションは genmancfg.sh -h の出力を参照してください。
31 #   ほとんどのオプションは、処理に必要となる名称等を指定するものです。
32 #   その中で重要なものが -m または -o であり、これは処理タイプを指定します。
33 #   以下に説明。
34 #
35 # 本スクリプトにおける処理タイプ
36 #   処理にあたっては二種類の po4a 処理タイプに対応します。
37 #   デフォルト(-m, -o の未指定時) は -m (multi) です。
38 #   常時これにしておいて (オプション未指定で) 問題はありません。
39 #
40 #   これを用いる必要があるケースとして upstream がたった一つの po ファイルを
41 #   提供していることがあり、それと同調して(upstream への提供も考慮して)
42 #   たった一つの po ファイルとしたい場合に -o (one) を指定します。
43 #
44 # TYPE=one:
45 #   1つめは処理タイプ one (オプション -o 指定時) です。
46 #   original ディレクトリ配下の man ページソースに対応づく ja.po を1つだけ作るタイプです。
47 #
48 #   (top) --+--original--+--man1
49 #           |            +--man3
50 #           |            +--man5
51 #           +--po4a--+--<package name>.cfg
52 #                    +--<package name>.pot
53 #                    +--ja.po
54 #
55 # TYPE=multi:
56 #   2つめは処理タイプ multi (オプション -m 指定時; オプション未指定時の
57 #   デフォルト) です。
58 #   original ディレクトリ配下のサブディレクトリ構造 (man1, man3 など) に合わせて
59 #   そのサブディレクトリごとに man1/ja.po, man3/ja.po などを分割して作るタイプです。
60 #
61 #   (top) --+--original--+--man1
62 #           |            +--man3
63 #           |            +--man5
64 #           +--po4a--+--man1--+--<package name>-man1.cfg
65 #                    |        +--<package name>-man1.pot
66 #                    |        +--ja.po
67 #                    +--man3--+--<package name>-man3.cfg
68 #                    |        +--<package name>-man3.pot
69 #                    |        +--ja.po
70 #                    +--man5--+--<package name>-man5.cfg
71 #                             +--<package name>-man5.pot
72 #                             +--ja.po
73 #
74 # ----------
75
76 THISARGS=$*
77 THISDATE=`date '+%F'`
78 THISTOOL=`basename $0`
79
80 # 処理タイプを表す変数 TYPE に multi をデフォルト設定する。
81 # これはオプション引数 -m の指定時に採用されるタイプである。
82 # オプション引数 -o の指定時には one が設定される。
83 TYPE=multi
84
85 # オプション -h 指定時のヘルプ表示(関数)
86 usage() {
87   echo "Usage: genmancfg.sh [options]"
88   echo "  Create po4a config file as TYPE as follows, in po4a directory."
89   echo "  This requires the original man sources under the \"original\" directory."
90   echo ""
91   echo "  options:"
92   echo "  -o:     TYPE=one;   for creating only one po file."
93   echo "  -m:     TYPE=multi; for creating po files per man sections [default]."
94   echo "  -n STR: name of the package [default: basename of the current directory]."
95   echo "  -d STR: release date of the package [default: \"YYYY/MM/DD\"]."
96   echo "  -v STR: version of the package [default: \"x.xx\"]."
97   echo "  -u STR: user name [default: git config --get user.name if exists]."
98   echo "  -e STR: email address [default: git config --get user.email if exists]."
99   echo "  -U "STR,..": list of commands untranslated [default: ""]."
100   echo "  -h:     print this help."
101   exit 0
102 }
103
104 # 以下の変数をそれぞれ定める。
105 #    PACKAGE_NAME: パッケージ名
106 #    PACKAGE_VER:  パッケージバージョン
107 #    PACKAGE_DATE: パッケージのリリース日付 ("YYYY/MM/DD" 形式)
108 # これらは def.mk ファイル内に同名変数定義が行われていれば、それを参照して定める。
109 # def.mk ファイルが存在しない場合、def.mk のひながたファイルを出力して終了する。
110 # 上の設定値はそれぞれ、オプション -n (パッケージ名)、-v (バージョン)、-d (リリース
111 # 日付) により上書き設定できる。
112 if test -f def.mk; then
113   PACKAGE_NAME=`grep "PACKAGE_NAME" def.mk | sed -e "s/.*[ ]*=[ ]*\(.*\)$/\1/"`
114   PACKAGE_VER=`grep "PACKAGE_VER" def.mk | sed -e "s/.*[ ]*=[ ]*\(.*\)$/\1/"`
115   PACKAGE_DATE=`grep "PACKAGE_DATE" def.mk | sed -e "s/.*[ ]*=[ ]*\(.*\)$/\1/"`
116 else
117   echo "Error: def.mk not found so newly created;"
118   echo " process again after editting it correctly."
119   cat > def.mk <<"EOF"
120 PACKAGE_NAME    = sample_package
121 PACKAGE_VERSION = x.xx
122 PACKAGE_DATE    = YYYY/MM/DD
123 EOF
124   exit 1
125 fi
126
127 # 当プロジェクトで用いている copyright ファイルに、ユーザー名とメールアドレス
128 # を書き入れるため、そのデフォルト値を git config の user.{name,email} から設定する。
129 # git config から取得できなかった場合は、それぞれ "TRANSLATOR NAME", "EMAIL@ADDRESS"
130 # とする。これはオプション -u (user name), -e (email address) により指定できる。
131 # (なおメールアドレスが正しい書式を有しているかどうかは確認しない。)
132 # これらは translation_list の出力項目にも利用する。
133 USERNAME=`git config --get user.name 2>/dev/null || echo "TRANSLATOR NAME"`
134 EMAILADDR=`git config --get user.email 2>/dev/null || echo "EMAIL@ADDRESS"`
135
136 # po4a cfg の "-o untranslated=xxxxxxx" に指定したいコマンドを
137 # オプション -U によって指定できるようにしているため、そのオプション値を
138 # 保持するための以下の変数 UNTRANS_INIT をここで初期化する。
139 # 下述の $OPT 処理文の中で、オプション -U が指定されていれば設定される。
140 # roff コマンドの先頭のピリオドは省く。複数指定する場合はカンマで区切る。
141 # 指定方法を誤ってもエラー処理は行わない。po4a 処理においてエラーとなるのみ。
142 UNTRANS_INIT=""
143
144 # オプション引数を走査して、前述までの各変数を定める。
145 # 処理タイプは、変数 TYPE に対応値 (one か multi か) を設定する。
146 # オプション -h 指定時はヘルプ表示、無効なオプション指定時はエラーとする。
147 while getopts :omn:d:v:u:e:U:h OPT; do
148   case $OPT in
149      o) TYPE=one;;
150      m) TYPE=multi;;
151      n) PACKAGE_NAME="$OPTARG";;
152      d) RELEASEDATE="$OPTARG";;
153      v) VERSION="$OPTARG";;
154      u) USERNAME="$OPTARG";;
155      e) EMAILADDR="$OPTARG";;
156      U) UNTRANS_INIT="$OPTARG";;
157      h) usage;;
158      *) echo "Illegal option: $OPT"; exit 1;;
159   esac
160 done
161
162 # original ディレクトリ配下に original/man[0-9n] のようなサブディレクトリが
163 # 存在するかどうかをチェックする。この構成でなければエラー終了する。
164 if ! ls original/man[0-9n] >/dev/null 2>&1; then
165   echo "Error: Not exists the original directory or"
166   echo "       not contains man[0-9n] subdirectories."
167   exit 1
168 fi
169
170 # カレントディレクトリ直下に po4a ディレクトリ生成
171 mkdir -p po4a
172
173 # po4a cfg ファイル内の各処理行に対するオプション指定追加処理
174 # $d, $f, $CFG_NAME などの変数は、上位処理のものを用いる。
175 #   $d: man ページディレクトリ名; man1, man3 など。
176 #   $f: man ファイル名; gcc.1, acl_check.3 など。
177 #   $CFG_NAME: 出力 cfg 名; gcc-man1.cfg など。
178 opt_proc_man() {
179
180   # (1) groff_code=verbatim 処理
181
182   # "-o groff_code=verbatim" を宣言すべき roff コマンド候補リストを定義する。
183   # (grep に直接受け渡すため、各コマンド(先頭ピリオド除く)を | (縦棒) で区切る。)
184   GROFF_CANDIDATES="de|ie"
185
186   # 上のコマンド候補リストがカレントな man ファイルに含まれているか
187   # どうかを grep 検索し、該当していれば cfg ファイルに
188   # "-o groff_code=verbatim" の宣言を出力する。
189   grep "^\.[$GROFF_CANDIDATES]" original/$d/$f >/dev/null 2>&1
190   if test $? -eq 0; then
191     echo -ne " \\\\\n\topt:\"-o groff_code=verbatim\"" >> $CFG_NAME
192   fi
193
194   # (2) generated 処理
195
196   # "-o generated" を宣言すべき記述候補リストを定義する。
197   GENERATED_CANDIDATES=(
198     "DO NOT EDIT"
199     "DO NOT MODIFY THIS FILE"
200     "It is generated"
201     "Man page generated from reStructuredText."
202     "Automatically generated by Pod::Man"
203     "\.\\\\\"Text automatically generated by"
204   )
205
206   # 上の記述候補リストのそれぞれがカレントな man ファイルに
207   # 含まれているかどうかを順に grep 検索して、含まれていれば cfg ファイルに
208   # "-o generated" の宣言を出力する。
209   GENERATED=0
210   for m in "${GENERATED_CANDIDATES[@]}"; do
211     grep "$m" original/$d/$f >/dev/null 2>&1
212     if test $? -eq 0; then
213       GENERATED=1; break
214     fi
215   done
216   if test $GENERATED -eq 1; then
217     echo -ne " \\\\\n\topt:\"-o generated\"" >> $CFG_NAME
218   fi
219
220   # (3) untranslated 処理
221
222   # "-o untranslated" を宣言すべきコマンド候補リストを定義する。
223   UNTRANS_CANDIDATES="\.\. \.\\\\} 'br\\\\} \.als \.bP \.cp \.de1 \.do \.el \.el\\\\{. \.FT \.ie \.INDENT \.LI \.MTO \.NE \.NOP \.NS \.PE \.PS \.Quoted \.rm \.rr \.Sp \.Vb \.UNINDENT \.Ve \.Xw"
224
225   # 上のコマンド候補リストのそれぞれがカレントな man ファイルに
226   # 含まれているかどうかを順に grep 検索して、含まれていれば cfg ファイルに
227   # "-o untranslated=XX,YY,ZZ,..." の宣言を出力する。
228   UNTRANS=
229   for u in $UNTRANS_CANDIDATES; do
230
231     grep "^$u" original/$d/$f >/dev/null 2>&1
232     if test $? -eq 0; then
233       if test -z "$UNTRANS"; then
234         UNTRANS="\\\\\n\topt:\"-o untranslated="
235       else
236         UNTRANS="$UNTRANS,"
237       fi
238       CMD=`echo $u | sed "s/^\\\\\.//g"`
239       if test "$CMD" = "\."; then
240         CMD="."
241       fi
242       case $CMD in
243         \'br\\*) CMD=`echo $CMD\' | sed "s/^\'//"`;;
244         *\\*) CMD="'$CMD'";;
245       esac
246
247       UNTRANS="$UNTRANS$CMD"
248     fi
249   done
250
251   # オプション引数 -U によりコマンドラインから untranslated 対象が指定されて
252   # いれば "-o untranslated=" 行に追加する。
253   if test "$UNTRANS_INIT" != ""; then
254     if test -z "$UNTRANS"; then
255       UNTRANS="\\\\\n\topt:\"-o untranslated="
256     else
257       UNTRANS=$UNTRANS,
258     fi
259     UNTRANS=$UNTRANS$UNTRANS_INIT
260   fi
261
262   # untranslated 指定対象が存在していれば cfg ファイルに指定行を出力する。
263   if test -n "$UNTRANS"; then
264     echo -ne " $UNTRANS\"" >> $CFG_NAME
265   fi
266
267   echo >> $CFG_NAME # 最終改行調整
268 }
269
270 # cfg 生成処理 (TYPE=one, multi 共通)
271 #  (copyright ファイルも同時生成する。)
272 create_cfg() {
273
274   echo "Creating cfg file:" # 処理進捗出力
275
276   # TYPE=one である場合、cfg ファイルは1つのみをここで作り始める。
277   if test $TYPE = one; then
278     CFG_NAME=po4a/$PACKAGE_NAME.cfg
279     echo "# Created by $THISTOOL, $THISDATE," > $CFG_NAME
280     echo "# with argument(s): $THISARGS" >> $CFG_NAME
281     echo "[po4a_langs] ja" >> $CFG_NAME
282     echo "[po4a_paths] po4a/$PACKAGE_NAME.pot \$lang:po4a/\$lang.po" >> $CFG_NAME
283     echo "[po4a_alias: man] man opt:\"-v --previous\" opt_ja:\"-M UTF-8\"" >> $CFG_NAME
284   fi
285
286   # original 配下の man[0-9n] サブディレクトリ $d について
287   for d in `cd original; ls -d man[0-9n]`; do
288
289     echo -n "  $d: " # 処理進捗出力
290
291     # TYPE=multi である場合、cfg ファイルを man[0-9n] ごとにここから生成する。
292     if test $TYPE = multi; then
293       mkdir -p po4a/$d
294       CFG_NAME=po4a/$d/$PACKAGE_NAME-$d.cfg
295       echo "# Created by $THISTOOL, $THISDATE," > $CFG_NAME
296       echo "# with argument(s): $THISARGS" >> $CFG_NAME
297       echo "[po4a_langs] ja" >> $CFG_NAME
298       echo "[po4a_paths] po4a/$d/$PACKAGE_NAME-$d.pot \$lang:po4a/$d/\$lang.po" >> $CFG_NAME
299       echo "[po4a_alias: man] man opt:\"-v --previous\" opt_ja:\"-M UTF-8\"" >> $CFG_NAME
300     fi
301
302     # original/man[0-9n]  配下の各ファイル $f について
303     for f in `cd original/$d; ls *`; do
304
305       echo -n "." # 処理進捗出力
306
307       # ファイルがシンボリックリンクである場合
308       if test -L original/$d/$f; then
309         : # シンボリックリンクは処理しない
310       else
311         LINECNT=`grep -v '^\.\\\"' original/$d/$f 2>/dev/null | wc -l | gawk -F" " '{print $1}'`
312         SOLINE=`grep -v '^\.\\\"' original/$d/$f 2>/dev/null | sed -n "/^\.so.*/p"`
313
314         # ファイルが ".so manN/*.N" の形式である場合
315         if ( test $LINECNT = "0" || test $LINECNT = "1" ) && test -n "$SOLINE"; then
316           : # .so 1行構成のものは処理しない
317         else
318
319           # ファイルが通常の場合 (シンボリックリンクや .so 形式でない場合) cfg 処理行を出力する。
320           echo >>$CFG_NAME
321           echo     "[type: man] original/$d/$f \$lang:release/$d/$f \\">>$CFG_NAME
322           echo -ne "\tadd_\$lang:?po4a/add_\$lang/copyright/$d/$f.txt">>$CFG_NAME
323
324           # po4a の処理設定各行においてオプション指定行を出力する。
325           opt_proc_man
326
327           # copyright ファイルの生成 (非存在時のみ)
328           if test -f po4a/add_ja/copyright/$d/$f.txt; then
329             : # 存在時は何もしない (上書き生成しない)
330           else
331             # 対象ディレクトリ生成
332             mkdir -p po4a/add_ja/copyright/$d
333
334             # コマンド .TH または .Dd が存在するかどうかを取得する。
335             FIRST=`grep "^\.TH" original/$d/$f >/dev/null 2>&1 && echo "^.TH"`
336             if test -z $FIRST; then
337               FIRST=`grep "^\.Dd" original/$d/$f >/dev/null 2>&1 && echo "^.Dd"`
338             fi
339
340             # 上で .TH または .Dd が取得できなかった場合は先頭行を取得。
341             if test $FIRST != "^.TH" && test $FIRST != "^.Dd"; then
342               FIRST=`head -1 original/$d/$f`
343             fi
344
345             # copyright ファイルのひながたを出力
346             cat > po4a/add_ja/copyright/$d/$f.txt <<"EOF"
347 PO4A-HEADER: mode=before; position=__FIRST__
348 .\"
349 .\" Translated __DATE__
350 .\"    by __USERNAME__ <__EMAILADDR__>
351 .\"
352 EOF
353             # 上記生成ファイルに対して変数部分を置換する。
354             sed -i -e "s/__FIRST__/$FIRST/" \
355                    -e "s/__DATE__/$THISDATE/" \
356                    -e "s/__USERNAME__/$USERNAME/" \
357                    -e "s/__EMAILADDR__/$EMAILADDR/" \
358                 po4a/add_ja/copyright/$d/$f.txt
359           fi
360         fi
361       fi
362     done
363
364     echo # 処理進捗出力 (最終改行)
365   done
366 }
367
368 # TYPE=one 用の Makefile 生成処理
369 makefile_one() {
370   cat > Makefile.tmp <<"EOF"
371 PACKAGE_NAME = __PACKAGE_NAME__
372
373 THRESH = 0
374 EXTFLAGS =
375 PO4AFLAGS += -k $(THRESH) $(EXTFLAGS)
376 PO4ACFG = po4a/$(PACKAGE_NAME).cfg
377 POFILE  = po4a/ja.po
378
379 all: translate
380
381 translate:
382         po4a $(PO4AFLAGS) $(PO4ACFG)
383
384 stat:
385         @msgfmt -v --statistics -o /dev/null $(POFILE)
386
387 page-stat:
388         @echo $(POFILE):
389         @po4a --force --no-update -k 0 $(PO4ACFG)
390
391 .PHONY: translate stat page-stat
392 EOF
393   sed -e "s/__PACKAGE_NAME__/$PACKAGE_NAME/" Makefile.tmp >Makefile
394   rm -f Makefile.tmp
395 }
396
397 # TYPE=one 用の Makefile 生成処理
398 makefile_multi() {
399   cat > Makefile.tmp <<"EOF"
400 PACKAGE_NAME = __PACKAGE_NAME__
401 man_numbers = __MAN_NUMBERS__
402
403 THRESH = 0
404 EXTFLAGS =
405 PO4AFLAGS += -k $(THRESH) $(EXTFLAGS)
406
407 target-mans = $(addprefix man,$(man_numbers))
408 po_dirs     = $(addprefix po4a/,$(target-mans))
409 po_files    = $(addsuffix /ja.po,$(po_dirs))
410
411 all: translate
412
413 translate: $(target-mans)
414
415 $(target-mans): man%:
416         po4a $(PO4AFLAGS) po4a/man$*/$(PACKAGE_NAME)-man$*.cfg
417
418 stat:
419         @for po in $(po_files); do \
420           msgfmt -v --statistics -o /dev/null $$po; \
421         done
422
423 page-stat:
424         @for n in $(man_numbers); do \
425           if test -f po4a/man$$n/$(PACKAGE_NAME)-man$$n.cfg; then \
426             echo po4a/man$$n/$(PACKAGE_NAME)-man$$n.cfg: ;\
427             po4a --force --no-update -k 0 po4a/man$$n/$(PACKAGE_NAME)-man$$n.cfg | \
428               sed "s/^/  /g" ;\
429           fi \
430         done
431
432 .PHONY: all translate stat page-stat
433 EOF
434   MAN_NUMBERS=`cd original; ls -dm man[0-9n] | sed -e "s/,//g" -e "s/man//g"`
435   sed -e "s/__PACKAGE_NAME__/$PACKAGE_NAME/" \
436       -e "s/__MAN_NUMBERS__/$MAN_NUMBERS/" \
437     Makefile.tmp >Makefile
438   rm -f Makefile.tmp
439 }
440
441 # メイン処理
442 # 変数 TYPE の設定に応じて、それぞれの処理を行う。
443 # これによって TYPE に応じた cfg ファイル、Makefile を生成する。
444 case $TYPE in
445   one)   create_cfg; makefile_one;;    # TYPE=one の場合の処理
446   multi) create_cfg; makefile_multi;;  # TYPE=multi の場合の処理
447 esac
448
449 # translation_list.tmp 生成処理
450 rm -f translation_list.tmp
451
452 echo "Creating translation_list.tmp file:" # 処理進捗出力
453
454 # original 配下の man[0-9n] サブディレクトリ $d について
455 for d in `cd original; ls -d man[0-9n]`; do
456
457   echo -n "  $d: " # 処理進捗出力
458
459   # original/man[0-9n]  配下の各ファイル $f について
460   for f in `cd original/$d; ls *`; do
461
462     echo -n "." # 処理進捗出力
463
464     # ファイルがシンボリックリンクである場合
465     if test -L original/$d/$f; then
466       LINK=1
467       LINK_ITEM=`readlink original/$d/$f | sed -e "s|\(.*\)\.\([1-9].*\)|\1:\2|"`
468       echo -n "※:" >>translation_list.tmp # 決め打ちで "※" 出力; "@"(リンク先翻訳済み)かどうかは判断できない。
469     else
470       LINECNT=`grep -v '^\.\\\"' original/$d/$f 2>/dev/null | wc -l | gawk -F" " '{print $1}'`
471       SOLINE=`grep -v '^\.\\\"' original/$d/$f 2>/dev/null | sed -n "/^\.so .*/p"`
472
473       # ファイルが ".so manN/*.N" の形式である場合
474       if ( test $LINECNT = "0" || test $LINECNT = "1" ) && test -n "$SOLINE"; then
475         LINK=1
476         LINK_ITEM=`echo $SOLINE | sed "s|^\.so man\([0-9n]\)/\(.*\)\..*|\2:\1|"`
477         echo -n "※:" >>translation_list.tmp # 決め打ちで "※" 出力; "@"(リンク先翻訳済み)かどうかは判断できない。
478       else
479         # ファイルが通常の場合 (シンボリックリンクや .so 形式でない場合)
480         LINK=0
481         echo -n "▲:" >>translation_list.tmp # 決め打ちで "▲" 出力; "■"(改訂予約)などかどうかは判断できない。
482       fi
483     fi
484
485     man_sect=`echo $d | sed "s/man//"`
486     man_base=`echo $f | sed 's/^\(.*\)\.[^\.]*$/\1/'`
487
488     # translation_list 用に本日日付を再定義
489     THISDATE=`date '+%Y/%m/%d'`
490
491     # リンク情報かどうか (LINK 値) の違いを切り分けて translation_list 行を出力する。
492     if test $LINK = "0"; then
493       echo "$PACKAGE_NAME:$PACKAGE_VER:$PACKAGE_DATE:$man_base:$man_sect:$THISDATE::$EMAILADDR:$USERNAME:" \
494         >>translation_list.tmp
495     else
496       echo "$PACKAGE_NAME:$PACKAGE_VER:$PACKAGE_DATE:$man_base:$man_sect:$LINK_ITEM" \
497         >>translation_list.tmp
498     fi
499   done
500
501   echo # 処理進捗出力 (最終改行)
502 done
503
504 exit 0