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