head	1.30;
access;
symbols
	netbsd-11-0-RC4:1.30
	netbsd-11-0-RC3:1.30
	netbsd-11-0-RC2:1.30
	netbsd-11-0-RC1:1.30
	perseant-exfatfs-base-20250801:1.30
	netbsd-11:1.30.0.4
	netbsd-11-base:1.30
	netbsd-10-1-RELEASE:1.29
	perseant-exfatfs-base-20240630:1.30
	perseant-exfatfs:1.30.0.2
	perseant-exfatfs-base:1.30
	netbsd-8-3-RELEASE:1.24.8.2
	netbsd-9-4-RELEASE:1.27
	netbsd-10-0-RELEASE:1.29
	netbsd-10-0-RC6:1.29
	netbsd-10-0-RC5:1.29
	netbsd-10-0-RC4:1.29
	netbsd-10-0-RC3:1.29
	netbsd-10-0-RC2:1.29
	netbsd-10-0-RC1:1.29
	netbsd-10:1.29.0.2
	netbsd-10-base:1.29
	netbsd-9-3-RELEASE:1.27
	cjep_sun2x-base1:1.28
	cjep_sun2x:1.28.0.4
	cjep_sun2x-base:1.28
	cjep_staticlib_x-base1:1.28
	netbsd-9-2-RELEASE:1.27
	cjep_staticlib_x:1.28.0.2
	cjep_staticlib_x-base:1.28
	netbsd-9-1-RELEASE:1.27
	phil-wifi-20200421:1.27
	phil-wifi-20200411:1.27
	is-mlppp:1.27.0.4
	is-mlppp-base:1.27
	phil-wifi-20200406:1.27
	netbsd-8-2-RELEASE:1.24.8.2
	netbsd-9-0-RELEASE:1.27
	netbsd-9-0-RC2:1.27
	netbsd-9-0-RC1:1.27
	phil-wifi-20191119:1.27
	netbsd-9:1.27.0.2
	netbsd-9-base:1.27
	phil-wifi-20190609:1.27
	netbsd-8-1-RELEASE:1.24.8.2
	netbsd-8-1-RC1:1.24.8.2
	pgoyette-compat-merge-20190127:1.26.2.1
	pgoyette-compat-20190127:1.27
	pgoyette-compat-20190118:1.27
	pgoyette-compat-1226:1.27
	pgoyette-compat-1126:1.27
	pgoyette-compat-1020:1.27
	pgoyette-compat-0930:1.27
	pgoyette-compat-0906:1.27
	netbsd-7-2-RELEASE:1.22.20.1
	pgoyette-compat-0728:1.26
	netbsd-8-0-RELEASE:1.24.8.1
	phil-wifi:1.26.0.4
	phil-wifi-base:1.26
	pgoyette-compat-0625:1.26
	netbsd-8-0-RC2:1.24.8.1
	pgoyette-compat-0521:1.26
	pgoyette-compat-0502:1.26
	pgoyette-compat-0422:1.26
	netbsd-8-0-RC1:1.24.8.1
	pgoyette-compat-0415:1.26
	pgoyette-compat-0407:1.26
	pgoyette-compat-0330:1.26
	pgoyette-compat-0322:1.26
	pgoyette-compat-0315:1.26
	netbsd-7-1-2-RELEASE:1.22
	pgoyette-compat:1.26.0.2
	pgoyette-compat-base:1.26
	netbsd-7-1-1-RELEASE:1.22
	matt-nb8-mediatek:1.24.0.12
	matt-nb8-mediatek-base:1.24
	perseant-stdc-iso10646:1.24.0.10
	perseant-stdc-iso10646-base:1.24
	netbsd-8:1.24.0.8
	netbsd-8-base:1.24
	prg-localcount2-base3:1.24
	prg-localcount2-base2:1.24
	prg-localcount2-base1:1.24
	prg-localcount2:1.24.0.6
	prg-localcount2-base:1.24
	pgoyette-localcount-20170426:1.24
	bouyer-socketcan-base1:1.24
	pgoyette-localcount-20170320:1.24
	netbsd-7-1:1.22.0.26
	netbsd-7-1-RELEASE:1.22
	netbsd-7-1-RC2:1.22
	netbsd-7-nhusb-base-20170116:1.22
	bouyer-socketcan:1.24.0.4
	bouyer-socketcan-base:1.24
	pgoyette-localcount-20170107:1.24
	netbsd-7-1-RC1:1.22
	pgoyette-localcount-20161104:1.24
	netbsd-7-0-2-RELEASE:1.22
	localcount-20160914:1.24
	netbsd-7-nhusb:1.22.0.24
	netbsd-7-nhusb-base:1.22
	pgoyette-localcount-20160806:1.24
	pgoyette-localcount-20160726:1.24
	pgoyette-localcount:1.24.0.2
	pgoyette-localcount-base:1.24
	netbsd-7-0-1-RELEASE:1.22
	netbsd-7-0:1.22.0.22
	netbsd-7-0-RELEASE:1.22
	netbsd-7-0-RC3:1.22
	netbsd-7-0-RC2:1.22
	netbsd-7-0-RC1:1.22
	netbsd-5-2-3-RELEASE:1.19
	netbsd-5-1-5-RELEASE:1.19
	netbsd-6-0-6-RELEASE:1.22
	netbsd-6-1-5-RELEASE:1.22
	netbsd-7:1.22.0.20
	netbsd-7-base:1.22
	yamt-pagecache-base9:1.22
	yamt-pagecache-tag8:1.22
	netbsd-6-1-4-RELEASE:1.22
	netbsd-6-0-5-RELEASE:1.22
	tls-earlyentropy:1.22.0.18
	tls-earlyentropy-base:1.22
	riastradh-xf86-video-intel-2-7-1-pre-2-21-15:1.22
	riastradh-drm2-base3:1.22
	netbsd-6-1-3-RELEASE:1.22
	netbsd-6-0-4-RELEASE:1.22
	netbsd-5-2-2-RELEASE:1.19
	netbsd-5-1-4-RELEASE:1.19
	netbsd-6-1-2-RELEASE:1.22
	netbsd-6-0-3-RELEASE:1.22
	netbsd-5-2-1-RELEASE:1.19
	netbsd-5-1-3-RELEASE:1.19
	netbsd-6-1-1-RELEASE:1.22
	riastradh-drm2-base2:1.22
	riastradh-drm2-base1:1.22
	riastradh-drm2:1.22.0.12
	riastradh-drm2-base:1.22
	netbsd-6-1:1.22.0.16
	netbsd-6-0-2-RELEASE:1.22
	netbsd-6-1-RELEASE:1.22
	netbsd-6-1-RC4:1.22
	netbsd-6-1-RC3:1.22
	agc-symver:1.22.0.14
	agc-symver-base:1.22
	netbsd-6-1-RC2:1.22
	netbsd-6-1-RC1:1.22
	yamt-pagecache-base8:1.22
	netbsd-5-2:1.19.0.46
	netbsd-6-0-1-RELEASE:1.22
	yamt-pagecache-base7:1.22
	netbsd-5-2-RELEASE:1.19
	netbsd-5-2-RC1:1.19
	matt-nb6-plus-nbase:1.22
	yamt-pagecache-base6:1.22
	netbsd-6-0:1.22.0.10
	netbsd-6-0-RELEASE:1.22
	netbsd-6-0-RC2:1.22
	tls-maxphys:1.22.0.8
	tls-maxphys-base:1.22
	matt-nb6-plus:1.22.0.6
	matt-nb6-plus-base:1.22
	netbsd-6-0-RC1:1.22
	yamt-pagecache-base5:1.22
	yamt-pagecache-base4:1.22
	netbsd-6:1.22.0.4
	netbsd-6-base:1.22
	netbsd-5-1-2-RELEASE:1.19
	netbsd-5-1-1-RELEASE:1.19
	yamt-pagecache-base3:1.22
	yamt-pagecache-base2:1.22
	yamt-pagecache:1.22.0.2
	yamt-pagecache-base:1.22
	cherry-xenmp:1.21.0.2
	cherry-xenmp-base:1.21
	bouyer-quota2-nbase:1.20
	bouyer-quota2:1.20.0.2
	bouyer-quota2-base:1.20
	matt-mips64-premerge-20101231:1.20
	matt-nb5-mips64-premerge-20101231:1.19
	matt-nb5-pq3:1.19.0.44
	matt-nb5-pq3-base:1.19
	netbsd-5-1:1.19.0.42
	netbsd-5-1-RELEASE:1.19
	netbsd-5-1-RC4:1.19
	matt-nb5-mips64-k15:1.19
	netbsd-5-1-RC3:1.19
	netbsd-5-1-RC2:1.19
	netbsd-5-1-RC1:1.19
	netbsd-5-0-2-RELEASE:1.19
	matt-nb5-mips64-premerge-20091211:1.19
	matt-premerge-20091211:1.20
	OPENBSD20091026:1.1.1.3
	OPENBSD:1.1.1
	matt-nb5-mips64-u2-k2-k4-k7-k8-k9:1.19
	matt-nb4-mips64-k7-u2a-k9b:1.19
	matt-nb5-mips64-u1-k1-k5:1.19
	matt-nb5-mips64:1.19.0.40
	netbsd-5-0-1-RELEASE:1.19
	jym-xensuspend-nbase:1.19
	netbsd-5-0:1.19.0.38
	netbsd-5-0-RELEASE:1.19
	netbsd-5-0-RC4:1.19
	netbsd-5-0-RC3:1.19
	netbsd-5-0-RC2:1.19
	jym-xensuspend:1.19.0.36
	jym-xensuspend-base:1.19
	netbsd-5-0-RC1:1.19
	netbsd-5:1.19.0.34
	netbsd-5-base:1.19
	matt-mips64-base2:1.19
	matt-mips64:1.19.0.32
	mjf-devfs2:1.19.0.30
	mjf-devfs2-base:1.19
	netbsd-4-0-1-RELEASE:1.19
	wrstuden-revivesa-base-3:1.19
	wrstuden-revivesa-base-2:1.19
	wrstuden-fixsa-newbase:1.19
	wrstuden-revivesa-base-1:1.19
	yamt-pf42-base4:1.19
	yamt-pf42-base3:1.19
	hpcarm-cleanup-nbase:1.19
	yamt-pf42-baseX:1.19
	yamt-pf42-base2:1.19
	wrstuden-revivesa:1.19.0.28
	wrstuden-revivesa-base:1.19
	yamt-pf42:1.19.0.26
	yamt-pf42-base:1.19
	keiichi-mipv6-nbase:1.19
	keiichi-mipv6:1.19.0.24
	keiichi-mipv6-base:1.19
	matt-armv6-nbase:1.19
	matt-armv6-prevmlocking:1.19
	wrstuden-fixsa-base-1:1.19
	netbsd-4-0:1.19.0.22
	netbsd-4-0-RELEASE:1.19
	cube-autoconf:1.19.0.20
	cube-autoconf-base:1.19
	netbsd-4-0-RC5:1.19
	netbsd-4-0-RC4:1.19
	netbsd-4-0-RC3:1.19
	netbsd-4-0-RC2:1.19
	netbsd-4-0-RC1:1.19
	matt-armv6:1.19.0.18
	matt-armv6-base:1.19
	matt-mips64-base:1.19
	hpcarm-cleanup:1.19.0.16
	hpcarm-cleanup-base:1.19
	netbsd-3-1-1-RELEASE:1.19
	netbsd-3-0-3-RELEASE:1.19
	wrstuden-fixsa:1.19.0.14
	wrstuden-fixsa-base:1.19
	abandoned-netbsd-4-base:1.19
	abandoned-netbsd-4:1.19.0.8
	netbsd-3-1:1.19.0.10
	netbsd-3-1-RELEASE:1.19
	netbsd-3-0-2-RELEASE:1.19
	netbsd-3-1-RC4:1.19
	netbsd-3-1-RC3:1.19
	netbsd-3-1-RC2:1.19
	netbsd-3-1-RC1:1.19
	netbsd-4:1.19.0.12
	netbsd-4-base:1.19
	chap-midi-nbase:1.19
	netbsd-3-0-1-RELEASE:1.19
	chap-midi:1.19.0.6
	chap-midi-base:1.19
	netbsd-3-0:1.19.0.4
	netbsd-3-0-RELEASE:1.19
	netbsd-3-0-RC6:1.19
	netbsd-3-0-RC5:1.19
	netbsd-3-0-RC4:1.19
	netbsd-3-0-RC3:1.19
	netbsd-3-0-RC2:1.19
	netbsd-3-0-RC1:1.19
	netbsd-2-0-3-RELEASE:1.17.2.2
	netbsd-2-1:1.17.2.2.0.4
	netbsd-2-1-RELEASE:1.17.2.2
	netbsd-2-1-RC6:1.17.2.2
	netbsd-2-1-RC5:1.17.2.2
	netbsd-2-1-RC4:1.17.2.2
	netbsd-2-1-RC3:1.17.2.2
	netbsd-2-1-RC2:1.17.2.2
	netbsd-2-1-RC1:1.17.2.2
	netbsd-2-0-2-RELEASE:1.17.2.2
	netbsd-3:1.19.0.2
	netbsd-3-base:1.19
	netbsd-2-0-1-RELEASE:1.17.2.2
	netbsd-2:1.17.2.2.0.2
	netbsd-2-base:1.17.2.2
	netbsd-2-0-RELEASE:1.17.2.2
	netbsd-2-0-RC5:1.17.2.2
	netbsd-2-0-RC4:1.17.2.2
	netbsd-2-0-RC3:1.17.2.2
	netbsd-2-0-RC2:1.17.2.2
	netbsd-2-0-RC1:1.17.2.2
	netbsd-2-0:1.17.0.2
	netbsd-2-0-base:1.17
	netbsd-1-6-PATCH002-RELEASE:1.16
	netbsd-1-6-PATCH002:1.16
	netbsd-1-6-PATCH002-RC4:1.16
	netbsd-1-6-PATCH002-RC3:1.16
	netbsd-1-6-PATCH002-RC2:1.16
	netbsd-1-6-PATCH002-RC1:1.16
	netbsd-1-6-PATCH001:1.16
	netbsd-1-6-PATCH001-RELEASE:1.16
	netbsd-1-6-PATCH001-RC3:1.16
	netbsd-1-6-PATCH001-RC2:1.16
	netbsd-1-6-PATCH001-RC1:1.16
	fvdl_fs64_base:1.16
	netbsd-1-6-RELEASE:1.16
	netbsd-1-6-RC3:1.16
	netbsd-1-6-RC2:1.16
	netbsd-1-6-RC1:1.16
	netbsd-1-6:1.16.0.2
	netbsd-1-6-base:1.16
	netbsd-1-5-PATCH003:1.11.8.1
	netbsd-1-5-PATCH002:1.11.8.1
	netbsd-1-5-PATCH001:1.11.8.1
	netbsd-1-5-RELEASE:1.11.8.1
	netbsd-1-5-BETA2:1.11.8.1
	netbsd-1-5-BETA:1.11.8.1
	netbsd-1-4-PATCH003:1.10.4.1
	netbsd-1-5-ALPHA2:1.11
	netbsd-1-5:1.11.0.8
	netbsd-1-5-base:1.11
	minoura-xpg4dl-base:1.11
	minoura-xpg4dl:1.11.0.6
	netbsd-1-4-PATCH002:1.10
	wrstuden-devbsize-19991221:1.11
	wrstuden-devbsize:1.11.0.4
	wrstuden-devbsize-base:1.11
	comdex-fall-1999:1.11.0.2
	comdex-fall-1999-base:1.11
	netbsd-1-4-PATCH001:1.10
	netbsd-1-4-RELEASE:1.10
	netbsd-1-4:1.10.0.4
	netbsd-1-4-base:1.10
	netbsd-1-3-PATCH003:1.10
	netbsd-1-3-PATCH003-CANDIDATE2:1.10
	netbsd-1-3-PATCH003-CANDIDATE1:1.10
	netbsd-1-3-PATCH003-CANDIDATE0:1.10
	netbsd-1-3-PATCH002:1.10
	netbsd-1-3-PATCH001:1.10
	netbsd-1-3-RELEASE:1.10
	netbsd-1-3-BETA:1.10
	netbsd-1-3:1.10.0.2
	netbsd-1-3-base:1.10
	netbsd-1-2-PATCH001:1.5
	netbsd-1-2-RELEASE:1.5
	netbsd-1-2-BETA:1.5
	netbsd-1-2:1.5.0.4
	netbsd-1-2-base:1.5
	netbsd-1-1-PATCH001:1.4
	netbsd-1-1-RELEASE:1.4
	netbsd-1-1:1.4.0.2
	netbsd-1-1-base:1.4
	lite-2:1.1.1.2
	CSRG:1.1.1
	netbsd-1-0-PATCH06:1.3
	netbsd-1-0-PATCH05:1.3
	netbsd-1-0-PATCH04:1.3
	netbsd-1-0-PATCH03:1.3
	netbsd-1-0-PATCH02:1.3
	netbsd-1-0-PATCH1:1.3
	netbsd-1-0-PATCH0:1.3
	netbsd-1-0-RELEASE:1.3
	netbsd-1-0:1.3.0.2
	netbsd-1-0-base:1.2
	netbsd-0-8:1.1.1.1
	netbsd-alpha-1:1.1.1.1
	patchkit-0-2-2:1.1.1.1
	WFJ-386bsd-01:1.1.1.1
	WFJ-920714:1.1.1;
locks; strict;
comment	@ * @;


1.30
date	2024.02.09.22.08.38;	author andvar;	state Exp;
branches;
next	1.29;
commitid	3HXU4I4WgbZi7OXE;

1.29
date	2022.05.24.20.50.21;	author andvar;	state Exp;
branches;
next	1.28;
commitid	qeoHiwzeniY8OlFD;

1.28
date	2020.06.27.19.18.58;	author uwe;	state Exp;
branches;
next	1.27;
commitid	rQHumyVBXRPvGTdC;

1.27
date	2018.07.30.22.58.09;	author kre;	state Exp;
branches;
next	1.26;
commitid	b11YqVIMJghnkdMA;

1.26
date	2017.10.23.02.38.46;	author christos;	state Exp;
branches
	1.26.2.1
	1.26.4.1;
next	1.25;
commitid	hoDrhmYZIV4pA7cA;

1.25
date	2017.10.22.23.01.34;	author christos;	state Exp;
branches;
next	1.24;
commitid	dLw5muzGSJeAn6cA;

1.24
date	2016.01.16.16.56.21;	author christos;	state Exp;
branches
	1.24.8.1;
next	1.23;
commitid	xCrwBqBKHcEL5bRy;

1.23
date	2015.01.29.19.26.20;	author christos;	state Exp;
branches;
next	1.22;
commitid	wJmVZeF0aXLWeX7y;

1.22
date	2011.08.21.23.38.43;	author dholland;	state Exp;
branches
	1.22.20.1;
next	1.21;

1.21
date	2011.03.05.16.38.25;	author christos;	state Exp;
branches;
next	1.20;

1.20
date	2009.10.26.21.11.28;	author christos;	state Exp;
branches;
next	1.19;

1.19
date	2004.07.06.13.19.42;	author mycroft;	state Exp;
branches;
next	1.18;

1.18
date	2004.06.20.22.20.15;	author jmc;	state Exp;
branches;
next	1.17;

1.17
date	2003.08.07.11.14.30;	author agc;	state Exp;
branches
	1.17.2.1;
next	1.16;

1.16
date	2002.01.31.19.36.47;	author tv;	state Exp;
branches;
next	1.15;

1.15
date	2002.01.21.21.49.57;	author tv;	state Exp;
branches;
next	1.14;

1.14
date	2001.11.14.06.16.08;	author tv;	state Exp;
branches;
next	1.13;

1.13
date	2000.10.17.18.51.32;	author jdolecek;	state Exp;
branches;
next	1.12;

1.12
date	2000.10.11.14.46.11;	author is;	state Exp;
branches;
next	1.11;

1.11
date	99.04.20.08.05.51;	author mrg;	state Exp;
branches
	1.11.8.1;
next	1.10;

1.10
date	97.10.19.04.39.51;	author lukem;	state Exp;
branches
	1.10.4.1;
next	1.9;

1.9
date	97.02.08.23.50.40;	author cgd;	state Exp;
branches;
next	1.8;

1.8
date	97.01.09.20.20.35;	author tls;	state Exp;
branches;
next	1.7;

1.7
date	96.11.10.21.21.29;	author pk;	state Exp;
branches;
next	1.6;

1.6
date	96.11.06.00.11.56;	author pk;	state Exp;
branches;
next	1.5;

1.5
date	96.01.13.23.25.23;	author pk;	state Exp;
branches;
next	1.4;

1.4
date	95.09.28.05.37.28;	author tls;	state Exp;
branches;
next	1.3;

1.3
date	94.08.29.03.24.44;	author mycroft;	state Exp;
branches
	1.3.2.1;
next	1.2;

1.2
date	94.06.19.03.58.29;	author glass;	state Exp;
branches;
next	1.1;

1.1
date	93.03.21.09.45.37;	author cgd;	state Exp;
branches
	1.1.1.1;
next	;

1.26.2.1
date	2018.09.06.06.56.50;	author pgoyette;	state Exp;
branches;
next	;
commitid	HCi1bXD317XIK0RA;

1.26.4.1
date	2019.06.10.22.10.21;	author christos;	state Exp;
branches;
next	;
commitid	jtc8rnCzWiEEHGqB;

1.24.8.1
date	2018.04.11.14.27.51;	author martin;	state Exp;
branches;
next	1.24.8.2;
commitid	B3q19IBFTRaV22yA;

1.24.8.2
date	2018.08.07.13.11.12;	author martin;	state Exp;
branches;
next	;
commitid	KeNhrM3UZnjsPbNA;

1.22.20.1
date	2018.03.21.12.08.43;	author martin;	state Exp;
branches;
next	;
commitid	SChfUTFSzZ92XjvA;

1.17.2.1
date	2004.06.22.07.21.53;	author tron;	state Exp;
branches;
next	1.17.2.2;

1.17.2.2
date	2004.07.10.12.40.21;	author tron;	state Exp;
branches;
next	;

1.11.8.1
date	2000.10.18.01.32.46;	author tv;	state Exp;
branches;
next	;

1.10.4.1
date	2000.10.19.16.31.45;	author he;	state Exp;
branches;
next	;

1.3.2.1
date	94.08.29.03.24.44;	author mycroft;	state dead;
branches;
next	1.3.2.2;

1.3.2.2
date	94.08.29.03.24.45;	author mycroft;	state Exp;
branches;
next	;

1.1.1.1
date	93.03.21.09.45.37;	author cgd;	state Exp;
branches;
next	1.1.1.2;

1.1.1.2
date	95.09.28.04.33.52;	author tls;	state Exp;
branches;
next	1.1.1.3;

1.1.1.3
date	2009.10.26.21.08.58;	author christos;	state Exp;
branches;
next	;


desc
@@


1.30
log
@fix spelling mistakes, mainly in comments and log messages.
@
text
@/*	$OpenBSD: eval.c,v 1.66 2008/08/21 21:01:47 espie Exp $	*/
/*	$NetBSD: eval.c,v 1.29 2022/05/24 20:50:21 andvar Exp $	*/

/*
 * Copyright (c) 1989, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * Ozan Yigit at York University.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/*
 * eval.c
 * Facility: m4 macro processor
 * by: oz
 */
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
__RCSID("$NetBSD: eval.c,v 1.29 2022/05/24 20:50:21 andvar Exp $");

#include <sys/types.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <inttypes.h>
#include <fcntl.h>
#include "mdef.h"
#include "stdd.h"
#include "extern.h"
#include "pathnames.h"

static void	dodefn(const char *);
static void	dopushdef(const char *, const char *);
static void	dodump(const char *[], int);
static void	dotrace(const char *[], int, int);
static void	doifelse(const char *[], int);
static int	doincl(const char *);
static int	dopaste(const char *);
static void	dochq(const char *[], int);
static void	dochc(const char *[], int);
static void	dom4wrap(const char *);
static void	dodiv(int);
static void	doundiv(const char *[], int);
static void	dosub(const char *[], int);
static void	map(char *, const char *, const char *, const char *);
static const char *handledash(char *, char *, const char *);
static void	expand_builtin(const char *[], int, int);
static void	expand_macro(const char *[], int);
static void	dump_one_def(const char *, struct macro_definition *);

unsigned long	expansion_id;

/*
 * eval - eval all macros and builtins calls
 *	  argc - number of elements in argv.
 *	  argv - element vector :
 *			argv[0] = definition of a user
 *				  macro or NULL if built-in.
 *			argv[1] = name of the macro or
 *				  built-in.
 *			argv[2] = parameters to user-defined
 *			   .	  macro or built-in.
 *			   .
 *
 * A call in the form of macro-or-builtin() will result in:
 *			argv[0] = nullstr
 *			argv[1] = macro-or-builtin
 *			argv[2] = nullstr
 *
 * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin
 */
void
eval(const char *argv[], int argc, int td, int is_traced)
{
	size_t mark = SIZE_MAX;

	expansion_id++;
	if (td & RECDEF) 
		m4errx(1, "expanding recursive definition for %s.", argv[1]);
	if (is_traced)
		mark = trace(argv, argc, infile+ilevel);
	if (td == MACRTYPE)
		expand_macro(argv, argc);
	else
		expand_builtin(argv, argc, td);
    	if (mark != SIZE_MAX)
		finish_trace(mark);
}

/*
 * expand_builtin - evaluate built-in macros.
 */
void
expand_builtin(const char *argv[], int argc, int td)
{
	int c, n;
	int ac;
	static int sysval = 0;

#ifdef DEBUG
	printf("argc = %d\n", argc);
	for (n = 0; n < argc; n++)
		printf("argv[%d] = %s\n", n, argv[n]);
	fflush(stdout);
#endif

 /*
  * if argc == 3 and argv[2] is null, then we
  * have macro-or-builtin() type call. We adjust
  * argc to avoid further checking..
  */
 /* we keep the initial value for those built-ins that differentiate
  * between builtin() and builtin.
  */
  	ac = argc;

	if (argc == 3 && !*(argv[2]) && !mimic_gnu)
		argc--;

	switch (td & TYPEMASK) {

	case DEFITYPE:
		if (argc > 2)
			dodefine(argv[2], (argc > 3) ? argv[3] : null);
		break;

	case PUSDTYPE:
		if (argc > 2)
			dopushdef(argv[2], (argc > 3) ? argv[3] : null);
		break;

	case DUMPTYPE:
		dodump(argv, argc);
		break;

	case TRACEONTYPE:
		dotrace(argv, argc, 1);
		break;

	case TRACEOFFTYPE:
		dotrace(argv, argc, 0);
		break;

	case EXPRTYPE:
	/*
	 * doexpr - evaluate arithmetic
	 * expression
	 */
	{
		int base = 10;
		int maxdigits = 0;
		int e;

		if (argc > 3 && *argv[3] != '\0') {
			base = strtoi(argv[3], NULL, 0, 2, 36, &e);
			if (e) {
				m4errx(1, "expr: base %s invalid.", argv[3]);
			}
		}
		if (argc > 4) {
			maxdigits = strtoi(argv[4], NULL, 0, 0, INT_MAX, &e);
			if (e) {
				m4errx(1, "expr: maxdigits %s invalid.", argv[4]);
			}
		}
		if (argc > 2)
			pbnumbase(expr(argv[2]), base, maxdigits);
		break;
	}

	case IFELTYPE:
		if (argc > 4)
			doifelse(argv, argc);
		break;

	case IFDFTYPE:
	/*
	 * doifdef - select one of two
	 * alternatives based on the existence of
	 * another definition
	 */
		if (argc > 3) {
			if (lookup_macro_definition(argv[2]) != NULL)
				pbstr(argv[3]);
			else if (argc > 4)
				pbstr(argv[4]);
		}
		break;

	case LENGTYPE:
	/*
	 * dolen - find the length of the
	 * argument
	 */
		pbnum((argc > 2) ? strlen(argv[2]) : 0);
		break;

	case INCRTYPE:
	/*
	 * doincr - increment the value of the
	 * argument
	 */
		if (argc > 2)
			pbnum(atoi(argv[2]) + 1);
		break;

	case DECRTYPE:
	/*
	 * dodecr - decrement the value of the
	 * argument
	 */
		if (argc > 2)
			pbnum(atoi(argv[2]) - 1);
		break;

	case SYSCTYPE:
	/*
	 * dosys - execute system command
	 */
		if (argc > 2) {
			fflush(stdout);
			sysval = system(argv[2]);
		}
		break;

	case SYSVTYPE:
	/*
	 * dosysval - return value of the last
	 * system call.
	 * 
	 */
		pbnum(sysval);
		break;

	case ESYSCMDTYPE:
		if (argc > 2)
			doesyscmd(argv[2]);
	    	break;
	case INCLTYPE:
		if (argc > 2)
			if (!doincl(argv[2]))
				err(1, "%s at line %lu: include(%s)",
				    CURRENT_NAME, CURRENT_LINE, argv[2]);
		break;

	case SINCTYPE:
		if (argc > 2)
			(void) doincl(argv[2]);
		break;
#ifdef EXTENDED
	case PASTTYPE:
		if (argc > 2)
			if (!dopaste(argv[2]))
				err(1, "%s at line %lu: paste(%s)", 
				    CURRENT_NAME, CURRENT_LINE, argv[2]);
		break;

	case SPASTYPE:
		if (argc > 2)
			(void) dopaste(argv[2]);
		break;
	case FORMATTYPE:
		doformat(argv, argc);
		break;
#endif
	case CHNQTYPE:
		dochq(argv, ac);
		break;

	case CHNCTYPE:
		dochc(argv, argc);
		break;

	case SUBSTYPE:
	/*
	 * dosub - select substring
	 * 
	 */
		if (argc > 3)
			dosub(argv, argc);
		break;

	case SHIFTYPE:
	/*
	 * doshift - push back all arguments
	 * except the first one (i.e. skip
	 * argv[2])
	 */
		if (argc > 3) {
			for (n = argc - 1; n > 3; n--) {
				pbstr(rquote);
				pbstr(argv[n]);
				pbstr(lquote);
				pushback(COMMA);
			}
			pbstr(rquote);
			pbstr(argv[3]);
			pbstr(lquote);
		}
		break;

	case DIVRTYPE:
		if (argc > 2 && (n = atoi(argv[2])) != 0)
			dodiv(n);
		else {
			active = stdout;
			oindex = 0;
		}
		break;

	case UNDVTYPE:
		doundiv(argv, argc);
		break;

	case DIVNTYPE:
	/*
	 * dodivnum - return the number of
	 * current output diversion
	 */
		pbnum(oindex);
		break;

	case UNDFTYPE:
	/*
	 * doundefine - undefine a previously
	 * defined macro(s) or m4 keyword(s).
	 */
		if (argc > 2)
			for (n = 2; n < argc; n++)
				macro_undefine(argv[n]);
		break;

	case POPDTYPE:
	/*
	 * dopopdef - remove the topmost
	 * definitions of macro(s) or m4
	 * keyword(s).
	 */
		if (argc > 2)
			for (n = 2; n < argc; n++)
				macro_popdef(argv[n]);
		break;

	case MKTMTYPE:
	/*
	 * dotemp - create a temporary file
	 */
		if (argc > 2) {
			int fd;
			char *temp;

			temp = xstrdup(argv[2]);
			
			fd = mkstemp(temp);
			if (fd == -1)
				err(1, 
	    "%s at line %lu: couldn't make temp file %s", 
	    CURRENT_NAME, CURRENT_LINE, argv[2]);
			close(fd);
			pbstr(temp);
			free(temp);
		}
		break;

	case TRNLTYPE:
	/*
	 * dotranslit - replace all characters in
	 * the source string that appears in the
	 * "from" string with the corresponding
	 * characters in the "to" string.
	 */
		if (argc > 3) {
			char *temp;

			temp = xalloc(strlen(argv[2])+1, NULL);
			if (argc > 4)
				map(temp, argv[2], argv[3], argv[4]);
			else
				map(temp, argv[2], argv[3], null);
			pbstr(temp);
			free(temp);
		} else if (argc > 2)
			pbstr(argv[2]);
		break;

	case INDXTYPE:
	/*
	 * doindex - find the index of the second
	 * argument string in the first argument
	 * string. -1 if not present.
	 */
		pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
		break;

	case ERRPTYPE:
	/*
	 * doerrp - print the arguments to stderr
	 * file
	 */
		if (argc > 2) {
			for (n = 2; n < argc; n++)
				fprintf(stderr, "%s%s",
				    mimic_gnu && n == 2 ? "" : " ",
				    argv[n]);
			if (!mimic_gnu)
				fprintf(stderr, "\n");
		}
		break;

	case DNLNTYPE:
	/*
	 * dodnl - eat-up-to and including
	 * newline
	 */
		while ((c = gpbc()) != '\n' && c != EOF)
			;
		break;

	case M4WRTYPE:
	/*
	 * dom4wrap - set up for
	 * wrap-up/wind-down activity
	 */
		if (argc > 2)
			dom4wrap(argv[2]);
		break;

	case EXITTYPE:
	/*
	 * doexit - immediate exit from m4.
	 */
		killdiv();
		exit((argc > 2) ? atoi(argv[2]) : 0);
		break;

	case DEFNTYPE:
		if (argc > 2)
			for (n = 2; n < argc; n++)
				dodefn(argv[n]);
		break;

	case INDIRTYPE:	/* Indirect call */
		if (argc > 2)
			doindir(argv, argc);
		break;
	
	case BUILTINTYPE: /* Builtins only */
		if (argc > 2)
			dobuiltin(argv, argc);
		break;

	case PATSTYPE:
		if (argc > 2)
			dopatsubst(argv, argc);
		break;
	case REGEXPTYPE:
		if (argc > 2)
			doregexp(argv, argc);
		break;
	case LINETYPE:
		doprintlineno(infile+ilevel);
		break;
	case FILENAMETYPE:
		doprintfilename(infile+ilevel);
		break;
	case SELFTYPE:
		pbstr(rquote);
		pbstr(argv[1]);
		pbstr(lquote);
		break;
	default:
		m4errx(1, "eval: major botch.");
		break;
	}
}

/*
 * expand_macro - user-defined macro expansion
 */
void
expand_macro(const char *argv[], int argc)
{
	const char *t;
	const char *p;
	int n;
	int argno;

	t = argv[0];		       /* defn string as a whole */
	p = t;
	while (*p)
		p++;
	p--;			       /* last character of defn */
	while (p > t) {
		if (*(p - 1) != ARGFLAG)
			PUSHBACK(*p);
		else {
			switch (*p) {

			case '#':
				pbnum(argc - 2);
				break;
			case '0':
			case '1':
			case '2':
			case '3':
			case '4':
			case '5':
			case '6':
			case '7':
			case '8':
			case '9':
				argno = *p - '0';
				if (mimic_gnu) {
					const unsigned char *q =
					    (const unsigned char *)p;
					while (isdigit(*++q)) {
						bp--;
						argno = argno * 10 + *q - '0';
					}
				}
				if (argno < argc - 1)
					pbstr(argv[argno + 1]);
				break;
			case '*':
				if (argc > 2) {
					for (n = argc - 1; n > 2; n--) {
						pbstr(argv[n]);
						pushback(COMMA);
					}
					pbstr(argv[2]);
			    	}
				break;
                        case '@@':
				if (argc > 2) {
					for (n = argc - 1; n > 2; n--) {
						pbstr(rquote);
						pbstr(argv[n]);
						pbstr(lquote);
						pushback(COMMA);
					}
					pbstr(rquote);
					pbstr(argv[2]);
					pbstr(lquote);
				}
                                break;
			default:
				PUSHBACK(*p);
				PUSHBACK('$');
				break;
			}
			p--;
		}
		p--;
	}
	if (p == t)		       /* do last character */
		PUSHBACK(*p);
}


/*
 * dodefine - install definition in the table
 */
void
dodefine(const char *name, const char *defn)
{
	if (!*name && !mimic_gnu)
		m4errx(1, "null definition.");
	else 
		macro_define(name, defn);
}

/*
 * dodefn - push back a quoted definition of
 *      the given name.
 */
static void
dodefn(const char *name)
{
	struct macro_definition *p;

	if ((p = lookup_macro_definition(name)) != NULL) {
		if ((p->type & TYPEMASK) == MACRTYPE) {
			pbstr(rquote);
			pbstr(p->defn);
			pbstr(lquote);
		} else {
			pbstr(p->defn);
			pbstr(BUILTIN_MARKER);
		}
	}
}

/*
 * dopushdef - install a definition in the hash table
 *      without removing a previous definition. Since
 *      each new entry is entered in *front* of the
 *      hash bucket, it hides a previous definition from
 *      lookup.
 */
static void
dopushdef(const char *name, const char *defn)
{
	if (!*name && !mimic_gnu)
		m4errx(1, "null definition.");
	else
		macro_pushdef(name, defn);
}

/*
 * dump_one_def - dump the specified definition.
 */
static void
dump_one_def(const char *name, struct macro_definition *p)
{
	if (!traceout)
		traceout = stderr;
	if (mimic_gnu) {
		if ((p->type & TYPEMASK) == MACRTYPE)
			fprintf(traceout, "%s:\t%s\n", name, p->defn);
		else {
			fprintf(traceout, "%s:\t<%s>\n", name, p->defn);
	    	}
	} else
		fprintf(traceout, "`%s'\t`%s'\n", name, p->defn);
}

/*
 * dodumpdef - dump the specified definitions in the hash
 *      table to stderr. If nothing is specified, the entire
 *      hash table is dumped.
 */
static void
dodump(const char *argv[], int argc)
{
	int n;
	struct macro_definition *p;

	if (argc > 2) {
		for (n = 2; n < argc; n++)
			if ((p = lookup_macro_definition(argv[n])) != NULL)
				dump_one_def(argv[n], p);
	} else
		macro_for_all(dump_one_def);
}

/*
 * dotrace - mark some macros as traced/untraced depending upon on.
 */
static void
dotrace(const char *argv[], int argc, int on)
{
	int n;

	if (argc > 2) {
		for (n = 2; n < argc; n++)
			mark_traced(argv[n], on);
	} else
		mark_traced(NULL, on);
}

/*
 * doifelse - select one of two alternatives - loop.
 */
static void
doifelse(const char *argv[], int argc)
{
	cycle {
		if (argc < 5)
			m4errx(1, "wrong number of args for ifelse");
		if (STREQ(argv[2], argv[3]))
			pbstr(argv[4]);
		else if (argc == 6)
			pbstr(argv[5]);
		else if (argc > 6) {
			argv += 3;
			argc -= 3;
			continue;
		}
		break;
	}
}

/*
 * doinclude - include a given file.
 */
static int
doincl(const char *ifile)
{
#ifndef REAL_FREEZE
	if (thawing)
		return 1;
#endif
	if (ilevel + 1 == MAXINP)
		m4errx(1, "too many include files.");
	if (fopen_trypath(infile+ilevel+1, ifile) != NULL) {
		ilevel++;
		bbase[ilevel] = bufbase = bp;
		return (1);
	} else
		return (0);
}

#ifdef EXTENDED
/*
 * dopaste - include a given file without any
 *           macro processing.
 */
static int
dopaste(const char *pfile)
{
	FILE *pf;
	int c;

	if ((pf = fopen(pfile, "r")) != NULL) {
		if (synch_lines)
		    fprintf(active, "#line 1 \"%s\"\n", pfile);
		while ((c = getc(pf)) != EOF)
			putc(c, active);
		(void) fclose(pf);
		emit_synchline();
		return (1);
	} else
		return (0);
}
#endif

/*
 * dochq - change quote characters
 */
static void
dochq(const char *argv[], int ac)
{
	if (ac == 2) {
		lquote[0] = LQUOTE; lquote[1] = EOS;
		rquote[0] = RQUOTE; rquote[1] = EOS;
	} else {
		strlcpy(lquote, argv[2], sizeof(lquote));
		if (ac > 3) {
			strlcpy(rquote, argv[3], sizeof(rquote));
		} else {
			rquote[0] = ECOMMT; rquote[1] = EOS;
		}
	}
}

/*
 * dochc - change comment characters
 */
static void
dochc(const char *argv[], int argc)
{
/* XXX Note that there is no difference between no argument and a single
 * empty argument.
 */
	if (argc == 2) {
		scommt[0] = EOS;
		ecommt[0] = EOS;
	} else {
		strlcpy(scommt, argv[2], sizeof(scommt));
		if (argc == 3) {
			ecommt[0] = ECOMMT; ecommt[1] = EOS;
		} else {
			strlcpy(ecommt, argv[3], sizeof(ecommt));
		}
	}
}

/*
 * dom4wrap - expand text at EOF
 */
static void
dom4wrap(const char *text)
{
	if (wrapindex >= maxwraps) {
		if (maxwraps == 0)
			maxwraps = 16;
		else
			maxwraps *= 2;
		m4wraps = xrealloc(m4wraps, maxwraps * sizeof(*m4wraps),
		   "too many m4wraps");
	}
	m4wraps[wrapindex++] = xstrdup(text);
}

/*
 * dodivert - divert the output to a temporary file
 */
static void
dodiv(int n)
{
	int fd;

	oindex = n;
	if (n >= maxout) {
		if (mimic_gnu)
			resizedivs(n + 10);
		else
			n = 0;		/* bitbucket */
    	}

	if (n < 0)
		n = 0;		       /* bitbucket */
	if (outfile[n] == NULL) {
		char fname[] = _PATH_DIVNAME;

		if ((fd = mkstemp(fname)) < 0 || 
			(outfile[n] = fdopen(fd, "w+")) == NULL)
				err(1, "%s: cannot divert", fname);
		if (unlink(fname) == -1)
			err(1, "%s: cannot unlink", fname);
	}
	active = outfile[n];
}

/*
 * doundivert - undivert a specified output, or all
 *              other outputs, in numerical order.
 */
static void
doundiv(const char *argv[], int argc)
{
	int ind;
	int n;

	if (argc > 2) {
		for (ind = 2; ind < argc; ind++) {
			int e;
			n = strtoi(argv[ind], NULL, 0, 1, INT_MAX, &e);
			if (e) {
				if (errno == EINVAL && mimic_gnu)
					getdivfile(argv[ind]);
			} else {
				if (n < maxout && outfile[n] != NULL)
					getdiv(n);
			}
		}
	}
	else
		for (n = 1; n < maxout; n++)
			if (outfile[n] != NULL)
				getdiv(n);
}

/*
 * dosub - select substring
 */
static void
dosub(const char *argv[], int argc)
{
	const char *ap, *fc, *k;
	int nc;

	ap = argv[2];		       /* target string */
#ifdef EXPR
	fc = ap + expr(argv[3]);       /* first char */
#else
	fc = ap + atoi(argv[3]);       /* first char */
#endif
	nc = strlen(fc);
	if (argc >= 5)
#ifdef EXPR
		nc = min(nc, expr(argv[4]));
#else
		nc = min(nc, atoi(argv[4]));
#endif
	if (fc >= ap && fc < ap + strlen(ap))
		for (k = fc + nc - 1; k >= fc; k--)
			pushback(*k);
}

/*
 * map:
 * map every character of s1 that is specified in from
 * into s3 and replace in s. (source s1 remains untouched)
 *
 * This is a standard implementation of map(s,from,to) function of ICON
 * language. Within mapvec, we replace every character of "from" with
 * the corresponding character in "to". If "to" is shorter than "from",
 * than the corresponding entries are null, which means that those
 * characters disappear altogether. Furthermore, imagine
 * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
 * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
 * ultimately maps to `*'. In order to achieve this effect in an efficient
 * manner (i.e. without multiple passes over the destination string), we
 * loop over mapvec, starting with the initial source character. if the
 * character value (dch) in this location is different than the source
 * character (sch), sch becomes dch, once again to index into mapvec, until
 * the character value stabilizes (i.e. sch = dch, in other words
 * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
 * character, it will stabilize, since mapvec[0] == 0 at all times. At the
 * end, we restore mapvec* back to normal where mapvec[n] == n for
 * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
 * about 5 times faster than any algorithm that makes multiple passes over
 * destination string.
 */
static void
map(char *dest, const char *src, const char *from, const char *to)
{
	const char *tmp;
	unsigned char sch, dch;
	unsigned char found[256];
	static char frombis[257];
	static char tobis[257];
	static unsigned char mapvec[256] = {
	    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
	    19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
	    36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
	    53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
	    70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
	    87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
	    103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
	    116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
	    129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
	    142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
	    155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
	    168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
	    181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193,
	    194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206,
	    207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
	    220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
	    233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245,
	    246, 247, 248, 249, 250, 251, 252, 253, 254, 255
	};

	if (*src) {
		if (mimic_gnu) {
			/*
			 * expand character ranges on the fly
			 */
			from = handledash(frombis, frombis + 256, from);
			to = handledash(tobis, tobis + 256, to);
		}
		tmp = from;
	/*
	 * create a mapping between "from" and
	 * "to"
	 */
		memset(found, 0, sizeof(found));
		for (; (sch = (unsigned char)*from) != '\0'; from++) {
			if (!mimic_gnu || !found[sch]) {
				found[sch] = 1;
				mapvec[sch] = *to;
			}
			if (*to)
				to++;
		}

		if (mimic_gnu) {
			for (; (sch = (unsigned char)*src) != '\0'; src++) {
				if (!found[sch])
					*dest++ = sch;
				else if ((dch = mapvec[sch]) != '\0')
					*dest++ = dch;
			}
		} else {
			while (*src) {
				sch = (unsigned char)(*src++);
				dch = mapvec[sch];
				while (dch != sch) {
					sch = dch;
					dch = mapvec[sch];
				}
				if ((*dest = (char)dch))
					dest++;
			}
		}
	/*
	 * restore all the changed characters
	 */
		while (*tmp) {
			mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp);
			tmp++;
		}
	}
	*dest = '\0';
}


/*
 * handledash:
 *  use buffer to copy the src string, expanding character ranges
 * on the way.
 */
static const char *
handledash(char *buffer, char *end, const char *src)
{
	char *p;
	
	p = buffer;
	while(*src) {
		if (src[1] == '-' && src[2]) {
			unsigned char i;
			if ((unsigned char)src[0] <= (unsigned char)src[2]) {
				for (i = (unsigned char)src[0]; 
				    i <= (unsigned char)src[2]; i++) {
					*p++ = i;
					if (p == end) {
						*p = '\0';
						return buffer;
					}
				}
			} else {
				for (i = (unsigned char)src[0]; 
				    i >= (unsigned char)src[2]; i--) {
					*p++ = i;
					if (p == end) {
						*p = '\0';
						return buffer;
					}
				}
			}
			src += 3;
		} else
			*p++ = *src++;
		if (p == end)
			break;
	}
	*p = '\0';
	return buffer;
}
@


1.29
log
@fix various typos in comment, documentation and log messages.
@
text
@d2 1
a2 1
/*	$NetBSD: eval.c,v 1.28 2020/06/27 19:18:58 uwe Exp $	*/
d45 1
a45 1
__RCSID("$NetBSD: eval.c,v 1.28 2020/06/27 19:18:58 uwe Exp $");
d913 1
a913 1
 * characters disapear altogether. Furthermore, imagine
@


1.28
log
@eval: Make radix optional even if minimum result width is specified.
This is what GNU m4 does too.
@
text
@d2 1
a2 1
/*	$NetBSD: eval.c,v 1.27 2018/07/30 22:58:09 kre Exp $	*/
d45 1
a45 1
__RCSID("$NetBSD: eval.c,v 1.27 2018/07/30 22:58:09 kre Exp $");
d913 1
a913 1
 * characters dissapear altogether. Furthermore, imagine
@


1.27
log
@
Avoid an infinite loop caused by a line accidentally dropped
in 1.22 (almost 30 months ago!)

[ Discovered by rhialto@@ ]
@
text
@d2 1
a2 1
/*	$NetBSD: eval.c,v 1.26 2017/10/23 02:38:46 christos Exp $	*/
d45 1
a45 1
__RCSID("$NetBSD: eval.c,v 1.26 2017/10/23 02:38:46 christos Exp $");
d187 1
a187 1
		if (argc > 3) {
@


1.26
log
@remove the braces I accidentally added.
@
text
@d2 1
a2 1
/*	$NetBSD: eval.c,v 1.25 2017/10/22 23:01:34 christos Exp $	*/
d45 1
a45 1
__RCSID("$NetBSD: eval.c,v 1.25 2017/10/22 23:01:34 christos Exp $");
d990 1
@


1.26.4.1
log
@Sync with HEAD
@
text
@d2 1
a2 1
/*	$NetBSD: eval.c,v 1.27 2018/07/30 22:58:09 kre Exp $	*/
d45 1
a45 1
__RCSID("$NetBSD: eval.c,v 1.27 2018/07/30 22:58:09 kre Exp $");
a989 1
				sch = (unsigned char)(*src++);
@


1.26.2.1
log
@Sync with HEAD

Resolve a couple of conflicts (result of the uimin/uimax changes)
@
text
@d2 1
a2 1
/*	$NetBSD: eval.c,v 1.27 2018/07/30 22:58:09 kre Exp $	*/
d45 1
a45 1
__RCSID("$NetBSD: eval.c,v 1.27 2018/07/30 22:58:09 kre Exp $");
a989 1
				sch = (unsigned char)(*src++);
@


1.25
log
@PR/52638: matthew green: missing argument check causes m4 to core in ifelse()
@
text
@d2 1
a2 1
/*	$NetBSD: eval.c,v 1.24 2016/01/16 16:56:21 christos Exp $	*/
d45 1
a45 1
__RCSID("$NetBSD: eval.c,v 1.24 2016/01/16 16:56:21 christos Exp $");
d703 1
a703 1
		if (STREQ(argv[2], argv[3])) {
d705 1
a705 1
		} else if (argc == 6)
@


1.24
log
@More gnu compatibility:
	- handle macros > $9
	- handle character remapping the the gnu way.
Add a shortcut for the "fake freeze" files to not expand include macros
during thawing.
@
text
@d2 1
a2 1
/*	$NetBSD: eval.c,v 1.23 2015/01/29 19:26:20 christos Exp $	*/
d45 1
a45 1
__RCSID("$NetBSD: eval.c,v 1.23 2015/01/29 19:26:20 christos Exp $");
d701 3
a703 1
		if (STREQ(argv[2], argv[3]))
d705 1
a705 1
		else if (argc == 6)
@


1.24.8.1
log
@Pull up following revision(s) (requested by mrg in ticket #732):

	usr.bin/m4/eval.c: revision 1.25
	usr.bin/m4/eval.c: revision 1.26

PR/52638: matthew green: missing argument check causes m4 to core in ifelse()

remove the braces I accidentally added.
@
text
@d2 1
a2 1
/*	$NetBSD: eval.c,v 1.24 2016/01/16 16:56:21 christos Exp $	*/
d45 1
a45 1
__RCSID("$NetBSD: eval.c,v 1.24 2016/01/16 16:56:21 christos Exp $");
a700 2
		if (argc < 5)
			m4errx(1, "wrong number of args for ifelse");
@


1.24.8.2
log
@Pull up following revision(s) (requested by kre in ticket #956):

	usr.bin/m4/eval.c: revision 1.27

Avoid an infinite loop caused by a line accidentally dropped
in 1.22 (almost 30 months ago!)
[ Discovered by rhialto@@ ]
@
text
@d2 1
a2 1
/*	$NetBSD: eval.c,v 1.24.8.1 2018/04/11 14:27:51 martin Exp $	*/
d45 1
a45 1
__RCSID("$NetBSD: eval.c,v 1.24.8.1 2018/04/11 14:27:51 martin Exp $");
a989 1
				sch = (unsigned char)(*src++);
@


1.23
log
@use strtoi instead of strtonum, since this is a tool.
@
text
@d2 1
a2 1
/*	$NetBSD: eval.c,v 1.22 2011/08/21 23:38:43 dholland Exp $	*/
d45 1
a45 1
__RCSID("$NetBSD: eval.c,v 1.22 2011/08/21 23:38:43 dholland Exp $");
d48 1
d545 10
a554 1
				if ((argno = *p - '0') < argc - 1)
d720 4
d932 1
d969 19
a987 9
		while (*from)
			mapvec[(unsigned char)(*from++)] = (*to) ? 
				(unsigned char)(*to++) : 0;

		while (*src) {
			sch = (unsigned char)(*src++);
			dch = mapvec[sch];
			while (dch != sch) {
				sch = dch;
d989 6
a995 2
			if ((*dest = (char)dch))
				dest++;
@


1.22
log
@Requires stdint.h.
@
text
@d2 1
a2 1
/*	$NetBSD: eval.c,v 1.21 2011/03/05 16:38:25 christos Exp $	*/
d45 1
a45 1
__RCSID("$NetBSD: eval.c,v 1.21 2011/03/05 16:38:25 christos Exp $");
d57 1
d184 1
a184 1
		const char *errstr;
d187 2
a188 2
			base = strtonum(argv[3], 2, 36, &errstr);
			if (errstr) {
d193 2
a194 2
			maxdigits = strtonum(argv[4], 0, INT_MAX, &errstr);
			if (errstr) {
d844 3
a846 3
			const char *errstr;
			n = strtonum(argv[ind], 1, INT_MAX, &errstr);
			if (errstr) {
@


1.22.20.1
log
@Pull up following revision(s) (requested by mrg in ticket #1587):
	usr.bin/m4/eval.c: revision 1.25
	usr.bin/m4/eval.c: revision 1.26
PR/52638: matthew green: missing argument check causes m4 to core in ifelse()

remove the braces I accidentally added.
@
text
@d2 1
a2 1
/*	$NetBSD: eval.c,v 1.22 2011/08/21 23:38:43 dholland Exp $	*/
d45 1
a45 1
__RCSID("$NetBSD: eval.c,v 1.22 2011/08/21 23:38:43 dholland Exp $");
a689 2
		if (argc < 5)
			m4errx(1, "wrong number of args for ifelse");
@


1.21
log
@add mimic_gnu for eval print.
@
text
@d2 1
a2 1
/*	$NetBSD: eval.c,v 1.20 2009/10/26 21:11:28 christos Exp $	*/
d45 1
a45 1
__RCSID("$NetBSD: eval.c,v 1.20 2009/10/26 21:11:28 christos Exp $");
d55 1
@


1.20
log
@resolve conflicts.
@
text
@d2 1
a2 1
/*	$NetBSD: eval.c,v 1.7 1996/11/10 21:21:29 pk Exp $	*/
d45 1
a45 1
__RCSID("$NetBSD$");
d432 5
a436 2
				fprintf(stderr, "%s ", argv[n]);
			fprintf(stderr, "\n");
@


1.19
log
@Fix a core dump.
@
text
@d1 2
a2 2
/*	$NetBSD: eval.c,v 1.18 2004/06/20 22:20:15 jmc Exp $	*/
/*	$OpenBSD: eval.c,v 1.41 2001/10/10 23:25:31 espie Exp $	*/
a35 13
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif

#include <sys/cdefs.h>
#if defined(__RCSID) && !defined(lint)
#if 0
static char sccsid[] = "@@(#)eval.c	8.2 (Berkeley) 4/27/95";
#else
__RCSID("$NetBSD: eval.c,v 1.18 2004/06/20 22:20:15 jmc Exp $");
#endif
#endif /* not lint */

d41 5
d48 1
d50 2
a51 1
#include <fcntl.h>
d56 1
d62 18
a79 21
#define BUILTIN_MARKER	"__builtin_"

static void	dodefn __P((const char *));
static void	dopushdef __P((const char *, const char *));
static void	dodump __P((const char *[], int));
static void	dotrace __P((const char *[], int, int));
static void	doifelse __P((const char *[], int));
static int	doincl __P((const char *));
static int	dopaste __P((const char *));
static void	gnu_dochq __P((const char *[], int));
static void	dochq __P((const char *[], int));
static void	gnu_dochc __P((const char *[], int));
static void	dochc __P((const char *[], int));
static void	dodiv __P((int));
static void	doundiv __P((const char *[], int));
static void	dosub __P((const char *[], int));
static void	map __P((char *, const char *, const char *, const char *));
static const char *handledash __P((char *, char *, const char *));
static void	expand_builtin __P((const char *[], int, int));
static void	expand_macro __P((const char *[], int));
static void	dump_one_def __P((ndptr));
d88 1
a88 1
 *				  macro or nil if built-in.
d103 1
a103 4
eval(argv, argc, td)
	const char *argv[];
	int argc;
	int td;
d105 1
a105 1
	ssize_t mark = -1;
d109 2
a110 3
		errx(1, "%s at line %lu: expanding recursive definition for %s",
			CURRENT_NAME, CURRENT_LINE, argv[1]);
	if (traced_macros && is_traced(argv[1]))
d116 1
a116 1
    	if (mark != -1)
d124 1
a124 4
expand_builtin(argv, argc, td)
	const char *argv[];
	int argc;
	int td;
d134 1
d142 3
d147 1
a147 1
	if (argc == 3 && !*(argv[2]))
d179 17
d197 1
a197 1
			pbnum(expr(argv[2]));
d199 1
d213 1
a213 1
			if (lookup(argv[2]) != nil)
d250 2
a251 1
		if (argc > 2)
d253 1
d292 3
d297 1
a297 4
		if (mimic_gnu)
			gnu_dochq(argv, ac);
		else
			dochq(argv, argc);
d301 1
a301 4
		if (mimic_gnu)
			gnu_dochc(argv, ac);
		else
			dochc(argv, argc);
d324 1
a324 1
				putback(COMMA);
d360 1
a360 1
				remhash(argv[n], ALL);
d371 1
a371 1
				remhash(argv[n], TOP);
d403 3
a405 1
			char temp[STRSPMAX+1];
d411 1
d451 2
a452 1
		m4wraps = (argc > 2) ? xstrdup(argv[2]) : null;
d499 1
a499 2
		errx(1, "%s at line %lu: eval: major botch.",
			CURRENT_NAME, CURRENT_LINE);
d508 1
a508 3
expand_macro(argv, argc)
	const char *argv[];
	int argc;
d522 1
a522 1
			PUTBACK(*p);
d546 1
a546 1
						putback(COMMA);
d557 1
a557 1
						putback(COMMA);
d565 2
a566 2
				PUTBACK(*p);
				PUTBACK('$');
d574 1
a574 1
		PUTBACK(*p);
d577 1
d582 1
a582 3
dodefine(name, defn)
	const char *name;
	const char *defn;
d584 4
a587 27
	ndptr p;
	int n;

	if (!*name)
		errx(1, "%s at line %lu: null definition.", CURRENT_NAME,
		    CURRENT_LINE);
	if ((p = lookup(name)) == nil)
		p = addent(name);
	else if (p->defn != null)
		free((char *) p->defn);
	if (strncmp(defn, BUILTIN_MARKER, sizeof(BUILTIN_MARKER)-1) == 0) {
		n = builtin_type(defn+sizeof(BUILTIN_MARKER)-1);
		if (n != -1) {
			p->type = n & TYPEMASK;
			if ((n & NOARGS) == 0)
				p->type |= NEEDARGS;
			p->defn = null;
			return;
		}
	}
	if (!*defn)
		p->defn = null;
	else
		p->defn = xstrdup(defn);
	p->type = MACRTYPE;
	if (STREQ(name, defn))
		p->type |= RECDEF;
d595 1
a595 2
dodefn(name)
	const char *name;
d597 1
a597 2
	ndptr p;
	const char *real;
d599 2
a600 2
	if ((p = lookup(name)) != nil) {
		if (p->defn != null) {
d604 2
a605 2
		} else if ((real = builtin_realname(p->type)) != NULL) {
			pbstr(real);
d619 1
a619 3
dopushdef(name, defn)
	const char *name;
	const char *defn;
d621 2
a622 8
	ndptr p;

	if (!*name)
		errx(1, "%s at line %lu: null definition", CURRENT_NAME,
		    CURRENT_LINE);
	p = addent(name);
	if (!*defn)
		p->defn = null;
d624 1
a624 4
		p->defn = xstrdup(defn);
	p->type = MACRTYPE;
	if (STREQ(name, defn))
		p->type |= RECDEF;
d631 1
a631 2
dump_one_def(p)
	ndptr p;
d633 2
a634 3
	FILE *out = traceout ? traceout : stderr;
	const char *real;

d637 1
a637 1
			fprintf(out, "%s:\t%s\n", p->name, p->defn);
d639 1
a639 4
			real = builtin_realname(p->type);
			if (real == NULL)
				real = null;
			fprintf(out, "%s:\t<%s>\n", p->name, real);
d642 1
a642 1
		fprintf(out, "`%s'\t`%s'\n", p->name, p->defn);
d651 1
a651 3
dodump(argv, argc)
	const char *argv[];
	int argc;
d654 1
a654 1
	ndptr p;
d658 4
a661 7
			if ((p = lookup(argv[n])) != nil)
				dump_one_def(p);
	} else {
		for (n = 0; n < HASHSIZE; n++)
			for (p = hashtab[n]; p != nil; p = p->nxtptr)
				dump_one_def(p);
	}
d668 1
a668 4
dotrace(argv, argc, on)
	const char *argv[];
	int argc;
	int on;
d683 1
a683 3
doifelse(argv, argc)
	const char *argv[];
	int argc;
d703 1
a703 2
doincl(ifile)
	const char *ifile;
d706 1
a706 2
		errx(1, "%s at line %lu: too many include files.",
		    CURRENT_NAME, CURRENT_LINE);
d721 1
a721 2
dopaste(pfile)
	const char *pfile;
d727 2
d732 1
d739 3
d743 1
a743 3
gnu_dochq(argv, ac)
	const char *argv[];
	int ac;
a744 2
	/* In gnu-m4 mode, the only way to restore quotes is to have no
	 * arguments at all. */
d746 2
a747 2
		lquote[0] = LQUOTE, lquote[1] = EOS;
		rquote[0] = RQUOTE, rquote[1] = EOS;
d750 1
a750 1
		if(ac > 3)
d752 3
a754 2
		else
			rquote[0] = EOS;
d759 1
a759 1
 * dochq - change quote characters
d762 1
a762 3
dochq(argv, argc)
	const char *argv[];
	int argc;
d764 4
a767 26
	if (argc > 2) {
		if (*argv[2])
			strlcpy(lquote, argv[2], sizeof(lquote));
		else {
			lquote[0] = LQUOTE;
			lquote[1] = EOS;
		}
		if (argc > 3) {
			if (*argv[3])
				strlcpy(rquote, argv[3], sizeof(rquote));
		} else
			strcpy(rquote, lquote);
	} else {
		lquote[0] = LQUOTE, lquote[1] = EOS;
		rquote[0] = RQUOTE, rquote[1] = EOS;
	}
}

static void
gnu_dochc(argv, ac)
	const char *argv[];
	int ac;
{
	/* In gnu-m4 mode, no arguments mean no comment
	 * arguments at all. */
	if (ac == 2) {
d771 4
a774 5
		if (*argv[2])
			strlcpy(scommt, argv[2], sizeof(scommt));
		else
			scommt[0] = SCOMMT, scommt[1] = EOS;
		if(ac > 3 && *argv[3])
d776 1
a776 2
		else
			ecommt[0] = ECOMMT, ecommt[1] = EOS;
d779 1
d781 1
a781 1
 * dochc - change comment characters
d784 1
a784 3
dochc(argv, argc)
	const char *argv[];
	int argc;
d786 3
a788 7
	if (argc > 2) {
		if (*argv[2])
			strlcpy(scommt, argv[2], sizeof(scommt));
		if (argc > 3) {
			if (*argv[3])
				strlcpy(ecommt, argv[3], sizeof(ecommt));
		}
d790 3
a792 5
			ecommt[0] = ECOMMT, ecommt[1] = EOS;
	}
	else {
		scommt[0] = SCOMMT, scommt[1] = EOS;
		ecommt[0] = ECOMMT, ecommt[1] = EOS;
d794 1
d801 1
a801 2
dodiv(n)
	int n;
d832 1
a832 3
doundiv(argv, argc)
	const char *argv[];
	int argc;
d839 9
a847 4
			n = atoi(argv[ind]);
			if (n > 0 && n < maxout && outfile[n] != NULL)
				getdiv(n);

d860 1
a860 3
dosub(argv, argc)
	const char *argv[];
	int argc;
d880 1
a880 1
			putback(*k);
d909 1
a909 5
map(dest, src, from, to)
	char *dest;
	const char *src;
	const char *from;
	const char *to;
d981 1
a981 4
handledash(buffer, end, src)
	char *buffer;
	char *end;
	const char *src;
d989 17
a1005 6
			for (i = (unsigned char)src[0]; 
			    i <= (unsigned char)src[2]; i++) {
				*p++ = i;
				if (p == end) {
					*p = '\0';
					return buffer;
a1016 1
			    
@


1.18
log
@Completely rework how tools/compat is done. Purge all uses/references to
_NETBSD_SOURCE as this makes cross building from older/newer versions of
NetBSD harder, not easier (and also makes the resulting tools 'different')

Wrap all required code with the inclusion of nbtool_config.h, attempt to
only use POSIX code in all places (or when reasonable test w. configure and
provide definitions: ala u_int, etc).

Reviewed by lukem. Tested on FreeBSD 4.9, Redhat Linux ES3, NetBSD 1.6.2 x86
NetBSD current (x86 and amd64) and Solaris 9.

Fixes PR's: PR#17762 PR#25944
@
text
@d1 1
a1 1
/*	$NetBSD: eval.c,v 1.17 2003/08/07 11:14:30 agc Exp $	*/
d45 1
a45 1
__RCSID("$NetBSD: eval.c,v 1.17 2003/08/07 11:14:30 agc Exp $");
d664 1
d669 1
a669 1
			fprintf(traceout, "%s:\t%s\n", p->name, p->defn);
d674 1
a674 1
			fprintf(traceout, "%s:\t<%s>\n", p->name, real);
d677 1
a677 1
		fprintf(traceout, "`%s'\t`%s'\n", p->name, p->defn);
@


1.17
log
@Move UCB-licensed code from 4-clause to 3-clause licence.

Patches provided by Joel Baker in PR 22365, verified by myself.
@
text
@d1 1
a1 1
/*	$NetBSD: eval.c,v 1.16 2002/01/31 19:36:47 tv Exp $	*/
d36 4
d45 1
a45 1
__RCSID("$NetBSD: eval.c,v 1.16 2002/01/31 19:36:47 tv Exp $");
@


1.17.2.1
log
@Pull up revision 1.18 (requested by jmc in ticket #527):
Completely rework how tools/compat is done. Purge all uses/references to
_NETBSD_SOURCE as this makes cross building from older/newer versions of
NetBSD harder, not easier (and also makes the resulting tools 'different')
Wrap all required code with the inclusion of nbtool_config.h, attempt to
only use POSIX code in all places (or when reasonable test w. configure and
provide definitions: ala u_int, etc).
Reviewed by lukem. Tested on FreeBSD 4.9, Redhat Linux ES3, NetBSD 1.6.2 x86
NetBSD current (x86 and amd64) and Solaris 9.
Fixes PR's: PR#17762 PR#25944
@
text
@d1 1
a1 1
/*	$NetBSD$	*/
a35 4
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif

d41 1
a41 1
__RCSID("$NetBSD$");
@


1.17.2.2
log
@Pull up revision 1.19 (requested by mycroft in ticket #615):
Fix a core dump.
@
text
@a663 1
	FILE *out = traceout ? traceout : stderr;
d668 1
a668 1
			fprintf(out, "%s:\t%s\n", p->name, p->defn);
d673 1
a673 1
			fprintf(out, "%s:\t<%s>\n", p->name, real);
d676 1
a676 1
		fprintf(out, "`%s'\t`%s'\n", p->name, p->defn);
@


1.16
log
@Protect __RCSID and __COPYRIGHT from being invoked if not defined.
@
text
@d1 1
a1 1
/*	$NetBSD: eval.c,v 1.15 2002/01/21 21:49:57 tv Exp $	*/
d19 1
a19 5
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
d41 1
a41 1
__RCSID("$NetBSD: eval.c,v 1.15 2002/01/21 21:49:57 tv Exp $");
@


1.15
log
@Make compilable from src/tools/m4 on non-NetBSD hosts.
@
text
@d1 1
a1 1
/*	$NetBSD: eval.c,v 1.14 2001/11/14 06:16:08 tv Exp $	*/
d41 1
a41 1
#ifndef lint
d45 1
a45 1
__RCSID("$NetBSD: eval.c,v 1.14 2001/11/14 06:16:08 tv Exp $");
@


1.14
log
@Pull in various changes from OpenBSD, most from Marc Espie, including:
* Provide some GNUisms as extensions.
* Provide dynamically growable string space.
* Make define(defn(foo)) work correctly for builtins.
(The current version is supposed to be capable of satisfying autoconf.)

All still relevant NetBSD changes have been preserved in this version, and
formatting and style fixes have been applied in various places.

Thanks to Masao Uebayashi <uebayasi@@soum.co.jp> for pointing this out.
@
text
@d1 1
a1 1
/*	$NetBSD: eval.c,v 1.13 2000/10/17 18:51:32 jdolecek Exp $	*/
d45 1
a45 1
__RCSID("$NetBSD: eval.c,v 1.13 2000/10/17 18:51:32 jdolecek Exp $");
a55 1
#include <err.h>
@


1.13
log
@Fix unconsistent spacing/tabs. Adresses bin/11158 by Nathan Ahlstrom.
@
text
@d1 2
a2 1
/*	$NetBSD: eval.c,v 1.12 2000/10/11 14:46:11 is Exp $	*/
d45 1
a45 1
__RCSID("$NetBSD: eval.c,v 1.12 2000/10/11 14:46:11 is Exp $");
d58 1
a58 1
#include <unistd.h>
d61 1
d68 24
d93 1
a93 1
 * eval - evaluate built-in macros.
d104 1
a104 2
 * Note that the minimum value for argc is 3. A call in the form
 * of macro-or-builtin() will result in:
d108 2
d111 7
d119 17
d137 2
a138 2
eval(argv, argc, td)
	char *argv[];
d143 1
d151 1
d157 2
d162 1
a162 1
	switch (td & ~STATIC) {
d178 8
d219 1
a219 2
		if (argc > 2)
			pbnum((argc > 2) ? strlen(argv[2]) : 0);
d257 4
d264 2
a265 1
				err(1, "%s", argv[2]);
d276 2
a277 1
				err(1, "%s", argv[2]);
d286 4
a289 1
		dochq(argv, argc);
d293 4
a296 1
		dochc(argv, argc);
d375 1
d377 3
a379 1
			fd = mkstemp(argv[2]);
d381 3
a383 1
				err(1, "mkstemp failed");
d385 2
a386 1
			pbstr(argv[2]);
d398 1
a398 1
			char temp[MAXTOK];
d404 1
a404 2
		}
		else if (argc > 2)
d460 29
d490 2
a491 1
		errx(1, "eval: major botch");
a495 2
const char dumpfmt[] = "`%s'\t`%s'\n";	       /* format string for dumpdef   */

d497 1
a497 1
 * expand - user-defined macro expansion
d500 2
a501 2
expand(argv, argc)
	char *argv[];
d504 2
a505 2
	char *t;
	char *p;
d516 1
a516 1
			putback(*p);
d537 7
a543 5
				for (n = argc - 1; n > 2; n--) {
					pbstr(argv[n]);
					putback(COMMA);
				}
				pbstr(argv[2]);
d545 8
a552 2
			case '@@':
				for (n = argc - 1; n > 2; n--) {
d554 1
a554 1
					pbstr(argv[n]);
a555 1
					putback(COMMA);
d557 1
a557 4
				pbstr(rquote);
				pbstr(argv[2]);
				pbstr(lquote);
				break;
d559 2
a560 2
				putback(*p);
				putback('$');
d568 1
a568 1
		putback(*p);
d576 2
a577 2
	char *name;
	char *defn;
d580 1
d583 2
a584 3
		errx(1, "null definition");
	if (STREQ(name, defn))
		errx(1, "%s: recursive definition", name);
d589 10
d604 2
d612 1
a612 1
void
d614 1
a614 1
	char *name;
d617 1
d619 9
a627 4
	if ((p = lookup(name)) != nil && p->defn != null) {
		pbstr(rquote);
		pbstr(p->defn);
		pbstr(lquote);
d638 1
a638 1
void
d640 2
a641 2
	char *name;
	char *defn;
d646 2
a647 3
		errx(1, "null definition");
	if (STREQ(name, defn))
		errx(1, "%s: recursive definition", name);
d654 24
d685 1
a685 1
void
d687 1
a687 1
	char *argv[];
d696 2
a697 4
				fprintf(stderr, dumpfmt, p->name,
					p->defn);
	}
	else {
d700 1
a700 2
				fprintf(stderr, dumpfmt, p->name,
					p->defn);
d705 18
d725 1
a725 1
void
d727 1
a727 1
	char *argv[];
d747 1
a747 1
int
d749 1
a749 1
	char *ifile;
d752 3
a754 2
		errx(1, "too many include files");
	if ((infile[ilevel + 1] = fopen(ifile, "r")) != NULL) {
d758 1
a758 2
	}
	else
d767 1
a767 1
int
d769 1
a769 1
	char *pfile;
d779 1
a779 2
	}
	else
d784 19
d806 1
a806 1
void
d808 1
a808 1
	char *argv[];
d813 5
a817 1
			strncpy(lquote, argv[2], MAXCCHARS);
d820 2
a821 3
				strncpy(rquote, argv[3], MAXCCHARS);
		}
		else
d823 3
d827 21
a847 3
	else {
		lquote[0] = LQUOTE, lquote[1] = '\0';
		rquote[0] = RQUOTE, rquote[1] = '\0';
a849 1

d853 1
a853 1
void
d855 1
a855 1
	char *argv[];
d860 1
a860 1
			strncpy(scommt, argv[2], MAXCCHARS);
d863 1
a863 1
				strncpy(ecommt, argv[3], MAXCCHARS);
d866 1
a866 1
			ecommt[0] = ECOMMT, ecommt[1] = '\0';
d869 2
a870 2
		scommt[0] = SCOMMT, scommt[1] = '\0';
		ecommt[0] = ECOMMT, ecommt[1] = '\0';
d877 1
a877 1
void
d881 1
a881 1
	int tempfilenum;
d883 7
a889 5
	/*
	 * direct output to the appropriate temporary file (the bit
	 * bucket, if out of range).
	 */
	tempfilenum = (n < 0 || n >= MAXOUT) ? 0 : n;
d891 10
a900 4
	if (outfile[tempfilenum] == NULL) {
		m4temp[UNIQUE] = tempfilenum + '0';
		if ((outfile[tempfilenum] = fopen(m4temp, "w")) == NULL)
			err(1, "%s: cannot divert", m4temp);
d902 1
a902 2
	oindex = n;
	active = outfile[tempfilenum];
d909 1
a909 1
void
d911 1
a911 1
	char *argv[];
d920 1
a920 1
			if (n > 0 && n < MAXOUT && outfile[n] != NULL)
d926 1
a926 1
		for (n = 1; n < MAXOUT; n++)
d934 1
a934 1
void
d936 1
a936 1
	char *argv[];
d939 1
a939 1
	char *ap, *fc, *k;
d942 1
a942 3
	if (argc < 5)
		nc = MAXTOK;
	else
d944 1
a944 1
		nc = expr(argv[4]);
d946 1
a946 1
		nc = atoi(argv[4]);
d948 2
a949 1
	ap = argv[2];		       /* target string */
d951 1
a951 1
	fc = ap + expr(argv[3]);       /* first char */
d953 1
a953 1
	fc = ap + atoi(argv[3]);       /* first char */
d956 1
a956 1
		for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--)
d985 1
a985 1
void
d988 27
a1014 18
	char *src;
	char *from;
	char *to;
{
	char *tmp;
	char sch, dch;
	static char mapvec[128] = {
		0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
		12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
		24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
		36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
		48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
		60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
		72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
		84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
		96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
		108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
		120, 121, 122, 123, 124, 125, 126, 127
d1018 7
d1031 2
a1032 1
			mapvec[(int)*from++] = (*to) ? *to++ : (char) 0;
d1035 2
a1036 2
			sch = *src++;
			dch = mapvec[(int)sch];
d1039 1
a1039 1
				dch = mapvec[(int)sch];
d1041 1
a1041 1
			if ((*dest = dch) != 0)
d1048 1
a1048 1
			mapvec[(int)*tmp] = *tmp;
d1052 37
a1088 1
	*dest = (char) 0;
d1090 1
@


1.12
log
@More format string cleanup by sommerfeld.
@
text
@d1 1
a1 1
/*	$NetBSD: eval.c,v 1.11 1999/04/20 08:05:51 mrg Exp $	*/
d44 1
a44 1
__RCSID("$NetBSD: eval.c,v 1.11 1999/04/20 08:05:51 mrg Exp $");
d436 5
a440 5
                        case '@@':
                                for (n = argc - 1; n > 2; n--) {
                                        pbstr(rquote);
                                        pbstr(argv[n]);
                                        pbstr(lquote);
d442 1
a442 1
                                }
d444 1
a444 1
                                pbstr(argv[2]);
d446 1
a446 1
                                break;
@


1.11
log
@use mkstemp.
@
text
@d1 1
a1 1
/*	$NetBSD: eval.c,v 1.10 1997/10/19 04:39:51 lukem Exp $	*/
d44 1
a44 1
__RCSID("$NetBSD: eval.c,v 1.10 1997/10/19 04:39:51 lukem Exp $");
d387 1
a387 1
char *dumpfmt = "`%s'\t`%s'\n";	       /* format string for dumpdef   */
@


1.11.8.1
log
@Pullup usr.bin string format fixes [is].
See "cvs log" for explicit revision numbers per file, from sommerfeld.
@
text
@d1 1
a1 1
/*	$NetBSD: eval.c,v 1.12 2000/10/11 14:46:11 is Exp $	*/
d44 1
a44 1
__RCSID("$NetBSD: eval.c,v 1.12 2000/10/11 14:46:11 is Exp $");
d387 1
a387 1
const char dumpfmt[] = "`%s'\t`%s'\n";	       /* format string for dumpdef   */
@


1.10
log
@WARNSify, fix .Nm usage, getopt returns -1 not EOF, deprecate register
@
text
@d1 1
a1 1
/*	$NetBSD: eval.c,v 1.9 1997/02/08 23:50:40 cgd Exp $	*/
d44 1
a44 1
__RCSID("$NetBSD$");
d299 9
a307 2
		if (argc > 2)
			pbstr(mktemp(argv[2]));
@


1.10.4.1
log
@Pull up revision 1.12 (requested by he):
  Format string cleanup.
@
text
@d1 1
a1 1
/*	$NetBSD$	*/
d380 1
a380 1
const char dumpfmt[] = "`%s'\t`%s'\n";	       /* format string for dumpdef   */
@


1.9
log
@Simplify some push-back code (e.g. for left and right quotes) so that
    it uses pbstr() instead of doing the characters individually (in
    reverse order) with putback().
Fix dodiv() so that divert(<out-of-range stream>) doesn't cause "divnum" to
    return 0, but rather the stream number specified to divert().  Macros
    like PUSHDIVERT/POPDIVERT rely on this.  The new behaviour is compatible
    with vendor m4 implementations.
@
text
@d1 1
a1 1
/*	$NetBSD: eval.c,v 1.8 1997/01/09 20:20:35 tls Exp $	*/
d39 1
d44 1
a44 1
static char rcsid[] = "$NetBSD: eval.c,v 1.8 1997/01/09 20:20:35 tls Exp $";
d55 1
d87 3
a89 3
register char *argv[];
register int argc;
register int td;
d91 1
a91 1
	register int c, n;
d198 1
a198 1
				oops("%s: %s", argv[2], strerror(errno));
d209 1
a209 1
				oops("%s: %s", argv[2], strerror(errno));
a240 1
			int k;
d375 1
a375 1
		oops("%s: major botch.", "eval");
d387 2
a388 2
register char *argv[];
register int argc;
d390 4
a393 4
	register char *t;
	register char *p;
	register int n;
	register int argno;
d458 2
a459 2
register char *name;
register char *defn;
d461 1
a461 1
	register ndptr p;
d464 1
a464 1
		oops("null definition.");
d466 1
a466 1
		oops("%s: recursive definition.", name);
d484 1
a484 1
char *name;
d486 1
a486 1
	register ndptr p;
d504 2
a505 2
register char *name;
register char *defn;
d507 1
a507 1
	register ndptr p;
d510 1
a510 1
		oops("null definition");
d512 1
a512 1
		oops("%s: recursive definition.", name);
d528 2
a529 2
register char *argv[];
register int argc;
d531 1
a531 1
	register int n;
d553 2
a554 2
register char *argv[];
register int argc;
d575 1
a575 1
char *ifile;
d578 1
a578 1
		oops("too many include files.");
d595 1
a595 1
char *pfile;
d598 1
a598 1
	register int c;
d616 2
a617 2
register char *argv[];
register int argc;
d640 2
a641 2
register char *argv[];
register int argc;
d664 1
a664 1
register int n;
d677 1
a677 1
			oops("%s: cannot divert.", m4temp);
d689 2
a690 2
register char *argv[];
register int argc;
d692 2
a693 2
	register int ind;
	register int n;
d714 2
a715 2
register char *argv[];
register int argc;
d717 2
a718 2
	register char *ap, *fc, *k;
	register int nc;
d766 4
a769 4
register char *dest;
register char *src;
register char *from;
register char *to;
d771 2
a772 2
	register char *tmp;
	register char sch, dch;
d794 1
a794 1
			mapvec[*from++] = (*to) ? *to++ : (char) 0;
d798 1
a798 1
			dch = mapvec[sch];
d801 1
a801 1
				dch = mapvec[sch];
d803 1
a803 1
			if (*dest = dch)
d810 1
a810 1
			mapvec[*tmp] = *tmp;
@


1.8
log
@RCS ID police
@
text
@d1 1
a1 1
/*	$NetBSD$	*/
d43 1
a43 1
static char rcsid[] = "$NetBSD: eval.c,v 1.7 1996/11/10 21:21:29 pk Exp $";
d241 1
a241 3
				k = strlen(rquote);
				while (k--)
					putback(rquote[k]);
d243 1
a243 3
				k = strlen(lquote);
				while (k--)
					putback(lquote[k]);
d246 1
a246 3
			k = strlen(rquote);
			while (k--)
				putback(rquote[k]);
d248 1
a248 3
			k = strlen(lquote);
			while (k--)
				putback(lquote[k]);
d488 1
a488 3
		int n = strlen(rquote);
		while (n--)
			putback(rquote[n]);
d490 1
a490 3
		n = strlen(lquote);
		while (n--)
			putback(lquote[n]);
d665 11
a675 5
	if (n < 0 || n >= MAXOUT)
		n = 0;		       /* bitbucket */
	if (outfile[n] == NULL) {
		m4temp[UNIQUE] = n + '0';
		if ((outfile[n] = fopen(m4temp, "w")) == NULL)
d679 1
a679 1
	active = outfile[n];
@


1.7
log
@Use COMMA in stead of ',' when pushing items back on the stack, for
consistency with the macro parsing routine. Suggested by Brian Grayson.
@
text
@d1 1
a1 1
/*      $NetBSD: eval.c,v 1.6 1996/11/06 00:11:56 pk Exp $      */
d43 1
a43 1
static char rcsid[] = "$NetBSD: eval.c,v 1.6 1996/11/06 00:11:56 pk Exp $";
@


1.6
log
@Implement `$@@' macro, as promised by the manual page (PR#2914).
@
text
@d1 1
a1 1
/*      $NetBSD: eval.c,v 1.5 1996/01/13 23:25:23 pk Exp $      */
d43 1
a43 1
static char rcsid[] = "$NetBSD: eval.c,v 1.5 1996/01/13 23:25:23 pk Exp $";
d248 1
a248 1
				putback(',');
d432 1
a432 1
					putback(',');
d441 1
a441 1
                                        putback(',');
@


1.5
log
@Handle multichar comment and quote delimiters (up to 5 characters, per the
manual page). Takes care of PR#485.
@
text
@d1 1
a1 1
/*      $NetBSD: eval.c,v 1.4 1995/09/28 05:37:28 tls Exp $      */
d43 1
a43 1
static char rcsid[] = "$NetBSD: eval.c,v 1.4 1995/09/28 05:37:28 tls Exp $";
d436 11
@


1.4
log
@Sync with 4.4BSD-Lite2
@
text
@d1 1
a1 1
/*      $NetBSD: $      */
d43 1
a43 1
static char rcsid[] = "$NetBSD: $";
d239 1
d241 3
a243 1
				putback(rquote);
d245 3
a247 1
				putback(lquote);
d250 3
a252 1
			putback(rquote);
d254 3
a256 1
			putback(lquote);
d485 3
a487 1
		putback(rquote);
d489 3
a491 1
		putback(lquote);
d621 1
a621 1
			lquote = *argv[2];
d624 1
a624 1
				rquote = *argv[3];
d627 1
a627 1
			rquote = lquote;
d630 2
a631 2
		lquote = LQUOTE;
		rquote = RQUOTE;
d645 1
a645 1
			scommt = *argv[2];
d648 1
a648 1
				ecommt = *argv[3];
d651 1
a651 1
			ecommt = ECOMMT;
d654 2
a655 2
		scommt = SCOMMT;
		ecommt = ECOMMT;
@


1.3
log
@Remove temporary files on m4exit, from Thomas Eberhardt.
@
text
@d1 2
d40 5
a44 1
static char sccsid[] = "@@(#)eval.c	8.1 (Berkeley) 6/6/93";
@


1.3.2.1
log
@file eval.c was added on branch netbsd-1-0 on 1994-08-29 03:24:45 +0000
@
text
@d1 790
@


1.3.2.2
log
@Remove temporary files on m4exit, from Thomas Eberhardt.
@
text
@a0 790
/*
 * Copyright (c) 1989, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * Ozan Yigit at York University.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#ifndef lint
static char sccsid[] = "@@(#)eval.c	8.1 (Berkeley) 6/6/93";
#endif /* not lint */

/*
 * eval.c
 * Facility: m4 macro processor
 * by: oz
 */

#include <sys/types.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mdef.h"
#include "stdd.h"
#include "extern.h"
#include "pathnames.h"

/*
 * eval - evaluate built-in macros.
 *	  argc - number of elements in argv.
 *	  argv - element vector :
 *			argv[0] = definition of a user
 *				  macro or nil if built-in.
 *			argv[1] = name of the macro or
 *				  built-in.
 *			argv[2] = parameters to user-defined
 *			   .	  macro or built-in.
 *			   .
 *
 * Note that the minimum value for argc is 3. A call in the form
 * of macro-or-builtin() will result in:
 *			argv[0] = nullstr
 *			argv[1] = macro-or-builtin
 *			argv[2] = nullstr
 */

void
eval(argv, argc, td)
register char *argv[];
register int argc;
register int td;
{
	register int c, n;
	static int sysval = 0;

#ifdef DEBUG
	printf("argc = %d\n", argc);
	for (n = 0; n < argc; n++)
		printf("argv[%d] = %s\n", n, argv[n]);
#endif
 /*
  * if argc == 3 and argv[2] is null, then we
  * have macro-or-builtin() type call. We adjust
  * argc to avoid further checking..
  */
	if (argc == 3 && !*(argv[2]))
		argc--;

	switch (td & ~STATIC) {

	case DEFITYPE:
		if (argc > 2)
			dodefine(argv[2], (argc > 3) ? argv[3] : null);
		break;

	case PUSDTYPE:
		if (argc > 2)
			dopushdef(argv[2], (argc > 3) ? argv[3] : null);
		break;

	case DUMPTYPE:
		dodump(argv, argc);
		break;

	case EXPRTYPE:
	/*
	 * doexpr - evaluate arithmetic
	 * expression
	 */
		if (argc > 2)
			pbnum(expr(argv[2]));
		break;

	case IFELTYPE:
		if (argc > 4)
			doifelse(argv, argc);
		break;

	case IFDFTYPE:
	/*
	 * doifdef - select one of two
	 * alternatives based on the existence of
	 * another definition
	 */
		if (argc > 3) {
			if (lookup(argv[2]) != nil)
				pbstr(argv[3]);
			else if (argc > 4)
				pbstr(argv[4]);
		}
		break;

	case LENGTYPE:
	/*
	 * dolen - find the length of the
	 * argument
	 */
		if (argc > 2)
			pbnum((argc > 2) ? strlen(argv[2]) : 0);
		break;

	case INCRTYPE:
	/*
	 * doincr - increment the value of the
	 * argument
	 */
		if (argc > 2)
			pbnum(atoi(argv[2]) + 1);
		break;

	case DECRTYPE:
	/*
	 * dodecr - decrement the value of the
	 * argument
	 */
		if (argc > 2)
			pbnum(atoi(argv[2]) - 1);
		break;

	case SYSCTYPE:
	/*
	 * dosys - execute system command
	 */
		if (argc > 2)
			sysval = system(argv[2]);
		break;

	case SYSVTYPE:
	/*
	 * dosysval - return value of the last
	 * system call.
	 * 
	 */
		pbnum(sysval);
		break;

	case INCLTYPE:
		if (argc > 2)
			if (!doincl(argv[2]))
				oops("%s: %s", argv[2], strerror(errno));
		break;

	case SINCTYPE:
		if (argc > 2)
			(void) doincl(argv[2]);
		break;
#ifdef EXTENDED
	case PASTTYPE:
		if (argc > 2)
			if (!dopaste(argv[2]))
				oops("%s: %s", argv[2], strerror(errno));
		break;

	case SPASTYPE:
		if (argc > 2)
			(void) dopaste(argv[2]);
		break;
#endif
	case CHNQTYPE:
		dochq(argv, argc);
		break;

	case CHNCTYPE:
		dochc(argv, argc);
		break;

	case SUBSTYPE:
	/*
	 * dosub - select substring
	 * 
	 */
		if (argc > 3)
			dosub(argv, argc);
		break;

	case SHIFTYPE:
	/*
	 * doshift - push back all arguments
	 * except the first one (i.e. skip
	 * argv[2])
	 */
		if (argc > 3) {
			for (n = argc - 1; n > 3; n--) {
				putback(rquote);
				pbstr(argv[n]);
				putback(lquote);
				putback(',');
			}
			putback(rquote);
			pbstr(argv[3]);
			putback(lquote);
		}
		break;

	case DIVRTYPE:
		if (argc > 2 && (n = atoi(argv[2])) != 0)
			dodiv(n);
		else {
			active = stdout;
			oindex = 0;
		}
		break;

	case UNDVTYPE:
		doundiv(argv, argc);
		break;

	case DIVNTYPE:
	/*
	 * dodivnum - return the number of
	 * current output diversion
	 */
		pbnum(oindex);
		break;

	case UNDFTYPE:
	/*
	 * doundefine - undefine a previously
	 * defined macro(s) or m4 keyword(s).
	 */
		if (argc > 2)
			for (n = 2; n < argc; n++)
				remhash(argv[n], ALL);
		break;

	case POPDTYPE:
	/*
	 * dopopdef - remove the topmost
	 * definitions of macro(s) or m4
	 * keyword(s).
	 */
		if (argc > 2)
			for (n = 2; n < argc; n++)
				remhash(argv[n], TOP);
		break;

	case MKTMTYPE:
	/*
	 * dotemp - create a temporary file
	 */
		if (argc > 2)
			pbstr(mktemp(argv[2]));
		break;

	case TRNLTYPE:
	/*
	 * dotranslit - replace all characters in
	 * the source string that appears in the
	 * "from" string with the corresponding
	 * characters in the "to" string.
	 */
		if (argc > 3) {
			char temp[MAXTOK];
			if (argc > 4)
				map(temp, argv[2], argv[3], argv[4]);
			else
				map(temp, argv[2], argv[3], null);
			pbstr(temp);
		}
		else if (argc > 2)
			pbstr(argv[2]);
		break;

	case INDXTYPE:
	/*
	 * doindex - find the index of the second
	 * argument string in the first argument
	 * string. -1 if not present.
	 */
		pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
		break;

	case ERRPTYPE:
	/*
	 * doerrp - print the arguments to stderr
	 * file
	 */
		if (argc > 2) {
			for (n = 2; n < argc; n++)
				fprintf(stderr, "%s ", argv[n]);
			fprintf(stderr, "\n");
		}
		break;

	case DNLNTYPE:
	/*
	 * dodnl - eat-up-to and including
	 * newline
	 */
		while ((c = gpbc()) != '\n' && c != EOF)
			;
		break;

	case M4WRTYPE:
	/*
	 * dom4wrap - set up for
	 * wrap-up/wind-down activity
	 */
		m4wraps = (argc > 2) ? xstrdup(argv[2]) : null;
		break;

	case EXITTYPE:
	/*
	 * doexit - immediate exit from m4.
	 */
		killdiv();
		exit((argc > 2) ? atoi(argv[2]) : 0);
		break;

	case DEFNTYPE:
		if (argc > 2)
			for (n = 2; n < argc; n++)
				dodefn(argv[n]);
		break;

	default:
		oops("%s: major botch.", "eval");
		break;
	}
}

char *dumpfmt = "`%s'\t`%s'\n";	       /* format string for dumpdef   */

/*
 * expand - user-defined macro expansion
 */
void
expand(argv, argc)
register char *argv[];
register int argc;
{
	register char *t;
	register char *p;
	register int n;
	register int argno;

	t = argv[0];		       /* defn string as a whole */
	p = t;
	while (*p)
		p++;
	p--;			       /* last character of defn */
	while (p > t) {
		if (*(p - 1) != ARGFLAG)
			putback(*p);
		else {
			switch (*p) {

			case '#':
				pbnum(argc - 2);
				break;
			case '0':
			case '1':
			case '2':
			case '3':
			case '4':
			case '5':
			case '6':
			case '7':
			case '8':
			case '9':
				if ((argno = *p - '0') < argc - 1)
					pbstr(argv[argno + 1]);
				break;
			case '*':
				for (n = argc - 1; n > 2; n--) {
					pbstr(argv[n]);
					putback(',');
				}
				pbstr(argv[2]);
				break;
			default:
				putback(*p);
				putback('$');
				break;
			}
			p--;
		}
		p--;
	}
	if (p == t)		       /* do last character */
		putback(*p);
}

/*
 * dodefine - install definition in the table
 */
void
dodefine(name, defn)
register char *name;
register char *defn;
{
	register ndptr p;

	if (!*name)
		oops("null definition.");
	if (STREQ(name, defn))
		oops("%s: recursive definition.", name);
	if ((p = lookup(name)) == nil)
		p = addent(name);
	else if (p->defn != null)
		free((char *) p->defn);
	if (!*defn)
		p->defn = null;
	else
		p->defn = xstrdup(defn);
	p->type = MACRTYPE;
}

/*
 * dodefn - push back a quoted definition of
 *      the given name.
 */
void
dodefn(name)
char *name;
{
	register ndptr p;

	if ((p = lookup(name)) != nil && p->defn != null) {
		putback(rquote);
		pbstr(p->defn);
		putback(lquote);
	}
}

/*
 * dopushdef - install a definition in the hash table
 *      without removing a previous definition. Since
 *      each new entry is entered in *front* of the
 *      hash bucket, it hides a previous definition from
 *      lookup.
 */
void
dopushdef(name, defn)
register char *name;
register char *defn;
{
	register ndptr p;

	if (!*name)
		oops("null definition");
	if (STREQ(name, defn))
		oops("%s: recursive definition.", name);
	p = addent(name);
	if (!*defn)
		p->defn = null;
	else
		p->defn = xstrdup(defn);
	p->type = MACRTYPE;
}

/*
 * dodumpdef - dump the specified definitions in the hash
 *      table to stderr. If nothing is specified, the entire
 *      hash table is dumped.
 */
void
dodump(argv, argc)
register char *argv[];
register int argc;
{
	register int n;
	ndptr p;

	if (argc > 2) {
		for (n = 2; n < argc; n++)
			if ((p = lookup(argv[n])) != nil)
				fprintf(stderr, dumpfmt, p->name,
					p->defn);
	}
	else {
		for (n = 0; n < HASHSIZE; n++)
			for (p = hashtab[n]; p != nil; p = p->nxtptr)
				fprintf(stderr, dumpfmt, p->name,
					p->defn);
	}
}

/*
 * doifelse - select one of two alternatives - loop.
 */
void
doifelse(argv, argc)
register char *argv[];
register int argc;
{
	cycle {
		if (STREQ(argv[2], argv[3]))
			pbstr(argv[4]);
		else if (argc == 6)
			pbstr(argv[5]);
		else if (argc > 6) {
			argv += 3;
			argc -= 3;
			continue;
		}
		break;
	}
}

/*
 * doinclude - include a given file.
 */
int
doincl(ifile)
char *ifile;
{
	if (ilevel + 1 == MAXINP)
		oops("too many include files.");
	if ((infile[ilevel + 1] = fopen(ifile, "r")) != NULL) {
		ilevel++;
		bbase[ilevel] = bufbase = bp;
		return (1);
	}
	else
		return (0);
}

#ifdef EXTENDED
/*
 * dopaste - include a given file without any
 *           macro processing.
 */
int
dopaste(pfile)
char *pfile;
{
	FILE *pf;
	register int c;

	if ((pf = fopen(pfile, "r")) != NULL) {
		while ((c = getc(pf)) != EOF)
			putc(c, active);
		(void) fclose(pf);
		return (1);
	}
	else
		return (0);
}
#endif

/*
 * dochq - change quote characters
 */
void
dochq(argv, argc)
register char *argv[];
register int argc;
{
	if (argc > 2) {
		if (*argv[2])
			lquote = *argv[2];
		if (argc > 3) {
			if (*argv[3])
				rquote = *argv[3];
		}
		else
			rquote = lquote;
	}
	else {
		lquote = LQUOTE;
		rquote = RQUOTE;
	}
}

/*
 * dochc - change comment characters
 */
void
dochc(argv, argc)
register char *argv[];
register int argc;
{
	if (argc > 2) {
		if (*argv[2])
			scommt = *argv[2];
		if (argc > 3) {
			if (*argv[3])
				ecommt = *argv[3];
		}
		else
			ecommt = ECOMMT;
	}
	else {
		scommt = SCOMMT;
		ecommt = ECOMMT;
	}
}

/*
 * dodivert - divert the output to a temporary file
 */
void
dodiv(n)
register int n;
{
	if (n < 0 || n >= MAXOUT)
		n = 0;		       /* bitbucket */
	if (outfile[n] == NULL) {
		m4temp[UNIQUE] = n + '0';
		if ((outfile[n] = fopen(m4temp, "w")) == NULL)
			oops("%s: cannot divert.", m4temp);
	}
	oindex = n;
	active = outfile[n];
}

/*
 * doundivert - undivert a specified output, or all
 *              other outputs, in numerical order.
 */
void
doundiv(argv, argc)
register char *argv[];
register int argc;
{
	register int ind;
	register int n;

	if (argc > 2) {
		for (ind = 2; ind < argc; ind++) {
			n = atoi(argv[ind]);
			if (n > 0 && n < MAXOUT && outfile[n] != NULL)
				getdiv(n);

		}
	}
	else
		for (n = 1; n < MAXOUT; n++)
			if (outfile[n] != NULL)
				getdiv(n);
}

/*
 * dosub - select substring
 */
void
dosub(argv, argc)
register char *argv[];
register int argc;
{
	register char *ap, *fc, *k;
	register int nc;

	if (argc < 5)
		nc = MAXTOK;
	else
#ifdef EXPR
		nc = expr(argv[4]);
#else
		nc = atoi(argv[4]);
#endif
	ap = argv[2];		       /* target string */
#ifdef EXPR
	fc = ap + expr(argv[3]);       /* first char */
#else
	fc = ap + atoi(argv[3]);       /* first char */
#endif
	if (fc >= ap && fc < ap + strlen(ap))
		for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--)
			putback(*k);
}

/*
 * map:
 * map every character of s1 that is specified in from
 * into s3 and replace in s. (source s1 remains untouched)
 *
 * This is a standard implementation of map(s,from,to) function of ICON
 * language. Within mapvec, we replace every character of "from" with
 * the corresponding character in "to". If "to" is shorter than "from",
 * than the corresponding entries are null, which means that those
 * characters dissapear altogether. Furthermore, imagine
 * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
 * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
 * ultimately maps to `*'. In order to achieve this effect in an efficient
 * manner (i.e. without multiple passes over the destination string), we
 * loop over mapvec, starting with the initial source character. if the
 * character value (dch) in this location is different than the source
 * character (sch), sch becomes dch, once again to index into mapvec, until
 * the character value stabilizes (i.e. sch = dch, in other words
 * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
 * character, it will stabilize, since mapvec[0] == 0 at all times. At the
 * end, we restore mapvec* back to normal where mapvec[n] == n for
 * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
 * about 5 times faster than any algorithm that makes multiple passes over
 * destination string.
 */
void
map(dest, src, from, to)
register char *dest;
register char *src;
register char *from;
register char *to;
{
	register char *tmp;
	register char sch, dch;
	static char mapvec[128] = {
		0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
		12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
		24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
		36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
		48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
		60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
		72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
		84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
		96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
		108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
		120, 121, 122, 123, 124, 125, 126, 127
	};

	if (*src) {
		tmp = from;
	/*
	 * create a mapping between "from" and
	 * "to"
	 */
		while (*from)
			mapvec[*from++] = (*to) ? *to++ : (char) 0;

		while (*src) {
			sch = *src++;
			dch = mapvec[sch];
			while (dch != sch) {
				sch = dch;
				dch = mapvec[sch];
			}
			if (*dest = dch)
				dest++;
		}
	/*
	 * restore all the changed characters
	 */
		while (*tmp) {
			mapvec[*tmp] = *tmp;
			tmp++;
		}
	}
	*dest = (char) 0;
}
@


1.2
log
@upgrade to 4.4-lite m4.  no local changes of note
@
text
@d356 1
@


1.1
log
@Initial revision
@
text
@d2 2
a3 2
 * Copyright (c) 1989 The Regents of the University of California.
 * All rights reserved.
d6 1
a6 1
 * Ozan Yigit.
d38 1
a38 1
static char sccsid[] = "@@(#)eval.c	5.4 (Berkeley) 2/26/91";
d47 2
d54 3
a56 3
#include "extr.h"

extern ndptr lookup();
a74 1
 *
d77 2
a78 1
eval (argv, argc, td)
d81 1
a81 1
register int  td;
d84 1
a84 1
	static int sysval;
d91 5
a95 6
	/*
	 * if argc == 3 and argv[2] is null,
	 * then we have macro-or-builtin() type call.
	 * We adjust argc to avoid further checking..
	 *
	 */
d116 4
a119 4
		/*
		 * doexpr - evaluate arithmetic expression
		 *
		 */
d130 5
a134 4
		/*
		 * doifdef - select one of two alternatives based
		 *	     on the existence of another definition
		 */
d144 4
a147 4
		/*
		 * dolen - find the length of the argument
		 *
		 */
d153 4
a156 4
		/*
		 * doincr - increment the value of the argument
		 *
		 */
d162 4
a165 4
		/*
		 * dodecr - decrement the value of the argument
		 *
		 */
d171 3
a173 4
		/*
		 * dosys - execute system command
		 *
		 */
d179 5
a183 4
		/*
		 * dosysval - return value of the last system call.
		 *
		 */
d189 2
a190 4
			if (!doincl(argv[2])) {
				fprintf(stderr,"m4: %s: ",argv[2]);
				error("cannot open for read.");
			}
d200 2
a201 4
			if (!dopaste(argv[2])) {
				fprintf(stderr,"m4: %s: ",argv[2]);
				error("cannot open for read.");
			}
d218 4
a221 4
		/*
		 * dosub - select substring
		 *
		 */
d223 1
a223 1
			dosub(argv,argc);
d227 5
a231 4
		/*
		 * doshift - push back all arguments except the
		 *	     first one (i.e. skip argv[2])
		 */
d233 1
a233 1
			for (n = argc-1; n > 3; n--) {
d259 4
a262 5
		/*
		 * dodivnum - return the number of current
		 * output diversion
		 *
		 */
d267 4
a270 4
		/*
		 * doundefine - undefine a previously defined
		 *		macro(s) or m4 keyword(s).
		 */
d277 5
a281 4
		/*
		 * dopopdef - remove the topmost definitions of
		 *	      macro(s) or m4 keyword(s).
		 */
d288 3
a290 4
		/*
		 * dotemp - create a temporary file
		 *
		 */
d296 6
a301 7
		/*
		 * dotranslit - replace all characters in the
		 *		source string that appears in
		 *		the "from" string with the corresponding
		 *		characters in the "to" string.
		 *
		 */
d310 1
a310 2
		else
		    if (argc > 2)
d315 5
a319 5
		/*
		 * doindex - find the index of the second argument
		 *	     string in the first argument string.
		 *	     -1 if not present.
		 */
d324 4
a327 4
		/*
		 * doerrp - print the arguments to stderr file
		 *
		 */
d330 1
a330 1
				fprintf(stderr,"%s ", argv[n]);
d336 4
a339 4
		/*
		 * dodnl - eat-up-to and including newline
		 *
		 */
d345 5
a349 5
		/*
		 * dom4wrap - set up for wrap-up/wind-down activity
		 *
		 */
		m4wraps = (argc > 2) ? strdup(argv[2]) : null;
d353 3
a355 4
		/*
		 * doexit - immediate exit from m4.
		 *
		 */
d366 1
a366 1
		error("m4: major botch in eval.");
d369 420
@


1.1.1.1
log
@initial import of 386bsd-0.1 sources
@
text
@@


1.1.1.2
log
@imported from 44lite2
@
text
@d2 2
a3 2
 * Copyright (c) 1989, 1993
 *	The Regents of the University of California.  All rights reserved.
d6 1
a6 1
 * Ozan Yigit at York University.
d38 1
a38 1
static char sccsid[] = "@@(#)eval.c	8.2 (Berkeley) 4/27/95";
a46 2
#include <sys/types.h>
#include <errno.h>
d52 3
a54 3
#include "stdd.h"
#include "extern.h"
#include "pathnames.h"
d73 1
d76 1
a76 2
void
eval(argv, argc, td)
d79 1
a79 1
register int td;
d82 1
a82 1
	static int sysval = 0;
d89 6
a94 5
 /*
  * if argc == 3 and argv[2] is null, then we
  * have macro-or-builtin() type call. We adjust
  * argc to avoid further checking..
  */
d115 4
a118 4
	/*
	 * doexpr - evaluate arithmetic
	 * expression
	 */
d129 4
a132 5
	/*
	 * doifdef - select one of two
	 * alternatives based on the existence of
	 * another definition
	 */
d142 4
a145 4
	/*
	 * dolen - find the length of the
	 * argument
	 */
d151 4
a154 4
	/*
	 * doincr - increment the value of the
	 * argument
	 */
d160 4
a163 4
	/*
	 * dodecr - decrement the value of the
	 * argument
	 */
d169 4
a172 3
	/*
	 * dosys - execute system command
	 */
d178 4
a181 5
	/*
	 * dosysval - return value of the last
	 * system call.
	 * 
	 */
d187 4
a190 2
			if (!doincl(argv[2]))
				oops("%s: %s", argv[2], strerror(errno));
d200 4
a203 2
			if (!dopaste(argv[2]))
				oops("%s: %s", argv[2], strerror(errno));
d220 4
a223 4
	/*
	 * dosub - select substring
	 * 
	 */
d225 1
a225 1
			dosub(argv, argc);
d229 4
a232 5
	/*
	 * doshift - push back all arguments
	 * except the first one (i.e. skip
	 * argv[2])
	 */
d234 1
a234 1
			for (n = argc - 1; n > 3; n--) {
d260 5
a264 4
	/*
	 * dodivnum - return the number of
	 * current output diversion
	 */
d269 4
a272 4
	/*
	 * doundefine - undefine a previously
	 * defined macro(s) or m4 keyword(s).
	 */
d279 4
a282 5
	/*
	 * dopopdef - remove the topmost
	 * definitions of macro(s) or m4
	 * keyword(s).
	 */
d289 4
a292 3
	/*
	 * dotemp - create a temporary file
	 */
d298 7
a304 6
	/*
	 * dotranslit - replace all characters in
	 * the source string that appears in the
	 * "from" string with the corresponding
	 * characters in the "to" string.
	 */
d313 2
a314 1
		else if (argc > 2)
d319 5
a323 5
	/*
	 * doindex - find the index of the second
	 * argument string in the first argument
	 * string. -1 if not present.
	 */
d328 4
a331 4
	/*
	 * doerrp - print the arguments to stderr
	 * file
	 */
d334 1
a334 1
				fprintf(stderr, "%s ", argv[n]);
d340 4
a343 4
	/*
	 * dodnl - eat-up-to and including
	 * newline
	 */
d349 5
a353 5
	/*
	 * dom4wrap - set up for
	 * wrap-up/wind-down activity
	 */
		m4wraps = (argc > 2) ? xstrdup(argv[2]) : null;
d357 4
a360 4
	/*
	 * doexit - immediate exit from m4.
	 */
		killdiv();
d371 1
a371 1
		oops("%s: major botch.", "eval");
a373 420
}

char *dumpfmt = "`%s'\t`%s'\n";	       /* format string for dumpdef   */

/*
 * expand - user-defined macro expansion
 */
void
expand(argv, argc)
register char *argv[];
register int argc;
{
	register char *t;
	register char *p;
	register int n;
	register int argno;

	t = argv[0];		       /* defn string as a whole */
	p = t;
	while (*p)
		p++;
	p--;			       /* last character of defn */
	while (p > t) {
		if (*(p - 1) != ARGFLAG)
			putback(*p);
		else {
			switch (*p) {

			case '#':
				pbnum(argc - 2);
				break;
			case '0':
			case '1':
			case '2':
			case '3':
			case '4':
			case '5':
			case '6':
			case '7':
			case '8':
			case '9':
				if ((argno = *p - '0') < argc - 1)
					pbstr(argv[argno + 1]);
				break;
			case '*':
				for (n = argc - 1; n > 2; n--) {
					pbstr(argv[n]);
					putback(',');
				}
				pbstr(argv[2]);
				break;
			default:
				putback(*p);
				putback('$');
				break;
			}
			p--;
		}
		p--;
	}
	if (p == t)		       /* do last character */
		putback(*p);
}

/*
 * dodefine - install definition in the table
 */
void
dodefine(name, defn)
register char *name;
register char *defn;
{
	register ndptr p;

	if (!*name)
		oops("null definition.");
	if (STREQ(name, defn))
		oops("%s: recursive definition.", name);
	if ((p = lookup(name)) == nil)
		p = addent(name);
	else if (p->defn != null)
		free((char *) p->defn);
	if (!*defn)
		p->defn = null;
	else
		p->defn = xstrdup(defn);
	p->type = MACRTYPE;
}

/*
 * dodefn - push back a quoted definition of
 *      the given name.
 */
void
dodefn(name)
char *name;
{
	register ndptr p;

	if ((p = lookup(name)) != nil && p->defn != null) {
		putback(rquote);
		pbstr(p->defn);
		putback(lquote);
	}
}

/*
 * dopushdef - install a definition in the hash table
 *      without removing a previous definition. Since
 *      each new entry is entered in *front* of the
 *      hash bucket, it hides a previous definition from
 *      lookup.
 */
void
dopushdef(name, defn)
register char *name;
register char *defn;
{
	register ndptr p;

	if (!*name)
		oops("null definition");
	if (STREQ(name, defn))
		oops("%s: recursive definition.", name);
	p = addent(name);
	if (!*defn)
		p->defn = null;
	else
		p->defn = xstrdup(defn);
	p->type = MACRTYPE;
}

/*
 * dodumpdef - dump the specified definitions in the hash
 *      table to stderr. If nothing is specified, the entire
 *      hash table is dumped.
 */
void
dodump(argv, argc)
register char *argv[];
register int argc;
{
	register int n;
	ndptr p;

	if (argc > 2) {
		for (n = 2; n < argc; n++)
			if ((p = lookup(argv[n])) != nil)
				fprintf(stderr, dumpfmt, p->name,
					p->defn);
	}
	else {
		for (n = 0; n < HASHSIZE; n++)
			for (p = hashtab[n]; p != nil; p = p->nxtptr)
				fprintf(stderr, dumpfmt, p->name,
					p->defn);
	}
}

/*
 * doifelse - select one of two alternatives - loop.
 */
void
doifelse(argv, argc)
register char *argv[];
register int argc;
{
	cycle {
		if (STREQ(argv[2], argv[3]))
			pbstr(argv[4]);
		else if (argc == 6)
			pbstr(argv[5]);
		else if (argc > 6) {
			argv += 3;
			argc -= 3;
			continue;
		}
		break;
	}
}

/*
 * doinclude - include a given file.
 */
int
doincl(ifile)
char *ifile;
{
	if (ilevel + 1 == MAXINP)
		oops("too many include files.");
	if ((infile[ilevel + 1] = fopen(ifile, "r")) != NULL) {
		ilevel++;
		bbase[ilevel] = bufbase = bp;
		return (1);
	}
	else
		return (0);
}

#ifdef EXTENDED
/*
 * dopaste - include a given file without any
 *           macro processing.
 */
int
dopaste(pfile)
char *pfile;
{
	FILE *pf;
	register int c;

	if ((pf = fopen(pfile, "r")) != NULL) {
		while ((c = getc(pf)) != EOF)
			putc(c, active);
		(void) fclose(pf);
		return (1);
	}
	else
		return (0);
}
#endif

/*
 * dochq - change quote characters
 */
void
dochq(argv, argc)
register char *argv[];
register int argc;
{
	if (argc > 2) {
		if (*argv[2])
			lquote = *argv[2];
		if (argc > 3) {
			if (*argv[3])
				rquote = *argv[3];
		}
		else
			rquote = lquote;
	}
	else {
		lquote = LQUOTE;
		rquote = RQUOTE;
	}
}

/*
 * dochc - change comment characters
 */
void
dochc(argv, argc)
register char *argv[];
register int argc;
{
	if (argc > 2) {
		if (*argv[2])
			scommt = *argv[2];
		if (argc > 3) {
			if (*argv[3])
				ecommt = *argv[3];
		}
		else
			ecommt = ECOMMT;
	}
	else {
		scommt = SCOMMT;
		ecommt = ECOMMT;
	}
}

/*
 * dodivert - divert the output to a temporary file
 */
void
dodiv(n)
register int n;
{
	if (n < 0 || n >= MAXOUT)
		n = 0;		       /* bitbucket */
	if (outfile[n] == NULL) {
		m4temp[UNIQUE] = n + '0';
		if ((outfile[n] = fopen(m4temp, "w")) == NULL)
			oops("%s: cannot divert.", m4temp);
	}
	oindex = n;
	active = outfile[n];
}

/*
 * doundivert - undivert a specified output, or all
 *              other outputs, in numerical order.
 */
void
doundiv(argv, argc)
register char *argv[];
register int argc;
{
	register int ind;
	register int n;

	if (argc > 2) {
		for (ind = 2; ind < argc; ind++) {
			n = atoi(argv[ind]);
			if (n > 0 && n < MAXOUT && outfile[n] != NULL)
				getdiv(n);

		}
	}
	else
		for (n = 1; n < MAXOUT; n++)
			if (outfile[n] != NULL)
				getdiv(n);
}

/*
 * dosub - select substring
 */
void
dosub(argv, argc)
register char *argv[];
register int argc;
{
	register char *ap, *fc, *k;
	register int nc;

	if (argc < 5)
		nc = MAXTOK;
	else
#ifdef EXPR
		nc = expr(argv[4]);
#else
		nc = atoi(argv[4]);
#endif
	ap = argv[2];		       /* target string */
#ifdef EXPR
	fc = ap + expr(argv[3]);       /* first char */
#else
	fc = ap + atoi(argv[3]);       /* first char */
#endif
	if (fc >= ap && fc < ap + strlen(ap))
		for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--)
			putback(*k);
}

/*
 * map:
 * map every character of s1 that is specified in from
 * into s3 and replace in s. (source s1 remains untouched)
 *
 * This is a standard implementation of map(s,from,to) function of ICON
 * language. Within mapvec, we replace every character of "from" with
 * the corresponding character in "to". If "to" is shorter than "from",
 * than the corresponding entries are null, which means that those
 * characters dissapear altogether. Furthermore, imagine
 * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
 * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
 * ultimately maps to `*'. In order to achieve this effect in an efficient
 * manner (i.e. without multiple passes over the destination string), we
 * loop over mapvec, starting with the initial source character. if the
 * character value (dch) in this location is different than the source
 * character (sch), sch becomes dch, once again to index into mapvec, until
 * the character value stabilizes (i.e. sch = dch, in other words
 * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
 * character, it will stabilize, since mapvec[0] == 0 at all times. At the
 * end, we restore mapvec* back to normal where mapvec[n] == n for
 * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
 * about 5 times faster than any algorithm that makes multiple passes over
 * destination string.
 */
void
map(dest, src, from, to)
register char *dest;
register char *src;
register char *from;
register char *to;
{
	register char *tmp;
	register char sch, dch;
	static char mapvec[128] = {
		0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
		12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
		24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
		36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
		48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
		60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
		72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
		84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
		96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
		108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
		120, 121, 122, 123, 124, 125, 126, 127
	};

	if (*src) {
		tmp = from;
	/*
	 * create a mapping between "from" and
	 * "to"
	 */
		while (*from)
			mapvec[*from++] = (*to) ? *to++ : (char) 0;

		while (*src) {
			sch = *src++;
			dch = mapvec[sch];
			while (dch != sch) {
				sch = dch;
				dch = mapvec[sch];
			}
			if (*dest = dch)
				dest++;
		}
	/*
	 * restore all the changed characters
	 */
		while (*tmp) {
			mapvec[*tmp] = *tmp;
			tmp++;
		}
	}
	*dest = (char) 0;
@


1.1.1.3
log
@Import new m4 from OpenBSD.
@
text
@a0 3
/*	$OpenBSD: eval.c,v 1.66 2008/08/21 21:01:47 espie Exp $	*/
/*	$NetBSD: eval.c,v 1.7 1996/11/10 21:21:29 pk Exp $	*/

d16 5
a20 1
 * 3. Neither the name of the University nor the names of its contributors
d37 4
a47 1
#include <err.h>
a48 1
#include <limits.h>
a51 1
#include <stddef.h>
a52 1
#include <fcntl.h>
a57 21
static void	dodefn(const char *);
static void	dopushdef(const char *, const char *);
static void	dodump(const char *[], int);
static void	dotrace(const char *[], int, int);
static void	doifelse(const char *[], int);
static int	doincl(const char *);
static int	dopaste(const char *);
static void	dochq(const char *[], int);
static void	dochc(const char *[], int);
static void	dom4wrap(const char *);
static void	dodiv(int);
static void	doundiv(const char *[], int);
static void	dosub(const char *[], int);
static void	map(char *, const char *, const char *, const char *);
static const char *handledash(char *, char *, const char *);
static void	expand_builtin(const char *[], int, int);
static void	expand_macro(const char *[], int);
static void	dump_one_def(const char *, struct macro_definition *);

unsigned long	expansion_id;

d59 1
a59 1
 * eval - eval all macros and builtins calls
d63 1
a63 1
 *				  macro or NULL if built-in.
d70 2
a71 1
 * A call in the form of macro-or-builtin() will result in:
a74 2
 *
 * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin
a75 4
void
eval(const char *argv[], int argc, int td, int is_traced)
{
	size_t mark = SIZE_MAX;
a76 16
	expansion_id++;
	if (td & RECDEF) 
		m4errx(1, "expanding recursive definition for %s.", argv[1]);
	if (is_traced)
		mark = trace(argv, argc, infile+ilevel);
	if (td == MACRTYPE)
		expand_macro(argv, argc);
	else
		expand_builtin(argv, argc, td);
    	if (mark != SIZE_MAX)
		finish_trace(mark);
}

/*
 * expand_builtin - evaluate built-in macros.
 */
d78 4
a81 1
expand_builtin(const char *argv[], int argc, int td)
d83 1
a83 2
	int c, n;
	int ac;
a89 1
	fflush(stdout);
a90 1

d96 1
a96 6
 /* we keep the initial value for those built-ins that differentiate
  * between builtin() and builtin.
  */
  	ac = argc;

	if (argc == 3 && !*(argv[2]) && !mimic_gnu)
d99 1
a99 1
	switch (td & TYPEMASK) {
a114 8
	case TRACEONTYPE:
		dotrace(argv, argc, 1);
		break;

	case TRACEOFFTYPE:
		dotrace(argv, argc, 0);
		break;

a119 17
	{
		int base = 10;
		int maxdigits = 0;
		const char *errstr;

		if (argc > 3) {
			base = strtonum(argv[3], 2, 36, &errstr);
			if (errstr) {
				m4errx(1, "expr: base %s invalid.", argv[3]);
			}
		}
		if (argc > 4) {
			maxdigits = strtonum(argv[4], 0, INT_MAX, &errstr);
			if (errstr) {
				m4errx(1, "expr: maxdigits %s invalid.", argv[4]);
			}
		}
d121 1
a121 1
			pbnumbase(expr(argv[2]), base, maxdigits);
a122 1
	}
d136 1
a136 1
			if (lookup_macro_definition(argv[2]) != NULL)
d148 2
a149 1
		pbnum((argc > 2) ? strlen(argv[2]) : 0);
d174 1
a174 2
		if (argc > 2) {
			fflush(stdout);
a175 1
		}
a186 4
	case ESYSCMDTYPE:
		if (argc > 2)
			doesyscmd(argv[2]);
	    	break;
d190 1
a190 2
				err(1, "%s at line %lu: include(%s)",
				    CURRENT_NAME, CURRENT_LINE, argv[2]);
d201 1
a201 2
				err(1, "%s at line %lu: paste(%s)", 
				    CURRENT_NAME, CURRENT_LINE, argv[2]);
a207 3
	case FORMATTYPE:
		doformat(argv, argc);
		break;
d210 1
a210 1
		dochq(argv, ac);
d234 1
a234 1
				pbstr(rquote);
d236 2
a237 2
				pbstr(lquote);
				pushback(COMMA);
d239 1
a239 1
			pbstr(rquote);
d241 1
a241 1
			pbstr(lquote);
d273 1
a273 1
				macro_undefine(argv[n]);
d284 1
a284 1
				macro_popdef(argv[n]);
d291 2
a292 15
		if (argc > 2) {
			int fd;
			char *temp;

			temp = xstrdup(argv[2]);
			
			fd = mkstemp(temp);
			if (fd == -1)
				err(1, 
	    "%s at line %lu: couldn't make temp file %s", 
	    CURRENT_NAME, CURRENT_LINE, argv[2]);
			close(fd);
			pbstr(temp);
			free(temp);
		}
d303 1
a303 3
			char *temp;

			temp = xalloc(strlen(argv[2])+1, NULL);
d309 2
a310 2
			free(temp);
		} else if (argc > 2)
d349 1
a349 2
		if (argc > 2)
			dom4wrap(argv[2]);
a365 29
	case INDIRTYPE:	/* Indirect call */
		if (argc > 2)
			doindir(argv, argc);
		break;
	
	case BUILTINTYPE: /* Builtins only */
		if (argc > 2)
			dobuiltin(argv, argc);
		break;

	case PATSTYPE:
		if (argc > 2)
			dopatsubst(argv, argc);
		break;
	case REGEXPTYPE:
		if (argc > 2)
			doregexp(argv, argc);
		break;
	case LINETYPE:
		doprintlineno(infile+ilevel);
		break;
	case FILENAMETYPE:
		doprintfilename(infile+ilevel);
		break;
	case SELFTYPE:
		pbstr(rquote);
		pbstr(argv[1]);
		pbstr(lquote);
		break;
d367 1
a367 1
		m4errx(1, "eval: major botch.");
d372 2
d375 1
a375 1
 * expand_macro - user-defined macro expansion
d378 8
a385 6
expand_macro(const char *argv[], int argc)
{
	const char *t;
	const char *p;
	int n;
	int argno;
d394 1
a394 1
			PUSHBACK(*p);
d415 5
a419 7
				if (argc > 2) {
					for (n = argc - 1; n > 2; n--) {
						pbstr(argv[n]);
						pushback(COMMA);
					}
					pbstr(argv[2]);
			    	}
a420 13
                        case '@@':
				if (argc > 2) {
					for (n = argc - 1; n > 2; n--) {
						pbstr(rquote);
						pbstr(argv[n]);
						pbstr(lquote);
						pushback(COMMA);
					}
					pbstr(rquote);
					pbstr(argv[2]);
					pbstr(lquote);
				}
                                break;
d422 2
a423 2
				PUSHBACK(*p);
				PUSHBACK('$');
d431 1
a431 1
		PUSHBACK(*p);
a433 1

d438 19
a456 6
dodefine(const char *name, const char *defn)
{
	if (!*name && !mimic_gnu)
		m4errx(1, "null definition.");
	else 
		macro_define(name, defn);
d463 3
a465 2
static void
dodefn(const char *name)
d467 1
a467 1
	struct macro_definition *p;
d469 4
a472 9
	if ((p = lookup_macro_definition(name)) != NULL) {
		if ((p->type & TYPEMASK) == MACRTYPE) {
			pbstr(rquote);
			pbstr(p->defn);
			pbstr(lquote);
		} else {
			pbstr(p->defn);
			pbstr(BUILTIN_MARKER);
		}
d483 14
a496 5
static void
dopushdef(const char *name, const char *defn)
{
	if (!*name && !mimic_gnu)
		m4errx(1, "null definition.");
d498 2
a499 19
		macro_pushdef(name, defn);
}

/*
 * dump_one_def - dump the specified definition.
 */
static void
dump_one_def(const char *name, struct macro_definition *p)
{
	if (!traceout)
		traceout = stderr;
	if (mimic_gnu) {
		if ((p->type & TYPEMASK) == MACRTYPE)
			fprintf(traceout, "%s:\t%s\n", name, p->defn);
		else {
			fprintf(traceout, "%s:\t<%s>\n", name, p->defn);
	    	}
	} else
		fprintf(traceout, "`%s'\t`%s'\n", name, p->defn);
d507 4
a510 2
static void
dodump(const char *argv[], int argc)
d512 2
a513 2
	int n;
	struct macro_definition *p;
d517 10
a526 19
			if ((p = lookup_macro_definition(argv[n])) != NULL)
				dump_one_def(argv[n], p);
	} else
		macro_for_all(dump_one_def);
}

/*
 * dotrace - mark some macros as traced/untraced depending upon on.
 */
static void
dotrace(const char *argv[], int argc, int on)
{
	int n;

	if (argc > 2) {
		for (n = 2; n < argc; n++)
			mark_traced(argv[n], on);
	} else
		mark_traced(NULL, on);
d532 4
a535 2
static void
doifelse(const char *argv[], int argc)
d554 3
a556 2
static int
doincl(const char *ifile)
d559 2
a560 2
		m4errx(1, "too many include files.");
	if (fopen_trypath(infile+ilevel+1, ifile) != NULL) {
d564 2
a565 1
	} else
d574 3
a576 2
static int
dopaste(const char *pfile)
d579 1
a579 1
	int c;
a581 2
		if (synch_lines)
		    fprintf(active, "#line 1 \"%s\"\n", pfile);
a584 1
		emit_synchline();
d586 2
a587 1
	} else
d595 4
a598 2
static void
dochq(const char *argv[], int ac)
d600 6
a605 9
	if (ac == 2) {
		lquote[0] = LQUOTE; lquote[1] = EOS;
		rquote[0] = RQUOTE; rquote[1] = EOS;
	} else {
		strlcpy(lquote, argv[2], sizeof(lquote));
		if (ac > 3) {
			strlcpy(rquote, argv[3], sizeof(rquote));
		} else {
			rquote[0] = ECOMMT; rquote[1] = EOS;
d607 6
d619 4
a622 2
static void
dochc(const char *argv[], int argc)
d624 6
a629 12
/* XXX Note that there is no difference between no argument and a single
 * empty argument.
 */
	if (argc == 2) {
		scommt[0] = EOS;
		ecommt[0] = EOS;
	} else {
		strlcpy(scommt, argv[2], sizeof(scommt));
		if (argc == 3) {
			ecommt[0] = ECOMMT; ecommt[1] = EOS;
		} else {
			strlcpy(ecommt, argv[3], sizeof(ecommt));
d631 2
d634 3
a636 15
}

/*
 * dom4wrap - expand text at EOF
 */
static void
dom4wrap(const char *text)
{
	if (wrapindex >= maxwraps) {
		if (maxwraps == 0)
			maxwraps = 16;
		else
			maxwraps *= 2;
		m4wraps = xrealloc(m4wraps, maxwraps * sizeof(*m4wraps),
		   "too many m4wraps");
a637 1
	m4wraps[wrapindex++] = xstrdup(text);
d643 3
a645 2
static void
dodiv(int n)
d647 1
a647 11
	int fd;

	oindex = n;
	if (n >= maxout) {
		if (mimic_gnu)
			resizedivs(n + 10);
		else
			n = 0;		/* bitbucket */
    	}

	if (n < 0)
d650 3
a652 7
		char fname[] = _PATH_DIVNAME;

		if ((fd = mkstemp(fname)) < 0 || 
			(outfile[n] = fdopen(fd, "w+")) == NULL)
				err(1, "%s: cannot divert", fname);
		if (unlink(fname) == -1)
			err(1, "%s: cannot unlink", fname);
d654 1
d662 4
a665 2
static void
doundiv(const char *argv[], int argc)
d667 2
a668 2
	int ind;
	int n;
d672 4
a675 9
			const char *errstr;
			n = strtonum(argv[ind], 1, INT_MAX, &errstr);
			if (errstr) {
				if (errno == EINVAL && mimic_gnu)
					getdivfile(argv[ind]);
			} else {
				if (n < maxout && outfile[n] != NULL)
					getdiv(n);
			}
d679 1
a679 1
		for (n = 1; n < maxout; n++)
d687 4
a690 2
static void
dosub(const char *argv[], int argc)
d692 2
a693 2
	const char *ap, *fc, *k;
	int nc;
d695 8
a708 7
	nc = strlen(fc);
	if (argc >= 5)
#ifdef EXPR
		nc = min(nc, expr(argv[4]));
#else
		nc = min(nc, atoi(argv[4]));
#endif
d710 2
a711 2
		for (k = fc + nc - 1; k >= fc; k--)
			pushback(*k);
d739 21
a759 26
static void
map(char *dest, const char *src, const char *from, const char *to)
{
	const char *tmp;
	unsigned char sch, dch;
	static char frombis[257];
	static char tobis[257];
	static unsigned char mapvec[256] = {
	    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
	    19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
	    36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
	    53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
	    70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
	    87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
	    103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
	    116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
	    129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
	    142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
	    155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
	    168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
	    181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193,
	    194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206,
	    207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
	    220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
	    233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245,
	    246, 247, 248, 249, 250, 251, 252, 253, 254, 255
a762 7
		if (mimic_gnu) {
			/*
			 * expand character ranges on the fly
			 */
			from = handledash(frombis, frombis + 256, from);
			to = handledash(tobis, tobis + 256, to);
		}
d769 1
a769 2
			mapvec[(unsigned char)(*from++)] = (*to) ? 
				(unsigned char)(*to++) : 0;
d772 1
a772 1
			sch = (unsigned char)(*src++);
d778 1
a778 1
			if ((*dest = (char)dch))
d785 1
a785 1
			mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp);
d789 1
a789 45
	*dest = '\0';
}


/*
 * handledash:
 *  use buffer to copy the src string, expanding character ranges
 * on the way.
 */
static const char *
handledash(char *buffer, char *end, const char *src)
{
	char *p;
	
	p = buffer;
	while(*src) {
		if (src[1] == '-' && src[2]) {
			unsigned char i;
			if ((unsigned char)src[0] <= (unsigned char)src[2]) {
				for (i = (unsigned char)src[0]; 
				    i <= (unsigned char)src[2]; i++) {
					*p++ = i;
					if (p == end) {
						*p = '\0';
						return buffer;
					}
				}
			} else {
				for (i = (unsigned char)src[0]; 
				    i >= (unsigned char)src[2]; i--) {
					*p++ = i;
					if (p == end) {
						*p = '\0';
						return buffer;
					}
				}
			}
			src += 3;
		} else
			*p++ = *src++;
		if (p == end)
			break;
	}
	*p = '\0';
	return buffer;
@

