#!@BASH@ # Driver for rastertogutenprint tester. # # Copyright 2007-2017 Robert Krawitz (rlk@alum.mit.edu) # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the Free # Software Foundation; either version 2 of the License, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . retval=0 if [[ -z $srcdir || $srcdir = . ]] ; then sdir=$(pwd) elif [[ $srcdir =~ ^/ ]] ; then sdir="$srcdir" else sdir="$(pwd)/$srcdir" fi export STP_DATA_PATH=${STP_DATA_PATH:-"$sdir/../xml"} export STP_MODULE_PATH=${STP_MODULE_PATH:-"$sdir/../main:$sdir/../main/.libs"} declare single=0 declare verbose=0 declare valgrind=0 declare make_ppds=1 declare skip_simplified=0 declare postscript=0 declare use_explicit_quality=0 declare extra_genppd_opts="-Z" declare use_smallest_pagesize=0 declare cupsargs='' declare -a printers_to_test declare dontrun=0 if [ -n "$STP_TEST_DEBUG" ] ; then echo "Would run with single=$single skip_simplified=$skip_simplified extra_genppd_opts=$extra_genppd_opts cupsargs=$cupsargs use_explicit_quality=$use_explicit_quality valopts=$valopts valgrind=$valgrind" exit 0 fi declare family=$STP_TEST_FAMILY declare all_models='' declare md5dir='' declare outdir='' declare qualarg='' declare npages=3 declare jobs=${STP_PARALLEL:-1} declare -A all_models= if [[ -r $sdir/../../src/cups/gutenprint-users-manual.pdf ]] ; then testfile="$sdir/../../src/cups/gutenprint-users-manual.pdf" else testfile="$sdir/../../doc/gutenprint-users-manual.pdf" fi quality_presets=(FastEconomy Economy Draft Standard High Photo HighPhoto UltraPhoto Best) usage() { cat <<'EOF' Usage: test-rastertogutenprint [options] [PPD files...] Options: -s Run only one PPD file with a given model ID/family -v Use valgrind -c Use cachegrind -g Use GDB attach in valgrind -V Verbose output -n Don't build PPD files prior to run -O dir Save output in specified directory -o opt Set option on CUPS command line -m dir Save MD5 checksums in specified directory -p pages Specify page range of input document to use -P Use PostScript rather than PDF input -t jobs Run jobs in parallel (alternatively, use STP_PARALLEL) -f family Run printers only in the particular family -S Skip simplified PPD files -l Use lowest available quality setting -L Use highest available quality setting -X Don't use explicit quality setting -N Use the smallest available page size -d Don't actually run the command EOF exit 0; } while getopts "hvcgsVnO:m:o:p:PSt:lLXf:Nd" opt ; do case "$opt" in h*) usage ;; v) valgrind=$((valgrind + 1)) ;; c) valgrind=4 ;; g) valopts='--vgdb=yes --error-exitcode=1' ;; s) single=1 ;; V) verbose=$((verbose+1)) ;; n) make_ppds=0 ;; O) outdir="$OPTARG"; mkdir -p "$outdir" ;; o) cupsargs="$cupsargs $OPTARG" ;; m) md5dir="$OPTARG"; mkdir -p "$md5dir" ;; p) npages="$OPTARG" ;; P) postscript=1 ;; t) jobs="$OPTARG" ;; f) family="$OPTARG" ;; S) skip_simplified=1 ;; X) use_explicit_quality=0 ;; l) use_explicit_quality=1 ;; L) use_explicit_quality=2 ;; N) use_smallest_pagesize=1 ;; d) dontrun=1 ;; \?) usage ;; *) echo "Unknown argument $opt"; usage ;; esac done STP_TEST_ROTOR=${STP_TEST_ROTOR:-0} STP_TEST_ROTOR_CIRCUMFERENCE=${STP_TEST_ROTOR_CIRCUMFERENCE:-1} case "$valgrind" in 4) valopts='--tool=callgrind --dump-instr=yes --trace-jump=yes --error-exitcode=1' ;; '') ;; *) valopts='--tool=memcheck --error-exitcode=1' ;; esac shift $((OPTIND - 1)) if (( $# > 0 )) ; then single=0 for i in $(seq 1 $#) ; do (( (i - 1) % $STP_TEST_ROTOR_CIRCUMFERENCE == $STP_TEST_ROTOR )) && printers_to_test+=($1) shift done (( ${#printers_to_test[@]} == 0 )) && exit 77 fi (( single > 0 )) && extra_genppd_opts="$extra_genppd_opts -S" if (( STP_TEST_ROTOR_CIRCUMFERENCE > 1 && STP_TEST_ROTOR >= 0 && STP_TEST_ROTOR < STP_TEST_ROTOR_CIRCUMFERENCE )) ; then extra_genppd_opts="$extra_genppd_opts -R $STP_TEST_ROTOR_CIRCUMFERENCE -r $STP_TEST_ROTOR" STP_TEST_ROTOR=0 STP_TEST_ROTOR_CIRCUMFERENCE=1 fi version="@GUTENPRINT_RELEASE_VERSION@"; rgp="./rastertogutenprint.$version" cupsdir="$(cups-config --serverbin)/filter" cgpdftoraster="$cupsdir/cgpdftoraster" gstoraster="$cupsdir/gstoraster" imagetoraster="$cupsdir/imagetoraster" pdftops="$cupsdir/pdftops" pstops="$cupsdir/pstops" pstoraster="$cupsdir/pstoraster" if [[ ! -x $cgpdftoraster && ! -x $pdftops && ! -x $gstoraster ]] ; then echo 'CUPS does not appear to be installed, skipping test' exit 0 fi if [[ -x $pstoraster || -x $gstoraster || -x $cgpdftoraster ]] ; then pages="24-$((24 + npages - 1))" (( postscript > 0 )) && pages="page-ranges=$pages" else pages='' fi cleanup() { [[ -n $tfile ]] && rm -f "$tfile" exit 1 } pdfjam=$(type -p pdfjam) [[ -z $pdfjam ]] && postscript=1 if (( postscript > 0 )) ; then pdftops=$(type -p pdftops) if [[ -n $pdftops && ! -x $cgpdftoraster ]] ; then tfile=$(mktemp) trap cleanup 1 2 3 6 14 15 30 "$pdftops" -f 24 -l $((24 + npages - 1)) "$testfile" "$tfile" fi else tfile=$(mktemp) trap cleanup 1 2 3 6 14 15 30 "$pdfjam" -q "$testfile" "$pages" -o "$tfile" fi case "$verbose" in 1) export STP_SUPPRESS_VERBOSE_MESSAGES=1 ;; 0|'') export STP_SUPPRESS_MESSAGES=1 export STP_SUPPRESS_VERBOSE_MESSAGES=1 ;; *) ;; esac # Note that using CUPS arguments may trigger valgrind memory leaks in # CUPS. #cupsargs='PageSize=Custom.400.00x500.00' #cupsargs='PageSize=Custom.324x495 Resolution=180dpi' #cupsargs='PageSize=w324h495 Resolution=180dpi' #cupsargs='PageSize=A8' get_ppds() { if [[ -n $* ]] ; then for f in "$@" ; do if [[ -r $f ]] ; then echo "$f" elif [[ -r ppd/C/$f ]] ; then echo "ppd/C/$f" elif [[ -f ppd/C/${f}.ppd ]] ; then echo "ppd/C/${f}.ppd" elif [[ -f ppd/C/${f}.ppd.gz ]] ; then echo "ppd/C/${f}.ppd.gz" elif [[ -f ppd/C/${f}.ppd.GZ ]] ; then echo "ppd/C/${f}.ppd.GZ" elif [[ -f ppd/C/${f}.ppd.bz2 ]] ; then echo "ppd/C/${f}.ppd.bz2" elif [[ -f ppd/C/${f}.ppd.BZ2 ]] ; then echo "ppd/C/${f}.ppd.BZ2" elif [[ -f ppd/C/${f}.ppd.z ]] ; then echo "ppd/C/${f}.ppd.z" elif [[ -f ppd/C/${f}.ppd.Z ]] ; then echo "ppd/C/${f}.ppd.Z" elif [[ -f ppd/C/stp-${f}.ppd ]] ; then echo "ppd/C/stp-${f}.ppd" elif [[ -f ppd/C/stp-${f}.ppd.gz ]] ; then echo "ppd/C/stp-${f}.ppd.gz" elif [[ -f ppd/C/stp-${f}.ppd.GZ ]] ; then echo "ppd/C/stp-${f}.ppd.GZ" elif [[ -f ppd/C/stp-${f}.ppd.bz2 ]] ; then echo "ppd/C/stp-${f}.ppd.bz2" elif [[ -f ppd/C/stp-${f}.ppd.BZ2 ]] ; then echo "ppd/C/stp-${f}.ppd.BZ2" elif [[ -f ppd/C/stp-${f}.ppd.z ]] ; then echo "ppd/C/stp-${f}.ppd.z" elif [[ -f ppd/C/stp-${f}.ppd.Z ]] ; then echo "ppd/C/stp-${f}.ppd.Z" elif [[ -f ppd/C/stp-${f}.${version}.ppd ]] ; then echo "ppd/C/stp-${f}.${version}.ppd" elif [[ -f ppd/C/stp-${f}.${version}.ppd.gz ]] ; then echo "ppd/C/stp-${f}.${version}.ppd.gz" elif [[ -f ppd/C/stp-${f}.${version}.ppd.GZ ]] ; then echo "ppd/C/stp-${f}.${version}.ppd.GZ" elif [[ -f ppd/C/stp-${f}.${version}.ppd.bz2 ]] ; then echo "ppd/C/stp-${f}.${version}.ppd.bz2" elif [[ -f ppd/C/stp-${f}.${version}.ppd.BZ2 ]] ; then echo "ppd/C/stp-${f}.${version}.ppd.BZ2" elif [[ -f ppd/C/stp-${f}.${version}.ppd.z ]] ; then echo "ppd/C/stp-${f}.${version}.ppd.z" elif [[ -f ppd/C/stp-${f}.${version}.ppd.Z ]] ; then echo "ppd/C/stp-${f}.${version}.ppd.Z" fi done else echo ppd/C/*.ppd* fi } if [[ $make_ppds -gt 0 || ! -d ppd/C ]] ; then rm -rf ppd/C ## not all systems can work with gzipped PPDs extra_genppd_opts="$extra_genppd_opts ${printers_to_test[*]}" if [[ $skip_simplified == 1 ]] ; then echo make ppd-nonls EXTRA_GENPPD_OPTS="$extra_genppd_opts" make ppd-nonls EXTRA_GENPPD_OPTS="$extra_genppd_opts" else make ppd-nonls-a EXTRA_GENPPD_OPTS="$extra_genppd_opts" fi fi find_page_size() { ppd=$1 (( use_smallest_pagesize == 0 )) && return; driver=$(grep '^\*StpDriverName' "$ppd" | sed -e 's/^[^"]*"//' -e 's/"//g') pagesize=$(./min-pagesize "$driver") [[ -n "$pagesize" ]] && echo "PageSize=$pagesize" } find_resolution() { ppd=$1 resolutions=$(grep "^\\*Resolution " "$ppd" |sed -e 's,/.*,,' -e 's/.* //') [[ -z "$resolutions" ]] && return low_resolution=9999999999 low_resolution_name='' high_resolution=0 high_resolution_name='' for r in $resolutions ; do res=$(sed -e 's/dpi//' -e 's/x/ \\\* /' -e 's/^\([0-9]*\)$/\1 \\\* \1/' <<< "$r") resnum=$(eval "expr $res") if (( resnum > high_resolution )) ; then high_resolution=$resnum high_resolution_name=$r fi if (( resnum < low_resolution )) ; then low_resolution=$resnum low_resolution_name=$r fi done if (( use_explicit_quality == 1 )) ; then echo "Resolution=$low_resolution_name" elif (( use_explicit_quality == 2 )) ; then echo "Resolution=$high_resolution_name" fi } find_quality_preset() { ppd=$1 if (( use_explicit_quality == 1 )) ; then for q in "${quality_presets[@]}" ; do if grep -q "^\\*StpQuality $q" "$ppd" ; then echo "StpQuality=$q" return fi done elif (( use_explicit_quality == 2 )) ; then best_quality='' for q in "${quality_presets[@]}" ; do grep -q "^\\*StpQuality $q" "$ppd" && best_quality=$q done [[ -n $best_quality ]] && echo "StpQuality=$best_quality" fi } find_quality() { ppd=$1 if [[ ! -r $ppd ]] ; then echo "Can't find $ppd!" 1>&2 exit 1; fi (( use_explicit_quality == 0 )) && return if grep -q '\*Resolution' "$ppd" ; then find_resolution "$ppd" else find_quality_preset "$ppd" fi } xgrep() { pat=$1 file=$2 if [[ $file == *.gz ]] ; then grep -E -m1 "$pat" "$file" else zgrep "$pat" "$file" fi } runcmd() { qualarg=$(find_quality "$PPD") sizearg=$(find_page_size "$PPD") a=(1 1 1 1) qarg="$qualarg $sizearg $cupsargs" if [[ -x $cgpdftoraster ]] ; then # cgpdftoraster doesn't like arguments. How rude. $cgpdftoraster "${a[@]}" "" < "$tfile" elif [[ -f $tfile && -x $gstoraster ]] ; then $gstoraster "${a[@]}" "$qarg" < "$tfile" elif [[ -f $tfile ]] ; then $pstops "${a[@]}" $"qarg" < "$tfile" elif [[ -x $pstoraster ]] ; then $pdftops "${a[@]}" "$qarg" < "$tfile" | $pstops "${a[@]}" "$pages$qarg" | $pstoraster elif [[ -x $gstoraster ]] ; then $pdftops "${a[@]}" "$qarg" < "$tfile" | $gstoraster "${a[@]}" "$pages$qarg" else $imagetoraster "${a[@]}" "$qarg" < calibrate.ppm fi } do_output() { driver=$(xgrep '^\*StpDriverName:' "$PPD" |awk '{print $2}' | sed 's/"//g') if [[ -n $outdir ]] ; then cat > "$outdir/$driver.prn" if [[ -n $md5dir ]] ; then md5sum < "$outdir/$driver.prn" | sed "s/-/\*$driver/" > "$md5dir/$driver.md5" fi elif [[ -n $md5dir ]] ; then cat | md5sum | sed "s/-/\*$driver/" > "$md5dir/$driver.md5" else cat >/dev/null fi } run_rastertogp() { qualarg=$(find_quality "$PPD") sizearg=$(find_page_size "$PPD") vg="libtool --mode=execute valgrind $valopts --log-fd=3" vg1="$vg --num-callers=50 --leak-check=yes --error-limit=no --error-exitcode=1" rgpc="$rgp 1 1 1 1" qarg="$qualarg $sizearg $cupsargs" case "$valgrind" in 1) $vg1 -q $rgpc ;; 2) $vg1 --leak-resolution=high $rgpc "$qarg" ;; 3) $vg1 --leak-resolution=high --show-reachable=yes $rgpc "$qarg";; 4) $vg $rgpc "$qarg" ;; 5) cat ;; 6) cat > /dev/null ;; *) $rgpc "$qarg" esac } runme() { f="$1" m=${all_models[$f]} p=${f#*stp-} p=${p/${version}./} export PPD=$f if (( dontrun > 0 )) ; then output="${p%.ppd*} ($m)" elif [[ -n $outdir || -n $md5dir ]] ; then output="${p%.ppd*} ($m)...$( (runcmd 2>/dev/null | run_rastertogp | do_output) 2>&1 3>&2)" else output="${p%.ppd*} ($m)...$( (runcmd 2>/dev/null | run_rastertogp >/dev/null) 2>&1 3>&2)" fi return $? } runall() { jobs="${1:-1}" rotor="${2:-0}" shift 2 retval=0 jobno=0 for f in "$@" ; do if (( jobno == rotor )) ; then runme "$f" || retval=1 echo "$output" grep -q 'ERROR:' <<< "$output" && retval=1 fi jobno=$(((jobno+1) % jobs)) done return $retval } get_models() { re='\*StpDriverModelFamily: ' if (( ${#all_models[*]} <= 1 )) ; then declare -a models=($(xargs grep -m1 -H "^$re" <<< "$*" | sed "s/:$re/=/")) for m in "${models[@]}" ; do model=${m#*=} file=${m%%=*} all_models[$file]=$model done fi } retval=0 if [[ -d ppd/C ]] ; then declare -a files=($(get_ppds)) declare -A models declare -a nfiles if (( skip_simplified > 0 )) ; then for f in "${files[@]}" ; do [[ $f != *.sim.ppd* ]] && nfiles+=("$f") done files=("${nfiles[@]}") fi get_models "${files[@]}" if [[ -n $family ]] ; then nfiles=() for f in "${files[@]}" ; do [[ ${all_models[$f]} =~ $family ]] && nfiles+=("$f") done files=("${nfiles[@]}") fi if (( single != 0 )) ; then declare -A seen_models nfiles=() get_models "${files[@]}" for f in "${files[@]}" ; do model=${all_models[$f]} [[ $f == *.sim.ppd ]] && model="${model}_sim" if [[ -z ${seen_models[$model]} ]] ; then nfiles+=("$f") seen_models[$model]=1 fi done files=("${nfiles[@]}") fi (( ${#files[@]} < jobs )) && jobs=${#files[@]} # Fire 'em off in the background... for i in $(seq 0 $((jobs-1))) ; do runall "$jobs" "$i" "${files[@]}" & done # And wait for them to complete. for i in $(seq 0 $((jobs-1))) ; do wait -n || retval=1 done fi [[ -n $tfile ]] && rm -f "$tfile" (( retval == 0 && make_ppds > 0 )) && rm -rf ppd/C && rmdir ppd exit "$retval"