OSDN Git Service

support/genmancfg.sh: 新規追加。
[linuxjm/jm.git] / support / genmancfg.sh
diff --git a/support/genmancfg.sh b/support/genmancfg.sh
new file mode 100755 (executable)
index 0000000..a8e5241
--- /dev/null
@@ -0,0 +1,504 @@
+#!/bin/bash
+
+# 概要
+#   本スクリプトは po4a の cfg ファイルと対応する Makefile を自動生成します。
+#   これに伴って関連ファイルも自動生成します。処理にあたっては original ディ
+#   レクトリ配下に original/man[0-9n]/* という、翻訳対象のオリジナル man ページ
+#   が配置済みであることが必要です。
+#
+#   生成ファイル
+#     po4a{,/man[0-9n]}/<package name>.cfg:
+#              po4a の cfg ファイル               (上書き生成)
+#     Makefile:        cfg ファイルを処理する Makefile        (上書き生成)
+#     translation_list.tmp:
+#              translation_list 相当の初期テンプレートファイル
+#                                              (上書き生成)
+#     po4a/add_ja/copyright/man[0-9n]/<manpage name>.[0-9n].txt:
+#              いわゆる"copyright"ファイル     (上書きはしない)
+#     def.mk:  パッケージ情報を提供するためのファイル
+#              非存在時にはエラー終了しテンプレートを生成する。
+#              テンプレート内容を適切に書き換えて再実行する。
+#
+# 使用方法
+#   翻訳パッケージディレクトリ (jm.git/manual/<package name>) にて実行。
+#   (manual ディレクトリと同列の support ディレクトリに本スクリプトを配置
+#    しており、相対パスで本スクリプトを実行することを前提とする)
+#
+#   $ cd jm.git/manual/<package name>
+#   $ ../../support/genmancfg.sh [options]
+#
+#   オプションは genmancfg.sh -h の出力を参照してください。
+#   ほとんどのオプションは、処理に必要となる名称等を指定するものです。
+#   その中で重要なものが -m または -o であり、これは処理タイプを指定します。
+#   以下に説明。
+#
+# 本スクリプトにおける処理タイプ
+#   処理にあたっては二種類の po4a 処理タイプに対応します。
+#   デフォルト(-m, -o の未指定時) は -m (multi) です。
+#   常時これにしておいて (オプション未指定で) 問題はありません。
+#
+#   これを用いる必要があるケースとして upstream がたった一つの po ファイルを
+#   提供していることがあり、それと同調して(upstream への提供も考慮して)
+#   たった一つの po ファイルとしたい場合に -o (one) を指定します。
+#
+# TYPE=one:
+#   1つめは処理タイプ one (オプション -o 指定時) です。
+#   original ディレクトリ配下の man ページソースに対応づく ja.po を1つだけ作るタイプです。
+#
+#   (top) --+--original--+--man1
+#           |            +--man3
+#           |            +--man5
+#           +--po4a--+--<package name>.cfg
+#                    +--<package name>.pot
+#                    +--ja.po
+#
+# TYPE=multi:
+#   2つめは処理タイプ multi (オプション -m 指定時; オプション未指定時の
+#   デフォルト) です。
+#   original ディレクトリ配下のサブディレクトリ構造 (man1, man3 など) に合わせて
+#   そのサブディレクトリごとに man1/ja.po, man3/ja.po などを分割して作るタイプです。
+#
+#   (top) --+--original--+--man1
+#           |            +--man3
+#           |            +--man5
+#           +--po4a--+--man1--+--<package name>-man1.cfg
+#                    |        +--<package name>-man1.pot
+#                    |        +--ja.po
+#                    +--man3--+--<package name>-man3.cfg
+#                    |        +--<package name>-man3.pot
+#                    |        +--ja.po
+#                    +--man5--+--<package name>-man5.cfg
+#                             +--<package name>-man5.pot
+#                             +--ja.po
+#
+# ----------
+
+THISARGS=$*
+THISDATE=`date '+%F'`
+THISTOOL=`basename $0`
+
+# 処理タイプを表す変数 TYPE に multi をデフォルト設定する。
+# これはオプション引数 -m の指定時に採用されるタイプである。
+# オプション引数 -o の指定時には one が設定される。
+TYPE=multi
+
+# オプション -h 指定時のヘルプ表示(関数)
+usage() {
+  echo "Usage: genmancfg.sh [options]"
+  echo "  Create po4a config file as TYPE as follows, in po4a directory."
+  echo "  This requires the original man sources under the \"original\" directory."
+  echo ""
+  echo "  options:"
+  echo "  -o:     TYPE=one;   for creating only one po file."
+  echo "  -m:     TYPE=multi; for creating po files per man sections [default]."
+  echo "  -n STR: name of the package [default: basename of the current directory]."
+  echo "  -d STR: release date of the package [default: \"YYYY/MM/DD\"]."
+  echo "  -v STR: version of the package [default: \"x.xx\"]."
+  echo "  -u STR: user name [default: git config --get user.name if exists]."
+  echo "  -e STR: email address [default: git config --get user.email if exists]."
+  echo "  -U "STR,..": list of commands untranslated [default: ""]."
+  echo "  -h:     print this help."
+  exit 0
+}
+
+# 以下の変数をそれぞれ定める。
+#    PACKAGE_NAME: パッケージ名
+#    PACKAGE_VER:  パッケージバージョン
+#    PACKAGE_DATE: パッケージのリリース日付 ("YYYY/MM/DD" 形式)
+# これらは def.mk ファイル内に同名変数定義が行われていれば、それを参照して定める。
+# def.mk ファイルが存在しない場合、def.mk のひながたファイルを出力して終了する。
+# 上の設定値はそれぞれ、オプション -n (パッケージ名)、-v (バージョン)、-d (リリース
+# 日付) により上書き設定できる。
+if test -f def.mk; then
+  PACKAGE_NAME=`grep "PACKAGE_NAME" def.mk | sed -e "s/.*[ ]*=[ ]*\(.*\)$/\1/"`
+  PACKAGE_VER=`grep "PACKAGE_VER" def.mk | sed -e "s/.*[ ]*=[ ]*\(.*\)$/\1/"`
+  PACKAGE_DATE=`grep "PACKAGE_DATE" def.mk | sed -e "s/.*[ ]*=[ ]*\(.*\)$/\1/"`
+else
+  echo "Error: def.mk not found so newly created;"
+  echo " process again after editting it correctly."
+  cat > def.mk <<"EOF"
+PACKAGE_NAME    = sample_package
+PACKAGE_VERSION = x.xx
+PACKAGE_DATE    = YYYY/MM/DD
+EOF
+  exit 1
+fi
+
+# 当プロジェクトで用いている copyright ファイルに、ユーザー名とメールアドレス
+# を書き入れるため、そのデフォルト値を git config の user.{name,email} から設定する。
+# git config から取得できなかった場合は、それぞれ "TRANSLATOR NAME", "EMAIL@ADDRESS"
+# とする。これはオプション -u (user name), -e (email address) により指定できる。
+# (なおメールアドレスが正しい書式を有しているかどうかは確認しない。)
+# これらは translation_list の出力項目にも利用する。
+USERNAME=`git config --get user.name 2>/dev/null || echo "TRANSLATOR NAME"`
+EMAILADDR=`git config --get user.email 2>/dev/null || echo "EMAIL@ADDRESS"`
+
+# po4a cfg の "-o untranslated=xxxxxxx" に指定したいコマンドを
+# オプション -U によって指定できるようにしているため、そのオプション値を
+# 保持するための以下の変数 UNTRANS_INIT をここで初期化する。
+# 下述の $OPT 処理文の中で、オプション -U が指定されていれば設定される。
+# roff コマンドの先頭のピリオドは省く。複数指定する場合はカンマで区切る。
+# 指定方法を誤ってもエラー処理は行わない。po4a 処理においてエラーとなるのみ。
+UNTRANS_INIT=""
+
+# オプション引数を走査して、前述までの各変数を定める。
+# 処理タイプは、変数 TYPE に対応値 (one か multi か) を設定する。
+# オプション -h 指定時はヘルプ表示、無効なオプション指定時はエラーとする。
+while getopts :omn:d:v:u:e:U:h OPT; do
+  case $OPT in
+     o) TYPE=one;;
+     m) TYPE=multi;;
+     n) PACKAGE_NAME="$OPTARG";;
+     d) RELEASEDATE="$OPTARG";;
+     v) VERSION="$OPTARG";;
+     u) USERNAME="$OPTARG";;
+     e) EMAILADDR="$OPTARG";;
+     U) UNTRANS_INIT="$OPTARG";;
+     h) usage;;
+     *) echo "Illegal option: $OPT"; exit 1;;
+  esac
+done
+
+# original ディレクトリ配下に original/man[0-9n] のようなサブディレクトリが
+# 存在するかどうかをチェックする。この構成でなければエラー終了する。
+if ! ls original/man[0-9n] >/dev/null 2>&1; then
+  echo "Error: Not exists the original directory or"
+  echo "       not contains man[0-9n] subdirectories."
+  exit 1
+fi
+
+# カレントディレクトリ直下に po4a ディレクトリ生成
+mkdir -p po4a
+
+# po4a cfg ファイル内の各処理行に対するオプション指定追加処理
+# $d, $f, $CFG_NAME などの変数は、上位処理のものを用いる。
+#   $d: man ページディレクトリ名; man1, man3 など。
+#   $f: man ファイル名; gcc.1, acl_check.3 など。
+#   $CFG_NAME: 出力 cfg 名; gcc-man1.cfg など。
+opt_proc_man() {
+
+  # (1) groff_code=verbatim 処理
+
+  # "-o groff_code=verbatim" を宣言すべき roff コマンド候補リストを定義する。
+  # (grep に直接受け渡すため、各コマンド(先頭ピリオド除く)を | (縦棒) で区切る。)
+  GROFF_CANDIDATES="de|ie"
+
+  # 上のコマンド候補リストがカレントな man ファイルに含まれているか
+  # どうかを grep 検索し、該当していれば cfg ファイルに
+  # "-o groff_code=verbatim" の宣言を出力する。
+  grep "^\.[$GROFF_CANDIDATES]" original/$d/$f >/dev/null 2>&1
+  if test $? -eq 0; then
+    echo -ne " \\\\\n\topt:\"-o groff_code=verbatim\"" >> $CFG_NAME
+  fi
+
+  # (2) generated 処理
+
+  # "-o generated" を宣言すべき記述候補リストを定義する。
+  GENERATED_CANDIDATES=(
+    "DO NOT EDIT"
+    "DO NOT MODIFY THIS FILE"
+    "It is generated"
+    "Man page generated from reStructuredText."
+    "Automatically generated by Pod::Man"
+    "\.\\\\\"Text automatically generated by"
+  )
+
+  # 上の記述候補リストのそれぞれがカレントな man ファイルに
+  # 含まれているかどうかを順に grep 検索して、含まれていれば cfg ファイルに
+  # "-o generated" の宣言を出力する。
+  GENERATED=0
+  for m in "${GENERATED_CANDIDATES[@]}"; do
+    grep "$m" original/$d/$f >/dev/null 2>&1
+    if test $? -eq 0; then
+      GENERATED=1; break
+    fi
+  done
+  if test $GENERATED -eq 1; then
+    echo -ne " \\\\\n\topt:\"-o generated\"" >> $CFG_NAME
+  fi
+
+  # (3) untranslated 処理
+
+  # "-o untranslated" を宣言すべきコマンド候補リストを定義する。
+  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"
+
+  # 上のコマンド候補リストのそれぞれがカレントな man ファイルに
+  # 含まれているかどうかを順に grep 検索して、含まれていれば cfg ファイルに
+  # "-o untranslated=XX,YY,ZZ,..." の宣言を出力する。
+  UNTRANS=
+  for u in $UNTRANS_CANDIDATES; do
+
+    grep "^$u" original/$d/$f >/dev/null 2>&1
+    if test $? -eq 0; then
+      if test -z "$UNTRANS"; then
+        UNTRANS="\\\\\n\topt:\"-o untranslated="
+      else
+        UNTRANS="$UNTRANS,"
+      fi
+      CMD=`echo $u | sed "s/^\\\\\.//g"`
+      if test "$CMD" = "\."; then
+        CMD="."
+      fi
+      case $CMD in
+        \'br\\*) CMD=`echo $CMD\' | sed "s/^\'//"`;;
+        *\\*) CMD="'$CMD'";;
+      esac
+
+      UNTRANS="$UNTRANS$CMD"
+    fi
+  done
+
+  # オプション引数 -U によりコマンドラインから untranslated 対象が指定されて
+  # いれば "-o untranslated=" 行に追加する。
+  if test "$UNTRANS_INIT" != ""; then
+    if test -z "$UNTRANS"; then
+      UNTRANS="\\\\\n\topt:\"-o untranslated="
+    else
+      UNTRANS=$UNTRANS,
+    fi
+    UNTRANS=$UNTRANS$UNTRANS_INIT
+  fi
+
+  # untranslated 指定対象が存在していれば cfg ファイルに指定行を出力する。
+  if test -n "$UNTRANS"; then
+    echo -ne " $UNTRANS\"" >> $CFG_NAME
+  fi
+
+  echo >> $CFG_NAME # 最終改行調整
+}
+
+# cfg 生成処理 (TYPE=one, multi 共通)
+#  (copyright ファイルも同時生成する。)
+create_cfg() {
+
+  echo "Creating cfg file:" # 処理進捗出力
+
+  # TYPE=one である場合、cfg ファイルは1つのみをここで作り始める。
+  if test $TYPE = one; then
+    CFG_NAME=po4a/$PACKAGE_NAME.cfg
+    echo "# Created by $THISTOOL, $THISDATE," > $CFG_NAME
+    echo "# with argument(s): $THISARGS" >> $CFG_NAME
+    echo "[po4a_langs] ja" >> $CFG_NAME
+    echo "[po4a_paths] po4a/$PACKAGE_NAME.pot \$lang:po4a/\$lang.po" >> $CFG_NAME
+    echo "[po4a_alias: man] man opt:\"-v --previous\" opt_ja:\"-M UTF-8\"" >> $CFG_NAME
+  fi
+
+  # original 配下の man[0-9n] サブディレクトリ $d について
+  for d in `cd original; ls -d man[0-9n]`; do
+
+    echo -n "  $d: " # 処理進捗出力
+
+    # TYPE=multi である場合、cfg ファイルを man[0-9n] ごとにここから生成する。
+    if test $TYPE = multi; then
+      mkdir -p po4a/$d
+      CFG_NAME=po4a/$d/$PACKAGE_NAME-$d.cfg
+      echo "# Created by $THISTOOL, $THISDATE," > $CFG_NAME
+      echo "# with argument(s): $THISARGS" >> $CFG_NAME
+      echo "[po4a_langs] ja" >> $CFG_NAME
+      echo "[po4a_paths] po4a/$d/$PACKAGE_NAME-$d.pot \$lang:po4a/$d/\$lang.po" >> $CFG_NAME
+      echo "[po4a_alias: man] man opt:\"-v --previous\" opt_ja:\"-M UTF-8\"" >> $CFG_NAME
+    fi
+
+    # original/man[0-9n]  配下の各ファイル $f について
+    for f in `cd original/$d; ls *`; do
+
+      echo -n "." # 処理進捗出力
+
+      # ファイルがシンボリックリンクである場合
+      if test -L original/$d/$f; then
+        : # シンボリックリンクは処理しない
+      else
+        LINECNT=`grep -v '^\.\\\"' original/$d/$f 2>/dev/null | wc -l | gawk -F" " '{print $1}'`
+        SOLINE=`grep -v '^\.\\\"' original/$d/$f 2>/dev/null | sed -n "/^\.so.*/p"`
+
+        # ファイルが ".so manN/*.N" の形式である場合
+        if ( test $LINECNT = "0" || test $LINECNT = "1" ) && test -n "$SOLINE"; then
+          : # .so 1行構成のものは処理しない
+        else
+
+          # ファイルが通常の場合 (シンボリックリンクや .so 形式でない場合) cfg 処理行を出力する。
+          echo >>$CFG_NAME
+          echo     "[type: man] original/$d/$f \$lang:release/$d/$f \\">>$CFG_NAME
+          echo -ne "\tadd_\$lang:?po4a/add_\$lang/copyright/$d/$f.txt">>$CFG_NAME
+
+          # po4a の処理設定各行においてオプション指定行を出力する。
+          opt_proc_man
+
+          # copyright ファイルの生成 (非存在時のみ)
+          if test -f po4a/add_ja/copyright/$d/$f.txt; then
+            : # 存在時は何もしない (上書き生成しない)
+          else
+            # 対象ディレクトリ生成
+            mkdir -p po4a/add_ja/copyright/$d
+
+            # コマンド .TH または .Dd が存在するかどうかを取得する。
+            FIRST=`grep "^\.TH" original/$d/$f >/dev/null 2>&1 && echo "^.TH"`
+            if test -z $FIRST; then
+              FIRST=`grep "^\.Dd" original/$d/$f >/dev/null 2>&1 && echo "^.Dd"`
+            fi
+
+            # 上で .TH または .Dd が取得できなかった場合は先頭行を取得。
+            if test $FIRST != "^.TH" && test $FIRST != "^.Dd"; then
+              FIRST=`head -1 original/$d/$f`
+            fi
+
+            # copyright ファイルのひながたを出力
+            cat > po4a/add_ja/copyright/$d/$f.txt <<"EOF"
+PO4A-HEADER: mode=before; position=__FIRST__
+.\"
+.\" Translated __DATE__
+.\"    by __USERNAME__ <__EMAILADDR__>
+.\"
+EOF
+            # 上記生成ファイルに対して変数部分を置換する。
+            sed -i -e "s/__FIRST__/$FIRST/" \
+                   -e "s/__DATE__/$THISDATE/" \
+                   -e "s/__USERNAME__/$USERNAME/" \
+                   -e "s/__EMAILADDR__/$EMAILADDR/" \
+                po4a/add_ja/copyright/$d/$f.txt
+          fi
+        fi
+      fi
+    done
+
+    echo # 処理進捗出力 (最終改行)
+  done
+}
+
+# TYPE=one 用の Makefile 生成処理
+makefile_one() {
+  cat > Makefile.tmp <<"EOF"
+PACKAGE_NAME = __PACKAGE_NAME__
+
+THRESH = 0
+EXTFLAGS =
+PO4AFLAGS += -k $(THRESH) $(EXTFLAGS)
+PO4ACFG = po4a/$(PACKAGE_NAME).cfg
+POFILE  = po4a/ja.po
+
+all: translate
+
+translate:
+       po4a $(PO4AFLAGS) $(PO4ACFG)
+
+stat:
+       @msgfmt -v --statistics -o /dev/null $(POFILE)
+
+page-stat:
+       @echo $(POFILE):
+       @po4a --force --no-update -k 0 $(PO4ACFG)
+
+.PHONY: translate stat page-stat
+EOF
+  sed -e "s/__PACKAGE_NAME__/$PACKAGE_NAME/" Makefile.tmp >Makefile
+  rm -f Makefile.tmp
+}
+
+# TYPE=one 用の Makefile 生成処理
+makefile_multi() {
+  cat > Makefile.tmp <<"EOF"
+PACKAGE_NAME = __PACKAGE_NAME__
+man_numbers = __MAN_NUMBERS__
+
+THRESH = 0
+EXTFLAGS =
+PO4AFLAGS += -k $(THRESH) $(EXTFLAGS)
+
+target-mans = $(addprefix man,$(man_numbers))
+po_dirs     = $(addprefix po4a/,$(target-mans))
+po_files    = $(addsuffix /ja.po,$(po_dirs))
+
+all: translate
+
+translate: $(target-mans)
+
+$(target-mans): man%:
+       po4a $(PO4AFLAGS) po4a/man$*/$(PACKAGE_NAME)-man$*.cfg
+
+stat:
+       @for po in $(po_files); do \
+         msgfmt -v --statistics -o /dev/null $$po; \
+       done
+
+page-stat:
+       @for n in $(man_numbers); do \
+         if test -f po4a/man$$n/$(PACKAGE_NAME)-man$$n.cfg; then \
+           echo po4a/man$$n/$(PACKAGE_NAME)-man$$n.cfg: ;\
+           po4a --force --no-update -k 0 po4a/man$$n/$(PACKAGE_NAME)-man$$n.cfg | \
+             sed "s/^/  /g" ;\
+         fi \
+       done
+
+.PHONY: all translate stat page-stat
+EOF
+  MAN_NUMBERS=`cd original; ls -dm man[0-9n] | sed -e "s/,//g" -e "s/man//g"`
+  sed -e "s/__PACKAGE_NAME__/$PACKAGE_NAME/" \
+      -e "s/__MAN_NUMBERS__/$MAN_NUMBERS/" \
+    Makefile.tmp >Makefile
+  rm -f Makefile.tmp
+}
+
+# メイン処理
+# 変数 TYPE の設定に応じて、それぞれの処理を行う。
+# これによって TYPE に応じた cfg ファイル、Makefile を生成する。
+case $TYPE in
+  one)   create_cfg; makefile_one;;    # TYPE=one の場合の処理
+  multi) create_cfg; makefile_multi;;  # TYPE=multi の場合の処理
+esac
+
+# translation_list.tmp 生成処理
+rm -f translation_list.tmp
+
+echo "Creating translation_list.tmp file:" # 処理進捗出力
+
+# original 配下の man[0-9n] サブディレクトリ $d について
+for d in `cd original; ls -d man[0-9n]`; do
+
+  echo -n "  $d: " # 処理進捗出力
+
+  # original/man[0-9n]  配下の各ファイル $f について
+  for f in `cd original/$d; ls *`; do
+
+    echo -n "." # 処理進捗出力
+
+    # ファイルがシンボリックリンクである場合
+    if test -L original/$d/$f; then
+      LINK=1
+      LINK_ITEM=`readlink original/$d/$f | sed -e "s|\(.*\)\.\([1-9].*\)|\1:\2|"`
+      echo -n "※:" >>translation_list.tmp # 決め打ちで "※" 出力; "@"(リンク先翻訳済み)かどうかは判断できない。
+    else
+      LINECNT=`grep -v '^\.\\\"' original/$d/$f 2>/dev/null | wc -l | gawk -F" " '{print $1}'`
+      SOLINE=`grep -v '^\.\\\"' original/$d/$f 2>/dev/null | sed -n "/^\.so .*/p"`
+
+      # ファイルが ".so manN/*.N" の形式である場合
+      if ( test $LINECNT = "0" || test $LINECNT = "1" ) && test -n "$SOLINE"; then
+        LINK=1
+        LINK_ITEM=`echo $SOLINE | sed "s|^\.so man\([0-9n]\)/\(.*\)\..*|\2:\1|"`
+        echo -n "※:" >>translation_list.tmp # 決め打ちで "※" 出力; "@"(リンク先翻訳済み)かどうかは判断できない。
+      else
+        # ファイルが通常の場合 (シンボリックリンクや .so 形式でない場合)
+        LINK=0
+        echo -n "▲:" >>translation_list.tmp # 決め打ちで "▲" 出力; "■"(改訂予約)などかどうかは判断できない。
+      fi
+    fi
+
+    man_sect=`echo $d | sed "s/man//"`
+    man_base=`echo $f | sed 's/^\(.*\)\.[^\.]*$/\1/'`
+
+    # translation_list 用に本日日付を再定義
+    THISDATE=`date '+%Y/%m/%d'`
+
+    # リンク情報かどうか (LINK 値) の違いを切り分けて translation_list 行を出力する。
+    if test $LINK = "0"; then
+      echo "$PACKAGE_NAME:$PACKAGE_VER:$PACKAGE_DATE:$man_base:$man_sect:$THISDATE::$EMAILADDR:$USERNAME:" \
+        >>translation_list.tmp
+    else
+      echo "$PACKAGE_NAME:$PACKAGE_VER:$PACKAGE_DATE:$man_base:$man_sect:$LINK_ITEM" \
+        >>translation_list.tmp
+    fi
+  done
+
+  echo # 処理進捗出力 (最終改行)
+done
+
+exit 0