#!/bin/bash set -e set -o posix ROOT_UID=0 OPTERR=1 loc_or_sysdir=/usr/local/share/groff # make this default version=current trap interrupt SIGINT shopt -s expand_aliases alias cp='cp -f' # -p flag for interactive alias ln='ln -f' alias mv='mv -f' show_usage() { printf \ "Usage: install-font.sh [-lscpdD] \ [-C \033[4mdir\033[0m] \ [-F \033[4mfamily\033[0m] \ [-f \033[4mgroff fontname\033[0m] | +\033[4mSTYLE\033[0m] file ...\n\ Longer help: install-font.sh -H (pipe through 'less' or 'more')\n" } long_help() { printf </, where is one of 'truetype', 'type1', or 'opentype'. If -s is given, copy to the family directory located under /usr/share/fonts//. If neither -c nor -C is given, a prompt asks whether to copy the file(s) named on the command line. -n Don't copy file(s) named on the command line to a system-accessible location. -d Make font available to gropdf. -D Do not make font available to gropdf. -p Ask before overwriting or linking files. Default is to overwrite without asking. -C \033[4mdir\033[0m Copy file(s) named on the command line to the family directory (see -F) in \033[4mdir\033[0m. -F \033[4mfamily\033[0m Family to which the font belongs. Creates a family for the groff font, which can then be accessed by calls to .fam or .FAMILY (mom macros). Also creates a family directory for fonts being made available system-wide (see -c and -C). -F is useful for batch processing fonts that belong to the same family. Use with care, since all files named on the command line will be assigned to \033[4mfamily\033[0m. If -F is not given, a prompt asks for the family name. -f \033[4mname\033[0m or +\033[4mSTYLE\033[0m Name by which to access the font with calls to .ft or .FT (mom macros). \033[4mname\033[0m may be arbitrary, or a '+' sign prefixed to an uppercase fontstyle recognized by groff, eg +R, +I, +B, +BI, which respectively stand for regular, italic, bold, and bold italic. The mom macros provide additional styles, which may also be used. +\033[4mSTYLE\033[0m is affixed to the family name to arrive at the groff fontname. install-font -F Garamond -f +R creates font GaramondR, which can be accessed by .fam Garamond .ft R or .ft GaramondR -f is not compatible with batch processing. \033[4minstall-font\033[0m will abort if the -f option is given and multiple files are named on the command line. If -f is not given, a prompt asks for the font name. " EOF } case $1 in -h | "") show_usage exit 0 ;; -H) long_help exit 0 ;; esac # if fontforge not installed, no point going any further type fontforge > /dev/null 2>&1 || { printf "fontforge not installed. Aborting.\n" >&2 exit 1 } tmp_dir=/tmp/install-font [ -d ${tmp_dir} ] || mkdir ${tmp_dir} clean_tmp() { for i in ${tmp_dir}/*[!pe] ; do rm -f "$i" ; done # everything but .pe for i in ${tmp_dir}/* ; do [ -L "$i" ] && rm "$i" ; done # symlinks } interrupt() { clean_tmp printf "\nAborting.\n" exit 130 } error() { case "$1" in no_filename) printf \ "[install-font]: Missing filename. \ Aborting.\n" >&2 exit 1 ;; no_file) printf \ "[install-font]: File \"${file}\" not found. \ Aborting.\n" >&2 exit 1 ;; no_arg) printf \ "[install-font]: Option \"-${option}\" requires an argument. \ Aborting.\n" >&2 show_usage exit 1 ;; filename_arg) printf \ "[install-font]: Option \"-${option}\" requires a non-filename argument. \ Aborting.\n" >&2 show_usage exit 1 ;; no_dir) printf \ "[install-font]: Directory \"${copy_dir}\" not found. \ Aborting.\n" >&2 exit 1 ;; not_dir) printf \ "[install-font]: \"${OPTARG}\" not a directory. \ Aborting.\n" >&2 exit 1 ;; not_writable) printf \ "[install-font]: \"${OPTARG}\" is not writable. \ Aborting.\n" >&2 exit 1 ;; incompatible) printf \ "[install-font]: Incompatible file type. Must have extension ttf|pfa|pfb|otf. \ Aborting.\n" >&2 exit 1 ;; arg_to_f) printf \ "[install-font]: Option -${option} incompatible with multiple filenames. \ Aborting.\n" >&2 exit 1 esac } generate_t42() { cat < ${tmp_dir}/generate-t42.pe # generate-t42.pe Open(\$1); Generate(\$fontname + ".pfa"); Generate(\$fontname + ".t42"); EOF } generate_pfa() { cat < ${tmp_dir}/generate-pfa.pe # generate-pfa.pe Open(\$1); Generate(\$fontname + ".pfa"); EOF } convert_font() { printf "Running fontforge...\n" fontforge -script ${script} "`basename "${file}"`" printf "Done.\n" } make_font() { printf "Creating \033[33m${groff_font}\033[0m...\n" if [ "${is_italic}" ] ; then afmtodit_opts="-e text.enc -i50" else afmtodit_opts="-e text.enc -i0 -m" fi afmtodit ${afmtodit_opts} ${font}.afm ${textmap} ${groff_font} unset afmtodit_opts rm ${font}.afm printf "Done.\n" } install_to_devps() { printf \ "Installing \033[33m${groff_font}\033[0m in ${site_font_devps}/... " mv ${font}.${ext} ${site_font_devps}/ mv ${groff_font} ${site_font_devps}/ chmod 644 ${site_font_devps}/${font}.${ext} chmod 644 ${site_font_devps}/${groff_font} # update the download file in site-font/devps [ -e ${site_font_devps}/download ] || { cp ${devps}/download ${site_font_devps} chmod 666 ${site_font_devps}/download } [ $argc -eq 1 ] && { cp ${site_font_devps}/download ${site_font_devps}/download.bak } printf "${font}\t${font}.${ext}\n" >> ${site_font_devps}/download printf "Done.\n" } install_to_devpdf() { if [ ${install_in_devpdf} ] ; then gropdf=yes else printf \ "Make \033[33m${groff_font}\033[0m available to gropdf? (y/n; default = y) " read gropdf fi case $gropdf in Y | y | YES | Yes | yes | "") printf "Checking for gropdf executable and devpdf directory... " have_gropdf=`type gropdf` if [ "$have_gropdf" ] ; then printf \ "gropdf found.\nInstalling \033[33m${groff_font}\033[0m in ${site_font_devpdf}/... " case ${ext} in t42) mv ${font}.pfa ${site_font_devpdf}/ chmod 644 ${site_font_devpdf}/${font}.pfa ;; pfa) ln -s ${site_font_devps}/${font}.pfa ${site_font_devpdf}/${font}.pfa ;; esac ln -s ${site_font_devps}/${groff_font} ${site_font_devpdf}/${groff_font} [ -e ${site_font_devpdf}/download ] || { touch ${site_font_devpdf}/download && chmod 666 ${site_font_devpdf}/download } [ $argc -eq 1 ] && { cp -f ${site_font_devpdf}/download ${site_font_devpdf}/download.bak } printf "\t${font}\t${font}.pfa\n" >> ${site_font_devpdf}/download printf "Done.\n" else printf \ "gropdf not found.\nNo fonts will be installed in ${site_font_devpdf}.\n" fi ;; esac } get_fontname() { printf \ "Enter +STYLE (eg +R, +I, +B, +BI), or a unique groff name for \ \033[36m${font}\033[0m.\n" printf \ "Leave blank to set name to '\033[36m${font}\033[0m': " } convert_install() { cd ${tmp_dir} convert_font # generate t42/pfa and afm files # get postscript family and font name from afm family_name=`grep "^FamilyName" *afm | \ sed -e 's/^FamilyName *\([[:graph:]]\{1,\}\) *[[:print:]]*$/\1/'` font=`grep "^FontName" *afm | \ sed -e 's/^FontName *\([[:graph:]]\{1,\}\) *[[:print:]]*$/\1/'` is_italic=`grep -i "^FullName .*italic" *afm | sed -e 's/.*\([Ii]talic\)/\1/'` if [ ! ${family} ] ; then # get user's name for family printf "Family name (default = ${family_name}): " read family [ ${family} ] || family=${family_name} fi printf \ " =>\033[36m${font}\033[0m (${file}) assigned to family \ '\033[33m${family}\033[0m'.\n" if [ ! ${groff_font} ] ; then # get groff fontname if [ ! ${append_style} ] ; then get_fontname read groff_font [ ${groff_font} ] || groff_font=${font} append_style=${groff_font:0:1} [ "$append_style" = "+" ] && { append_style=${groff_font##*+} groff_font=${family}${append_style} } else groff_font=${family}${append_style} fi fi printf \ " =>\033[36m${font}\033[0m assigned groff fontname \ '\033[33m${groff_font}\033[0m'.\n" # make links to textmap and text.enc if not already present in tmp_dir # test for textmap or text.map first. [ -e ${devps}/generate/text.map ] && textmap=text.map [ -e ${devps}/generate/textmap ] && textmap=textmap if [ ! -e ${textmap} ] ; then [ -e ${devps}/generate/${textmap} ] && ln -s ${devps}/generate/${textmap} . || { printf "'\${textmap}' not found. Aborting.\n" >&2 ; exit 1 } fi if [ ! -e text.enc ] ; then [ -e ${devps}/text.enc ] && ln -s ${devps}/text.enc . || { printf "'text.enc' not found. Aborting.\n" >&2 ; exit 1 } fi make_font install_to_devps [ ${skip_devpdf} ] || install_to_devpdf rm -f ${font}* cd - &>/dev/null } copy_file() { [ -d ${copy_dir} ] || { echo "${copy_dir} not found; creating." mkdir -p ${copy_dir} chmod 755 ${copy_dir} ; } [ -d ${copy_dir}/${family} ] || { mkdir -p ${copy_dir}/${family} chmod 755 ${copy_dir}/${family} } printf "Installing ${file} in ${copy_dir}/${family}/... " cp "${file}" ${copy_dir}/${family}/ chmod 644 ${copy_dir}/${family}/"${file}" printf "Done.\n" } print_sep() { printf \ "======================================================================\n" } # getopts doesn't check if OPTARG is a flag, or a filename when some # other value is expected check_optarg() { [ "${OPTARG:0:1}" = "-" ] && error no_arg # is an opt when arg to opt expected eval "has_ext=`echo ${OPTARG} | sed -e 's/^[[:graph:]]*\.[[:graph:]]*$/./'`" [ "${has_ext}" = "." ] && error filename_arg # is a filename when filename not expected : } check_optarg_dir() { [ "${OPTARG:0:1}" = "-" ] && error no_arg # is an opt when arg to opt expected [ ! -d "${OPTARG}" ] && error not_dir [ ! -w "${OPTARG}" ] && error not_writable : } while getopts ":C:cndDF:f:hHlpP:s" opt do case "$opt" in c) copy_orig=yes ;; C) option=C check_optarg copy_orig=yes copy_dir=${OPTARG} [ -d ${copy_dir} ] || error no_dir ;; n) dont_copy=yes ;; d) install_in_devpdf=yes ;; D) skip_devpdf=yes ;; F) option=F check_optarg family=${OPTARG} ;; f) option=f opt_f=true check_optarg append_style=${OPTARG:0:1} case ${append_style} in "+") append_style=${OPTARG##*+} ;; *) groff_font=${OPTARG} ;; esac ;; h) show_usage exit 0 ;; H) long_help exit 0 ;; l) loc_or_sysdir=/usr/local/share/groff ;; P) option=P check_optarg_dir loc_or_sysdir=${OPTARG} ;; p) alias mv='mv -i' alias ln='ln -i' alias cp='cp -i' ;; s) loc_or_sysdir=/usr/share/groff ;; \?) printf "Option \"-${OPTARG}\" not valid. Aborting.\n" >&2 show_usage exit 1 ;; :) printf "Option \"-${OPTARG}\" requires an argument. Aborting.\n" >&2 show_usage exit 1 ;; esac done shift $((OPTIND-1)) [ "$#" -eq 0 ] && error no_filename [ $# -gt 1 -a "${opt_f}" ] && { error arg_to_f exit 1 } if [ ! -w "$loc_or_sysdir" ] ; then # need write access to $loc_or_sysdir scriptname=`basename $0` printf \ "You don't have write access to ${loc_or_sysdir} Superuser priviledges required.\nRerun as \ '\033[33msudo ${scriptname} \033[4margs\033[0m' \ or \ '\033[33msu root -c \"${scriptname} \033[4margs\033[0m\033[33m\"\033[0m'\n" exit 126 fi devps=${loc_or_sysdir}/${version}/font/devps devpdf=${loc_or_sysdir}/${version}/font/devpdf site_font_devps=${loc_or_sysdir}/site-font/devps site_font_devpdf=${loc_or_sysdir}/site-font/devpdf # create site-font and site-font/devps and site-font/devpdf # if not present [ -d ${loc_or_sysdir}/site-font ] || { printf "${loc_or_sysdir}/site-font not found; creating.\n" mkdir -p ${loc_or_sysdir}/site-font chmod 755 ${loc_or_sysdir}/site-font } [ -d ${site_font_devps} ] || { printf "${site_font_devps} not found; creating.\n" mkdir -p ${site_font_devps} chmod 755 ${site_font_devps} } [ -d ${site_font_devpdf} ] || { printf "${site_font_devpdf} not found; creating.\n" mkdir -p ${site_font_devpdf} chmod 755 ${site_font_devpdf} } # process files for i in "$@" ; do file="$i" argc=$((argc+1)) [ -f "${file}" ] || error no_file case ${file##*.} in TTF | ttf | PFB | pfb | PFA | pfa | OTF | otf) font_type=${file##*.} ;; *) error incompatible ;; esac ln -s "$PWD/${file}" "${tmp_dir}/`basename "${file}"`" # make a link in tmp dir to file [ $argc -gt 1 ] && print_sep printf "Processing \033[36m$file\033[0m...\n" case ${font_type} in TTF | ttf | OTF | otf) script=generate-t42.pe ext=t42 [ -e /tmp/$script ] || generate_t42 # create if it doesn't exist convert_install if [ "${font_type}" = "TTF" -o "${font_type}" = "ttf" ] ; then [ ${copy_dir} ] || copy_dir=/usr/local/share/fonts/truetype else [ ${copy_dir} ] || copy_dir=/usr/local/share/fonts/opentype fi ;; PFB | pfb | PFA | pfa) script=generate-pfa.pe ext=pfa [ -e /tmp/$script ] || generate_pfa # create if it doesn't exist convert_install [ ${copy_dir} ] || copy_dir=/usr/local/share/fonts/type1 ;; esac # copy input file to a system or named directory if [ ! "$dont_copy" ] ; then if [ ! "$copy_orig" ] ; then printf \ "Copy \033[36m${file}\033[0m to ${copy_dir}/${family}/?\n (y/n; default = n) " read copy_file case "$copy_file" in Y | y | YES | Yes | yes) copy_file ;; * ) printf \ "Install \033[36m${file}\033[0m manually to make it available system-wide.\n" ;; esac else copy_file fi fi unset append_style unset ext unset font unset groff_font unset is_italic done clean_tmp exit 0