lib/erbtex/command_line.rb in erbtex-0.2.0 vs lib/erbtex/command_line.rb in erbtex-0.3.0

- old
+ new

@@ -2,139 +2,109 @@ module ErbTeX class NoInputFile < StandardError; end class CommandLine - attr_reader :command_line, :marked_command_line, :input_file - attr_reader :progname, :input_path, :output_dir, :run_dir + attr_reader :erbtex_name, :tex_program, :tex_options + attr_reader :tex_commands, :input_file - def initialize(command_line) - @command_line = command_line - @input_file = @marked_command_line = nil - @run_dir = Dir.pwd - find_output_dir - find_progname - find_input_file - find_input_path - mark_command_line - end + def initialize(argv) + # Note: argv will be the command line arguments after processing by the + # shell, so if we see things such as '&', '~', '\' in the args, these were + # quoted by the user on the command-line and need no special treatment + # here. For example, '~/junk' on the commandline will show up here as + # '/home/ded/junk'. If we see '~/junk', that means the user has quoted the + # ~ on the command line with something like '\~junk', so we should assume + # that the user wants to keep it that way. Likewise, an arg with spaces in + # it will have been quoted by the user to be seen as a single argument. + # When we output these for use by the shell in the system command, we + # should apply shellquote to everything so that the receiving shell sees + # the args in the same way. - def find_progname - @progname = @command_line.split(' ')[0] - end + @erbtex_name = File.basename($0) - def find_output_dir - args = @command_line.split(' ') - # There is an -output-comment option, so -output-d is the shortest - # unambiguous way to write the -output-directory option. It can use - # one or two dashes at the beginning, and the argument can be - # seaparated from it with an '=' or white space. - have_out_dir = false - out_dir = nil - args.each do |a| - if have_out_dir - # Found -output-directory on last pass without an equals sign - out_dir = a - end - if a =~ /^--?output-d(irectory)?=(\S+)/ - out_dir = $2 - elsif a =~ /^--?output-d(irectory)?$/ - # Next arg is the out_dir - have_out_dir = true - end + # Find the tex_commands + @tex_commands = [] + if argv.any? { |a| a =~ /\A\\/ } + # All args after first starting with '\' should be interpreted as TeX + # commands, even if they don't start with '\' + @tex_commands = argv.drop_while { |a| a !~ /\A\\/ } + first_tex_command_k = argv.size - @tex_commands.size + argv = argv[0..first_tex_command_k - 1] end - if out_dir.nil? - if File.writable?(Dir.pwd) - @output_dir = Dir.pwd - else - @output_dir = File.expand_path(ENV['TEXMFOUTPUT']) - end - else - @output_dir = File.expand_path(out_dir) - end - end - def find_input_file - # Remove the initial command from the command line - cmd = @command_line.split(/\s+/)[1..-1].join(' ') - cmd = cmd.gsub(/\s+--?[-a-zA-Z]+(=\S+)?/, ' ') - infile_re = %r{(\\input\s+)?(([-.~_/A-Za-z0-9]+)(\.[a-z]+)?)\s*$} - if cmd =~ infile_re - @input_file = "#{$2}" - if @input_file =~ /\.tex(\.erb)?$/ - @input_file = @input_file - else - @input_file += ".tex" - end - elsif cmd =~ %r{(\\input\s+)?(["'])((?:\\?.)*?)\2} #" - # The re above captures single- or double-quoted strings with - # the insides in $3 - @input_file = "#{$3}" - if @input_file !~ /\.tex$/ - @input_file += ".tex#{$1}" - end - else - @input_file = nil + # Look for our --invoke=tex_command option + @tex_program = 'pdflatex' + if argv.any? { |a| a =~ /\A--invoke=(\w+)/ } + @tex_program = $1 + argv.reject! { |a| a =~ /\A--invoke=(\w+)/ } end - end - def find_input_path - # If input_file is absolute, don't look further - if @input_file =~ /^\// - @input_path = @input_file - elsif @input_file.nil? - @input_path = nil - else - # The following cribbed from kpathsea.rb - @progname.untaint - @input_file.untaint - kpsewhich = "kpsewhich -progname=\"#{@progname}\" -format=\"tex\" \"#{@input_file}\"" - lines = "" - IO.popen(kpsewhich) do |io| - lines = io.readlines - end - if $? == 0 - @input_path = lines[0].chomp.untaint - else - raise NoInputFile, "Can't find #{@input_file} in TeX search path; try kpsewhich -format=tex #{@input_file}." - end + # The last argument, assuming it does not start with a '-' or '&', is + # assumed to be the name of the input_file. + if !argv.empty? && argv[-1] !~ /\A[-&]/ + @input_file = CommandLine.expand_input_file(argv.pop) end + + # What remains in argv should be the tex program's '-options', which + # should be passed through untouched. So, can form the full command line + # for tex_processing + @tex_options = argv.dup end - def new_command_line(new_progname, new_infile) - ncl = @marked_command_line.sub('^p^', new_progname) - # Quote the new_infile in case it has spaces - if new_infile - ncl = ncl.sub('^f^', "'#{new_infile}'") - end - ncl + def tex_command(tex_file = input_file) + "#{tex_program} " \ + "#{tex_options.shelljoin} " \ + "#{tex_commands.shelljoin} " \ + "#{tex_file}" + .strip.squeeze(' ') end - def mark_command_line - # Replace input file with '^f^' - infile_re = %r{(\\input\s+)?(([-.~_/A-Za-z0-9]+)(\.[a-z]+)?)\s*$} - quoted_infile_re = %r{(\\input\s+)?(["'])((?:\\?.)*?)\2} #" - if @input_file.nil? - @marked_command_line = @command_line - elsif @command_line =~ infile_re - @marked_command_line = @command_line.sub(infile_re, "#{$1}^f^") - elsif @command_line =~ quoted_infile_re - @marked_command_line = @command_line.sub(quoted_infile_re, "#{$1}^f^") + # Return the name of the input file based on the name given in the command + # line. Try to find the right extension for the input file if none is given. + def self.expand_input_file(input_file) + full_ext = input_file[/\A(.*)(\.[\w.]+)\z/, 2] + if full_ext.nil? || full_ext.empty? + if File.exist?("#{input_file}.tex.erb") + "#{input_file}.tex.erb" + elsif File.exist?("#{input_file}.tex") + "#{input_file}.tex" + elsif File.exist?("#{input_file}.erb") + "#{input_file}.erb" + else + input_file + end else - @marked_command_line = @command_line + input_file end - # Replace progname with '^p^' - @marked_command_line = @marked_command_line.lstrip - @marked_command_line = @marked_command_line.sub(/\S+/, '^p^') end end end # NOTES: - # The following text is from the Web2C documentation at # http://tug.org/texinfohtml/web2c.html#Output-file-location # +# 4.1 TeX invocation +# +# TeX, Metafont, and MetaPost process the command line (described here) +# and determine their memory dump (fmt) file in the same way (*note Memory +# dumps::). Synopses: +# +# tex [OPTION]... [TEXNAME[.tex]] [TEX-COMMANDS] +# tex [OPTION]... \FIRST-LINE +# tex [OPTION]... &FMT ARGS +# +# TeX searches the usual places for the main input file TEXNAME (*note +# (kpathsea)Supported file formats::), extending TEXNAME with '.tex' if +# necessary. To see all the relevant paths, set the environment variable +# 'KPATHSEA_DEBUG' to '-1' before running the program. +# +# After TEXNAME is read, TeX processes any remaining TEX-COMMANDS on +# the command line as regular TeX input. Also, if the first non-option +# argument begins with a TeX escape character (usually '\'), TeX processes +# all non-option command-line arguments as a line of regular TeX input. + # 3.4 Output file location # # All the programs generally follow the usual convention for output # files. Namely, they are placed in the directory current when the # program is run, regardless of any input file location; or, in a few