今年度の講義では,授業資料を配ることにしました.
一つは,PowerPointファイルを6up両面1枚で印刷したもの.学生アンケートの「ノートが取りづらい」に配慮したものです*1.
もう一つは,例題プログラムです.これまでは,配列を使うプログラムあたりから配り始めていましたが,座学でソースコードを「手元に置く」ほうがいいと考え,初回から配布しました.
これまで,例題プログラムはWindowsのメモ帳で開き,印刷していました.ゴシック体です.試験問題はTeXベースで作っていまして,有名な「\」を含め,字形が違います*2.さらにメモ帳ベースだと,行番号を付けるのに苦労します*3.
何ができるといいか,整理してみると…
- Cのソースファイルを入力として,Rubyスクリプトを一つ起動すれば,例題プログラムのPDFファイルが生成できるようにしたい.
- 行番号を振りたい.できればソースファイルと別フォント(小さくするなど)にしたい.
- Cのソースファイルが,1ページに収まらない行数でも,生成されるPDFファイルに問題がないようにしたい.
3番目の要請は,実はこれまでの試験問題作成で,このトラブルがありまして,いつも,1ページに収めるよう,プログラム読解問題を選定・修正していたのでした.
それと,これくらいならシェルスクリプトでも書けそうですが,これまで例題ソースファイルを,Webやその他への提供する(基本的にファイルコピーですが)ためRubyスクリプトを書いていて,require "src2pdf.rb" などとして連携したいとも考えました.
そんなこんなでプログラムです.src2pdf.rbというファイル名で,一見任意のファイルを変換できそうですが,実際には入力ファイル名は「.c」決め打ちです.
#!/usr/bin/env ruby # -*- coding: utf-8 -*- # src2pdf.rb require "fileutils" class Src2pdf def initialize(cf) @input_file = cf @input_file_fullpath = File.expand_path(@input_file) @targetdir = File.dirname(@input_file_fullpath) @workdir = File.dirname(__FILE__) @basename = File.basename(@input_file, ".c") @cfile = @basename + ".c" @texfile = @basename + ".tex" @pdffile = @basename + ".pdf" @opt_fu = {:verbose => true} @opt_keeptmpfile = false end def my_system(command) puts command system command end def create_texsrc # @cfile my_system("nkf -s -Lw #{@input_file_fullpath} > #{@cfile}") # @texfile body = open("src2pdf.tex").read body.sub!(/CFILENAME/, @cfile) open(@texfile, "w") do |fout| fout.print body end end def tex2dvi my_system("platex #{@basename}") end def dvi2pdf my_system("dvipdfmx #{@basename}") end def mv_pdf FileUtils.mv(@pdffile, @targetdir, @opt_fu) end def cleanup FileUtils.rm(Dir.glob("#{@basename}*"), @opt_fu) end def start Dir.chdir(@workdir) do create_texsrc tex2dvi dvi2pdf mv_pdf cleanup unless @opt_keeptmpfile end end end if __FILE__ == $0 if ARGV.empty? puts "usage: ruby #{$0} C_file ..." exit end ARGV.each do |filename| Src2pdf.new(filename).start end end
処理内容は次のとおり.
- 入力ファイル(.c),中間ファイル,出力ファイル(.pdf)の名前を求めます.なお,中間ファイルは,src2pdf.rbと同じディレクトリに作ります.
- 入力ファイルをWindows環境のplatexに通せるよう,文字コードを変換します.
- texファイルを作ります.
- platexコマンドを実行し,dviファイルを作ります.
- dvipdfmxコマンドを実行し,pdfファイルを作ります.
- pdfファイルを,入力ファイルと同じディレクトリに移動します.
- 中間ファイルを削除します.
スクリプトの中で,"src2pdf.tex" というファイルを開いています.その内容は以下のとおり.「CFILENAME」のところを置き換えて別ファイルで保存し,platexの入力とします.もう少し複雑な置き換えが必要なら,eRubyを使うべきですね.
% src2pdf.tex \documentclass[12pt,a4paper]{jsarticle} \usepackage{misc} \parindent=0pt \unitlength=1mm \pagestyle{empty} \addtolength{\evensidemargin}{-1cm} \addtolength{\oddsidemargin}{-1cm} \addtolength{\textwidth}{2cm} \addtolength{\topmargin}{-2cm} \addtolength{\textheight}{3cm} \begin{document} \baselineskip=.7\baselineskip \listing{CFILENAME} \end{document}
「\usepackage{misc}」ですが,TeXにソースコードを埋め込む. - ぴょぴょぴょ? - Linuxとかプログラミングの覚え書き -からmisc.styを知りました.このファイル,Windowsのplatex環境には含まれていないようですが,Googleで探すと,ほどなく見つかりましたので,これもsrc2pdf.rbと同じディレクトリに置きました.二十数年前のファイルが今でも動くのは,すごいものです.
なのですが,src2pdf.rbを実行してPDF化したところ,行番号のフォントがソースと同じ形・大きさなのは,うれしくありません.そこで
\everypar{\advance\lineno by 1 \llap{\the\lineno\ \ }}\input#1
のところを
\everypar{\advance\lineno by 1 \llap{{\rm\scriptsize\the\lineno}\ \ }}\input#1
と変更してから,PDF化やり直し.いい感じになりました.
このRubyスクリプトには,「入力ファイルをsrc2pdf.rbがあるディレクトリに置いてから,実行すると,nkfのところでおかしな挙動になる」「入力ファイルの名前がsrc2pdf.cやmisc.cだと,src2pdf.texやmisc.styが中間ファイルと勘違いされて削除してしまう」というバグが含まれています.自分が使う際にはそういうことがないので放置なのですが,警告を出すか何かすべきですね….