From: awpaeth@watpix.uwaterloo.ca (Alan Wm Paeth)
Subject: vdrive.c de VEAWP -- Graphical Antenna Software [enclosed]
Summary: C program for azimuthal plots of driven arrays (Tektronics/Postscript)
Organization: University of Waterloo
Date: Thu, 17 Dec 1992 21:29:22 GMT

Dear and Fellow Netters,

Enclosed please find one (1) homegrown C-language program: vdrive.c. This code
generates azimuthal (polar) plots of antenna fields in both Postscript and
Tektronics format. I'm placing the code in public domain for non-commercial
use. Feel free to give it to a good home (local BBS or FTP server).

Happy Holidays to all...

   Alan Wm Paeth
       de VE3AWP

-------------------
Abstract

Vdrive.c was written to explore the ``design space'' of (phased) vertical
arrays having multiple driven elements. The present version is short on its
electromagnetics models but long on its graphics. Version 1.0 assumes isotropic
``point'' source radiators having arbitrary phase. These are placed as desired
in the (x,y) plane and the resulting electic field computed by vector algebra.
(This is not terribly restrictive -- any radially-symmetric element such as
a vertical dipole may be substituted by the principle of field multiplication).

The output is the antenna pattern plotted against a background. The pattern
line style (solid, dotdash...) is under user control, as are the number of
bearing lines and circles of equal energy which form the background. Additional
graphics include optional annotation of minima and maxima of the pattern with
accompanying table. An optional title line may also be specified.

The stand-alone program was created for use on Unix-based workstations
as an alternative to huge, non-graphical systems or PC-based non-public
domain systems. Other goals include (1) compact size (2) portability and
(3) extensibility. Any extensions or other contributions most welcome.
[amplitude scaling of elements is straightfoward; treatment of parasitic
elements far more desirable...].

Instructions for compiling and testing appear in the source code; the command
"./vdrive -u" gives a full usage "man" summary page. I may be reached at the
e-mail address appearing in the source code.

   /Alan Paeth
-----

/*
 * vdrive.c - Vertical Driven Element Array Plots
 *
 * copyright (c) 1992 by Alan Wm Paeth
 * The author may be reached as VE3AWP, KD3XG, awpaeth@alumni.caltech.edu
 *
 * This is a shareware package created for amateur radio use. Its free and
 * general redistribution is encouraged among private users, groups, clubs
 * and other non-profit organizations, provided that this placard, copyright,
 * and other author references remain affixed. Redistribution for commercial
 * purpose or other tangible remuneration is expressly prohibited.
 *
 * Help defeat software pirates' black marketeering: send a copy to a friend!
 */

/*
 * To Compile: 'cc -O vdrive.c -lm -o vdrive'
 * To Test:    './vdrive -e -m -a .75 10 315'
 *
 * testing/use requires Tek-4010 emulation turned on
 *     X-windows: use xterm 'switch to Tek' mode
 *     Sun users: run 'tektool' before invoking
 */

#include <stdio.h>
#include <math.h>

#define VERNO 1		/* August,  1992 (created)  by AWP */
#define REVNO 1		/* December 1992 (modified) by AWP */

#define HEADINGS 360	/* # of discrete computed/plotted headings */
#define MAXN 100	/* Max # of sources */
#define NLOBE 9
#define NNULL 9

#define PI2 (2.0*3.14159265358979324)
#define dsin(x) sin(PI2*(x)/360.0)
#define dcos(x) cos(PI2*(x)/360.0)


#define USAGE "\
vdrive: -- USAGE--\n\
Azimuthal plots of driven vertical arrays in Tektronix or Postscript.\n\
Three {two} entry input lines define the [R, {theta}, phase] of each\n\
driven element on stdin, with [x y phase] rectangular data an option.\n\
Single element descriptions assume an element at the origin: [0 0 0].\n\
Input may alternately appear on the command line in groups of three with\n\
zeros fill assumed. By both rules, \"vdrive .25 90\" describes a 1/4-wave\n\
end-array on the x axis (even under -r); The same layout with broadside\n\
(inphase) drive and annotated postscript output is \"vdrive .5 0 -a -m -p\".\n\
\n\
Switches:\n\
  -a   {off} antenna sources are plotted\n\
  -b n {6}   # of bearing lines = 180/n radials ('-b 0' to omit)\n\
  -c n {4}   circles of energy ('-c 0' to omit)\n\
  -e   {off} erase the display before plotting\n\
  -f n {1.0} frequency scaling of element phases\n\
  -l n {0}   line style; n=[0..4]: solid, dot, dotdash, small dash, dash\n\
  -m   {off} lobe minima and maxima annotations\n\
  -n   {off} normalize to absolute field strenth: 1/(# of sources)\n\
  -p   {off} postscript output to stdout\n\
  -r   {off} rectangular coordinates on input\n\
  -s n {1.0} scale factor of element positions\n\
  -t   {\"\"}  title text\n\
  -u   {off} usage message\n\
\n\
Example:\n\
\n\
   ./vdrive -e -a -l 4 -m -c 5 -b 12\n\
   # 1/4 wave 'upward' (y-axis) end-fire, dashed lines, more background\n\
   .125  90.0  0\n\
   .125 270.0 90\n\
   ^D\n"

/* cmd data */

int antennaswitch, eraseswitch, maxswitch, normswitch, postswitch, rectswitch;
int bearingswitch, circleswitch, lineswitch; /* int */
double freqswitch, scaleswitch; /* float */
char *titleswitch; /* string */

/*
 * Array Data Format
 *
 * Internal data format is N records, each having an origin distance,
 * a polar-angle (to origin) and the EM phase of excitation. Following
 * standard conventions (see _Kraus_) a positive phase angle indicates
 * an advance in the arrival of the wave-front.
 *
 * External record format is polar: (r, theta, phase) in which linear distance
 * "r" is in terms of wavelength (1 = 1 lambda). Alternatively rectangular data
 * uses the "-r" switch and (x, y, phase) triples are presented.
 *
 */

int N;			/* # of sources */
double R[MAXN];		/* origin distance for nth source */
double theta[MAXN];	/* origin angle for nth source */
double phase[MAXN];	/* EM phase of source (- leads, + lags) */

/* derived data */

double field[HEADINGS];	/* wavefront energy in polar form */
double lobemax;		/* the amount of maximum energy */
double lobeang;		/* (first) angle of maximum energy */

/* screen & char sizes + vector styles (4010-based but used generally) */

#define XSCALE 1024
#define YSCALE  768

#define CHARWID 14
#define CHARHGT 18

#define SOLID   0
#define DOTTED  1
#define DOTDASH 2
#define LITDASH 3
#define BIGDASH 4

/* CODE */

err(s)
    char *s;
    {
    fprintf(stderr, "\nvdrive: %s\n(use '-u' for usage)\n", s);
    exit(1);
    }

/* Generic Low-Level Line Graphics */

gstart()		{ postswitch ? pstart()   : tstart();   }
gstop()			{ postswitch ? pstop()    : tstop();    }
gerase()		{ postswitch ? perase()   : terase();   }
gline(i)    int i;	{ postswitch ? pline(i)   : tline(i);   }
gthick(i)   int i;	{ postswitch ? pthick(i)  : tthick(i); }
gmove(x,y)  int x,y;	{ postswitch ? pmove(x,y) : tmove(x,y); }
gdraw(x,y)  int x,y;	{ postswitch ? pdraw(x,y) : tdraw(x,y); }
galpha(x,y,s) int x,y; char *s;	{ postswitch ? palpha(x,y,s) : talpha(x,y,s); }

/* Tek 4010 Line Graphics */

/* codes for tek plot routines -- move, draw, plot and alpha */

#define GS    035
#define US    037
#define ESC   033
#define FF    014
#define LC     96

/* internal state (current drawing position) */

static int oldHiY = 0, oldLoY = 0, oldHiX = 0;

tstart()    /* switch to plot mode */
    {
    putchar(GS);
    putchar('@');
    oldHiY = oldLoY = oldHiX = 0;
    }

tstop()    /* home to origin, switch to alpha mode */
    {
    talpha(0, 0, "");
    }

talpha(x, y, s)
    int x, y;
    char *s;
    {
    tmove(x, y);
    putchar(US);
    puts(s);
    fflush(stdout);
    }

terase()
    {
    putchar(ESC);
    putchar(FF);
    fflush(stdout);
    }

tline(s)
    {
    if ((s < 0) || (s > 4)) s = 0;	/* zero for normal vec */
    putchar(ESC);
    putchar(LC + s);
   }

tthick(i)
    int i;
    {
/* tek lines are all of one thickness. */
    }

tmove(x, y)    /* move to (x,y) */
    {
    putchar(GS);
    tdraw(x, y);
    }

tdraw(x, y)    /* draw to (x,y) */
    {
    int hiY, loY, hiX, loX;
    if (x < 0) x = 0;
    if (y < 0) y = 0;
    if (x >= XSCALE) x = XSCALE;
    if (y >= YSCALE) y = YSCALE;

    hiY = 0040 | (y>>5 & 037),
    loY = 0140 | (y    & 037),
    hiX = 0040 | (x>>5 & 037),
    loX = 0100 | (x    & 037);
    if (hiY != oldHiY		      ) putchar(hiY);
    if (loY != oldLoY || hiX != oldHiX) putchar(loY);
    if (hiX != oldHiX		      ) putchar(hiX);
					putchar(loX);
    oldHiY = hiY;
    oldLoY = loY;
    oldHiX = hiX;
    }

/* Postscript  */

int ppage;	/* should this page be printed? */
int drawmode;	/* vector move/draw flag */

pout(s)
    char *s;
    {
/* all postscript output comes thru here -- replace 'stdout' as desired */
    fprintf(stdout, "%s", s);
    }

pstart()    /* switch to plot mode */
    {
    ppage = 0;
    drawmode = -1;	/* no vectors drawn yet */
    pout("\
%!PS-Adobe-2.0 EPSF-1.2\n\
%%Creator: AWPaeth@Alumni.Caltech.edu\n\
%%Title: VEAP-PostScript\n\
%%Pages: 1\n\
%%DocumentFonts: Helvetica\n\
%%BoundingBox: 0 0 1024 768\n\
%%EndComments\n\
%%EndProlog\n\
%%Page: 0 1\n\
% attribute macros\n\
%\n\
/solid   {[   ] 0 setdash} def\n\
/dotted  {[1 4] 0 setdash} def\n\
/dotdash {[6 8 1 6] 0 setdash} def\n\
/sdashed {[4 6] 0 setdash} def\n\
/dashed  {[8 12] 0 setdash} def\n\
/newwid  {setlinewidth} def\n\
/newfont {exch findfont exch scalefont setfont} def\n\
%\n\
/T {moveto show} def\n\
/M {moveto} def\n\
/L {lineto} def\n\
%\n\
% global defaults\n\
%\n\
1 setlinecap\n\
1 setlinejoin\n\
%% PAGE SCALE + OFFSET %%\n\
0.6 0.6 scale\n\
 50  50 translate\n\
%%\n\
%\n\
1 newwid\n\
/Helvetica 24 newfont\n\
%\n\
% THE STUFF\n\
%\n");
    }

pstop()    /* home to origin, switch to alpha mode */
    {
    pendvert();
    pout("\
%\n\
%%Trailer\n\
%%Pages: 1\n\
");
    ppage = 1;		/* PUT SHOWPAGE REGARDLESS */
    if (ppage) pout("showpage\n");  /* no "erase"; comment out the showpage */
    pout("%%end\n");
    }

pline(s)
    {
    pendvert();
/* one may optimize "changes" to the current line style, if wanted */
    switch(s)
	{
	default:
	case 0: pout("solid\n"); break;
	case 1: pout("dotted\n"); break;
	case 2: pout("dotdash\n"); break;
	case 3: pout("sdashed\n"); break;
	case 4: pout("dashed\n"); break;
	}
    }

pthick(i)
    int i;
    {
    pendvert();
    printf("%d newwid\n", i);
    }

pendvert()
    {
    if (drawmode > 0) pout("stroke\n");
    drawmode = 0;
    }

pmove(x, y)    /* move to (x,y) */
    int x, y;
    {
/* drawmode: -1: first call (init); 0: vector off; 1: vector in progress */
    if (drawmode) pendvert(); /* and then fall through to the next line... */
    if (drawmode <= 0) pout("newpath");
    printf(" %d %d M\n", x, y);
    drawmode = 1;
    }

pdraw(x, y)    /* draw to (x,y) */
    int x, y;
    {
    if (drawmode < 0) pmove(0, 0);	/* if kicked-started with "draw" */
    printf(" %d %d L\n", x, y);
    }

palpha(x, y, s)
    int x, y;
    char *s;
    {
    pendvert();
    printf("(%s) %d %d T\n", s, x, y);
    }

perase()
    {
    ppage = 1;
    drawmode = -1;
    }

/* Higher-level graphics routines */

ltext(x, y, s)
    int x, y;
    char *s;
    {
    galpha(x, y, s);
    }

rtext(x, y, s)
    int x, y;
    char *s;
    {
    galpha(x-CHARWID*strlen(s), y, s);
    }

ctext(x, y, s)
    int x, y;
    char *s;
    {
    galpha(x-(CHARWID*strlen(s))/2, y, s);
    }

plotheader()
    {
    char s[100];
    sprintf(s,
	"VDRIVE %d.%d Vertical Driven Array Plots de VE3AWP -- Alan Paeth",
	VERNO, REVNO);
    ltext(50, 720, s);
    if (titleswitch && (strlen(titleswitch) > 0)) ltext(50, 680, titleswitch);
    }

#if HYPOT
/* use this if not provided by Unix. Not as well-conditioned numerically */
double hypot(x, y)
    double x, y;
    {
    return(sqrt(x*x+y*y));
    }
#endif

torect(r, th, x, y)
    double r, th, *x, *y;
    {
    *x = r * dcos(th);
    *y = r * dsin(th);
    }

double toang(az)
    int az;
    {
    double d;
    d = (double)(az)*360.0/HEADINGS;
    if (d > 360.0) d -= 360.0;
    else if (d < 0.0) d += 360.0;
    return(d);
    }

plotscale(x, y, ix, iy)
    double x, y;
    int *ix, *iy;
    {
    int scale;
    scale = (YSCALE < XSCALE) ? YSCALE : XSCALE;
/* bipolar-> unipolar -> integers; add 10% margins */
    *ix = (2.0/5.0)*(scale)*(x + 1.1);
    *iy = (2.0/5.0)*(scale)*(y + 1.1);
    }

radtext(rad, th, s)
    double rad, th;
    char *s;
    {
/* left justify in left-half plane (-90..90], right for right: (90..270] */
    double x, y;
    int ix, iy;
    torect(rad, th, &x, &y);
    plotscale(x, y, &ix, &iy);
    ctext(ix, iy-CHARHGT/2, s);
    }

/*
 * NOTE: radial and circle drawing would be better handled as low-level
 * graphics primitives. This would make the .ps output both more compact
 * and less jaggy.
 */

 plotradials(style1, style2)
    int style1, style2;
    {
    double x, y;
    int b, t, ix, iy;
    char s[10];
    for (b=0; b<bearingswitch; b++)	/* radials every 'ang' degrees */
	{
	t = (180*b)/bearingswitch;
/*
 *  style1, style2 describe the line style (1) on-axis and (2) off-axis.
 *  the radial lengths are 5% larger than the unit circle
 */
	gline( ((t%90) == 0) ? style1 : style2);
	torect(1.0, (double)t, &x, &y);
	plotscale(  x,  y, &ix, &iy); gmove(ix, iy);
	plotscale( -x, -y, &ix, &iy); gdraw(ix, iy);
	sprintf(s, "%3d", t);
	radtext(1.05, (double)t, s);
	sprintf(s, "%3d", t+180);
	radtext(1.05, (double)(t+180), s);
	}
    }

plotcircle(rad, style)
    double rad;
    int style;
    {
    double x, y;
    int az, ix, iy, ix2, iy2;
    gline(style);
    for (az=0; az<HEADINGS; az++)
	{
	torect(rad, toang(az), &x, &y);
	plotscale(x, y, &ix, &iy);
	if (az == 0) gmove(ix2 = ix, iy2 = iy); else gdraw(ix, iy);
	}
    gdraw(ix2, iy2);
    }

plotfield(style)
    int style;
    {
    double x, y, radial;
    int az, ix, iy, ix2, iy2;
    gline(style);
    gthick(2);
    for (az=0; az<HEADINGS; az++)
	{
	torect(field[az], toang(az), &x, &y);
	plotscale(x, y, &ix, &iy);
	if (az == 0) gmove(ix2 = ix, iy2 = iy); else gdraw(ix, iy);
	}
    gdraw(ix2, iy2);
    gthick(1);
    }

plottick(ang)
    double ang;
    {
    double x, y;
    int ix, iy;
    torect(1.02, ang, &x, &y); plotscale(x, y, &ix, &iy); gmove(ix, iy);
    torect( .98, ang, &x, &y); plotscale(x, y, &ix, &iy); gdraw(ix, iy);
    }

plotlobeinf()
    {
    double x, y, odir, dir, ofield, refdB;
    int az, ix, iy;
    int xp, yp, ld, lobes[NLOBE], lobesi, nulls[NNULL], nullsi, lim, i;
    char s[50];
/* placard location, line leading, paragraph leading */
    xp = 700;
    yp = 645;
#define LEAD  (CHARHGT+2)
#define LEADP ((LEAD*3)/2)
/* find extrema by watching monotonicity; dir = +/- for in/decreasing field */
    gline(SOLID);
    ofield = field[HEADINGS-1];
    odir = ofield - field[HEADINGS-2];
    lobesi = nullsi = 0;
    for (az=0; az<HEADINGS; az++)
	{
	dir = field[az] - ofield;
	if (odir*dir < 0.0)		/* extrema */
	    {
	    if (dir < 0.0) {if ((lobesi++)<NLOBE) lobes[lobesi-1]=az-1;} /*max*/
	    else	   {if ((nullsi++)<NNULL) nulls[nullsi-1]=az-1;} /*min*/
	    plottick(toang(az-1));
	    }
	ofield = field[az];
	odir = dir;
	}
/* then add extrema placard */
    refdB = 0.0; /* (maxswitch) log10(1/n) : 0.0; */
    if (lobesi > 0)
	{
	ltext(xp, yp, sprintf(s, "Lobes/Maxima (%d)", lobesi));
	lim = (lobesi > NLOBE) ? NLOBE : lobesi;
	for(i=0; i<lim; i++) ltext(xp+20, yp -= LEAD,
	    sprintf(s, "%1d %.1f %.1fdB", i+1, toang(lobes[i]),
	    20.0 * (log10(field[lobes[i]]) - refdB)));
	if (lobesi > lim) ltext(xp+20, yp -= LEAD, " . . .");
	}
    if (nullsi > 0)
	{
	ltext(xp, yp -= LEADP, sprintf(s, "Nulls/Minima (%d)", nullsi));
	lim = (nullsi > NNULL) ? NNULL : nullsi;
	for(i=0; i<lim; i++) ltext(xp+20, yp -= LEAD,
		sprintf(s, "%1d %.1f %.1fdB", i+1, toang(nulls[i]),
		20.0 * (log10(field[nulls[i]]) - refdB)));
	if (nullsi > lim) ltext(xp+20, yp -= LEAD, " . . .");
	}
    }

plotcross(x, y)
    int x, y;
    {
    gmove(x-5, y+5); gdraw(x+5, y-5);
    gmove(x+5, y+5); gdraw(x-5, y-5);
    }


plotantinf()
    {
#define SXMIN 700
#define SXMAX 900
#define SYMIN  80
#define SYMAX 280
    int i, ix, iy;
    double x, y, xmin, xmax, ymin, ymax, xscale, yscale, scale;
    char s[50];
    xmin = ymin =  1e30;
    xmax = ymax = -1e30;
    gline(SOLID);
    for (i=0; i<N; i++)
	{
	torect(R[i], theta[i], &x, &y);
	if (x < xmin) xmin = x;
	if (x > xmax) xmax = x;
	if (y < ymin) ymin = y;
	if (y > ymax) ymax = y;
	}
    xscale = xmax - xmin;
    yscale = ymax - ymin;
    scale = (xscale > yscale) ? xscale : yscale;
/* plotting an absolute scale symbol would also be useful, eg: |<--.25L -->| */
    for (i=0; i<N; i++)
	{
	torect(R[i], theta[i], &x, &y);
	x = (x - xmin)/scale - xscale/(2.0*scale);
	y = (y - ymin)/scale - yscale/(2.0*scale);
	plotscale(x, y, &ix, &iy);
	plotcross(ix, iy);
	ctext(ix, iy-22,
	    sprintf(s, (phase[i] == 0.0 ? "%d" : "%d/%.0f"), i+1, phase[i]));
	}
    }

plotchart()
    {
    int i;
/* first the circles, then the radials */
    plotheader();
    if (circleswitch)
	{
	plotcircle(1.0, SOLID);
	for (i=1; i<circleswitch; i++)
	    plotcircle((double)(i)/circleswitch, DOTTED);
	}
    plotradials(SOLID, DOTTED);
    plotfield(((lineswitch < 0) || (lineswitch>4)) ? SOLID : lineswitch);
    if (maxswitch) plotlobeinf();
    if (antennaswitch) plotantinf();
    }

/* i/o routines */

getdata()
    {
    if (feof(stdin)) err("no input data");
    while (N< MAXN)
	{
	char buf[80];
	double tmp;
	int recs;
	gets(buf);
	if (feof(stdin)) break;
	if ((buf[0] == '#') || (buf[0] == '\0')) continue;
	recs = sscanf(buf, "%F %F %F %F", &R[N], &theta[N], &phase[N], &tmp);
	if (recs == 0) continue;
	if (recs == 2)
	    {
/* assume just (R, phase) data (along X axis), elide bearing (middle column) */
	    phase[N] = theta[N];
	    theta[N] = 0.0;
	    }
	else if (recs != 3) err("data record did not have two or three fields");
	N++;
	}
    if (N == 0) err("no input detail");
    }

addorigin()
    {
    if (N == 1)
	{
/* one vertical given -> assume 2-el system referenced to vert at the origin */
	R[1] = theta[1] = phase[1] = 0.0;
	N = 2;
	}
    }

datatopolar()
    {
    int i;
    for (i=0; i<N; i++)
	{
	double t1, t2;
	t1 = hypot(R[i], theta[i]);
/* atan(y, x) returns NaN if y = x = 0 (!!!) */
	if ((theta[i] == 0.0) && (R[i] == 0.0)) t2 = 0.0;
	else t2 = atan2(theta[i], R[i])*(360.0/PI2);
	R[i] = t1;
	theta[i] = t2;
	}
    }

/* not presently called */

datatorect()
    {
    int i;
    for (i=0; i<N; i++) torect(R[i], theta[i], &R[i], &theta[i]);
    }

/*
 * Electro-magnetic field calculations
 */

fieldcomp()
    {
    int s, az;
    lobemax = 0.0;
/*
 * add any phase or scale adjustments to the input data before proceeding
 */
    if (freqswitch != 1.0) for(s=0; s<N; s++) phase[s] *= freqswitch;
    if (scaleswitch != 1.0) for(s=0; s<N; s++) R[s] *= scaleswitch;
/*
 * now the electrostatic field computation loop
 */
   for (az=0; az<HEADINGS; az++)
	{
	double tphase, samp, camp, amp;
	samp = camp = 0.0;
	for (s=0; s<N; s++)
	    {
/*
 * source on x axis R wavelengths from the origin; find total phase delay
 * and then sum the phase/ampl vector of all N sources in rect. coordinates.
 * (note: wavelengths are circumferential units so multiply by 360 [2Pi])
 */
	    tphase = (R[s]*360.0) * dcos(theta[s]-az) + phase[s];
/* scale each RHS term for isotropic sources having dissimilar amplitudes */
	    samp += dsin(tphase);
	    camp += dcos(tphase);
	    }
	amp = hypot(samp, camp);
	field[az] = amp;
	if (amp > lobemax) lobemax = amp;
	}
    }

fieldnorm(n)
    double n;
    {
    int az;
    double inv;
    if (n <= 1.0e-9) err("Electric Field is everywhere zero");
    inv = 1.0 / n;
    for (az=0; az<HEADINGS; az++) field[az] *= inv;
    }

#define STACKLIM 3

parseargs(argc, argv)
    char *argv[];
    {
    int i, fstacki;
    double fstack[STACKLIM];
    char msg[50];
    fstacki = 0;
/* set up defaults */
    antennaswitch = eraseswitch = maxswitch = postswitch = rectswitch = 0;
    bearingswitch = 6;
    circleswitch = 4;
    lineswitch = SOLID;
    freqswitch = scaleswitch = 1.0;
    titleswitch = "";

/* scan for commands */

#define Nextint(xx)    ((argv[++i]) ? atoi(argv[i]) : Checktrail(xx))
#define Nextfloat(xx)  ((argv[++i]) ? atof(argv[i]) : Checktrail(xx))
#define Nextstr(xx)    ((argv[++i]) ?      argv[i]  : (char*) Checktrail(xx))
#define Checktrail(xx) err(sprintf(msg,"trailing '%s' switch needs a value",xx))

    for (i=1; i<argc; i++)
	{
	if (argv[i][0] == '-') switch(argv[i][1])
	    {
	    case 'a':
	    case 'A': antennaswitch = 1; break;
	    case 'b':
	    case 'B': bearingswitch = Nextint("Bearing"); break;
	    case 'c':
	    case 'C': circleswitch = Nextint("Circle"); break;
	    case 'e':
	    case 'E': eraseswitch = 1; break;
	    case 'f':
	    case 'F': freqswitch = Nextfloat("Freq_scale"); break;
	    case 'l':
	    case 'L': lineswitch = Nextint("Lines"); break;
	    case 'm':
	    case 'M': maxswitch = 1; break;
	    case 'n':
	    case 'N': normswitch = 1; break;
	    case 'p':
	    case 'P': postswitch = 1; break;
	    case 'r':
	    case 'R': rectswitch = 1; break;
	    case 's':
	    case 'S': scaleswitch = Nextfloat("Scale"); break;
	    case 't':
	    case 'T': titleswitch = Nextstr("Title"); break;
	    case 'u':
	    case 'U': fprintf(stderr, "%s", USAGE); exit(0); break;
	    case '\0': err("empty '-' switch"); break;
	    default: err("unknown switch");
	    }
	else
	    {
	    if (fstacki >= STACKLIM) err("too many command line data");
	    fstack[fstacki++] = atof(argv[i]);
	    }
	}
/* restack any cmd line data into records */
    if (fstacki) R[N++] = fstack[0];
    if (fstacki == 2)
	{
	theta[0] = 0.0;
	phase[0] = fstack[1];
	}
    if (fstacki == 3)
	{
	theta[0] = fstack[1];
	phase[0] = fstack[2];
	}
    }

main(argc, argv)
    char *argv[];
    {
    parseargs(argc, argv);
    if (N == 0) getdata();
    if (N == 1) addorigin();
    if (rectswitch) datatopolar();
    fieldcomp();
    fieldnorm(normswitch ? (double)(N) : lobemax);
    gstart();
    if (eraseswitch) gerase();
    plotchart();
    gstop();
    exit(0);
    }

---