#!@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 printers_to_test='' 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 EOF exit 0; } while getopts "hvcgsVnO:m:o:p:St:lLXf:N" 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='' ;; 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 ;; \?) usage ;; *) echo "Unknown argument $opt"; usage ;; esac done 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)) 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) [[ -n $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 $@ || -n $printers_to_test ]] ; then for f in "$@" $printers_to_test ; 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 [[ -n $make_ppds || ! -d ppd/C ]] ; then rm -rf ppd/C ## not all systems can work with gzipped PPDs if [[ $skip_simplified == 1 ]] ; then EXTRA_GENPPD_OPTS="$extra_genppd_opts" make ppd-nonls else EXTRA_GENPPD_OPTS="$extra_genppd_opts" make ppd-nonls-a 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 egrep -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 ;; *) $rgp 1 1 1 1 "$qarg" esac } runme() { f="$1" p=${f#*stp-} p=${p/${version}./} export PPD=$f if [[ -n $outdir || -n $md5dir ]] ; then output="${p%.ppd*}...$( (runcmd 2>/dev/null | run_rastertogp | do_output) 2>&1 3>&2)" else output="${p%.ppd*}...$( (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" (( $? != 0 )) && 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 if [[ -n $family ]] ; then get_models ${files[@]} 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[@]} declare -a subproc=($(seq 0 $((jobs-1)))) # Fire 'em off in the background... for i in ${subproc[@]} ; do runall $jobs $i ${files[@]} & done # And wait for them to complete. for i in ${subproc[@]} ; do wait -n (( $? != 0 )) && retval=1 done fi [[ -n $tfile ]] && rm -f "$tfile" (( $retval == 0 )) && rm -rf ppd/C && rmdir ppd exit $retval