Josh Hurst wrote:
> 
> How can I get the getopts function in ksh93 to output a full manual
> page, including the long options? does anyone have an example script
> which uses getopts with long options like '--test' as alias for '-t'
> and prints a full manual page for '--man'?

1. I've looked a little bit around and it seems we have two examples in
the tree (usr/src/cmd/ast/msgcc/msgcc.sh and
usr/src/cmd/ast/msgcc/msgadmin.sh). 

2. I've spend some more time thinking about this and then hacked some
"getopts" support into my mandelbrot demo application (attached as
"mandelbrotset1.ksh").

$ mandelbrotset1.ksh --man # output now looks like this:
-- snip --
NAME
  mandelbrotset1.ksh - generate mandelbrot set fractals with ksh93

SYNOPSIS
  mandelbrotset1.ksh [ options ]

DESCRIPTION
  \bmandelbrotset1.ksh\b mandelbrot set fractal generator which runs
  either in serial or parallel mode (using multiple worker jobs).

OPTIONS
  -w, --width=width
                  Width of fractal.
  -h, --height=height
                  Height of fractal.
  -s, --symbols=symbolstring
                  Symbols to build the fractal from.
  -m, --mag=magnificationlevel
                  Magnification level.
  -p, --stepwidth=widthperstep
                  Width per step.
  -S, --serial    Run in serial mode.
  -P, --parallel  Run in parallel mode.
  -M, --mode=mode Execution mode.
  -C, --numcpus=numcpus
                  Number of processors used for parallel execution.

SEE ALSO
  \bjuliaset1.ksh\b(1), \bksh93\b(1)

IMPLEMENTATION
  version         mandelbrotset1.ksh (Roland Mainz) 2006-11-15
-- snip --

Note that the manual page is localised, e.g. "ksh93 -D
mandelbrotset1.ksh" will list the string passed to "getopts" as
localiseable, allowing easy translation of the whole manual page.

Known bugs (related to the "getopts" usage in the script):
- I found no way (yet) to limit an option to the long form only (e.g. no
single-letter option specfied (for example "--mode" would be a good
canidate))
- ksh93's getopts has a way to force that an option only takes numbers
as argument for an option. I've tried various combinations but none of
them seems to work

----

Bye,
Roland

-- 
  __ .  . __
 (o.\ \/ /.o) roland.mainz at nrubsig.org
  \__\/\/__/  MPEG specialist, C&&JAVA&&Sun&&Unix programmer
  /O /==\ O\  TEL +49 641 7950090
 (;O/ \/ \O;)
-------------- next part --------------
#!/bin/ksh93

#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#

#
# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I%     %E% SMI"
#

#
# mandelbrotset1.ksh - a simple mandelbrot set and parallel execution
# demo
#
# Written by Roland Mainz <roland.mainz at nrubsig.org>
#

export PATH=/bin:/usr/bin:/usr/X11R6/bin:/usr/openwin/bin

function printmsg
{
    print "$@" >&2
}

function fatal_error
{
    print "${progname}: $@" >&2
}

function print_color
{   
    print -n "${symbollist:${1}:1}"
}

function mandelbrot
{
    float   x=$1
    float   y=$2
    float   xx
    float   yy
    float   x1=$3
    float   y1=$4
    integer iteration=$5
    integer max_iteration=$6
    float   mag
       
    for (( mag=0 ; mag < max_mag && iteration < max_iteration ; iteration++ )) 
; do
        (( xx=x*x ))
        (( yy=y*y ))
        (( mag=xx+yy ))

        (( y=x*y*2+y1 ))
        (( x=xx-yy+x1 ))
    done

    print ${iteration}

    return 0
}

function loop_serial
{
    for (( y=y_min ; y < y_max ; y+=stepwidth )) ; do
        for (( x=x_min ; x < x_max ; x+=stepwidth )) ; do
            print_color $(mandelbrot ${x} ${y} ${x} ${y} 1 ${symbollistlen})
        done

        print
    done
}

function loop_parallel
{
    integer numjobs=0
    # the following calculation suffers from rounding errors
    integer lines_per_job=$(( ((m_height+(numcpus-1)) / numcpus) ))

    printmsg "# lines_per_job=${lines_per_job}"
    printmsg "# numcpus=${numcpus}"
    
    # "renice" worker jobs
    set -o bgnice
    
    # try to generate a job identifer prefix which is unique across multiple 
hosts
    jobident="job_host_$(uname -n)pid_$$_ppid${PPID}"
    
    printmsg $"## prepare..."
    for (( y=y_min ; y < y_max ; y+=(stepwidth*lines_per_job) )) ; do
        rm -f "/tmp/mandelbrot_${jobident}_child_$y.joboutput"

        let numjobs++
    done

    printmsg $"## running ${numjobs} children..."
    for (( y=y_min ; y < y_max ; y+=(stepwidth*lines_per_job) )) ; do
        (
            for (( ; y < y_max && lines_per_job-- > 0 ; y+=stepwidth )) ; do
                for (( x=x_min ; x < x_max ; x+=stepwidth )) ; do
                    print_color $(mandelbrot ${x} ${y} ${x} ${y} 1 
${symbollistlen})
                done
                
                print
            done >"/tmp/mandelbrot_${jobident}_child_$y.joboutput"
        ) &     
    done
    
    printmsg $"## waiting for ${numjobs} children..."
    wait

    printmsg $"## output:"
    for (( y=y_min ; y < y_max ; y+=(stepwidth*lines_per_job) )) ; do
        print "$(cat "/tmp/mandelbrot_${jobident}_child_$y.joboutput")"
        rm "/tmp/mandelbrot_${jobident}_child_$y.joboutput"
    done
}

# main
builtin printf
builtin cat
builtin rm
builtin sleep
builtin uname # loop_parallel needs the ksh93 builtin version to generate 
unique job file names

float x_max
float x_min
float y_max
float y_min
float m_width
float m_height
float max_mag
float stepwidth
integer numcpus

# make sure ${COLUMN} and ${LINES} are set
eval $(resize)

symbollist='    
.:0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ%#'
symbollistlen=$(( ${#symbollist} - 1))
mode="parallel"
progname="${0}"
max_mag=400
stepwidth=0.1
numcpus=16

let m_width=COLUMNS-1 m_height=LINES-2

progname="${0}"

USAGE=$"
[-?
@(#)\$Id: mandelbrotset1.ksh (Roland Mainz) 2006-11-15 \$
]
[+NAME?mandelbrotset1.ksh - generate mandelbrot set fractals with ksh93]
[+DESCRIPTION?\bmandelbrotset1.ksh\b mandelbrot set fractal generator
        which runs either in serial or parallel mode (using multiple worker 
jobs).]
[w:width?Width of fractal.]:[width]
[h:height?Height of fractal.]:[height]
[s:symbols?Symbols to build the fractal from.]:[symbolstring]
[m:mag?Magnification level.]:[magnificationlevel]
[p:stepwidth?Width per step.]:[widthperstep]
[S:serial?Run in serial mode.]
[P:parallel?Run in parallel mode.]
[M:mode?Execution mode.]:[mode]
[C:numcpus?Number of processors used for parallel execution.]:[numcpus]
[+SEE ALSO?\bjuliaset1.ksh\b(1), \bksh93\b(1)]
"

function usage
{
    OPTIND=0
    getopts -a "${progname}" "${USAGE}" OPT '-?'
    exit 2
}

while getopts -a "${progname}" "${USAGE}" OPT ; do 
    printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|"
    case ${OPT} in
        w)    m_width="${OPTARG}" ;;
        h)    m_height="${OPTARG}" ;;
        s)    symbollist="${OPTARG}" ;;
        m)    max_mag="${OPTARG}" ;;
        p)    stepwidth="${OPTARG}" ;;
        S)    mode="serial" ;;
        P)    mode="parallel" ;;
        M)    mode="${OPTARG}" ;;
        C)    numcpus="${OPTARG}" ;;
        *)    usage ;;
    esac
done
shift ${OPTIND}-1

printmsg "# width=${m_width}"
printmsg "# height=${m_height}"
printmsg "# max_mag=${max_mag}"
printmsg "# stepwidth=${stepwidth}"
printmsg "# symbollist='${symbollist}'"
printmsg "# mode=${mode}"

symbollistlen=$(( ${#symbollist} - 1))

let x_max=m_width*stepwidth/2.  x_min=-x_max
let y_max=m_height*stepwidth/2. y_min=-y_max

case "${mode}" in
    parallel) loop_parallel ;;
    serial)   loop_serial ;;
    *) fatal_error $"Unknown mode \"${mode}\"."
esac

# EOF.

Reply via email to