xref: /aosp_15_r20/external/one-true-awk/testdir/chem.awk (revision 9a7741de182b2776d7b30d6355f2585c0780a51b)
1*9a7741deSElliott HughesBEGIN {
2*9a7741deSElliott Hughes	macros = "/usr/bwk/chem/chem.macros"	# CHANGE ME!!!!!
3*9a7741deSElliott Hughes	macros = "/dev/null" # since originals are lost
4*9a7741deSElliott Hughes
5*9a7741deSElliott Hughes	pi = 3.141592654
6*9a7741deSElliott Hughes	deg = 57.29578
7*9a7741deSElliott Hughes	setparams(1.0)
8*9a7741deSElliott Hughes	set(dc, "up 0 right 90 down 180 left 270 ne 45 se 135 sw 225 nw 315")
9*9a7741deSElliott Hughes	set(dc, "0 n 30 ne 45 ne 60 ne 90 e 120 se 135 se 150 se 180 s")
10*9a7741deSElliott Hughes	set(dc, "300 nw 315 nw 330 nw 270 w 210 sw 225 sw 240 sw")
11*9a7741deSElliott Hughes}
12*9a7741deSElliott Hughesfunction init() {
13*9a7741deSElliott Hughes	printf ".PS\n"
14*9a7741deSElliott Hughes	if (firsttime++ == 0) {
15*9a7741deSElliott Hughes		printf "copy \"%s\"\n", macros
16*9a7741deSElliott Hughes		printf "\ttextht = %g; textwid = .1; cwid = %g\n", textht, cwid
17*9a7741deSElliott Hughes		printf "\tlineht = %g; linewid = %g\n", lineht, linewid
18*9a7741deSElliott Hughes	}
19*9a7741deSElliott Hughes	printf "Last: 0,0\n"
20*9a7741deSElliott Hughes	RING = "R"; MOL = "M"; BOND = "B"; OTHER = "O"	# manifests
21*9a7741deSElliott Hughes	last = OTHER
22*9a7741deSElliott Hughes	dir = 90
23*9a7741deSElliott Hughes}
24*9a7741deSElliott Hughesfunction setparams(scale) {
25*9a7741deSElliott Hughes	lineht = scale * 0.2
26*9a7741deSElliott Hughes	linewid = scale * 0.2
27*9a7741deSElliott Hughes	textht = scale * 0.16
28*9a7741deSElliott Hughes	db = scale * 0.2		# bond length
29*9a7741deSElliott Hughes	cwid = scale * 0.12		# character width
30*9a7741deSElliott Hughes	cr = scale * 0.08		# rad of invis circles at ring vertices
31*9a7741deSElliott Hughes	crh = scale * 0.16		# ht of invis ellipse at ring vertices
32*9a7741deSElliott Hughes	crw = scale * 0.12		# wid
33*9a7741deSElliott Hughes	dav = scale * 0.015		# vertical shift up for atoms in atom macro
34*9a7741deSElliott Hughes	dew = scale * 0.02		# east-west shift for left of/right of
35*9a7741deSElliott Hughes	ringside = scale * 0.3		# side of all rings
36*9a7741deSElliott Hughes	dbrack = scale * 0.1		# length of bottom of bracket
37*9a7741deSElliott Hughes}
38*9a7741deSElliott Hughes
39*9a7741deSElliott Hughes	{ lineno++ }
40*9a7741deSElliott Hughes
41*9a7741deSElliott Hughes/^(\.cstart)|(begin chem)/	{ init(); inchem = 1; next }
42*9a7741deSElliott Hughes/^(\.cend)|(end)/		{ inchem = 0; print ".PE"; next }
43*9a7741deSElliott Hughes
44*9a7741deSElliott Hughes/^\./		{ print; next }		# troff
45*9a7741deSElliott Hughes
46*9a7741deSElliott Hughesinchem == 0	{ print; next }		# everything else
47*9a7741deSElliott Hughes
48*9a7741deSElliott Hughes$1 == "pic"	{ shiftfields(1); print; next }	# pic pass-thru
49*9a7741deSElliott Hughes$1 ~ /^#/	{ next }	# comment
50*9a7741deSElliott Hughes
51*9a7741deSElliott Hughes$1 == "textht"	{ textht = $NF; next }
52*9a7741deSElliott Hughes$1 == "cwid"	{ cwid = $NF; next }
53*9a7741deSElliott Hughes$1 == "db"	{ db = $NF; next }
54*9a7741deSElliott Hughes$1 == "size"	{ if ($NF <= 4) size = $NF; else size = $NF/10
55*9a7741deSElliott Hughes		  setparams(size); next }
56*9a7741deSElliott Hughes
57*9a7741deSElliott Hughes	{ print "\n#", $0 }	# debugging, etc.
58*9a7741deSElliott Hughes	{ lastname = "" }
59*9a7741deSElliott Hughes
60*9a7741deSElliott Hughes$1 ~ /^[A-Z].*:$/ {	# label;  falls thru after shifting left
61*9a7741deSElliott Hughes	lastname = substr($1, 1, length($1)-1)
62*9a7741deSElliott Hughes	print $1
63*9a7741deSElliott Hughes	shiftfields(1)
64*9a7741deSElliott Hughes}
65*9a7741deSElliott Hughes
66*9a7741deSElliott Hughes$1 ~ /^\"/	{ print "Last: ", $0; last = OTHER; next }
67*9a7741deSElliott Hughes
68*9a7741deSElliott Hughes$1 ~ /bond/	{ bond($1); next }
69*9a7741deSElliott Hughes$1 ~ /^(double|triple|front|back)$/ && $2 == "bond" {
70*9a7741deSElliott Hughes		   $1 = $1 $2; shiftfields(2); bond($1); next }
71*9a7741deSElliott Hughes
72*9a7741deSElliott Hughes$1 == "aromatic" { temp = $1; $1 = $2; $2 = temp }
73*9a7741deSElliott Hughes$1 ~ /ring|benz/ { ring($1); next }
74*9a7741deSElliott Hughes
75*9a7741deSElliott Hughes$1 == "methyl"	{ $1 = "CH3" }	# left here as an example
76*9a7741deSElliott Hughes
77*9a7741deSElliott Hughes$1 ~ /^[A-Z]/	{ molecule(); next }
78*9a7741deSElliott Hughes
79*9a7741deSElliott Hughes$1 == "left"	{ left[++stack] = fields(2, NF); printf("Last: [\n"); next }
80*9a7741deSElliott Hughes
81*9a7741deSElliott Hughes$1 == "right"	{ bracket(); stack--; next }
82*9a7741deSElliott Hughes
83*9a7741deSElliott Hughes$1 == "label"	{ label(); next }
84*9a7741deSElliott Hughes
85*9a7741deSElliott Hughes/./	{ print "Last: ", $0; last = OTHER }
86*9a7741deSElliott Hughes
87*9a7741deSElliott HughesEND	{ if (firsttime == 0) error("did you forget .cstart and .cend?")
88*9a7741deSElliott Hughes	  if (inchem) printf ".PE\n"
89*9a7741deSElliott Hughes}
90*9a7741deSElliott Hughes
91*9a7741deSElliott Hughesfunction bond(type,	i, goes, from) {
92*9a7741deSElliott Hughes	goes = ""
93*9a7741deSElliott Hughes	for (i = 2; i <= NF; i++)
94*9a7741deSElliott Hughes		if ($i == ";") {
95*9a7741deSElliott Hughes			goes = $(i+1)
96*9a7741deSElliott Hughes			NF = i - 1
97*9a7741deSElliott Hughes			break
98*9a7741deSElliott Hughes		}
99*9a7741deSElliott Hughes	leng = db
100*9a7741deSElliott Hughes	from = ""
101*9a7741deSElliott Hughes	for (cf = 2; cf <= NF; ) {
102*9a7741deSElliott Hughes		if ($cf ~ /(\+|-)?[0-9]+|up|down|right|left|ne|se|nw|sw/)
103*9a7741deSElliott Hughes			dir = cvtdir(dir)
104*9a7741deSElliott Hughes		else if ($cf ~ /^leng/) {
105*9a7741deSElliott Hughes			leng = $(cf+1)
106*9a7741deSElliott Hughes			cf += 2
107*9a7741deSElliott Hughes		} else if ($cf == "to") {
108*9a7741deSElliott Hughes			leng = 0
109*9a7741deSElliott Hughes			from = fields(cf, NF)
110*9a7741deSElliott Hughes			break
111*9a7741deSElliott Hughes		} else if ($cf == "from") {
112*9a7741deSElliott Hughes			from = dofrom()
113*9a7741deSElliott Hughes			break
114*9a7741deSElliott Hughes		} else if ($cf ~ /^#/) {
115*9a7741deSElliott Hughes			cf = NF+1
116*9a7741deSElliott Hughes			break;
117*9a7741deSElliott Hughes		} else {
118*9a7741deSElliott Hughes			from = fields(cf, NF)
119*9a7741deSElliott Hughes			break
120*9a7741deSElliott Hughes		}
121*9a7741deSElliott Hughes	}
122*9a7741deSElliott Hughes	if (from ~ /( to )|^to/)	# said "from ... to ...", so zap length
123*9a7741deSElliott Hughes		leng = 0
124*9a7741deSElliott Hughes	else if (from == "")	# no from given at all
125*9a7741deSElliott Hughes		from = "from Last." leave(last, dir) " " fields(cf, NF)
126*9a7741deSElliott Hughes	printf "Last: %s(%g, %g, %s)\n", type, leng, dir, from
127*9a7741deSElliott Hughes	last = BOND
128*9a7741deSElliott Hughes	if (lastname != "")
129*9a7741deSElliott Hughes		labsave(lastname, last, dir)
130*9a7741deSElliott Hughes	if (goes) {
131*9a7741deSElliott Hughes		$0 = goes
132*9a7741deSElliott Hughes		molecule()
133*9a7741deSElliott Hughes	}
134*9a7741deSElliott Hughes}
135*9a7741deSElliott Hughes
136*9a7741deSElliott Hughesfunction dofrom(	n, s) {
137*9a7741deSElliott Hughes	cf++	# skip "from"
138*9a7741deSElliott Hughes	n = $cf
139*9a7741deSElliott Hughes	if (n in labtype)	# "from Thing" => "from Thing.V.s"
140*9a7741deSElliott Hughes		return "from " n "." leave(labtype[n], dir)
141*9a7741deSElliott Hughes	if (n ~ /^\.[A-Z]/)	# "from .V" => "from Last.V.s"
142*9a7741deSElliott Hughes		return "from Last" n "." corner(dir)
143*9a7741deSElliott Hughes	if (n ~ /^[A-Z][^.]*\.[A-Z][^.]*$/)	# "from X.V" => "from X.V.s"
144*9a7741deSElliott Hughes		return "from " n "." corner(dir)
145*9a7741deSElliott Hughes	return fields(cf-1, NF)
146*9a7741deSElliott Hughes}
147*9a7741deSElliott Hughes
148*9a7741deSElliott Hughesfunction bracket(	t) {
149*9a7741deSElliott Hughes	printf("]\n")
150*9a7741deSElliott Hughes	if ($2 == ")")
151*9a7741deSElliott Hughes		t = "spline"
152*9a7741deSElliott Hughes	else
153*9a7741deSElliott Hughes		t = "line"
154*9a7741deSElliott Hughes	printf("%s from last [].sw+(%g,0) to last [].sw to last [].nw to last [].nw+(%g,0)\n",
155*9a7741deSElliott Hughes		t, dbrack, dbrack)
156*9a7741deSElliott Hughes	printf("%s from last [].se-(%g,0) to last [].se to last [].ne to last [].ne-(%g,0)\n",
157*9a7741deSElliott Hughes		t, dbrack, dbrack)
158*9a7741deSElliott Hughes	if ($3 == "sub")
159*9a7741deSElliott Hughes		printf("\" %s\" ljust at last [].se\n", fields(4,NF))
160*9a7741deSElliott Hughes}
161*9a7741deSElliott Hughes
162*9a7741deSElliott Hughesfunction molecule(	n, type) {
163*9a7741deSElliott Hughes	n = $1
164*9a7741deSElliott Hughes	if (n == "BP") {
165*9a7741deSElliott Hughes		$1 = "\"\" ht 0 wid 0"
166*9a7741deSElliott Hughes		type = OTHER
167*9a7741deSElliott Hughes	} else {
168*9a7741deSElliott Hughes		$1 = atom(n)
169*9a7741deSElliott Hughes		type = MOL
170*9a7741deSElliott Hughes	}
171*9a7741deSElliott Hughes	gsub(/[^A-Za-z0-9]/, "", n)	# for stuff like C(OH3): zap non-alnum
172*9a7741deSElliott Hughes	if ($2 == "")
173*9a7741deSElliott Hughes		printf "Last: %s: %s with .%s at Last.%s\n", \
174*9a7741deSElliott Hughes			n, $0, leave(type,dir+180), leave(last,dir)
175*9a7741deSElliott Hughes	else if ($2 == "below")
176*9a7741deSElliott Hughes		printf("Last: %s: %s with .n at %s.s\n", n, $1, $3)
177*9a7741deSElliott Hughes	else if ($2 == "above")
178*9a7741deSElliott Hughes		printf("Last: %s: %s with .s at %s.n\n", n, $1, $3)
179*9a7741deSElliott Hughes	else if ($2 == "left" && $3 == "of")
180*9a7741deSElliott Hughes		printf("Last: %s: %s with .e at %s.w+(%g,0)\n", n, $1, $4, dew)
181*9a7741deSElliott Hughes	else if ($2 == "right" && $3 == "of")
182*9a7741deSElliott Hughes		printf("Last: %s: %s with .w at %s.e-(%g,0)\n", n, $1, $4, dew)
183*9a7741deSElliott Hughes	else
184*9a7741deSElliott Hughes		printf "Last: %s: %s\n", n, $0
185*9a7741deSElliott Hughes	last = type
186*9a7741deSElliott Hughes	if (lastname != "")
187*9a7741deSElliott Hughes		labsave(lastname, last, dir)
188*9a7741deSElliott Hughes	labsave(n, last, dir)
189*9a7741deSElliott Hughes}
190*9a7741deSElliott Hughes
191*9a7741deSElliott Hughesfunction label(	i, v) {
192*9a7741deSElliott Hughes	if (substr(labtype[$2], 1, 1) != RING)
193*9a7741deSElliott Hughes		error(sprintf("%s is not a ring", $2))
194*9a7741deSElliott Hughes	else {
195*9a7741deSElliott Hughes		v = substr(labtype[$2], 2, 1)
196*9a7741deSElliott Hughes		for (i = 1; i <= v; i++)
197*9a7741deSElliott Hughes			printf("\"\\s-3%d\\s0\" at 0.%d<%s.C,%s.V%d>\n", i, v+2, $2, $2, i)
198*9a7741deSElliott Hughes	}
199*9a7741deSElliott Hughes}
200*9a7741deSElliott Hughes
201*9a7741deSElliott Hughesfunction ring(type,	typeint, pt, verts, i) {
202*9a7741deSElliott Hughes	pt = 0	# points up by default
203*9a7741deSElliott Hughes	if (type ~ /[1-8]$/)
204*9a7741deSElliott Hughes		verts = substr(type, length(type), 1)
205*9a7741deSElliott Hughes	else if (type ~ /flat/)
206*9a7741deSElliott Hughes		verts = 5
207*9a7741deSElliott Hughes	else
208*9a7741deSElliott Hughes		verts = 6
209*9a7741deSElliott Hughes	fused = other = ""
210*9a7741deSElliott Hughes	for (i = 1; i <= verts; i++)
211*9a7741deSElliott Hughes		put[i] = dbl[i] = ""
212*9a7741deSElliott Hughes	nput = aromatic = withat = 0
213*9a7741deSElliott Hughes	for (cf = 2; cf <= NF; ) {
214*9a7741deSElliott Hughes		if ($cf == "pointing")
215*9a7741deSElliott Hughes			pt = cvtdir(0)
216*9a7741deSElliott Hughes		else if ($cf == "double" || $cf == "triple")
217*9a7741deSElliott Hughes			dblring(verts)
218*9a7741deSElliott Hughes		else if ($cf ~ /arom/) {
219*9a7741deSElliott Hughes			aromatic++
220*9a7741deSElliott Hughes			cf++	# handled later
221*9a7741deSElliott Hughes		} else if ($cf == "put") {
222*9a7741deSElliott Hughes			putring(verts)
223*9a7741deSElliott Hughes			nput++
224*9a7741deSElliott Hughes		} else if ($cf ~ /^#/) {
225*9a7741deSElliott Hughes			cf = NF+1
226*9a7741deSElliott Hughes			break;
227*9a7741deSElliott Hughes		} else {
228*9a7741deSElliott Hughes			if ($cf == "with" || $cf == "at")
229*9a7741deSElliott Hughes				withat = 1
230*9a7741deSElliott Hughes			other = other " " $cf
231*9a7741deSElliott Hughes			cf++
232*9a7741deSElliott Hughes		}
233*9a7741deSElliott Hughes	}
234*9a7741deSElliott Hughes	typeint = RING verts pt		# RING | verts | dir
235*9a7741deSElliott Hughes	if (withat == 0)
236*9a7741deSElliott Hughes		fused = joinring(typeint, dir, last)
237*9a7741deSElliott Hughes	printf "Last: [\n"
238*9a7741deSElliott Hughes	makering(type, pt, verts)
239*9a7741deSElliott Hughes	printf "] %s %s\n", fused, other
240*9a7741deSElliott Hughes	last = typeint
241*9a7741deSElliott Hughes	if (lastname != "")
242*9a7741deSElliott Hughes		labsave(lastname, last, dir)
243*9a7741deSElliott Hughes}
244*9a7741deSElliott Hughes
245*9a7741deSElliott Hughesfunction makering(type, pt, v,       i, a, r) {
246*9a7741deSElliott Hughes	if (type ~ /flat/)
247*9a7741deSElliott Hughes		v = 6
248*9a7741deSElliott Hughes    # vertices
249*9a7741deSElliott Hughes	r = ringside / (2 * sin(pi/v))
250*9a7741deSElliott Hughes	printf "\tC: 0,0\n"
251*9a7741deSElliott Hughes	for (i = 0; i <= v+1; i++) {
252*9a7741deSElliott Hughes		a = ((i-1) / v * 360 + pt) / deg
253*9a7741deSElliott Hughes		printf "\tV%d: (%g,%g)\n", i, r * sin(a), r * cos(a)
254*9a7741deSElliott Hughes	}
255*9a7741deSElliott Hughes	if (type ~ /flat/) {
256*9a7741deSElliott Hughes		printf "\tV4: V5; V5: V6\n"
257*9a7741deSElliott Hughes		v = 5
258*9a7741deSElliott Hughes	}
259*9a7741deSElliott Hughes    # sides
260*9a7741deSElliott Hughes	if (nput > 0) {	# hetero ...
261*9a7741deSElliott Hughes		for (i = 1; i <= v; i++) {
262*9a7741deSElliott Hughes			c1 = c2 = 0
263*9a7741deSElliott Hughes			if (put[i] != "") {
264*9a7741deSElliott Hughes				printf("\tV%d: ellipse invis ht %g wid %g at V%d\n",
265*9a7741deSElliott Hughes					i, crh, crw, i)
266*9a7741deSElliott Hughes				printf("\t%s at V%d\n", put[i], i)
267*9a7741deSElliott Hughes				c1 = cr
268*9a7741deSElliott Hughes			}
269*9a7741deSElliott Hughes			j = i+1
270*9a7741deSElliott Hughes			if (j > v)
271*9a7741deSElliott Hughes				j = 1
272*9a7741deSElliott Hughes			if (put[j] != "")
273*9a7741deSElliott Hughes				c2 = cr
274*9a7741deSElliott Hughes			printf "\tline from V%d to V%d chop %g chop %g\n", i, j, c1, c2
275*9a7741deSElliott Hughes			if (dbl[i] != "") {	# should check i<j
276*9a7741deSElliott Hughes				if (type ~ /flat/ && i == 3) {
277*9a7741deSElliott Hughes					rat = 0.75; fix = 5
278*9a7741deSElliott Hughes				} else {
279*9a7741deSElliott Hughes					rat = 0.85; fix = 1.5
280*9a7741deSElliott Hughes				}
281*9a7741deSElliott Hughes				if (put[i] == "")
282*9a7741deSElliott Hughes					c1 = 0
283*9a7741deSElliott Hughes				else
284*9a7741deSElliott Hughes					c1 = cr/fix
285*9a7741deSElliott Hughes				if (put[j] == "")
286*9a7741deSElliott Hughes					c2 = 0
287*9a7741deSElliott Hughes				else
288*9a7741deSElliott Hughes					c2 = cr/fix
289*9a7741deSElliott Hughes				printf "\tline from %g<C,V%d> to %g<C,V%d> chop %g chop %g\n",
290*9a7741deSElliott Hughes					rat, i, rat, j, c1, c2
291*9a7741deSElliott Hughes				if (dbl[i] == "triple")
292*9a7741deSElliott Hughes					printf "\tline from %g<C,V%d> to %g<C,V%d> chop %g chop %g\n",
293*9a7741deSElliott Hughes						2-rat, i, 2-rat, j, c1, c2
294*9a7741deSElliott Hughes			}
295*9a7741deSElliott Hughes		}
296*9a7741deSElliott Hughes	} else {	# regular
297*9a7741deSElliott Hughes		for (i = 1; i <= v; i++) {
298*9a7741deSElliott Hughes			j = i+1
299*9a7741deSElliott Hughes			if (j > v)
300*9a7741deSElliott Hughes				j = 1
301*9a7741deSElliott Hughes			printf "\tline from V%d to V%d\n", i, j
302*9a7741deSElliott Hughes			if (dbl[i] != "") {	# should check i<j
303*9a7741deSElliott Hughes				if (type ~ /flat/ && i == 3) {
304*9a7741deSElliott Hughes					rat = 0.75
305*9a7741deSElliott Hughes				} else
306*9a7741deSElliott Hughes					rat = 0.85
307*9a7741deSElliott Hughes				printf "\tline from %g<C,V%d> to %g<C,V%d>\n",
308*9a7741deSElliott Hughes					rat, i, rat, j
309*9a7741deSElliott Hughes				if (dbl[i] == "triple")
310*9a7741deSElliott Hughes					printf "\tline from %g<C,V%d> to %g<C,V%d>\n",
311*9a7741deSElliott Hughes						2-rat, i, 2-rat, j
312*9a7741deSElliott Hughes			}
313*9a7741deSElliott Hughes		}
314*9a7741deSElliott Hughes	}
315*9a7741deSElliott Hughes	# punt on triple temporarily
316*9a7741deSElliott Hughes    # circle
317*9a7741deSElliott Hughes	if (type ~ /benz/ || aromatic > 0) {
318*9a7741deSElliott Hughes		if (type ~ /flat/)
319*9a7741deSElliott Hughes			r *= .4
320*9a7741deSElliott Hughes		else
321*9a7741deSElliott Hughes			r *= .5
322*9a7741deSElliott Hughes		printf "\tcircle rad %g at 0,0\n", r
323*9a7741deSElliott Hughes	}
324*9a7741deSElliott Hughes}
325*9a7741deSElliott Hughes
326*9a7741deSElliott Hughesfunction putring(v) {	# collect "put Mol at n"
327*9a7741deSElliott Hughes	cf++
328*9a7741deSElliott Hughes	mol = $(cf++)
329*9a7741deSElliott Hughes	if ($cf == "at")
330*9a7741deSElliott Hughes		cf++
331*9a7741deSElliott Hughes	if ($cf >= 1 && $cf <= v) {
332*9a7741deSElliott Hughes		m = mol
333*9a7741deSElliott Hughes		gsub(/[^A-Za-z0-9]/, "", m)
334*9a7741deSElliott Hughes		put[$cf] = m ":" atom(mol)
335*9a7741deSElliott Hughes	}
336*9a7741deSElliott Hughes	cf++
337*9a7741deSElliott Hughes}
338*9a7741deSElliott Hughes
339*9a7741deSElliott Hughesfunction joinring(type, dir, last) {	# join a ring to something
340*9a7741deSElliott Hughes	if (substr(last, 1, 1) == RING) {	# ring to ring
341*9a7741deSElliott Hughes		if (substr(type, 3) == substr(last, 3))	# fails if not 6-sided
342*9a7741deSElliott Hughes			return "with .V6 at Last.V2"
343*9a7741deSElliott Hughes	}
344*9a7741deSElliott Hughes	# if all else fails
345*9a7741deSElliott Hughes	return sprintf("with .%s at Last.%s", \
346*9a7741deSElliott Hughes		leave(type,dir+180), leave(last,dir))
347*9a7741deSElliott Hughes}
348*9a7741deSElliott Hughes
349*9a7741deSElliott Hughesfunction leave(last, d,		c, c1) {	# return vertex of last in dir d
350*9a7741deSElliott Hughes	if (last == BOND)
351*9a7741deSElliott Hughes		return "end"
352*9a7741deSElliott Hughes	d = reduce(d)
353*9a7741deSElliott Hughes	if (substr(last, 1, 1) == RING)
354*9a7741deSElliott Hughes		return ringleave(last, d)
355*9a7741deSElliott Hughes	if (last == MOL) {
356*9a7741deSElliott Hughes		if (d == 0 || d == 180)
357*9a7741deSElliott Hughes			c = "C"
358*9a7741deSElliott Hughes		else if (d > 0 && d < 180)
359*9a7741deSElliott Hughes			c = "R"
360*9a7741deSElliott Hughes		else
361*9a7741deSElliott Hughes			c = "L"
362*9a7741deSElliott Hughes		if (d in dc)
363*9a7741deSElliott Hughes			c1 = dc[d]
364*9a7741deSElliott Hughes		else
365*9a7741deSElliott Hughes			c1 = corner(d)
366*9a7741deSElliott Hughes		return sprintf("%s.%s", c, c1)
367*9a7741deSElliott Hughes	}
368*9a7741deSElliott Hughes	if (last == OTHER)
369*9a7741deSElliott Hughes		return corner(d)
370*9a7741deSElliott Hughes	return "c"
371*9a7741deSElliott Hughes}
372*9a7741deSElliott Hughes
373*9a7741deSElliott Hughesfunction ringleave(last, d,	rd, verts) {	# return vertex of ring in dir d
374*9a7741deSElliott Hughes	verts = substr(last, 2, 1)
375*9a7741deSElliott Hughes	rd = substr(last, 3)
376*9a7741deSElliott Hughes	return sprintf("V%d.%s", int(reduce(d-rd)/(360/verts)) + 1, corner(d))
377*9a7741deSElliott Hughes}
378*9a7741deSElliott Hughes
379*9a7741deSElliott Hughesfunction corner(dir) {
380*9a7741deSElliott Hughes	return dc[reduce(45 * int((dir+22.5)/45))]
381*9a7741deSElliott Hughes}
382*9a7741deSElliott Hughes
383*9a7741deSElliott Hughesfunction labsave(name, type, dir) {
384*9a7741deSElliott Hughes	labtype[name] = type
385*9a7741deSElliott Hughes	labdir[name] = dir
386*9a7741deSElliott Hughes}
387*9a7741deSElliott Hughes
388*9a7741deSElliott Hughesfunction dblring(v,	d, v1, v2) {	# should canonicalize to i,i+1 mod v
389*9a7741deSElliott Hughes	d = $cf
390*9a7741deSElliott Hughes	for (cf++; $cf ~ /^[1-9]/; cf++) {
391*9a7741deSElliott Hughes		v1 = substr($cf,1,1)
392*9a7741deSElliott Hughes		v2 = substr($cf,3,1)
393*9a7741deSElliott Hughes		if (v2 == v1+1 || v1 == v && v2 == 1)	# e.g., 2,3 or 5,1
394*9a7741deSElliott Hughes			dbl[v1] = d
395*9a7741deSElliott Hughes		else if (v1 == v2+1 || v2 == v && v1 == 1)	# e.g., 3,2 or 1,5
396*9a7741deSElliott Hughes			dbl[v2] = d
397*9a7741deSElliott Hughes		else
398*9a7741deSElliott Hughes			error(sprintf("weird %s bond in\n\t%s", d, $0))
399*9a7741deSElliott Hughes	}
400*9a7741deSElliott Hughes}
401*9a7741deSElliott Hughes
402*9a7741deSElliott Hughesfunction cvtdir(d) {	# maps "[pointing] somewhere" to degrees
403*9a7741deSElliott Hughes	if ($cf == "pointing")
404*9a7741deSElliott Hughes		cf++
405*9a7741deSElliott Hughes	if ($cf ~ /^[+\-]?[0-9]+/)
406*9a7741deSElliott Hughes		return reduce($(cf++))
407*9a7741deSElliott Hughes	else if ($cf ~ /left|right|up|down|ne|nw|se|sw/)
408*9a7741deSElliott Hughes		return reduce(dc[$(cf++)])
409*9a7741deSElliott Hughes	else {
410*9a7741deSElliott Hughes		cf++
411*9a7741deSElliott Hughes		return d
412*9a7741deSElliott Hughes	}
413*9a7741deSElliott Hughes}
414*9a7741deSElliott Hughes
415*9a7741deSElliott Hughesfunction reduce(d) {	# reduces d to 0 <= d < 360
416*9a7741deSElliott Hughes	while (d >= 360)
417*9a7741deSElliott Hughes		d -= 360
418*9a7741deSElliott Hughes	while (d < 0)
419*9a7741deSElliott Hughes		d += 360
420*9a7741deSElliott Hughes	return d
421*9a7741deSElliott Hughes}
422*9a7741deSElliott Hughes
423*9a7741deSElliott Hughesfunction atom(s,    c, i, n, nsub, cloc, nsubc) { # convert CH3 to atom(...)
424*9a7741deSElliott Hughes	if (s == "\"\"")
425*9a7741deSElliott Hughes		return s
426*9a7741deSElliott Hughes	n = length(s)
427*9a7741deSElliott Hughes	nsub = nsubc = 0
428*9a7741deSElliott Hughes	cloc = index(s, "C")
429*9a7741deSElliott Hughes	if (cloc == 0)
430*9a7741deSElliott Hughes		cloc = 1
431*9a7741deSElliott Hughes	for (i = 1; i <= n; i++)
432*9a7741deSElliott Hughes		if (substr(s, i, 1) !~ /[A-Z]/) {
433*9a7741deSElliott Hughes			nsub++
434*9a7741deSElliott Hughes			if (i < cloc)
435*9a7741deSElliott Hughes				nsubc++
436*9a7741deSElliott Hughes		}
437*9a7741deSElliott Hughes	gsub(/([0-9]+\.[0-9]+)|([0-9]+)/, "\\s-3\\d&\\u\\s+3", s)
438*9a7741deSElliott Hughes	if (s ~ /([^0-9]\.)|(\.[^0-9])/)	# centered dot
439*9a7741deSElliott Hughes		gsub(/\./, "\\v#-.3m#.\\v#.3m#", s)
440*9a7741deSElliott Hughes	return sprintf("atom(\"%s\", %g, %g, %g, %g, %g, %g)",
441*9a7741deSElliott Hughes		s, (n-nsub/2)*cwid, textht, (cloc-nsubc/2-0.5)*cwid, crh, crw, dav)
442*9a7741deSElliott Hughes}
443*9a7741deSElliott Hughes
444*9a7741deSElliott Hughesfunction in_line(	i, n, s, s1, os) {
445*9a7741deSElliott Hughes	s = $0
446*9a7741deSElliott Hughes	os = ""
447*9a7741deSElliott Hughes	while ((n = match(s, /!?[A-Z][A-Za-z]*(([0-9]+\.[0-9]+)|([0-9]+))/)) > 0) {
448*9a7741deSElliott Hughes		os = os substr(s, 1, n-1)	# prefix
449*9a7741deSElliott Hughes		s1 = substr(s, n, RLENGTH)	# molecule
450*9a7741deSElliott Hughes		if (substr(s1, 1, 1) == "!") {	# !mol => leave alone
451*9a7741deSElliott Hughes			s1 = substr(s1, 2)
452*9a7741deSElliott Hughes		} else {
453*9a7741deSElliott Hughes			gsub(/([0-9]+\.[0-9]+)|([0-9]+)/, "\\s-3\\d&\\u\\s+3", s1)
454*9a7741deSElliott Hughes			if (s1 ~ /([^0-9]\.)|(\.[^0-9])/)	# centered dot
455*9a7741deSElliott Hughes				gsub(/\./, "\\v#-.3m#.\\v#.3m#", s1)
456*9a7741deSElliott Hughes		}
457*9a7741deSElliott Hughes		os = os s1
458*9a7741deSElliott Hughes		s = substr(s, n + RLENGTH)	# tail
459*9a7741deSElliott Hughes	}
460*9a7741deSElliott Hughes	os = os s
461*9a7741deSElliott Hughes	print os
462*9a7741deSElliott Hughes	return
463*9a7741deSElliott Hughes}
464*9a7741deSElliott Hughes
465*9a7741deSElliott Hughesfunction shiftfields(n,		i) {	# move $n+1..$NF to $n..$NF-1, zap $NF
466*9a7741deSElliott Hughes	for (i = n; i < NF; i++)
467*9a7741deSElliott Hughes		$i = $(i+1)
468*9a7741deSElliott Hughes	$NF = ""
469*9a7741deSElliott Hughes	NF--
470*9a7741deSElliott Hughes}
471*9a7741deSElliott Hughes
472*9a7741deSElliott Hughesfunction fields(n1, n2,		i, s) {
473*9a7741deSElliott Hughes	if (n1 > n2)
474*9a7741deSElliott Hughes		return ""
475*9a7741deSElliott Hughes	s = ""
476*9a7741deSElliott Hughes	for (i = n1; i <= n2; i++) {
477*9a7741deSElliott Hughes		if ($i ~ /^#/)
478*9a7741deSElliott Hughes			break;
479*9a7741deSElliott Hughes		s = s $i " "
480*9a7741deSElliott Hughes	}
481*9a7741deSElliott Hughes	return s
482*9a7741deSElliott Hughes}
483*9a7741deSElliott Hughes
484*9a7741deSElliott Hughesfunction set(a, s,     i, n, q) {
485*9a7741deSElliott Hughes	n = split(s, q)
486*9a7741deSElliott Hughes	for (i = 1; i <= n; i += 2)
487*9a7741deSElliott Hughes		a[q[i]] = q[i+1]
488*9a7741deSElliott Hughes}
489*9a7741deSElliott Hughes
490*9a7741deSElliott Hughesfunction error(s) {
491*9a7741deSElliott Hughes	printf "chem\007: error on line %d: %s\n", lineno, s | "cat 1>&2"
492*9a7741deSElliott Hughes}
493