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