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