aboutsummaryrefslogtreecommitdiffstats
path: root/adv_cmds
diff options
context:
space:
mode:
authorCameron Katri <me@cameronkatri.com>2021-05-09 14:20:58 -0400
committerCameron Katri <me@cameronkatri.com>2021-05-09 14:20:58 -0400
commit5fd83771641d15c418f747bd343ba6738d3875f7 (patch)
tree5abf0f78f680d9837dbd93d4d4c3933bb7509599 /adv_cmds
downloadapple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.tar.gz
apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.tar.zst
apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.zip
Import macOS userland
adv_cmds-176 basic_cmds-55 bootstrap_cmds-116.100.1 developer_cmds-66 diskdev_cmds-667.40.1 doc_cmds-53.60.1 file_cmds-321.40.3 mail_cmds-35 misc_cmds-34 network_cmds-606.40.1 patch_cmds-17 remote_cmds-63 shell_cmds-216.60.1 system_cmds-880.60.2 text_cmds-106
Diffstat (limited to 'adv_cmds')
-rw-r--r--adv_cmds/.upstream_base_commits3
-rw-r--r--adv_cmds/adv_cmds.xcodeproj/project.pbxproj1806
-rw-r--r--adv_cmds/adv_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata7
-rw-r--r--adv_cmds/cap_mkdb/cap_mkdb.1101
-rw-r--r--adv_cmds/cap_mkdb/cap_mkdb.c228
-rw-r--r--adv_cmds/colldef/colldef.1274
-rw-r--r--adv_cmds/colldef/common.h36
-rw-r--r--adv_cmds/colldef/locale/collate.h121
-rw-r--r--adv_cmds/colldef/parse.y1416
-rw-r--r--adv_cmds/colldef/scan.l398
-rw-r--r--adv_cmds/finger/extern.h68
-rw-r--r--adv_cmds/finger/finger.1257
-rw-r--r--adv_cmds/finger/finger.c416
-rw-r--r--adv_cmds/finger/finger.conf.591
-rw-r--r--adv_cmds/finger/finger.h78
-rw-r--r--adv_cmds/finger/lprint.c367
-rw-r--r--adv_cmds/finger/net.c250
-rw-r--r--adv_cmds/finger/pathnames.h41
-rw-r--r--adv_cmds/finger/sprint.c187
-rw-r--r--adv_cmds/finger/util.c419
-rw-r--r--adv_cmds/gencat/gencat.1177
-rw-r--r--adv_cmds/gencat/gencat.c199
-rw-r--r--adv_cmds/gencat/gencat.h87
-rw-r--r--adv_cmds/gencat/genlib.c836
-rw-r--r--adv_cmds/last/last.1111
-rw-r--r--adv_cmds/last/last.c419
-rw-r--r--adv_cmds/locale/locale.1101
-rw-r--r--adv_cmds/locale/locale.cc428
-rw-r--r--adv_cmds/localedef/charmap.p-123
-rw-r--r--adv_cmds/localedef/charmap.p-2115
-rw-r--r--adv_cmds/localedef/charmap.test38
-rw-r--r--adv_cmds/localedef/def.a556
-rw-r--r--adv_cmds/localedef/def.p-1157
-rw-r--r--adv_cmds/localedef/def.p-2280
-rw-r--r--adv_cmds/localedef/localedef.1122
-rw-r--r--adv_cmds/localedef/localedef.pl1166
-rw-r--r--adv_cmds/lsvfs/lsvfs.167
-rw-r--r--adv_cmds/lsvfs/lsvfs.c99
-rw-r--r--adv_cmds/mklocale/extern.h40
-rw-r--r--adv_cmds/mklocale/ldef.h68
-rw-r--r--adv_cmds/mklocale/lex.l179
-rw-r--r--adv_cmds/mklocale/mklocale.1308
-rw-r--r--adv_cmds/mklocale/runefile.h87
-rw-r--r--adv_cmds/mklocale/yacc.y929
-rw-r--r--adv_cmds/pkill/entitlements.plist8
-rw-r--r--adv_cmds/pkill/pkill.1232
-rw-r--r--adv_cmds/pkill/pkill.c1111
-rw-r--r--adv_cmds/ps/entitlements.plist10
-rw-r--r--adv_cmds/ps/extern.h98
-rw-r--r--adv_cmds/ps/fmt.c132
-rw-r--r--adv_cmds/ps/keyword.c340
-rw-r--r--adv_cmds/ps/nlist.c86
-rw-r--r--adv_cmds/ps/print.c1225
-rw-r--r--adv_cmds/ps/ps.1663
-rw-r--r--adv_cmds/ps/ps.c1373
-rw-r--r--adv_cmds/ps/ps.h131
-rw-r--r--adv_cmds/ps/tasks.c246
-rw-r--r--adv_cmds/stty/cchar.c153
-rw-r--r--adv_cmds/stty/extern.h49
-rw-r--r--adv_cmds/stty/gfmt.c135
-rw-r--r--adv_cmds/stty/key.c297
-rw-r--r--adv_cmds/stty/modes.c308
-rw-r--r--adv_cmds/stty/print.c291
-rw-r--r--adv_cmds/stty/stty.1633
-rw-r--r--adv_cmds/stty/stty.c164
-rw-r--r--adv_cmds/stty/stty.h59
-rw-r--r--adv_cmds/stty/util.c68
-rw-r--r--adv_cmds/tabs/tabs.1160
-rw-r--r--adv_cmds/tabs/tabs.c240
-rw-r--r--adv_cmds/tty/tty.187
-rw-r--r--adv_cmds/tty/tty.c83
-rw-r--r--adv_cmds/whois/whois.1287
-rw-r--r--adv_cmds/whois/whois.c629
-rw-r--r--adv_cmds/xcodescripts/variant_links.sh11
74 files changed, 21915 insertions, 0 deletions
diff --git a/adv_cmds/.upstream_base_commits b/adv_cmds/.upstream_base_commits
new file mode 100644
index 0000000..2e37ca8
--- /dev/null
+++ b/adv_cmds/.upstream_base_commits
@@ -0,0 +1,3 @@
+#freebsd = https://github.com/freebsd/freebsd.git
+usr.bin/whois/whois.c freebsd whois/whois.c 872b698bd4a1bfc0bf008c09228e6fd238809c75
+usr.bin/whois/whois.1 freebsd whois/whois.1 7e6cabd06e6caa6a02eeb86308dc0cb3f27e10da
diff --git a/adv_cmds/adv_cmds.xcodeproj/project.pbxproj b/adv_cmds/adv_cmds.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..d1eda3c
--- /dev/null
+++ b/adv_cmds/adv_cmds.xcodeproj/project.pbxproj
@@ -0,0 +1,1806 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXAggregateTarget section */
+ FD0D7F98108FE550004F2A1C /* localedef */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = FD0D7FA2108FE56E004F2A1C /* Build configuration list for PBXAggregateTarget "localedef" */;
+ buildPhases = (
+ FD0D7F97108FE550004F2A1C /* ShellScript */,
+ FD0D7FA5108FE5AA004F2A1C /* Install man1 */,
+ );
+ dependencies = (
+ );
+ name = localedef;
+ productName = localedef2;
+ };
+ FD201DCD14369D0C00906237 /* pgrep */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = FD201DCE14369D0C00906237 /* Build configuration list for PBXAggregateTarget "pgrep" */;
+ buildPhases = (
+ FD201DD014369D1000906237 /* ShellScript */,
+ );
+ dependencies = (
+ FD201DD214369D5C00906237 /* PBXTargetDependency */,
+ );
+ name = pgrep;
+ productName = pgrep;
+ };
+ FDF2764E0FC60ECD00D7A3C6 /* Embedded */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = FDF276580FC60EE600D7A3C6 /* Build configuration list for PBXAggregateTarget "Embedded" */;
+ buildPhases = (
+ );
+ dependencies = (
+ FD201DD614369D6700906237 /* PBXTargetDependency */,
+ FD201DBF14369B1700906237 /* PBXTargetDependency */,
+ FDF2766D0FC60F0D00D7A3C6 /* PBXTargetDependency */,
+ FDF2766B0FC60F0D00D7A3C6 /* PBXTargetDependency */,
+ );
+ name = Embedded;
+ productName = Embedded;
+ };
+ FDF276500FC60EDA00D7A3C6 /* Desktop */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = FDF276570FC60EE600D7A3C6 /* Build configuration list for PBXAggregateTarget "Desktop" */;
+ buildPhases = (
+ );
+ dependencies = (
+ FDF277670FC6102600D7A3C6 /* PBXTargetDependency */,
+ FDF277650FC6102600D7A3C6 /* PBXTargetDependency */,
+ FDF277630FC6102600D7A3C6 /* PBXTargetDependency */,
+ FDF2775F0FC6102600D7A3C6 /* PBXTargetDependency */,
+ FDF2775D0FC6102600D7A3C6 /* PBXTargetDependency */,
+ FDF2775B0FC6102600D7A3C6 /* PBXTargetDependency */,
+ FD0D7FA9108FE5C3004F2A1C /* PBXTargetDependency */,
+ FDF277570FC6102600D7A3C6 /* PBXTargetDependency */,
+ FDF277530FC6102600D7A3C6 /* PBXTargetDependency */,
+ FD201DD414369D6300906237 /* PBXTargetDependency */,
+ FD201DC114369B1D00906237 /* PBXTargetDependency */,
+ FDF2766F0FC60F0F00D7A3C6 /* PBXTargetDependency */,
+ FDF276710FC60F1300D7A3C6 /* PBXTargetDependency */,
+ FDF2776D0FC6102B00D7A3C6 /* PBXTargetDependency */,
+ FDF2776B0FC6102B00D7A3C6 /* PBXTargetDependency */,
+ FDF277690FC6102B00D7A3C6 /* PBXTargetDependency */,
+ );
+ name = Desktop;
+ productName = Desktop;
+ };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+ FD0D7FA4108FE58C004F2A1C /* localedef.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF277140FC60FDF00D7A3C6 /* localedef.1 */; };
+ FD201DC214369B4200906237 /* pkill.c in Sources */ = {isa = PBXBuildFile; fileRef = FD201DB014369AD000906237 /* pkill.c */; };
+ FD201DC314369B4600906237 /* pkill.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD201DAF14369AD000906237 /* pkill.1 */; };
+ FDCD383B143BC63000AB81C6 /* libsysmon.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FDCD383A143BC63000AB81C6 /* libsysmon.dylib */; };
+ FDF2774B0FC6100400D7A3C6 /* cap_mkdb.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF276DE0FC60FDF00D7A3C6 /* cap_mkdb.c */; };
+ FDF277730FC6105F00D7A3C6 /* cap_mkdb.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF276DD0FC60FDF00D7A3C6 /* cap_mkdb.1 */; };
+ FDF277790FC610EC00D7A3C6 /* finger.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF276EC0FC60FDF00D7A3C6 /* finger.c */; };
+ FDF2777A0FC610EC00D7A3C6 /* lprint.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF276EF0FC60FDF00D7A3C6 /* lprint.c */; };
+ FDF2777B0FC610EC00D7A3C6 /* net.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF276F10FC60FDF00D7A3C6 /* net.c */; };
+ FDF2777C0FC610EC00D7A3C6 /* sprint.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF276F30FC60FDF00D7A3C6 /* sprint.c */; };
+ FDF2777D0FC610EC00D7A3C6 /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF276F40FC60FDF00D7A3C6 /* util.c */; };
+ FDF2779D0FC611B800D7A3C6 /* finger.conf.5 in Install man5 */ = {isa = PBXBuildFile; fileRef = FDF276ED0FC60FDF00D7A3C6 /* finger.conf.5 */; };
+ FDF2779E0FC611BA00D7A3C6 /* finger.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF276EB0FC60FDF00D7A3C6 /* finger.1 */; };
+ FDF277BE0FC612B000D7A3C6 /* whois.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277490FC60FDF00D7A3C6 /* whois.c */; };
+ FDF277C20FC612C800D7A3C6 /* whois.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF277480FC60FDF00D7A3C6 /* whois.1 */; };
+ FDF277C40FC6133400D7A3C6 /* tty.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277450FC60FDF00D7A3C6 /* tty.c */; };
+ FDF277C70FC6137B00D7A3C6 /* tty.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF277440FC60FDF00D7A3C6 /* tty.1 */; };
+ FDF277D70FC613F500D7A3C6 /* tabs.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277410FC60FDF00D7A3C6 /* tabs.c */; };
+ FDF277D90FC6140400D7A3C6 /* tabs.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FDF277400FC60FDF00D7A3C6 /* tabs.1 */; };
+ FDF277E80FC6144400D7A3C6 /* libtermcap.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FDF277E70FC6144400D7A3C6 /* libtermcap.dylib */; };
+ FDF277EE0FC6148500D7A3C6 /* cchar.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277330FC60FDF00D7A3C6 /* cchar.c */; };
+ FDF277EF0FC6148500D7A3C6 /* gfmt.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277350FC60FDF00D7A3C6 /* gfmt.c */; };
+ FDF277F00FC6148500D7A3C6 /* key.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277360FC60FDF00D7A3C6 /* key.c */; };
+ FDF277F10FC6148500D7A3C6 /* modes.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277380FC60FDF00D7A3C6 /* modes.c */; };
+ FDF277F20FC6148500D7A3C6 /* print.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277390FC60FDF00D7A3C6 /* print.c */; };
+ FDF277F30FC6148500D7A3C6 /* stty.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF2773B0FC60FDF00D7A3C6 /* stty.c */; };
+ FDF277F40FC6148500D7A3C6 /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF2773D0FC60FDF00D7A3C6 /* util.c */; };
+ FDF277F80FC614A300D7A3C6 /* stty.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF2773A0FC60FDF00D7A3C6 /* stty.1 */; };
+ FDF278060FC6151E00D7A3C6 /* fmt.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277290FC60FDF00D7A3C6 /* fmt.c */; };
+ FDF278070FC6151E00D7A3C6 /* keyword.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF2772A0FC60FDF00D7A3C6 /* keyword.c */; };
+ FDF278080FC6151E00D7A3C6 /* nlist.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF2772C0FC60FDF00D7A3C6 /* nlist.c */; };
+ FDF278090FC6151E00D7A3C6 /* print.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF2772D0FC60FDF00D7A3C6 /* print.c */; };
+ FDF2780A0FC6151E00D7A3C6 /* ps.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF2772F0FC60FDF00D7A3C6 /* ps.c */; };
+ FDF2780B0FC6151E00D7A3C6 /* tasks.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277310FC60FDF00D7A3C6 /* tasks.c */; };
+ FDF278280FC615F900D7A3C6 /* ps.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF2772E0FC60FDF00D7A3C6 /* ps.1 */; };
+ FDF278370FC6167800D7A3C6 /* lex.l in Sources */ = {isa = PBXBuildFile; fileRef = FDF277220FC60FDF00D7A3C6 /* lex.l */; };
+ FDF278380FC6167800D7A3C6 /* yacc.y in Sources */ = {isa = PBXBuildFile; fileRef = FDF277260FC60FDF00D7A3C6 /* yacc.y */; };
+ FDF278A30FC61D8900D7A3C6 /* mklocale.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF277240FC60FDF00D7A3C6 /* mklocale.1 */; };
+ FDF278C60FC61FDF00D7A3C6 /* lsvfs.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277180FC60FDF00D7A3C6 /* lsvfs.c */; };
+ FDF278CA0FC61FFD00D7A3C6 /* lsvfs.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF277170FC60FDF00D7A3C6 /* lsvfs.1 */; };
+ FDF278D60FC6204E00D7A3C6 /* locale.cc in Sources */ = {isa = PBXBuildFile; fileRef = FDF2770A0FC60FDF00D7A3C6 /* locale.cc */; };
+ FDF278DA0FC6206500D7A3C6 /* locale.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF277090FC60FDF00D7A3C6 /* locale.1 */; };
+ FDF278DB0FC6208600D7A3C6 /* last.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277060FC60FDF00D7A3C6 /* last.c */; };
+ FDF278E00FC620A000D7A3C6 /* last.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF277050FC60FDF00D7A3C6 /* last.1 */; };
+ FDF278F50FC623D300D7A3C6 /* gencat.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF276FE0FC60FDF00D7A3C6 /* gencat.c */; };
+ FDF278F60FC623D300D7A3C6 /* genlib.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277000FC60FDF00D7A3C6 /* genlib.c */; };
+ FDF2792D0FC625B800D7A3C6 /* gencat.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF276FD0FC60FDF00D7A3C6 /* gencat.1 */; };
+ FDF279390FC6263E00D7A3C6 /* parse.y in Sources */ = {isa = PBXBuildFile; fileRef = FDF276E70FC60FDF00D7A3C6 /* parse.y */; };
+ FDF2793A0FC6263E00D7A3C6 /* scan.l in Sources */ = {isa = PBXBuildFile; fileRef = FDF276E80FC60FDF00D7A3C6 /* scan.l */; };
+ FDF2795E0FC6272500D7A3C6 /* libl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FDF2795D0FC6272500D7A3C6 /* libl.a */; };
+ FDF2798F0FC62B0800D7A3C6 /* colldef.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF276E10FC60FDF00D7A3C6 /* colldef.1 */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ FD0D7FA8108FE5C3004F2A1C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FD0D7F98108FE550004F2A1C;
+ remoteInfo = localedef;
+ };
+ FD201DBE14369B1700906237 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FD201DB414369B0300906237;
+ remoteInfo = pkill;
+ };
+ FD201DC014369B1D00906237 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FD201DB414369B0300906237;
+ remoteInfo = pkill;
+ };
+ FD201DD114369D5C00906237 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FD201DB414369B0300906237;
+ remoteInfo = pkill;
+ };
+ FD201DD314369D6300906237 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FD201DCD14369D0C00906237;
+ remoteInfo = pgrep;
+ };
+ FD201DD514369D6700906237 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FD201DCD14369D0C00906237;
+ remoteInfo = pgrep;
+ };
+ FDF2766A0FC60F0D00D7A3C6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDF276630FC60EFD00D7A3C6;
+ remoteInfo = stty;
+ };
+ FDF2766C0FC60F0D00D7A3C6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDF2765B0FC60EF600D7A3C6;
+ remoteInfo = ps;
+ };
+ FDF2766E0FC60F0F00D7A3C6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDF2765B0FC60EF600D7A3C6;
+ remoteInfo = ps;
+ };
+ FDF276700FC60F1300D7A3C6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDF276630FC60EFD00D7A3C6;
+ remoteInfo = stty;
+ };
+ FDF277520FC6102600D7A3C6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDF276B00FC60F7600D7A3C6;
+ remoteInfo = mklocale;
+ };
+ FDF277560FC6102600D7A3C6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDF276A40FC60F5E00D7A3C6;
+ remoteInfo = lsvfs;
+ };
+ FDF2775A0FC6102600D7A3C6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDF276980FC60F5000D7A3C6;
+ remoteInfo = locale;
+ };
+ FDF2775C0FC6102600D7A3C6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDF276920FC60F4B00D7A3C6;
+ remoteInfo = last;
+ };
+ FDF2775E0FC6102600D7A3C6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDF2768C0FC60F3D00D7A3C6;
+ remoteInfo = gencat;
+ };
+ FDF277620FC6102600D7A3C6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDF276800FC60F3100D7A3C6;
+ remoteInfo = finger;
+ };
+ FDF277640FC6102600D7A3C6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDF2767A0FC60F2A00D7A3C6;
+ remoteInfo = colldef;
+ };
+ FDF277660FC6102600D7A3C6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDF276740FC60F2100D7A3C6;
+ remoteInfo = cap_mkdb;
+ };
+ FDF277680FC6102B00D7A3C6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDF276C20FC60F8A00D7A3C6;
+ remoteInfo = whois;
+ };
+ FDF2776A0FC6102B00D7A3C6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDF276BC0FC60F8400D7A3C6;
+ remoteInfo = tty;
+ };
+ FDF2776C0FC6102B00D7A3C6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDF276B60FC60F7F00D7A3C6;
+ remoteInfo = tabs;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ FD0D7FA5108FE5AA004F2A1C /* Install man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FD0D7FA4108FE58C004F2A1C /* localedef.1 in Install man1 */,
+ );
+ name = "Install man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FD201DB314369B0300906237 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FD201DC314369B4600906237 /* pkill.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDF277780FC610A400D7A3C6 /* Install man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FDF277730FC6105F00D7A3C6 /* cap_mkdb.1 in Install man1 */,
+ );
+ name = "Install man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDF277A10FC611D800D7A3C6 /* Install man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FDF2779E0FC611BA00D7A3C6 /* finger.1 in Install man1 */,
+ );
+ name = "Install man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDF277A20FC611D800D7A3C6 /* Install man5 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man5;
+ dstSubfolderSpec = 0;
+ files = (
+ FDF2779D0FC611B800D7A3C6 /* finger.conf.5 in Install man5 */,
+ );
+ name = "Install man5";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDF277C30FC612D900D7A3C6 /* Install man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FDF277C20FC612C800D7A3C6 /* whois.1 in Install man1 */,
+ );
+ name = "Install man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDF277C60FC6135D00D7A3C6 /* Install man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FDF277C70FC6137B00D7A3C6 /* tty.1 in Install man1 */,
+ );
+ name = "Install man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDF277E60FC6143000D7A3C6 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FDF277D90FC6140400D7A3C6 /* tabs.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDF278030FC614B900D7A3C6 /* Install man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FDF277F80FC614A300D7A3C6 /* stty.1 in Install man1 */,
+ );
+ name = "Install man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDF278300FC6160800D7A3C6 /* Install man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FDF278280FC615F900D7A3C6 /* ps.1 in Install man1 */,
+ );
+ name = "Install man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDF278A40FC61D9600D7A3C6 /* Install man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FDF278A30FC61D8900D7A3C6 /* mklocale.1 in Install man1 */,
+ );
+ name = "Install man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDF278D50FC6201600D7A3C6 /* Install man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FDF278CA0FC61FFD00D7A3C6 /* lsvfs.1 in Install man1 */,
+ );
+ name = "Install man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDF278E70FC620B600D7A3C6 /* Install man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FDF278E00FC620A000D7A3C6 /* last.1 in Install man1 */,
+ );
+ name = "Install man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDF278E80FC620B600D7A3C6 /* Install man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FDF278DA0FC6206500D7A3C6 /* locale.1 in Install man1 */,
+ );
+ name = "Install man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDF279300FC625CB00D7A3C6 /* Install man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FDF2792D0FC625B800D7A3C6 /* gencat.1 in Install man1 */,
+ );
+ name = "Install man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDF279930FC62B0B00D7A3C6 /* Install man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FDF2798F0FC62B0800D7A3C6 /* colldef.1 in Install man1 */,
+ );
+ name = "Install man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ FD201DAF14369AD000906237 /* pkill.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; name = pkill.1; path = pkill/pkill.1; sourceTree = "<group>"; };
+ FD201DB014369AD000906237 /* pkill.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = pkill.c; path = pkill/pkill.c; sourceTree = "<group>"; };
+ FD201DB514369B0400906237 /* pkill */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = pkill; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDCD383A143BC63000AB81C6 /* libsysmon.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsysmon.dylib; path = /usr/lib/libsysmon.dylib; sourceTree = "<absolute>"; };
+ FDF2765C0FC60EF600D7A3C6 /* ps */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ps; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDF276640FC60EFD00D7A3C6 /* stty */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = stty; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDF276750FC60F2100D7A3C6 /* cap_mkdb */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = cap_mkdb; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDF2767B0FC60F2A00D7A3C6 /* colldef */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = colldef; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDF276810FC60F3100D7A3C6 /* finger */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = finger; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDF2768D0FC60F3D00D7A3C6 /* gencat */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = gencat; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDF276930FC60F4B00D7A3C6 /* last */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = last; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDF276990FC60F5000D7A3C6 /* locale */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = locale; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDF276A50FC60F5E00D7A3C6 /* lsvfs */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = lsvfs; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDF276B10FC60F7600D7A3C6 /* mklocale */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mklocale; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDF276B70FC60F7F00D7A3C6 /* tabs */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = tabs; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDF276BD0FC60F8400D7A3C6 /* tty */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = tty; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDF276C30FC60F8A00D7A3C6 /* whois */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = whois; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDF276DD0FC60FDF00D7A3C6 /* cap_mkdb.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = cap_mkdb.1; sourceTree = "<group>"; };
+ FDF276DE0FC60FDF00D7A3C6 /* cap_mkdb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cap_mkdb.c; sourceTree = "<group>"; };
+ FDF276E10FC60FDF00D7A3C6 /* colldef.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = colldef.1; sourceTree = "<group>"; };
+ FDF276E20FC60FDF00D7A3C6 /* common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = "<group>"; };
+ FDF276E50FC60FDF00D7A3C6 /* collate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = collate.h; sourceTree = "<group>"; };
+ FDF276E70FC60FDF00D7A3C6 /* parse.y */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.yacc; path = parse.y; sourceTree = "<group>"; };
+ FDF276E80FC60FDF00D7A3C6 /* scan.l */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.lex; path = scan.l; sourceTree = "<group>"; };
+ FDF276EA0FC60FDF00D7A3C6 /* extern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = extern.h; sourceTree = "<group>"; };
+ FDF276EB0FC60FDF00D7A3C6 /* finger.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = finger.1; sourceTree = "<group>"; };
+ FDF276EC0FC60FDF00D7A3C6 /* finger.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = finger.c; sourceTree = "<group>"; };
+ FDF276ED0FC60FDF00D7A3C6 /* finger.conf.5 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = finger.conf.5; sourceTree = "<group>"; };
+ FDF276EE0FC60FDF00D7A3C6 /* finger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = finger.h; sourceTree = "<group>"; };
+ FDF276EF0FC60FDF00D7A3C6 /* lprint.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lprint.c; sourceTree = "<group>"; };
+ FDF276F10FC60FDF00D7A3C6 /* net.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = net.c; sourceTree = "<group>"; };
+ FDF276F20FC60FDF00D7A3C6 /* pathnames.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pathnames.h; sourceTree = "<group>"; };
+ FDF276F30FC60FDF00D7A3C6 /* sprint.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sprint.c; sourceTree = "<group>"; };
+ FDF276F40FC60FDF00D7A3C6 /* util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = util.c; sourceTree = "<group>"; };
+ FDF276F60FC60FDF00D7A3C6 /* finger.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = finger.plist; sourceTree = "<group>"; };
+ FDF276F70FC60FDF00D7A3C6 /* fingerd.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = fingerd.8; sourceTree = "<group>"; };
+ FDF276F80FC60FDF00D7A3C6 /* fingerd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fingerd.c; sourceTree = "<group>"; };
+ FDF276FA0FC60FDF00D7A3C6 /* pathnames.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pathnames.h; sourceTree = "<group>"; };
+ FDF276FD0FC60FDF00D7A3C6 /* gencat.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = gencat.1; sourceTree = "<group>"; };
+ FDF276FE0FC60FDF00D7A3C6 /* gencat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gencat.c; sourceTree = "<group>"; };
+ FDF276FF0FC60FDF00D7A3C6 /* gencat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gencat.h; sourceTree = "<group>"; };
+ FDF277000FC60FDF00D7A3C6 /* genlib.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = genlib.c; sourceTree = "<group>"; };
+ FDF277050FC60FDF00D7A3C6 /* last.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = last.1; sourceTree = "<group>"; };
+ FDF277060FC60FDF00D7A3C6 /* last.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = last.c; sourceTree = "<group>"; };
+ FDF277090FC60FDF00D7A3C6 /* locale.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = locale.1; sourceTree = "<group>"; };
+ FDF2770A0FC60FDF00D7A3C6 /* locale.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = locale.cc; sourceTree = "<group>"; };
+ FDF277140FC60FDF00D7A3C6 /* localedef.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = localedef.1; sourceTree = "<group>"; };
+ FDF277170FC60FDF00D7A3C6 /* lsvfs.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = lsvfs.1; sourceTree = "<group>"; };
+ FDF277180FC60FDF00D7A3C6 /* lsvfs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lsvfs.c; sourceTree = "<group>"; };
+ FDF2771F0FC60FDF00D7A3C6 /* extern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = extern.h; sourceTree = "<group>"; };
+ FDF277210FC60FDF00D7A3C6 /* ldef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ldef.h; sourceTree = "<group>"; };
+ FDF277220FC60FDF00D7A3C6 /* lex.l */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.lex; path = lex.l; sourceTree = "<group>"; };
+ FDF277240FC60FDF00D7A3C6 /* mklocale.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = mklocale.1; sourceTree = "<group>"; };
+ FDF277250FC60FDF00D7A3C6 /* runefile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = runefile.h; sourceTree = "<group>"; };
+ FDF277260FC60FDF00D7A3C6 /* yacc.y */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.yacc; path = yacc.y; sourceTree = "<group>"; };
+ FDF277280FC60FDF00D7A3C6 /* extern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = extern.h; sourceTree = "<group>"; };
+ FDF277290FC60FDF00D7A3C6 /* fmt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fmt.c; sourceTree = "<group>"; };
+ FDF2772A0FC60FDF00D7A3C6 /* keyword.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = keyword.c; sourceTree = "<group>"; };
+ FDF2772C0FC60FDF00D7A3C6 /* nlist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nlist.c; sourceTree = "<group>"; };
+ FDF2772D0FC60FDF00D7A3C6 /* print.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = print.c; sourceTree = "<group>"; };
+ FDF2772E0FC60FDF00D7A3C6 /* ps.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = ps.1; sourceTree = "<group>"; };
+ FDF2772F0FC60FDF00D7A3C6 /* ps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps.c; sourceTree = "<group>"; };
+ FDF277300FC60FDF00D7A3C6 /* ps.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ps.h; sourceTree = "<group>"; };
+ FDF277310FC60FDF00D7A3C6 /* tasks.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tasks.c; sourceTree = "<group>"; };
+ FDF277330FC60FDF00D7A3C6 /* cchar.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cchar.c; sourceTree = "<group>"; };
+ FDF277340FC60FDF00D7A3C6 /* extern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = extern.h; sourceTree = "<group>"; };
+ FDF277350FC60FDF00D7A3C6 /* gfmt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gfmt.c; sourceTree = "<group>"; };
+ FDF277360FC60FDF00D7A3C6 /* key.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = key.c; sourceTree = "<group>"; };
+ FDF277380FC60FDF00D7A3C6 /* modes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = modes.c; sourceTree = "<group>"; };
+ FDF277390FC60FDF00D7A3C6 /* print.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = print.c; sourceTree = "<group>"; };
+ FDF2773A0FC60FDF00D7A3C6 /* stty.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = stty.1; sourceTree = "<group>"; };
+ FDF2773B0FC60FDF00D7A3C6 /* stty.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = stty.c; sourceTree = "<group>"; };
+ FDF2773C0FC60FDF00D7A3C6 /* stty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stty.h; sourceTree = "<group>"; };
+ FDF2773D0FC60FDF00D7A3C6 /* util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = util.c; sourceTree = "<group>"; };
+ FDF277400FC60FDF00D7A3C6 /* tabs.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = tabs.1; sourceTree = "<group>"; };
+ FDF277410FC60FDF00D7A3C6 /* tabs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tabs.c; sourceTree = "<group>"; };
+ FDF277440FC60FDF00D7A3C6 /* tty.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = tty.1; sourceTree = "<group>"; };
+ FDF277450FC60FDF00D7A3C6 /* tty.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tty.c; sourceTree = "<group>"; };
+ FDF277480FC60FDF00D7A3C6 /* whois.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = whois.1; sourceTree = "<group>"; };
+ FDF277490FC60FDF00D7A3C6 /* whois.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = whois.c; sourceTree = "<group>"; };
+ FDF277E70FC6144400D7A3C6 /* libtermcap.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libtermcap.dylib; path = /usr/lib/libtermcap.dylib; sourceTree = "<absolute>"; };
+ FDF2795D0FC6272500D7A3C6 /* libl.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libl.a; path = /usr/lib/libl.a; sourceTree = "<absolute>"; };
+ FDF279760FC629B100D7A3C6 /* localedef.pl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; path = localedef.pl; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ FD201DB214369B0300906237 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDCD383B143BC63000AB81C6 /* libsysmon.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF2765A0FC60EF600D7A3C6 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276620FC60EFD00D7A3C6 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276730FC60F2100D7A3C6 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276790FC60F2A00D7A3C6 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDF2795E0FC6272500D7A3C6 /* libl.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF2767F0FC60F3100D7A3C6 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF2768B0FC60F3D00D7A3C6 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276910FC60F4B00D7A3C6 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276970FC60F5000D7A3C6 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276A30FC60F5E00D7A3C6 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276AF0FC60F7600D7A3C6 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276B50FC60F7F00D7A3C6 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDF277E80FC6144400D7A3C6 /* libtermcap.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276BB0FC60F8400D7A3C6 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276C10FC60F8A00D7A3C6 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ FD201DAD14369AB300906237 /* pkill */ = {
+ isa = PBXGroup;
+ children = (
+ FD201DB014369AD000906237 /* pkill.c */,
+ FD201DAF14369AD000906237 /* pkill.1 */,
+ );
+ name = pkill;
+ sourceTree = "<group>";
+ };
+ FDF276410FC60E9000D7A3C6 = {
+ isa = PBXGroup;
+ children = (
+ FDF276DA0FC60FD800D7A3C6 /* Source */,
+ FDF2765D0FC60EF600D7A3C6 /* Products */,
+ FDF277E70FC6144400D7A3C6 /* libtermcap.dylib */,
+ FDF2795D0FC6272500D7A3C6 /* libl.a */,
+ FDCD383A143BC63000AB81C6 /* libsysmon.dylib */,
+ );
+ sourceTree = "<group>";
+ };
+ FDF2765D0FC60EF600D7A3C6 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ FDF2765C0FC60EF600D7A3C6 /* ps */,
+ FDF276640FC60EFD00D7A3C6 /* stty */,
+ FDF276750FC60F2100D7A3C6 /* cap_mkdb */,
+ FDF2767B0FC60F2A00D7A3C6 /* colldef */,
+ FDF276810FC60F3100D7A3C6 /* finger */,
+ FDF2768D0FC60F3D00D7A3C6 /* gencat */,
+ FDF276930FC60F4B00D7A3C6 /* last */,
+ FDF276990FC60F5000D7A3C6 /* locale */,
+ FDF276A50FC60F5E00D7A3C6 /* lsvfs */,
+ FDF276B10FC60F7600D7A3C6 /* mklocale */,
+ FDF276B70FC60F7F00D7A3C6 /* tabs */,
+ FDF276BD0FC60F8400D7A3C6 /* tty */,
+ FDF276C30FC60F8A00D7A3C6 /* whois */,
+ FD201DB514369B0400906237 /* pkill */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ FDF276DA0FC60FD800D7A3C6 /* Source */ = {
+ isa = PBXGroup;
+ children = (
+ FDF276DC0FC60FDF00D7A3C6 /* cap_mkdb */,
+ FDF276E00FC60FDF00D7A3C6 /* colldef */,
+ FDF276E90FC60FDF00D7A3C6 /* finger */,
+ FDF276F50FC60FDF00D7A3C6 /* fingerd */,
+ FDF276FB0FC60FDF00D7A3C6 /* gencat */,
+ FDF277040FC60FDF00D7A3C6 /* last */,
+ FDF277080FC60FDF00D7A3C6 /* locale */,
+ FDF2770C0FC60FDF00D7A3C6 /* localedef */,
+ FDF277160FC60FDF00D7A3C6 /* lsvfs */,
+ FDF2771E0FC60FDF00D7A3C6 /* mklocale */,
+ FD201DAD14369AB300906237 /* pkill */,
+ FDF277270FC60FDF00D7A3C6 /* ps */,
+ FDF277320FC60FDF00D7A3C6 /* stty */,
+ FDF2773E0FC60FDF00D7A3C6 /* tabs */,
+ FDF277420FC60FDF00D7A3C6 /* tty */,
+ FDF277460FC60FDF00D7A3C6 /* whois */,
+ );
+ name = Source;
+ sourceTree = "<group>";
+ };
+ FDF276DC0FC60FDF00D7A3C6 /* cap_mkdb */ = {
+ isa = PBXGroup;
+ children = (
+ FDF276DE0FC60FDF00D7A3C6 /* cap_mkdb.c */,
+ FDF276DD0FC60FDF00D7A3C6 /* cap_mkdb.1 */,
+ );
+ path = cap_mkdb;
+ sourceTree = "<group>";
+ };
+ FDF276E00FC60FDF00D7A3C6 /* colldef */ = {
+ isa = PBXGroup;
+ children = (
+ FDF276E70FC60FDF00D7A3C6 /* parse.y */,
+ FDF276E80FC60FDF00D7A3C6 /* scan.l */,
+ FDF276E20FC60FDF00D7A3C6 /* common.h */,
+ FDF276E40FC60FDF00D7A3C6 /* locale */,
+ FDF276E10FC60FDF00D7A3C6 /* colldef.1 */,
+ );
+ path = colldef;
+ sourceTree = "<group>";
+ };
+ FDF276E40FC60FDF00D7A3C6 /* locale */ = {
+ isa = PBXGroup;
+ children = (
+ FDF276E50FC60FDF00D7A3C6 /* collate.h */,
+ );
+ path = locale;
+ sourceTree = "<group>";
+ };
+ FDF276E90FC60FDF00D7A3C6 /* finger */ = {
+ isa = PBXGroup;
+ children = (
+ FDF276EC0FC60FDF00D7A3C6 /* finger.c */,
+ FDF276EF0FC60FDF00D7A3C6 /* lprint.c */,
+ FDF276F10FC60FDF00D7A3C6 /* net.c */,
+ FDF276F30FC60FDF00D7A3C6 /* sprint.c */,
+ FDF276F40FC60FDF00D7A3C6 /* util.c */,
+ FDF276EA0FC60FDF00D7A3C6 /* extern.h */,
+ FDF276EE0FC60FDF00D7A3C6 /* finger.h */,
+ FDF276F20FC60FDF00D7A3C6 /* pathnames.h */,
+ FDF276EB0FC60FDF00D7A3C6 /* finger.1 */,
+ FDF276ED0FC60FDF00D7A3C6 /* finger.conf.5 */,
+ );
+ path = finger;
+ sourceTree = "<group>";
+ };
+ FDF276F50FC60FDF00D7A3C6 /* fingerd */ = {
+ isa = PBXGroup;
+ children = (
+ FDF276F80FC60FDF00D7A3C6 /* fingerd.c */,
+ FDF276FA0FC60FDF00D7A3C6 /* pathnames.h */,
+ FDF276F70FC60FDF00D7A3C6 /* fingerd.8 */,
+ FDF276F60FC60FDF00D7A3C6 /* finger.plist */,
+ );
+ path = fingerd;
+ sourceTree = "<group>";
+ };
+ FDF276FB0FC60FDF00D7A3C6 /* gencat */ = {
+ isa = PBXGroup;
+ children = (
+ FDF276FE0FC60FDF00D7A3C6 /* gencat.c */,
+ FDF277000FC60FDF00D7A3C6 /* genlib.c */,
+ FDF276FF0FC60FDF00D7A3C6 /* gencat.h */,
+ FDF276FD0FC60FDF00D7A3C6 /* gencat.1 */,
+ );
+ path = gencat;
+ sourceTree = "<group>";
+ };
+ FDF277040FC60FDF00D7A3C6 /* last */ = {
+ isa = PBXGroup;
+ children = (
+ FDF277050FC60FDF00D7A3C6 /* last.1 */,
+ FDF277060FC60FDF00D7A3C6 /* last.c */,
+ );
+ path = last;
+ sourceTree = "<group>";
+ };
+ FDF277080FC60FDF00D7A3C6 /* locale */ = {
+ isa = PBXGroup;
+ children = (
+ FDF277090FC60FDF00D7A3C6 /* locale.1 */,
+ FDF2770A0FC60FDF00D7A3C6 /* locale.cc */,
+ );
+ path = locale;
+ sourceTree = "<group>";
+ };
+ FDF2770C0FC60FDF00D7A3C6 /* localedef */ = {
+ isa = PBXGroup;
+ children = (
+ FDF279760FC629B100D7A3C6 /* localedef.pl */,
+ FDF277140FC60FDF00D7A3C6 /* localedef.1 */,
+ );
+ path = localedef;
+ sourceTree = "<group>";
+ };
+ FDF277160FC60FDF00D7A3C6 /* lsvfs */ = {
+ isa = PBXGroup;
+ children = (
+ FDF277170FC60FDF00D7A3C6 /* lsvfs.1 */,
+ FDF277180FC60FDF00D7A3C6 /* lsvfs.c */,
+ );
+ path = lsvfs;
+ sourceTree = "<group>";
+ };
+ FDF2771E0FC60FDF00D7A3C6 /* mklocale */ = {
+ isa = PBXGroup;
+ children = (
+ FDF277220FC60FDF00D7A3C6 /* lex.l */,
+ FDF277260FC60FDF00D7A3C6 /* yacc.y */,
+ FDF2771F0FC60FDF00D7A3C6 /* extern.h */,
+ FDF277210FC60FDF00D7A3C6 /* ldef.h */,
+ FDF277250FC60FDF00D7A3C6 /* runefile.h */,
+ FDF277240FC60FDF00D7A3C6 /* mklocale.1 */,
+ );
+ path = mklocale;
+ sourceTree = "<group>";
+ };
+ FDF277270FC60FDF00D7A3C6 /* ps */ = {
+ isa = PBXGroup;
+ children = (
+ FDF277290FC60FDF00D7A3C6 /* fmt.c */,
+ FDF2772A0FC60FDF00D7A3C6 /* keyword.c */,
+ FDF2772C0FC60FDF00D7A3C6 /* nlist.c */,
+ FDF2772D0FC60FDF00D7A3C6 /* print.c */,
+ FDF2772F0FC60FDF00D7A3C6 /* ps.c */,
+ FDF277310FC60FDF00D7A3C6 /* tasks.c */,
+ FDF277300FC60FDF00D7A3C6 /* ps.h */,
+ FDF277280FC60FDF00D7A3C6 /* extern.h */,
+ FDF2772E0FC60FDF00D7A3C6 /* ps.1 */,
+ );
+ path = ps;
+ sourceTree = "<group>";
+ };
+ FDF277320FC60FDF00D7A3C6 /* stty */ = {
+ isa = PBXGroup;
+ children = (
+ FDF277330FC60FDF00D7A3C6 /* cchar.c */,
+ FDF277350FC60FDF00D7A3C6 /* gfmt.c */,
+ FDF277360FC60FDF00D7A3C6 /* key.c */,
+ FDF277380FC60FDF00D7A3C6 /* modes.c */,
+ FDF277390FC60FDF00D7A3C6 /* print.c */,
+ FDF2773B0FC60FDF00D7A3C6 /* stty.c */,
+ FDF2773D0FC60FDF00D7A3C6 /* util.c */,
+ FDF277340FC60FDF00D7A3C6 /* extern.h */,
+ FDF2773C0FC60FDF00D7A3C6 /* stty.h */,
+ FDF2773A0FC60FDF00D7A3C6 /* stty.1 */,
+ );
+ path = stty;
+ sourceTree = "<group>";
+ };
+ FDF2773E0FC60FDF00D7A3C6 /* tabs */ = {
+ isa = PBXGroup;
+ children = (
+ FDF277400FC60FDF00D7A3C6 /* tabs.1 */,
+ FDF277410FC60FDF00D7A3C6 /* tabs.c */,
+ );
+ path = tabs;
+ sourceTree = "<group>";
+ };
+ FDF277420FC60FDF00D7A3C6 /* tty */ = {
+ isa = PBXGroup;
+ children = (
+ FDF277440FC60FDF00D7A3C6 /* tty.1 */,
+ FDF277450FC60FDF00D7A3C6 /* tty.c */,
+ );
+ path = tty;
+ sourceTree = "<group>";
+ };
+ FDF277460FC60FDF00D7A3C6 /* whois */ = {
+ isa = PBXGroup;
+ children = (
+ FDF277480FC60FDF00D7A3C6 /* whois.1 */,
+ FDF277490FC60FDF00D7A3C6 /* whois.c */,
+ );
+ path = whois;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ FD201DB414369B0300906237 /* pkill */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FD201DBC14369B0400906237 /* Build configuration list for PBXNativeTarget "pkill" */;
+ buildPhases = (
+ FD201DB114369B0300906237 /* Sources */,
+ FD201DB214369B0300906237 /* Frameworks */,
+ FD201DB314369B0300906237 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = pkill;
+ productName = pkill;
+ productReference = FD201DB514369B0400906237 /* pkill */;
+ productType = "com.apple.product-type.tool";
+ };
+ FDF2765B0FC60EF600D7A3C6 /* ps */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDF276600FC60EF700D7A3C6 /* Build configuration list for PBXNativeTarget "ps" */;
+ buildPhases = (
+ FDF276590FC60EF600D7A3C6 /* Sources */,
+ FDF2765A0FC60EF600D7A3C6 /* Frameworks */,
+ FDF278300FC6160800D7A3C6 /* Install man1 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = ps;
+ productName = ps;
+ productReference = FDF2765C0FC60EF600D7A3C6 /* ps */;
+ productType = "com.apple.product-type.tool";
+ };
+ FDF276630FC60EFD00D7A3C6 /* stty */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDF276690FC60EFF00D7A3C6 /* Build configuration list for PBXNativeTarget "stty" */;
+ buildPhases = (
+ FDF276610FC60EFD00D7A3C6 /* Sources */,
+ FDF276620FC60EFD00D7A3C6 /* Frameworks */,
+ FDF278030FC614B900D7A3C6 /* Install man1 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = stty;
+ productName = stty;
+ productReference = FDF276640FC60EFD00D7A3C6 /* stty */;
+ productType = "com.apple.product-type.tool";
+ };
+ FDF276740FC60F2100D7A3C6 /* cap_mkdb */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDF276C80FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "cap_mkdb" */;
+ buildPhases = (
+ FDF276720FC60F2100D7A3C6 /* Sources */,
+ FDF276730FC60F2100D7A3C6 /* Frameworks */,
+ FDF277780FC610A400D7A3C6 /* Install man1 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = cap_mkdb;
+ productName = cap_mkdb;
+ productReference = FDF276750FC60F2100D7A3C6 /* cap_mkdb */;
+ productType = "com.apple.product-type.tool";
+ };
+ FDF2767A0FC60F2A00D7A3C6 /* colldef */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDF276C90FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "colldef" */;
+ buildPhases = (
+ FDF276780FC60F2A00D7A3C6 /* Sources */,
+ FDF276790FC60F2A00D7A3C6 /* Frameworks */,
+ FDF279930FC62B0B00D7A3C6 /* Install man1 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = colldef;
+ productName = colldef;
+ productReference = FDF2767B0FC60F2A00D7A3C6 /* colldef */;
+ productType = "com.apple.product-type.tool";
+ };
+ FDF276800FC60F3100D7A3C6 /* finger */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDF276CA0FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "finger" */;
+ buildPhases = (
+ FDF2767E0FC60F3100D7A3C6 /* Sources */,
+ FDF2767F0FC60F3100D7A3C6 /* Frameworks */,
+ FDF277A10FC611D800D7A3C6 /* Install man1 */,
+ FDF277A20FC611D800D7A3C6 /* Install man5 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = finger;
+ productName = finger;
+ productReference = FDF276810FC60F3100D7A3C6 /* finger */;
+ productType = "com.apple.product-type.tool";
+ };
+ FDF2768C0FC60F3D00D7A3C6 /* gencat */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDF276CC0FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "gencat" */;
+ buildPhases = (
+ FDF2768A0FC60F3D00D7A3C6 /* Sources */,
+ FDF2768B0FC60F3D00D7A3C6 /* Frameworks */,
+ FDF279300FC625CB00D7A3C6 /* Install man1 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = gencat;
+ productName = gencat;
+ productReference = FDF2768D0FC60F3D00D7A3C6 /* gencat */;
+ productType = "com.apple.product-type.tool";
+ };
+ FDF276920FC60F4B00D7A3C6 /* last */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDF276CD0FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "last" */;
+ buildPhases = (
+ FDF276900FC60F4B00D7A3C6 /* Sources */,
+ FDF276910FC60F4B00D7A3C6 /* Frameworks */,
+ FDF278E70FC620B600D7A3C6 /* Install man1 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = last;
+ productName = last;
+ productReference = FDF276930FC60F4B00D7A3C6 /* last */;
+ productType = "com.apple.product-type.tool";
+ };
+ FDF276980FC60F5000D7A3C6 /* locale */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDF276CE0FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "locale" */;
+ buildPhases = (
+ FDF276960FC60F5000D7A3C6 /* Sources */,
+ FDF276970FC60F5000D7A3C6 /* Frameworks */,
+ FDF278E80FC620B600D7A3C6 /* Install man1 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = locale;
+ productName = locale;
+ productReference = FDF276990FC60F5000D7A3C6 /* locale */;
+ productType = "com.apple.product-type.tool";
+ };
+ FDF276A40FC60F5E00D7A3C6 /* lsvfs */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDF276D00FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "lsvfs" */;
+ buildPhases = (
+ FDF276A20FC60F5E00D7A3C6 /* Sources */,
+ FDF276A30FC60F5E00D7A3C6 /* Frameworks */,
+ FDF278D50FC6201600D7A3C6 /* Install man1 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = lsvfs;
+ productName = lsvfs;
+ productReference = FDF276A50FC60F5E00D7A3C6 /* lsvfs */;
+ productType = "com.apple.product-type.tool";
+ };
+ FDF276B00FC60F7600D7A3C6 /* mklocale */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDF276D20FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "mklocale" */;
+ buildPhases = (
+ FDF276AE0FC60F7600D7A3C6 /* Sources */,
+ FDF276AF0FC60F7600D7A3C6 /* Frameworks */,
+ FDF278A40FC61D9600D7A3C6 /* Install man1 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = mklocale;
+ productName = mklocale;
+ productReference = FDF276B10FC60F7600D7A3C6 /* mklocale */;
+ productType = "com.apple.product-type.tool";
+ };
+ FDF276B60FC60F7F00D7A3C6 /* tabs */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDF276D30FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "tabs" */;
+ buildPhases = (
+ FDF276B40FC60F7F00D7A3C6 /* Sources */,
+ FDF276B50FC60F7F00D7A3C6 /* Frameworks */,
+ FDF277E60FC6143000D7A3C6 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = tabs;
+ productName = tabs;
+ productReference = FDF276B70FC60F7F00D7A3C6 /* tabs */;
+ productType = "com.apple.product-type.tool";
+ };
+ FDF276BC0FC60F8400D7A3C6 /* tty */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDF276D40FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "tty" */;
+ buildPhases = (
+ FDF276BA0FC60F8400D7A3C6 /* Sources */,
+ FDF276BB0FC60F8400D7A3C6 /* Frameworks */,
+ FDF277C60FC6135D00D7A3C6 /* Install man1 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = tty;
+ productName = tty;
+ productReference = FDF276BD0FC60F8400D7A3C6 /* tty */;
+ productType = "com.apple.product-type.tool";
+ };
+ FDF276C20FC60F8A00D7A3C6 /* whois */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDF276D50FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "whois" */;
+ buildPhases = (
+ FDF276C00FC60F8A00D7A3C6 /* Sources */,
+ FDF276C10FC60F8A00D7A3C6 /* Frameworks */,
+ FDF277C30FC612D900D7A3C6 /* Install man1 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = whois;
+ productName = whois;
+ productReference = FDF276C30FC60F8A00D7A3C6 /* whois */;
+ productType = "com.apple.product-type.tool";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ FDF276430FC60E9000D7A3C6 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0820;
+ };
+ buildConfigurationList = FDF276460FC60E9000D7A3C6 /* Build configuration list for PBXProject "adv_cmds" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ );
+ mainGroup = FDF276410FC60E9000D7A3C6;
+ productRefGroup = FDF2765D0FC60EF600D7A3C6 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ FDF276500FC60EDA00D7A3C6 /* Desktop */,
+ FDF2764E0FC60ECD00D7A3C6 /* Embedded */,
+ FDF276740FC60F2100D7A3C6 /* cap_mkdb */,
+ FDF2767A0FC60F2A00D7A3C6 /* colldef */,
+ FDF276800FC60F3100D7A3C6 /* finger */,
+ FDF2768C0FC60F3D00D7A3C6 /* gencat */,
+ FDF276920FC60F4B00D7A3C6 /* last */,
+ FDF276980FC60F5000D7A3C6 /* locale */,
+ FD0D7F98108FE550004F2A1C /* localedef */,
+ FDF276A40FC60F5E00D7A3C6 /* lsvfs */,
+ FDF276B00FC60F7600D7A3C6 /* mklocale */,
+ FD201DCD14369D0C00906237 /* pgrep */,
+ FD201DB414369B0300906237 /* pkill */,
+ FDF2765B0FC60EF600D7A3C6 /* ps */,
+ FDF276630FC60EFD00D7A3C6 /* stty */,
+ FDF276B60FC60F7F00D7A3C6 /* tabs */,
+ FDF276BC0FC60F8400D7A3C6 /* tty */,
+ FDF276C20FC60F8A00D7A3C6 /* whois */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ FD0D7F97108FE550004F2A1C /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "set -ex\n/usr/bin/install -m ${INSTALL_MODE_FLAG} ${SRCROOT}/localedef/localedef.pl ${INSTALL_DIR}/localedef\n${CHMOD} +x ${INSTALL_DIR}/localedef";
+ };
+ FD201DD014369D1000906237 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = ". ${SRCROOT}/xcodescripts/variant_links.sh";
+ showEnvVarsInLog = 0;
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ FD201DB114369B0300906237 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FD201DC214369B4200906237 /* pkill.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276590FC60EF600D7A3C6 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDF278060FC6151E00D7A3C6 /* fmt.c in Sources */,
+ FDF278070FC6151E00D7A3C6 /* keyword.c in Sources */,
+ FDF278080FC6151E00D7A3C6 /* nlist.c in Sources */,
+ FDF278090FC6151E00D7A3C6 /* print.c in Sources */,
+ FDF2780A0FC6151E00D7A3C6 /* ps.c in Sources */,
+ FDF2780B0FC6151E00D7A3C6 /* tasks.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276610FC60EFD00D7A3C6 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDF277EE0FC6148500D7A3C6 /* cchar.c in Sources */,
+ FDF277EF0FC6148500D7A3C6 /* gfmt.c in Sources */,
+ FDF277F00FC6148500D7A3C6 /* key.c in Sources */,
+ FDF277F10FC6148500D7A3C6 /* modes.c in Sources */,
+ FDF277F20FC6148500D7A3C6 /* print.c in Sources */,
+ FDF277F30FC6148500D7A3C6 /* stty.c in Sources */,
+ FDF277F40FC6148500D7A3C6 /* util.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276720FC60F2100D7A3C6 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDF2774B0FC6100400D7A3C6 /* cap_mkdb.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276780FC60F2A00D7A3C6 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDF279390FC6263E00D7A3C6 /* parse.y in Sources */,
+ FDF2793A0FC6263E00D7A3C6 /* scan.l in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF2767E0FC60F3100D7A3C6 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDF277790FC610EC00D7A3C6 /* finger.c in Sources */,
+ FDF2777A0FC610EC00D7A3C6 /* lprint.c in Sources */,
+ FDF2777B0FC610EC00D7A3C6 /* net.c in Sources */,
+ FDF2777C0FC610EC00D7A3C6 /* sprint.c in Sources */,
+ FDF2777D0FC610EC00D7A3C6 /* util.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF2768A0FC60F3D00D7A3C6 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDF278F50FC623D300D7A3C6 /* gencat.c in Sources */,
+ FDF278F60FC623D300D7A3C6 /* genlib.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276900FC60F4B00D7A3C6 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDF278DB0FC6208600D7A3C6 /* last.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276960FC60F5000D7A3C6 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDF278D60FC6204E00D7A3C6 /* locale.cc in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276A20FC60F5E00D7A3C6 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDF278C60FC61FDF00D7A3C6 /* lsvfs.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276AE0FC60F7600D7A3C6 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDF278380FC6167800D7A3C6 /* yacc.y in Sources */,
+ FDF278370FC6167800D7A3C6 /* lex.l in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276B40FC60F7F00D7A3C6 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDF277D70FC613F500D7A3C6 /* tabs.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276BA0FC60F8400D7A3C6 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDF277C40FC6133400D7A3C6 /* tty.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276C00FC60F8A00D7A3C6 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDF277BE0FC612B000D7A3C6 /* whois.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ FD0D7FA9108FE5C3004F2A1C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FD0D7F98108FE550004F2A1C /* localedef */;
+ targetProxy = FD0D7FA8108FE5C3004F2A1C /* PBXContainerItemProxy */;
+ };
+ FD201DBF14369B1700906237 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FD201DB414369B0300906237 /* pkill */;
+ targetProxy = FD201DBE14369B1700906237 /* PBXContainerItemProxy */;
+ };
+ FD201DC114369B1D00906237 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FD201DB414369B0300906237 /* pkill */;
+ targetProxy = FD201DC014369B1D00906237 /* PBXContainerItemProxy */;
+ };
+ FD201DD214369D5C00906237 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FD201DB414369B0300906237 /* pkill */;
+ targetProxy = FD201DD114369D5C00906237 /* PBXContainerItemProxy */;
+ };
+ FD201DD414369D6300906237 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FD201DCD14369D0C00906237 /* pgrep */;
+ targetProxy = FD201DD314369D6300906237 /* PBXContainerItemProxy */;
+ };
+ FD201DD614369D6700906237 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FD201DCD14369D0C00906237 /* pgrep */;
+ targetProxy = FD201DD514369D6700906237 /* PBXContainerItemProxy */;
+ };
+ FDF2766B0FC60F0D00D7A3C6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDF276630FC60EFD00D7A3C6 /* stty */;
+ targetProxy = FDF2766A0FC60F0D00D7A3C6 /* PBXContainerItemProxy */;
+ };
+ FDF2766D0FC60F0D00D7A3C6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDF2765B0FC60EF600D7A3C6 /* ps */;
+ targetProxy = FDF2766C0FC60F0D00D7A3C6 /* PBXContainerItemProxy */;
+ };
+ FDF2766F0FC60F0F00D7A3C6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDF2765B0FC60EF600D7A3C6 /* ps */;
+ targetProxy = FDF2766E0FC60F0F00D7A3C6 /* PBXContainerItemProxy */;
+ };
+ FDF276710FC60F1300D7A3C6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDF276630FC60EFD00D7A3C6 /* stty */;
+ targetProxy = FDF276700FC60F1300D7A3C6 /* PBXContainerItemProxy */;
+ };
+ FDF277530FC6102600D7A3C6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDF276B00FC60F7600D7A3C6 /* mklocale */;
+ targetProxy = FDF277520FC6102600D7A3C6 /* PBXContainerItemProxy */;
+ };
+ FDF277570FC6102600D7A3C6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDF276A40FC60F5E00D7A3C6 /* lsvfs */;
+ targetProxy = FDF277560FC6102600D7A3C6 /* PBXContainerItemProxy */;
+ };
+ FDF2775B0FC6102600D7A3C6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDF276980FC60F5000D7A3C6 /* locale */;
+ targetProxy = FDF2775A0FC6102600D7A3C6 /* PBXContainerItemProxy */;
+ };
+ FDF2775D0FC6102600D7A3C6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDF276920FC60F4B00D7A3C6 /* last */;
+ targetProxy = FDF2775C0FC6102600D7A3C6 /* PBXContainerItemProxy */;
+ };
+ FDF2775F0FC6102600D7A3C6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDF2768C0FC60F3D00D7A3C6 /* gencat */;
+ targetProxy = FDF2775E0FC6102600D7A3C6 /* PBXContainerItemProxy */;
+ };
+ FDF277630FC6102600D7A3C6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDF276800FC60F3100D7A3C6 /* finger */;
+ targetProxy = FDF277620FC6102600D7A3C6 /* PBXContainerItemProxy */;
+ };
+ FDF277650FC6102600D7A3C6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDF2767A0FC60F2A00D7A3C6 /* colldef */;
+ targetProxy = FDF277640FC6102600D7A3C6 /* PBXContainerItemProxy */;
+ };
+ FDF277670FC6102600D7A3C6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDF276740FC60F2100D7A3C6 /* cap_mkdb */;
+ targetProxy = FDF277660FC6102600D7A3C6 /* PBXContainerItemProxy */;
+ };
+ FDF277690FC6102B00D7A3C6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDF276C20FC60F8A00D7A3C6 /* whois */;
+ targetProxy = FDF277680FC6102B00D7A3C6 /* PBXContainerItemProxy */;
+ };
+ FDF2776B0FC6102B00D7A3C6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDF276BC0FC60F8400D7A3C6 /* tty */;
+ targetProxy = FDF2776A0FC6102B00D7A3C6 /* PBXContainerItemProxy */;
+ };
+ FDF2776D0FC6102B00D7A3C6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDF276B60FC60F7F00D7A3C6 /* tabs */;
+ targetProxy = FDF2776C0FC6102B00D7A3C6 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ FD0D7F99108FE550004F2A1C /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = localedef;
+ };
+ name = Release;
+ };
+ FD201DBD14369B0400906237 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = pkill/entitlements.plist;
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FD201DCF14369D0C00906237 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FDF276450FC60E9000D7A3C6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = YES;
+ CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
+ DEAD_CODE_STRIPPING = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
+ GCC_WARN_MISSING_PARENTHESES = YES;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNKNOWN_PRAGMAS = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_LABEL = YES;
+ GCC_WARN_UNUSED_VALUE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ PREBINDING = NO;
+ SDKROOT = macosx.internal;
+ USE_HEADERMAP = NO;
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_PREFIX = __;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ FDF2764F0FC60ECD00D7A3C6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = Embedded;
+ };
+ name = Release;
+ };
+ FDF276510FC60EDA00D7A3C6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = Desktop;
+ };
+ name = Release;
+ };
+ FDF2765F0FC60EF700D7A3C6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = ps/entitlements.plist;
+ GCC_PREPROCESSOR_DEFINITIONS = "__FBSDID=__RCSID";
+ "INSTALL_MODE_FLAG[sdk=macosx*]" = "u+sw,go-w,a+rX";
+ INSTALL_PATH = /bin;
+ PRODUCT_NAME = ps;
+ WARNING_CFLAGS = "-Wno-#warnings";
+ };
+ name = Release;
+ };
+ FDF276660FC60EFD00D7A3C6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /bin;
+ PRODUCT_NAME = stty;
+ };
+ name = Release;
+ };
+ FDF276770FC60F2100D7A3C6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = cap_mkdb;
+ };
+ name = Release;
+ };
+ FDF2767D0FC60F2A00D7A3C6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "__FBSDID=__RCSID",
+ COLLATE_DEBUG,
+ YY_NO_UNPUT,
+ );
+ GCC_WARN_UNUSED_FUNCTION = NO;
+ GCC_WARN_UNUSED_VARIABLE = NO;
+ INSTALL_PATH = /usr/bin;
+ LEXFLAGS = "-8";
+ LEX_CASE_INSENSITIVE_SCANNER = YES;
+ PRODUCT_NAME = colldef;
+ USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/colldef $(SRCROOT)/colldef/locale";
+ };
+ name = Release;
+ };
+ FDF276830FC60F3100D7A3C6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = "__FBSDID=__RCSID";
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = finger;
+ };
+ name = Release;
+ };
+ FDF2768F0FC60F3E00D7A3C6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = "__FBSDID=__RCSID";
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = gencat;
+ };
+ name = Release;
+ };
+ FDF276950FC60F4C00D7A3C6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = last;
+ };
+ name = Release;
+ };
+ FDF2769B0FC60F5100D7A3C6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = locale;
+ };
+ name = Release;
+ };
+ FDF276A70FC60F5F00D7A3C6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = lsvfs;
+ };
+ name = Release;
+ };
+ FDF276B30FC60F7700D7A3C6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = "__FBSDID=__RCSID";
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = mklocale;
+ USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/mklocale";
+ };
+ name = Release;
+ };
+ FDF276B90FC60F8000D7A3C6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = "__FBSDID=__RCSID";
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = tabs;
+ };
+ name = Release;
+ };
+ FDF276BF0FC60F8500D7A3C6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = "__FBSDID=__RCSID";
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = tty;
+ };
+ name = Release;
+ };
+ FDF276C50FC60F8A00D7A3C6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = whois;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ FD0D7FA2108FE56E004F2A1C /* Build configuration list for PBXAggregateTarget "localedef" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FD0D7F99108FE550004F2A1C /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FD201DBC14369B0400906237 /* Build configuration list for PBXNativeTarget "pkill" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FD201DBD14369B0400906237 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FD201DCE14369D0C00906237 /* Build configuration list for PBXAggregateTarget "pgrep" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FD201DCF14369D0C00906237 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDF276460FC60E9000D7A3C6 /* Build configuration list for PBXProject "adv_cmds" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDF276450FC60E9000D7A3C6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDF276570FC60EE600D7A3C6 /* Build configuration list for PBXAggregateTarget "Desktop" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDF276510FC60EDA00D7A3C6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDF276580FC60EE600D7A3C6 /* Build configuration list for PBXAggregateTarget "Embedded" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDF2764F0FC60ECD00D7A3C6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDF276600FC60EF700D7A3C6 /* Build configuration list for PBXNativeTarget "ps" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDF2765F0FC60EF700D7A3C6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDF276690FC60EFF00D7A3C6 /* Build configuration list for PBXNativeTarget "stty" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDF276660FC60EFD00D7A3C6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDF276C80FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "cap_mkdb" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDF276770FC60F2100D7A3C6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDF276C90FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "colldef" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDF2767D0FC60F2A00D7A3C6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDF276CA0FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "finger" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDF276830FC60F3100D7A3C6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDF276CC0FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "gencat" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDF2768F0FC60F3E00D7A3C6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDF276CD0FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "last" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDF276950FC60F4C00D7A3C6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDF276CE0FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "locale" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDF2769B0FC60F5100D7A3C6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDF276D00FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "lsvfs" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDF276A70FC60F5F00D7A3C6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDF276D20FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "mklocale" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDF276B30FC60F7700D7A3C6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDF276D30FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "tabs" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDF276B90FC60F8000D7A3C6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDF276D40FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "tty" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDF276BF0FC60F8500D7A3C6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDF276D50FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "whois" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDF276C50FC60F8A00D7A3C6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = FDF276430FC60E9000D7A3C6 /* Project object */;
+}
diff --git a/adv_cmds/adv_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/adv_cmds/adv_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..919434a
--- /dev/null
+++ b/adv_cmds/adv_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+ version = "1.0">
+ <FileRef
+ location = "self:">
+ </FileRef>
+</Workspace>
diff --git a/adv_cmds/cap_mkdb/cap_mkdb.1 b/adv_cmds/cap_mkdb/cap_mkdb.1
new file mode 100644
index 0000000..5bc4674
--- /dev/null
+++ b/adv_cmds/cap_mkdb/cap_mkdb.1
@@ -0,0 +1,101 @@
+.\" Copyright (c) 1992, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" 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.
+.\"
+.\" @(#)cap_mkdb.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd "June 6, 1993"
+.Dt CAP_MKDB 1
+.Os
+.Sh NAME
+.Nm cap_mkdb
+.Nd create capability database
+.Pp
+.Sh SYNOPSIS
+.Nm cap_mkdb
+.Op Fl v
+.Op Fl f Ar outfile
+.Ar file1
+.Op Ar file2 ...
+.Pp
+.Sh DESCRIPTION
+.Nm Cap_mkdb
+builds a hashed database out of the
+.Xr getcap 3
+logical database constructed by the concatenation of the specified
+files .
+.Pp
+The database is named by the basename of the first file argument and
+the string
+.Dq .db .
+The
+.Xr getcap 3
+routines can access the database in this form much more quickly
+than they can the original text file(s).
+.Pp
+The ``tc'' capabilities of the records are expanded before the
+record is stored into the database.
+.Pp
+The options as as follows:
+.Bl -tag -width XXXXXX
+.It Fl f Ar outfile
+Specify a different database basename.
+.It Fl v
+Print out the number of capability records in the database.
+.El
+.Pp
+.Sh FORMAT
+Each record is stored in the database using two different types of keys.
+.Pp
+The first type is a key which consists of the first capability of
+the record (not including the trailing colon (``:'')) with a data
+field consisting of a special byte followed by the rest of the record.
+The special byte is either a 0 or 1, where a 0 means that the record
+is okay, and a 1 means that there was a ``tc'' capability in the record
+that couldn't be expanded.
+.Pp
+The second type is a key which consists of one of the names from the
+first capability of the record with a data field consisting a special
+byte followed by the the first capability of the record.
+The special byte is a 2.
+.Pp
+In normal operation names are looked up in the database, resulting
+in a key/data pair of the second type.
+The data field of this key/data pair is used to look up a key/data
+pair of the first type which has the real data associated with the
+name.
+.Sh RETURN VALUE
+The
+.Nm cap_mkdb
+utility exits 0 on success and >0 if an error occurs.
+.Sh SEE ALSO
+.Xr dbopen 3 ,
+.Xr getcap 3 ,
+.Xr termcap 5
diff --git a/adv_cmds/cap_mkdb/cap_mkdb.c b/adv_cmds/cap_mkdb/cap_mkdb.c
new file mode 100644
index 0000000..9c26d59
--- /dev/null
+++ b/adv_cmds/cap_mkdb/cap_mkdb.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved
+ *
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * The NEXTSTEP Software License Agreement specifies the terms
+ * and conditions for redistribution.
+ *
+ * @(#)cap_mkdb.c 8.2 (Berkeley) 4/27/95
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <db.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+void db_build __P((char **));
+void dounlink __P((void));
+void usage __P((void));
+
+DB *capdbp;
+int verbose;
+char *capdb, *capname, buf[8 * 1024];
+
+HASHINFO openinfo = {
+ 4096, /* bsize */
+ 16, /* ffactor */
+ 256, /* nelem */
+ 2048 * 1024, /* cachesize */
+ NULL, /* hash() */
+ 0 /* lorder */
+};
+
+/*
+ * Mkcapdb creates a capability hash database for quick retrieval of capability
+ * records. The database contains 2 types of entries: records and references
+ * marked by the first byte in the data. A record entry contains the actual
+ * capability record whereas a reference contains the name (key) under which
+ * the correct record is stored.
+ */
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int c;
+
+ capname = NULL;
+ while ((c = getopt(argc, argv, "f:v")) != EOF) {
+ switch(c) {
+ case 'f':
+ capname = optarg;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (*argv == NULL)
+ usage();
+
+ /*
+ * The database file is the first argument if no name is specified.
+ * Make arrangements to unlink it if exit badly.
+ */
+ (void)snprintf(buf, sizeof(buf), "%s.db", capname ? capname : *argv);
+ if ((capname = strdup(buf)) == NULL)
+ err(1, "");
+ if ((capdbp = dbopen(capname, O_CREAT | O_TRUNC | O_RDWR,
+ DEFFILEMODE, DB_HASH, &openinfo)) == NULL)
+ err(1, "%s", buf);
+
+ if (atexit(dounlink))
+ err(1, "atexit");
+
+ db_build(argv);
+
+ if (capdbp->close(capdbp) < 0)
+ err(1, "%s", capname);
+ capname = NULL;
+ exit(0);
+}
+
+void
+dounlink()
+{
+ if (capname != NULL)
+ (void)unlink(capname);
+}
+
+/*
+ * Any changes to these definitions should be made also in the getcap(3)
+ * library routines.
+ */
+#define RECOK (char)0
+#define TCERR (char)1
+#define SHADOW (char)2
+
+/*
+ * Db_build() builds the name and capabilty databases according to the
+ * details above.
+ */
+void
+db_build(ifiles)
+ char **ifiles;
+{
+ DBT key, data;
+ recno_t reccnt;
+ size_t len, bplen;
+ int st;
+ char *bp, *p, *t;
+
+ data.data = NULL;
+ key.data = NULL;
+ for (reccnt = 0, bplen = 0; (st = cgetnext(&bp, ifiles)) > 0;) {
+
+ /*
+ * Allocate enough memory to store record, terminating
+ * NULL and one extra byte.
+ */
+ len = strlen(bp);
+ if (bplen <= len + 2) {
+ bplen += MAX(256, len + 2);
+ if ((data.data = realloc(data.data, bplen)) == NULL)
+ err(1, "");
+ }
+
+ /* Find the end of the name field. */
+ if ((p = strchr(bp, ':')) == NULL) {
+ warnx("no name field: %.*s", MIN(len, 20), bp);
+ continue;
+ }
+
+ /* First byte of stored record indicates status. */
+ switch(st) {
+ case 1:
+ ((char *)(data.data))[0] = RECOK;
+ break;
+ case 2:
+ ((char *)(data.data))[0] = TCERR;
+ warnx("Record not tc expanded: %.*s", p - bp, bp);
+ break;
+ }
+
+ /* Create the stored record. */
+ memmove(&((u_char *)(data.data))[1], bp, len + 1);
+ data.size = len + 2;
+
+ /* Store the record under the name field. */
+ key.data = bp;
+ key.size = p - bp;
+
+ switch(capdbp->put(capdbp, &key, &data, R_NOOVERWRITE)) {
+ case -1:
+ err(1, "put");
+ /* NOTREACHED */
+ case 1:
+ warnx("ignored duplicate: %.*s",
+ key.size, (char *)key.data);
+ continue;
+ }
+ ++reccnt;
+
+ /* If only one name, ignore the rest. */
+ if ((p = strchr(bp, '|')) == NULL)
+ continue;
+
+ /* The rest of the names reference the entire name. */
+ ((char *)(data.data))[0] = SHADOW;
+ memmove(&((u_char *)(data.data))[1], key.data, key.size);
+ data.size = key.size + 1;
+
+ /* Store references for other names. */
+ for (p = t = bp;; ++p) {
+ if (p > t && (*p == ':' || *p == '|')) {
+ key.size = p - t;
+ key.data = t;
+ switch(capdbp->put(capdbp,
+ &key, &data, R_NOOVERWRITE)) {
+ case -1:
+ err(1, "put");
+ /* NOTREACHED */
+ case 1:
+ warnx("ignored duplicate: %.*s",
+ key.size, (char *)key.data);
+ }
+ t = p + 1;
+ }
+ if (*p == ':')
+ break;
+ }
+ }
+
+ switch(st) {
+ case -1:
+ err(1, "file argument");
+ /* NOTREACHED */
+ case -2:
+ errx(1, "potential reference loop detected");
+ /* NOTREACHED */
+ }
+
+ if (verbose)
+ (void)printf("cap_mkdb: %d capability records\n", reccnt);
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr,
+ "usage: cap_mkdb [-v] [-f outfile] file1 [file2 ...]\n");
+ exit(1);
+}
diff --git a/adv_cmds/colldef/colldef.1 b/adv_cmds/colldef/colldef.1
new file mode 100644
index 0000000..f4f875b
--- /dev/null
+++ b/adv_cmds/colldef/colldef.1
@@ -0,0 +1,274 @@
+.\" Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
+.\" at Electronni Visti IA, Kiev, Ukraine.
+.\" All rights reserved.
+.\"
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+.\"
+.\" $FreeBSD: src/usr.bin/colldef/colldef.1,v 1.21 2004/05/19 09:45:46 ru Exp $
+.\"
+.Dd January 27, 1995
+.Dt COLLDEF 1
+.Os
+.Sh NAME
+.Nm colldef
+.Nd convert collation sequence source definition
+.Sh SYNOPSIS
+.Nm
+.Op Fl I Ar map_dir
+.Op Fl o Ar out_file
+.Op Ar filename
+.Sh DESCRIPTION
+The
+.Nm
+utility converts a collation sequence source definition
+into a format usable by the
+.Fn strxfrm
+and
+.Fn strcoll
+functions.
+It is used to define the many ways in which
+strings can be ordered and collated.
+The
+.Fn strxfrm
+function transforms
+its first argument and places the result in its second
+argument.
+The transformed string is such that it can be
+correctly ordered with other transformed strings by using
+.Fn strcmp ,
+.Fn strncmp ,
+or
+.Fn memcmp .
+The
+.Fn strcoll
+function transforms its arguments and does a
+comparison.
+.Pp
+The
+.Nm
+utility reads the collation sequence source definition
+from the standard input and stores the converted definition in filename.
+The output file produced contains the
+database with collating sequence information in a form
+usable by system commands and routines.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl I Ar map_dir
+Set directory name where
+.Ar charmap
+files can be found, current directory by default.
+.It Fl o Ar out_file
+Set output file name,
+.Ar LC_COLLATE
+by default.
+.El
+.Pp
+The collation sequence definition specifies a set of collating elements and
+the rules defining how strings containing these should be ordered.
+This is most useful for different language definitions.
+.Pp
+The specification file can consist of three statements:
+.Ar charmap ,
+.Ar substitute
+and
+.Ar order .
+.Pp
+Of these, only the
+.Ar order
+statement is required.
+When
+.Ar charmap
+or
+.Ar substitute
+is
+supplied, these statements must be ordered as above.
+Any
+statements after the order statement are ignored.
+.Pp
+Lines in the specification file beginning with a
+.Ql #
+are
+treated as comments and are ignored.
+Blank lines are also
+ignored.
+.Pp
+.Dl "charmap charmapfile"
+.Pp
+.Ar Charmap
+defines where a mapping of the character
+and collating element symbols to the actual
+character encoding can be found.
+.Pp
+The format of
+.Ar charmapfile
+is shown below.
+Symbol
+names are separated from their values by TAB or
+SPACE characters.
+Symbol-value can be specified in
+a hexadecimal (\ex\fI??\fR) or octal (\e\fI???\fR)
+representation, and can be only one character in length.
+.Pp
+.Bd -literal -offset indent
+symbol-name1 symbol-value1
+symbol-name2 symbol-value2
+\&...
+.Ed
+.Pp
+Symbol names cannot be specified in
+.Ar substitute
+fields.
+.Pp
+The
+.Ar charmap
+statement is optional.
+.Pp
+.Bd -literal -offset indent
+substitute "symbol" with "repl_string"
+.Ed
+.Pp
+The
+.Ar substitute
+statement substitutes the character
+.Ar symbol
+with the string
+.Ar repl_string .
+Symbol names cannot be specified in
+.Ar repl_string
+field.
+The
+.Ar substitute
+statement is optional.
+.Pp
+.Dl "order order_list"
+.Pp
+.Ar Order_list
+is a list of symbols, separated by semi colons, that defines the
+collating sequence.
+The
+special symbol
+.Ar ...
+specifies, in a short-hand
+form, symbols that are sequential in machine code
+order.
+.Pp
+An order list element
+can be represented in any one of the following
+ways:
+.Bl -bullet
+.It
+The symbol itself (for example,
+.Ar a
+for the lower-case letter
+.Ar a ) .
+.It
+The symbol in octal representation (for example,
+.Ar \e141
+for the letter
+.Ar a ) .
+.It
+The symbol in hexadecimal representation (for example,
+.Ar \ex61
+for the letter
+.Ar a ) .
+.It
+The symbol name as defined in the
+.Ar charmap
+file (for example,
+.Ar <letterA>
+for
+.Ar letterA \e023
+record in
+.Ar charmapfile ) .
+If character map name have
+.Ar >
+character, it must be escaped as
+.Ar /> ,
+single
+.Ar /
+must be escaped as
+.Ar // .
+.It
+Symbols
+.Ar \ea ,
+.Ar \eb ,
+.Ar \ef ,
+.Ar \en ,
+.Ar \er ,
+.Ar \ev
+are permitted in its usual C-language meaning.
+.It
+The symbol chain (for example:
+.Ar abc ,
+.Ar <letterA><letterB>c ,
+.Ar \exf1b\exf2 )
+.It
+The symbol range (for example,
+.Ar a;...;z ) .
+.It
+Comma-separated symbols, ranges and chains enclosed in parenthesis (for example
+.Ar \&(
+.Ar sym1 ,
+.Ar sym2 ,
+.Ar ...
+.Ar \&) )
+are assigned the
+same primary ordering but different secondary
+ordering.
+.It
+Comma-separated symbols, ranges and chains enclosed in curly brackets (for example
+.Ar \&{
+.Ar sym1 ,
+.Ar sym2 ,
+.Ar ...
+.Ar \&} )
+are assigned the same primary ordering only.
+.El
+.Pp
+The backslash character
+.Ar \e
+is used for continuation.
+In this case, no characters are permitted
+after the backslash character.
+.Sh DIAGNOSTICS
+The
+.Nm
+utility exits with the following values:
+.Bl -tag -width indent
+.It Li 0
+No errors were found and the output was successfully created.
+.It Li !=0
+Errors were found.
+.El
+.Sh FILES
+.Bl -tag -width indent
+.It Pa /usr/share/locale/ Ns Ao Ar language Ac Ns Pa /LC_COLLATE
+The standard shared location for collation orders
+under the locale
+.Aq Ar language .
+.El
+.Sh SEE ALSO
+.Xr mklocale 1 ,
+.Xr setlocale 3 ,
+.Xr strcoll 3 ,
+.Xr strxfrm 3
diff --git a/adv_cmds/colldef/common.h b/adv_cmds/colldef/common.h
new file mode 100644
index 0000000..b59c125
--- /dev/null
+++ b/adv_cmds/colldef/common.h
@@ -0,0 +1,36 @@
+/*
+ * $FreeBSD: src/usr.bin/colldef/common.h,v 1.2 2001/11/28 09:50:24 ache Exp $
+ */
+
+#include <sys/types.h>
+#include <db.h>
+#include <fcntl.h>
+
+#define CHARMAP_SYMBOL_LEN 64
+#define BUFSIZE 80
+
+#define NOTEXISTS 0
+#define EXISTS 1
+
+#define SYMBOL_CHAR 0
+#define SYMBOL_CHAIN 1
+#define SYMBOL_SYMBOL 2
+#define SYMBOL_STRING 3
+#define SYMBOL_IGNORE 4
+#define SYMBOL_ELLIPSIS 5
+struct symbol {
+ int type;
+ int val;
+ wchar_t name[CHARMAP_SYMBOL_LEN];
+ union {
+ wchar_t wc;
+ wchar_t str[STR_LEN];
+ } u;
+};
+
+extern int line_no;
+
+struct symbol *getsymbol(const wchar_t *, int);
+extern char *showwcs(const wchar_t *, int);
+
+extern char map_name[FILENAME_MAX];
diff --git a/adv_cmds/colldef/locale/collate.h b/adv_cmds/colldef/locale/collate.h
new file mode 100644
index 0000000..494e231
--- /dev/null
+++ b/adv_cmds/colldef/locale/collate.h
@@ -0,0 +1,121 @@
+/*-
+ * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
+ * at Electronni Visti IA, Kiev, Ukraine.
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $FreeBSD: src/lib/libc/locale/collate.h,v 1.14 2002/08/30 20:26:02 ache Exp $
+ */
+
+#ifndef _COLLATE_H_
+#define _COLLATE_H_
+
+#include <sys/cdefs.h>
+#ifndef __LIBC__
+#include <sys/types.h>
+#endif /* !__LIBC__ */
+#include <limits.h>
+
+#define STR_LEN 10
+#define TABLE_SIZE 100
+#define COLLATE_VERSION "1.0\n"
+#define COLLATE_VERSION1_1 "1.1\n"
+#define COLLATE_VERSION1_1A "1.1A\n"
+/* see discussion in string/FreeBSD/strxfrm for this value */
+#define COLLATE_MAX_PRIORITY ((1 << 24) - 1)
+
+#define DIRECTIVE_UNDEF 0x00
+#define DIRECTIVE_FORWARD 0x01
+#define DIRECTIVE_BACKWARD 0x02
+#define DIRECTIVE_POSITION 0x04
+
+#define DIRECTIVE_DIRECTION_MASK (DIRECTIVE_FORWARD | DIRECTIVE_BACKWARD)
+
+#define COLLATE_SUBST_DUP 0x0001
+
+#define IGNORE_EQUIV_CLASS 1
+
+struct __collate_st_info {
+ __uint8_t directive[COLL_WEIGHTS_MAX];
+ __uint8_t flags;
+#if __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN
+ __uint8_t directive_count:4;
+ __uint8_t chain_max_len:4;
+#else
+ __uint8_t chain_max_len:4;
+ __uint8_t directive_count:4;
+#endif
+ __int32_t undef_pri[COLL_WEIGHTS_MAX];
+ __int32_t subst_count[COLL_WEIGHTS_MAX];
+ __int32_t chain_count;
+ __int32_t large_pri_count;
+};
+
+struct __collate_st_char_pri {
+ __int32_t pri[COLL_WEIGHTS_MAX];
+};
+struct __collate_st_chain_pri {
+ __darwin_wchar_t str[STR_LEN];
+ __int32_t pri[COLL_WEIGHTS_MAX];
+};
+struct __collate_st_large_char_pri {
+ __int32_t val;
+ struct __collate_st_char_pri pri;
+};
+struct __collate_st_subst {
+ __int32_t val;
+ __darwin_wchar_t str[STR_LEN];
+};
+
+#ifndef __LIBC__
+extern int __collate_load_error;
+extern int __collate_substitute_nontrivial;
+#define __collate_char_pri_table (*__collate_char_pri_table_ptr)
+extern struct __collate_st_char_pri __collate_char_pri_table[UCHAR_MAX + 1];
+extern struct __collate_st_chain_pri *__collate_chain_pri_table;
+extern __int32_t *__collate_chain_equiv_table;
+extern struct __collate_st_info __collate_info;
+#endif /* !__LIBC__ */
+
+__BEGIN_DECLS
+#ifdef __LIBC__
+__darwin_wchar_t *__collate_mbstowcs(const char *, locale_t);
+__darwin_wchar_t *__collate_wcsdup(const __darwin_wchar_t *);
+__darwin_wchar_t *__collate_substitute(const __darwin_wchar_t *, int, locale_t);
+int __collate_load_tables(const char *, locale_t);
+void __collate_lookup_l(const __darwin_wchar_t *, int *, int *, int *, locale_t);
+void __collate_lookup_which(const __darwin_wchar_t *, int *, int *, int, locale_t);
+void __collate_xfrm(const __darwin_wchar_t *, __darwin_wchar_t **, locale_t);
+int __collate_range_cmp(__darwin_wchar_t, __darwin_wchar_t, locale_t);
+size_t __collate_collating_symbol(__darwin_wchar_t *, size_t, const char *, size_t, __darwin_mbstate_t *, locale_t);
+int __collate_equiv_class(const char *, size_t, __darwin_mbstate_t *, locale_t);
+size_t __collate_equiv_match(int, __darwin_wchar_t *, size_t, __darwin_wchar_t, const char *, size_t, __darwin_mbstate_t *, size_t *, locale_t);
+#else /* !__LIBC__ */
+void __collate_lookup(const unsigned char *, int *, int *, int *);
+#endif /* __LIBC__ */
+#ifdef COLLATE_DEBUG
+void __collate_print_tables(void);
+#endif
+__END_DECLS
+
+#endif /* !_COLLATE_H_ */
diff --git a/adv_cmds/colldef/parse.y b/adv_cmds/colldef/parse.y
new file mode 100644
index 0000000..495c2f3
--- /dev/null
+++ b/adv_cmds/colldef/parse.y
@@ -0,0 +1,1416 @@
+%{
+/*-
+ * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
+ * at Electronni Visti IA, Kiev, Ukraine.
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/colldef/parse.y,v 1.31 2002/10/16 12:56:22 charnier Exp $");
+
+#include <arpa/inet.h>
+#include <err.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <unistd.h>
+#include <sysexits.h>
+#include <limits.h>
+#include "collate.h"
+#include "common.h"
+
+#define PRI_UNDEFINED (-1)
+#define PRI_IGNORE 0
+#define LINE_NONE (-1)
+#define LINE_NORMAL 0
+#define LINE_ELLIPSIS 1
+#define LINE_UNDEFINED 2
+/* If UNDEFINED is specified with ellipses, we reposition prim_pri to
+ * UNDEFINED_PRI, leaving gap for undefined characters. */
+#define UNDEFINED_PRI (COLLATE_MAX_PRIORITY - (COLLATE_MAX_PRIORITY >> 2))
+
+extern FILE *yyin;
+void yyerror(const char *fmt, ...) __printflike(1, 2);
+int yyparse(void);
+int yylex(void);
+static void usage(void);
+static void collate_print_tables(void);
+static struct __collate_st_char_pri *getpri(int32_t);
+static struct __collate_st_char_pri *haspri(int32_t);
+static struct __collate_st_chain_pri *getchain(const wchar_t *, int);
+static struct symbol *getsymbolbychar(wchar_t);
+static struct symbol *hassymbolbychar(wchar_t);
+static void setsymbolbychar(struct symbol *);
+struct symbol *getstring(const wchar_t *);
+static void makeforwardref(int, const struct symbol *, const struct symbol *);
+static int charpricompar(const void *, const void *);
+static int substcompar(const void *, const void *);
+static int chainpricompar(const void *, const void *);
+static void putsubst(int32_t, int, const wchar_t *);
+static int hassubst(int32_t, int);
+static const wchar_t *__collate_wcsnchr(const wchar_t *, wchar_t, int);
+static int __collate_wcsnlen(const wchar_t *, int);
+char *showwcs(const wchar_t *, int);
+static char *charname(wchar_t);
+static char *charname2(wchar_t);
+
+char map_name[FILENAME_MAX] = ".";
+wchar_t curr_chain[STR_LEN + 1];
+
+char __collate_version[STR_LEN];
+DB *charmapdb;
+static DB *charmapdb2;
+static DB *largemapdb;
+static int nlargemap = 0;
+static DB *substdb[COLL_WEIGHTS_MAX];
+static int nsubst[COLL_WEIGHTS_MAX];
+static DB *chaindb;
+static int nchain = 0;
+static DB *stringdb;
+static DB *forward_ref[COLL_WEIGHTS_MAX];
+static struct symbol *prev_weight_table[COLL_WEIGHTS_MAX];
+static struct symbol *prev2_weight_table[COLL_WEIGHTS_MAX];
+static struct symbol *weight_table[COLL_WEIGHTS_MAX];
+static int prev_line = LINE_NONE;
+static struct symbol *prev_elem;
+static int weight_index = 0;
+static int allow_ellipsis = 0;
+static struct symbol sym_ellipsis = {SYMBOL_ELLIPSIS, PRI_UNDEFINED};
+static struct symbol sym_ignore = {SYMBOL_IGNORE, PRI_IGNORE};
+static struct symbol sym_undefined = {SYMBOL_CHAR, PRI_UNDEFINED};
+static int order_pass = 0;
+
+#undef __collate_char_pri_table
+struct __collate_st_char_pri __collate_char_pri_table[UCHAR_MAX + 1];
+struct __collate_st_chain_pri *__collate_chain_pri_table;
+struct __collate_st_subst *__collate_substitute_table[COLL_WEIGHTS_MAX];
+struct __collate_st_large_char_pri *__collate_large_char_pri_table;
+
+int prim_pri = 2, sec_pri = 2;
+#ifdef COLLATE_DEBUG
+int debug;
+#endif
+struct __collate_st_info info = {{DIRECTIVE_FORWARD, DIRECTIVE_FORWARD}, 0, 0, 0, {PRI_UNDEFINED, PRI_UNDEFINED}};
+
+/* Some of the code expects COLL_WEIGHTS_MAX == 2 */
+int directive_count = COLL_WEIGHTS_MAX;
+
+const char *out_file = "LC_COLLATE";
+%}
+%union {
+ int32_t ch;
+ wchar_t str[BUFSIZE];
+}
+%token SUBSTITUTE WITH
+%token START_LC_COLLATE END_LC_COLLATE COLLATING_ELEMENT FROM COLLATING_SYMBOL
+%token ELLIPSIS IGNORE UNDEFINED
+%token ORDER RANGE ORDER_START ORDER_END ORDER_SECOND_PASS
+%token <str> STRING
+%token <str> DEFN
+%token <str> ELEM
+%token <ch> CHAR
+%token <ch> ORDER_DIRECTIVE
+%%
+collate : datafile {
+ FILE *fp;
+ int localedef = (stringdb != NULL);
+ int z;
+
+ if (nchain > 0) {
+ DBT key, val;
+ struct __collate_st_chain_pri *t, *v;
+ wchar_t *wp, *tp;
+ int flags, i, len;
+
+ if ((__collate_chain_pri_table = (struct __collate_st_chain_pri *)malloc(nchain * sizeof(struct __collate_st_chain_pri))) == NULL)
+ err(1, "chain malloc");
+ flags = R_FIRST;
+ t = __collate_chain_pri_table;
+ for(i = 0; i < nchain; i++) {
+ if (chaindb->seq(chaindb, &key, &val, flags) != 0)
+ err(1, "Can't retrieve chaindb %d", i);
+ memcpy(&v, val.data, sizeof(struct __collate_st_chain_pri *));
+ *t++ = *v;
+ if ((len = __collate_wcsnlen(v->str, STR_LEN)) > info.chain_max_len)
+ info.chain_max_len = len;
+ flags = R_NEXT;
+ }
+ if (chaindb->seq(chaindb, &key, &val, flags) == 0)
+ err(1, "More in chaindb after retrieving %d", nchain);
+ qsort(__collate_chain_pri_table, nchain, sizeof(struct __collate_st_chain_pri), chainpricompar);
+ }
+ for(z = 0; z < directive_count; z++) {
+ if (nsubst[z] > 0) {
+ DBT key, val;
+ struct __collate_st_subst *t;
+ wchar_t *wp, *tp;
+ int flags, i, j;
+ int32_t cval;
+
+ if ((__collate_substitute_table[z] = (struct __collate_st_subst *)calloc(nsubst[z], sizeof(struct __collate_st_subst))) == NULL)
+ err(1, "__collate_substitute_table[%d] calloc", z);
+ flags = R_FIRST;
+ t = __collate_substitute_table[z];
+ for(i = 0; i < nsubst[z]; i++) {
+ if (substdb[z]->seq(substdb[z], &key, &val, flags) != 0)
+ err(1, "Can't retrieve substdb[%d]", z);
+ memcpy(&cval, key.data, sizeof(int32_t));
+ /* we don't set the byte order of t->val, since we
+ * need it for sorting */
+ t->val = cval;
+ for(wp = (wchar_t *)val.data, tp = t->str, j = STR_LEN; *wp && j-- > 0;)
+ *tp++ = htonl(*wp++);
+ t++;
+ flags = R_NEXT;
+ }
+ if (substdb[z]->seq(substdb[z], &key, &val, flags) == 0)
+ err(1, "More in substdb[%d] after retrieving %d", z, nsubst[z]);
+ qsort(__collate_substitute_table[z], nsubst[z], sizeof(struct __collate_st_subst), substcompar);
+ }
+ }
+ if (nlargemap > 0) {
+ DBT key, val;
+ struct __collate_st_large_char_pri *t;
+ struct __collate_st_char_pri *p;
+ int flags, i, z;
+ int32_t cval;
+
+ if ((__collate_large_char_pri_table = (struct __collate_st_large_char_pri *)malloc(nlargemap * sizeof(struct __collate_st_large_char_pri))) == NULL)
+ err(1, "nlargemap malloc");
+ flags = R_FIRST;
+ t = __collate_large_char_pri_table;
+ for(i = 0; i < nlargemap; i++) {
+ if (largemapdb->seq(largemapdb, &key, &val, flags) != 0)
+ err(1, "Can't retrieve largemapdb %d", i);
+ memcpy(&cval, key.data, sizeof(int32_t));
+ memcpy(&p, val.data, sizeof(struct __collate_st_char_pri *));
+ /* we don't set the byte order of t->val, since we
+ * need it for sorting */
+ t->val = cval;
+ for(z = 0; z < directive_count; z++)
+ t->pri.pri[z] = htonl(p->pri[z]);
+ t++;
+ flags = R_NEXT;
+ }
+ if (largemapdb->seq(largemapdb, &key, &val, flags) == 0)
+ err(1, "More in largemapdb after retrieving %d", nlargemap);
+ qsort(__collate_large_char_pri_table, nlargemap, sizeof(struct __collate_st_large_char_pri), charpricompar);
+ }
+
+ if (info.undef_pri[0] == PRI_UNDEFINED) {
+ int i;
+ info.undef_pri[0] = prim_pri;
+ for(i = 1; i < directive_count; i++)
+ info.undef_pri[i] = -prim_pri;
+ }
+
+ if (localedef) {
+ int ch, z, ret;
+ if (sym_undefined.val == PRI_UNDEFINED) {
+ int flags = R_FIRST;
+ DBT key, val;
+ struct symbol *v;
+ while((ret = charmapdb->seq(charmapdb, &key, &val, flags)) == 0) {
+ memcpy(&v, val.data, sizeof(struct symbol *));
+ switch(v->type) {
+ case SYMBOL_CHAR: {
+ struct __collate_st_char_pri *p = haspri(v->u.wc);
+ if (!p || p->pri[0] == PRI_UNDEFINED)
+ warnx("<%s> was not defined", showwcs((const wchar_t *)key.data, key.size / sizeof(wchar_t)));
+ break;
+ }
+ case SYMBOL_CHAIN: {
+ struct __collate_st_chain_pri *p = getchain(v->u.str, EXISTS);
+ if (p->pri[0] == PRI_UNDEFINED)
+ warnx("<%s> was not defined", showwcs((const wchar_t *)key.data, key.size / sizeof(wchar_t)));
+ break;
+ }
+ }
+ flags = R_NEXT;
+ }
+ if (ret < 0)
+ err(1, "Error retrieving from charmapdb");
+ }
+ for (ch = 1; ch < UCHAR_MAX + 1; ch++) {
+ for(z = 0; z < directive_count; z++)
+ if (__collate_char_pri_table[ch].pri[z] == PRI_UNDEFINED)
+ __collate_char_pri_table[ch].pri[z] = (info.undef_pri[z] >= 0) ? info.undef_pri[z] : (ch - info.undef_pri[z]);
+ }
+ for (ch = 0; ch < nlargemap; ch++) {
+ for(z = 0; z < directive_count; z++)
+ if (__collate_large_char_pri_table[ch].pri.pri[z] == PRI_UNDEFINED)
+ __collate_large_char_pri_table[ch].pri.pri[z] = (info.undef_pri[z] >= 0) ? info.undef_pri[z] : (__collate_large_char_pri_table[ch].val - info.undef_pri[z]);
+ }
+ } else {
+ int ch, substed, ordered;
+ int fatal = 0;
+ for (ch = 1; ch < UCHAR_MAX + 1; ch++) {
+ substed = hassubst(ch, 0);
+ ordered = (__collate_char_pri_table[ch].pri[0] != PRI_UNDEFINED);
+ if (!ordered && !substed) {
+ fatal = 1;
+ warnx("%s not found", charname(ch));
+ }
+ if (substed && ordered) {
+ fatal = 1;
+ warnx("%s can't be ordered since substituted", charname(ch));
+ }
+ }
+ if (fatal)
+ exit(1);
+ }
+
+ /* COLLATE_SUBST_DUP depends on COLL_WEIGHTS_MAX == 2 */
+ if (localedef) {
+ if (nsubst[0] == nsubst[1] && (nsubst[0] == 0 ||
+ memcmp(__collate_substitute_table[0], __collate_substitute_table[1], nsubst[0] * sizeof(struct __collate_st_subst)) == 0)) {
+ info.flags |= COLLATE_SUBST_DUP;
+ nsubst[1] = 0;
+ }
+ } else {
+ info.flags |= COLLATE_SUBST_DUP;
+ nsubst[1] = 0;
+ }
+
+ for(z = 0; z < directive_count; z++)
+ info.subst_count[z] = nsubst[z];
+
+ info.directive_count = directive_count;
+ info.chain_count = nchain;
+ info.large_pri_count = nlargemap;
+
+ if ((fp = fopen(out_file, "w")) == NULL)
+ err(EX_UNAVAILABLE, "can't open destination file %s",
+ out_file);
+
+ strcpy(__collate_version, COLLATE_VERSION1_1A);
+ if (fwrite(__collate_version, sizeof(__collate_version), 1, fp) != 1)
+ err(EX_IOERR,
+ "IO error writting collate version to destination file %s",
+ out_file);
+#if __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN
+ for(z = 0; z < directive_count; z++) {
+ info.undef_pri[z] = htonl(info.undef_pri[z]);
+ info.subst_count[z] = htonl(info.subst_count[z]);
+ }
+ info.chain_count = htonl(info.chain_count);
+ info.large_pri_count = htonl(info.large_pri_count);
+#endif /* __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN */
+ if (fwrite(&info, sizeof(info), 1, fp) != 1)
+ err(EX_IOERR,
+ "IO error writting collate info to destination file %s",
+ out_file);
+#if __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN
+ {
+ int i, z;
+ struct __collate_st_char_pri *p = __collate_char_pri_table;
+
+ for(i = UCHAR_MAX + 1; i-- > 0; p++) {
+ for(z = 0; z < directive_count; z++)
+ p->pri[z] = htonl(p->pri[z]);
+ }
+ }
+#endif /* __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN */
+ if (fwrite(__collate_char_pri_table,
+ sizeof(__collate_char_pri_table), 1, fp) != 1)
+ err(EX_IOERR,
+ "IO error writting char table to destination file %s",
+ out_file);
+ for(z = 0; z < directive_count; z++) {
+ if (nsubst[z] > 0) {
+#if __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN
+ struct __collate_st_subst *t = __collate_substitute_table[z];
+ int i;
+ for(i = nsubst[z]; i > 0; i--) {
+ t->val = htonl(t->val);
+ t++;
+ }
+#endif /* __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN */
+ if (fwrite(__collate_substitute_table[z], sizeof(struct __collate_st_subst), nsubst[z], fp) != nsubst[z])
+ err(EX_IOERR,
+ "IO error writting large substprim table %d to destination file %s",
+ z, out_file);
+ }
+ }
+ if (nchain > 0) {
+#if __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN
+ int i, j, z;
+ struct __collate_st_chain_pri *p = __collate_chain_pri_table;
+ wchar_t *w;
+
+ for(i = nchain; i-- > 0; p++) {
+ for(j = STR_LEN, w = p->str; *w && j-- > 0; w++)
+ *w = htonl(*w);
+ for(z = 0; z < directive_count; z++)
+ p->pri[z] = htonl(p->pri[z]);
+ }
+#endif /* __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN */
+ if (fwrite(__collate_chain_pri_table,
+ sizeof(*__collate_chain_pri_table), nchain, fp) !=
+ (size_t)nchain)
+ err(EX_IOERR,
+ "IO error writting chain table to destination file %s",
+ out_file);
+ }
+
+ if (nlargemap > 0) {
+#if __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN
+ struct __collate_st_large_char_pri *t = __collate_large_char_pri_table;
+ int i;
+ for(i = 0; i < nlargemap; i++) {
+ t->val = htonl(t->val);
+ t++;
+ }
+#endif /* __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN */
+ if (fwrite(__collate_large_char_pri_table, sizeof(struct __collate_st_large_char_pri), nlargemap, fp) != nlargemap)
+ err(EX_IOERR,
+ "IO error writting large pri tables to destination file %s",
+ out_file);
+ }
+
+ if (fclose(fp) != 0)
+ err(EX_IOERR, "IO error closing destination file %s",
+ out_file);
+
+#ifdef COLLATE_DEBUG
+ if (debug)
+ collate_print_tables();
+#endif
+ exit(EX_OK);
+}
+;
+datafile : statment_list
+ | blank_lines start_localedef localedef_sections blank_lines end_localedef blank_lines
+;
+statment_list : statment
+ | statment_list '\n' statment
+;
+statment :
+ | charmap
+ | substitute
+ | order
+;
+blank_lines :
+ | '\n'
+ | blank_lines '\n'
+;
+start_localedef : START_LC_COLLATE '\n' {
+ int i;
+ if ((stringdb = dbopen(NULL, O_CREAT | O_RDWR, 0600, DB_HASH, NULL)) == NULL)
+ err(1, "dbopen stringdb");
+ directive_count = 0;
+ for(i = 0; i < COLL_WEIGHTS_MAX; i++)
+ info.directive[i] = DIRECTIVE_UNDEF;
+}
+;
+end_localedef : END_LC_COLLATE '\n'
+;
+localedef_sections : localedef_preface localedef_order
+;
+localedef_preface : localedef_statment '\n'
+ | localedef_preface localedef_statment '\n'
+;
+localedef_statment :
+ | charmap
+ | collating_element
+ | collating_symbol
+;
+collating_element : COLLATING_ELEMENT ELEM FROM STRING {
+ int len;
+ struct symbol *s;
+ if (wcslen($2) > CHARMAP_SYMBOL_LEN)
+ yyerror("collating-element symbol name '%s' is too long", showwcs($2, CHARMAP_SYMBOL_LEN));
+ if ((len = wcslen($4)) > STR_LEN)
+ yyerror("collating-element string '%s' is too long", showwcs($4, STR_LEN));
+ if (len < 2)
+ yyerror("collating-element string '%s' must be at least two characters", showwcs($4, STR_LEN));
+ s = getsymbol($2, NOTEXISTS);
+ s->val = PRI_UNDEFINED;
+ s->type = SYMBOL_CHAIN;
+ wcsncpy(s->u.str, $4, STR_LEN);
+ getchain($4, NOTEXISTS);
+}
+;
+collating_symbol : COLLATING_SYMBOL ELEM {
+ struct symbol *s;
+ if (wcslen($2) > CHARMAP_SYMBOL_LEN)
+ yyerror("collating-element symbol name '%s' is too long", showwcs($2, CHARMAP_SYMBOL_LEN));
+ s = getsymbol($2, NOTEXISTS);
+ s->val = PRI_UNDEFINED;
+ s->type = SYMBOL_SYMBOL;
+}
+;
+localedef_order : order_start order_lines1 order_second_pass order_lines2 order_end
+;
+order_start: ORDER_START order_start_list '\n'
+;
+order_second_pass: ORDER_SECOND_PASS {
+ prev_line = LINE_NONE;
+ prev_elem = NULL;
+ order_pass++;
+}
+;
+order_start_list : order_start_list_directives {
+ if (directive_count > 0)
+ yyerror("Multiple order_start lines not allowed");
+ if ((info.directive[0] & DIRECTIVE_DIRECTION_MASK) == 0)
+ info.directive[0] |= DIRECTIVE_FORWARD;
+ directive_count++;
+}
+ | order_start_list ';' order_start_list_directives {
+ if (directive_count >= COLL_WEIGHTS_MAX)
+ yyerror("only COLL_WEIGHTS_MAX weights allowed");
+ if ((info.directive[directive_count] & DIRECTIVE_DIRECTION_MASK) == 0)
+ info.directive[directive_count] |= DIRECTIVE_FORWARD;
+ directive_count++;
+}
+;
+order_start_list_directives : ORDER_DIRECTIVE {
+ info.directive[directive_count] = $1;
+}
+ | order_start_list_directives ',' ORDER_DIRECTIVE {
+ int direction = ($3 & DIRECTIVE_DIRECTION_MASK);
+ int prev = (info.directive[directive_count] & DIRECTIVE_DIRECTION_MASK);
+ if (direction && prev && direction != prev)
+ yyerror("The forward and backward directives are mutually exclusive");
+ info.directive[directive_count] |= $3;
+}
+;
+order_lines1 : order_line1 '\n'
+ | order_lines1 order_line1 '\n'
+;
+order_line1 :
+ | ELEM {
+ struct symbol *s = getsymbol($1, EXISTS);
+ if (s->val != PRI_UNDEFINED)
+ yyerror("<%s> redefined", showwcs($1, CHARMAP_SYMBOL_LEN));
+ if (prev_line == LINE_ELLIPSIS) {
+ struct symbol *m;
+ wchar_t i;
+ int v;
+ switch (s->type) {
+ case SYMBOL_CHAIN:
+ yyerror("Chain <%s> can't be endpoints of ellipsis", showwcs($1, CHARMAP_SYMBOL_LEN));
+ case SYMBOL_SYMBOL:
+ yyerror("Collating symbol <%s> can't be endpoints of ellipsis", showwcs($1, CHARMAP_SYMBOL_LEN));
+ }
+ if (s->u.wc <= prev_elem->u.wc)
+ yyerror("<%s> is before starting point of ellipsis", showwcs($1, CHARMAP_SYMBOL_LEN));
+ for(i = prev_elem->u.wc + 1, v = prev_elem->val + 1; i < s->u.wc; i++, v++) {
+ m = getsymbolbychar(i);
+ if (m->val != PRI_UNDEFINED)
+ yyerror("<%s> was previously defined while filling ellipsis symbols", showwcs(m->name, CHARMAP_SYMBOL_LEN));
+ m->val = v;
+ }
+ s->val = v;
+ } else
+ s->val = prim_pri;
+ prim_pri = s->val + 1;
+ weight_index = 0;
+} weights {
+ int i;
+ struct symbol *s = getsymbol($1, EXISTS);
+ if (s->type == SYMBOL_SYMBOL) {
+ if (weight_index != 0)
+ yyerror("Can't specify weights for collating symbol <%s>", showwcs($1, CHARMAP_SYMBOL_LEN));
+ } else if (weight_index == 0) {
+ for(i = 0; i < directive_count; i++)
+ weight_table[i] = s;
+ } else if (weight_index != directive_count)
+ yyerror("Not enough weights specified");
+ memcpy(prev_weight_table, weight_table, sizeof(weight_table));
+ prev_line = LINE_NORMAL;
+ prev_elem = s;
+}
+ | ELLIPSIS { weight_index = 0; allow_ellipsis = 1; } weights {
+ int i;
+ if (prev_line == LINE_ELLIPSIS)
+ yyerror("Illegal sequential ellipsis lines");
+ if (prev_line == LINE_UNDEFINED)
+ yyerror("Ellipsis line can not follow UNDEFINED line");
+ if (prev_line == LINE_NONE)
+ yyerror("Ellipsis line must follow a collating identifier lines");
+ if (weight_index == 0) {
+ for(i = 0; i < directive_count; i++)
+ weight_table[i] = &sym_ellipsis;
+ } else if (weight_index != directive_count)
+ yyerror("Not enough weights specified");
+ for(i = 0; i < directive_count; i++) {
+ if (weight_table[i]->type != SYMBOL_ELLIPSIS)
+ continue;
+ switch (prev_weight_table[i]->type) {
+ case SYMBOL_CHAIN:
+ yyerror("Startpoint of ellipsis can't be a collating element");
+ case SYMBOL_IGNORE:
+ yyerror("Startpoint of ellipsis can't be IGNORE");
+ case SYMBOL_SYMBOL:
+ yyerror("Startpoint of ellipsis can't be a collating symbol");
+ case SYMBOL_STRING:
+ yyerror("Startpoint of ellipsis can't be a string");
+ }
+ }
+ memcpy(prev2_weight_table, prev_weight_table, sizeof(prev_weight_table));
+ memcpy(prev_weight_table, weight_table, sizeof(weight_table));
+ prev_line = LINE_ELLIPSIS;
+ allow_ellipsis = 0;
+}
+ | UNDEFINED {
+ if (sym_undefined.val != PRI_UNDEFINED)
+ yyerror("Multiple UNDEFINED lines not allowed");
+ sym_undefined.val = prim_pri++;
+ weight_index = 0;
+ allow_ellipsis = 1;
+} weights {
+ int i;
+ if (weight_index == 0) {
+ weight_table[0] = &sym_undefined;
+ for(i = 1; i < directive_count; i++)
+ weight_table[i] = &sym_ellipsis;
+ } else if (weight_index != directive_count)
+ yyerror("Not enough weights specified");
+ memcpy(prev_weight_table, weight_table, sizeof(weight_table));
+ prev_line = LINE_UNDEFINED;
+}
+;
+order_lines2 : order_line2 '\n'
+ | order_lines2 order_line2 '\n'
+;
+order_line2 :
+ | ELEM { weight_index = 0; } weights {
+ int i;
+ struct symbol *s = getsymbol($1, EXISTS);
+ if (s->val == PRI_UNDEFINED)
+ yyerror("<%s> undefined", showwcs($1, CHARMAP_SYMBOL_LEN));
+ if (s->type == SYMBOL_SYMBOL) {
+ if (weight_index != 0)
+ yyerror("Can't specify weights for collating symbol <%s>", showwcs($1, CHARMAP_SYMBOL_LEN));
+ } else if (weight_index == 0) {
+ for(i = 0; i < directive_count; i++)
+ weight_table[i] = s;
+ } else if (weight_index != directive_count)
+ yyerror("Not enough weights specified");
+ if (prev_line == LINE_ELLIPSIS) {
+ int w, x;
+ for(i = 0; i < directive_count; i++) {
+ switch (prev_weight_table[i]->type) {
+ case SYMBOL_CHAR:
+ case SYMBOL_CHAIN:
+ case SYMBOL_IGNORE:
+ case SYMBOL_SYMBOL:
+ for (w = prev_elem->u.wc + 1; w < s->u.wc; w++) {
+ struct __collate_st_char_pri *p = getpri(w);
+ if (p->pri[i] != PRI_UNDEFINED)
+ yyerror("Char 0x02x previously defined", w);
+ p->pri[i] = prev_weight_table[i]->val;
+ }
+ break;
+ case SYMBOL_ELLIPSIS:
+
+ switch (weight_table[i]->type) {
+ case SYMBOL_STRING:
+ yyerror("Strings can't be endpoints of ellipsis");
+ case SYMBOL_CHAIN:
+ yyerror("Chains can't be endpoints of ellipsis");
+ case SYMBOL_IGNORE:
+ yyerror("IGNORE can't be endpoints of ellipsis");
+ case SYMBOL_SYMBOL:
+ yyerror("Collation symbols can't be endpoints of ellipsis");
+ }
+ if (s->val - prev_elem->val != weight_table[i]->val - prev2_weight_table[i]->val)
+ yyerror("Range mismatch in weight %d", i);
+ x = prev2_weight_table[i]->val + 1;
+ for (w = prev_elem->u.wc + 1; w < s->u.wc; w++) {
+ struct __collate_st_char_pri *p = getpri(w);
+ if (p->pri[i] != PRI_UNDEFINED)
+ yyerror("Char 0x02x previously defined", w);
+ p->pri[i] = x++;
+ }
+ break;
+ case SYMBOL_STRING:
+ for (w = prev_elem->u.wc + 1; w < s->u.wc; w++) {
+ struct __collate_st_char_pri *p = getpri(w);
+ if (p->pri[i] != PRI_UNDEFINED)
+ yyerror("Char 0x02x previously defined", w);
+ putsubst(w, i, prev_weight_table[i]->u.str);
+ p->pri[i] = prev_weight_table[i]->val;
+ }
+ break;
+ }
+ }
+ }
+ switch(s->type) {
+ case SYMBOL_CHAR: {
+ struct __collate_st_char_pri *p = getpri(s->u.wc);
+ for(i = 0; i < directive_count; i++) {
+ switch (weight_table[i]->type) {
+ case SYMBOL_CHAR:
+ case SYMBOL_CHAIN:
+ case SYMBOL_IGNORE:
+ case SYMBOL_SYMBOL:
+ if (p->pri[i] != PRI_UNDEFINED)
+ yyerror("Char 0x02x previously defined", s->u.wc);
+ p->pri[i] = weight_table[i]->val;
+ break;
+ case SYMBOL_STRING:
+ if (p->pri[i] != PRI_UNDEFINED)
+ yyerror("Char 0x02x previously defined", s->u.wc);
+ putsubst(s->u.wc, i, weight_table[i]->u.str);
+ p->pri[i] = weight_table[i]->val;
+ break;
+ }
+ }
+ break;
+ }
+ case SYMBOL_CHAIN: {
+ struct __collate_st_chain_pri *p = getchain(s->u.str, EXISTS);
+ for(i = 0; i < directive_count; i++) {
+ switch (weight_table[i]->type) {
+ case SYMBOL_CHAR:
+ case SYMBOL_CHAIN:
+ case SYMBOL_IGNORE:
+ case SYMBOL_SYMBOL:
+ if (p->pri[i] != PRI_UNDEFINED)
+ yyerror("Chain %s previously defined", showwcs(s->u.str, STR_LEN));
+ p->pri[i] = weight_table[i]->val;
+ break;
+ case SYMBOL_STRING :
+ if (wcsncmp(s->u.str, weight_table[i]->u.str, STR_LEN) != 0)
+ yyerror("Chain/string mismatch");
+ if (p->pri[i] != PRI_UNDEFINED)
+ yyerror("Chain %s previously defined", showwcs(s->u.str, STR_LEN));
+ /* negative value mean don't substitute
+ * the chain, but it is in an
+ * equivalence class */
+ p->pri[i] = -weight_table[i]->val;
+ }
+ }
+ break;
+ }
+ }
+ memcpy(prev_weight_table, weight_table, sizeof(weight_table));
+ prev_line = LINE_NORMAL;
+ prev_elem = s;
+}
+ | ELLIPSIS { weight_index = 0; allow_ellipsis = 1; } weights {
+ int i;
+ if (prev_line == LINE_ELLIPSIS)
+ yyerror("Illegal sequential ellipsis lines");
+ if (prev_line == LINE_UNDEFINED)
+ yyerror("Ellipsis line can not follow UNDEFINED line");
+ if (prev_line == LINE_NONE)
+ yyerror("Ellipsis line must follow a collating identifier lines");
+ if (weight_index == 0) {
+ for(i = 0; i < directive_count; i++)
+ weight_table[i] = &sym_ellipsis;
+ } else if (weight_index != directive_count)
+ yyerror("Not enough weights specified");
+ for(i = 0; i < directive_count; i++) {
+ if (weight_table[i]->type != SYMBOL_ELLIPSIS)
+ continue;
+ switch (prev_weight_table[i]->type) {
+ case SYMBOL_CHAIN:
+ yyerror("Startpoint of ellipsis can't be a collating element");
+ case SYMBOL_IGNORE:
+ yyerror("Startpoint of ellipsis can't be IGNORE");
+ case SYMBOL_SYMBOL:
+ yyerror("Startpoint of ellipsis can't be a collating symbol");
+ case SYMBOL_STRING:
+ yyerror("Startpoint of ellipsis can't be a string");
+ }
+ }
+ memcpy(prev2_weight_table, prev_weight_table, sizeof(prev_weight_table));
+ memcpy(prev_weight_table, weight_table, sizeof(weight_table));
+ prev_line = LINE_ELLIPSIS;
+ allow_ellipsis = 0;
+}
+ | UNDEFINED { weight_index = 0; allow_ellipsis = 1; } weights {
+ int i;
+
+ if (weight_index == 0) {
+ weight_table[0] = &sym_undefined;
+ for(i = 1; i < directive_count; i++)
+ weight_table[i] = &sym_ellipsis;
+ } else if (weight_index != directive_count)
+ yyerror("Not enough weights specified");
+ for(i = 0; i < directive_count; i++) {
+ switch (weight_table[i]->type) {
+ case SYMBOL_CHAR:
+ case SYMBOL_CHAIN:
+ case SYMBOL_IGNORE:
+ case SYMBOL_SYMBOL:
+ info.undef_pri[i] = weight_table[i]->val;
+ break;
+ case SYMBOL_ELLIPSIS :
+ /* Negative values mean that the priority is
+ * relative to the lexical value */
+ info.undef_pri[i] = -sym_undefined.val;
+ prim_pri = UNDEFINED_PRI;
+ break;
+ case SYMBOL_STRING :
+ yyerror("Strings can't be used with UNDEFINED");
+ }
+ }
+ memcpy(prev_weight_table, weight_table, sizeof(weight_table));
+ prev_line = LINE_UNDEFINED;
+}
+;
+weights :
+ | weight
+ | weights ';' weight
+;
+weight : ELEM {
+ struct symbol *s;
+ if (weight_index >= directive_count)
+ yyerror("More weights than specified by order_start");
+ s = getsymbol($1, EXISTS);
+ if (order_pass && s->val == PRI_UNDEFINED)
+ yyerror("<%s> is undefined", showwcs($1, CHARMAP_SYMBOL_LEN));
+ weight_table[weight_index++] = s;
+}
+ | ELLIPSIS {
+ if (weight_index >= directive_count)
+ yyerror("More weights than specified by order_start");
+ if (!allow_ellipsis)
+ yyerror("Ellipsis weight not allowed");
+ weight_table[weight_index++] = &sym_ellipsis;
+}
+ | IGNORE {
+ if (weight_index >= directive_count)
+ yyerror("More weights than specified by order_start");
+ weight_table[weight_index++] = &sym_ignore;
+}
+ | STRING {
+ if (weight_index >= directive_count)
+ yyerror("More weights than specified by order_start");
+ if (wcslen($1) > STR_LEN)
+ yyerror("String '%s' is too long", showwcs($1, STR_LEN));
+ weight_table[weight_index++] = getstring($1);
+}
+;
+order_end : ORDER_END '\n'
+;
+charmap : DEFN CHAR {
+ int len = wcslen($1);
+ struct symbol *s;
+ if (len > CHARMAP_SYMBOL_LEN)
+ yyerror("Charmap symbol name '%s' is too long", showwcs($1, CHARMAP_SYMBOL_LEN));
+ s = getsymbol($1, NOTEXISTS);
+ s->type = SYMBOL_CHAR;
+ s->val = PRI_UNDEFINED;
+ s->u.wc = $2;
+ setsymbolbychar(s);
+}
+;
+substitute : SUBSTITUTE CHAR WITH STRING {
+ if (wcslen($4) + 1 > STR_LEN)
+ yyerror("%s substitution is too long", charname($2));
+ putsubst($2, 0, $4);
+}
+;
+order : ORDER order_list
+;
+order_list : item
+ | order_list ';' item
+;
+chain : CHAR CHAR {
+ curr_chain[0] = $1;
+ curr_chain[1] = $2;
+ if (curr_chain[0] == '\0' || curr_chain[1] == '\0')
+ yyerror("\\0 can't be chained");
+ curr_chain[2] = '\0';
+}
+ | chain CHAR {
+ static wchar_t tb[2];
+ tb[0] = $2;
+ if (tb[0] == '\0')
+ yyerror("\\0 can't be chained");
+ if (wcslen(curr_chain) + 1 > STR_LEN)
+ yyerror("Chain '%s' grows too long", curr_chain);
+ (void)wcscat(curr_chain, tb);
+}
+;
+item : CHAR {
+ struct __collate_st_char_pri *p = getpri($1);
+ if (p->pri[0] >= 0)
+ yyerror("%s duplicated", charname($1));
+ p->pri[0] = p->pri[1] = prim_pri;
+ sec_pri = ++prim_pri;
+}
+ | chain {
+ struct __collate_st_chain_pri *c = getchain(curr_chain, NOTEXISTS);
+ c->pri[0] = c->pri[1] = prim_pri;
+ sec_pri = ++prim_pri;
+}
+ | CHAR RANGE CHAR {
+ u_int i;
+ struct __collate_st_char_pri *p;
+
+ if ($3 <= $1)
+ yyerror("Illegal range %s -- %s", charname($1), charname2($3));
+
+ for (i = $1; i <= $3; i++) {
+ p = getpri(i);
+ if (p->pri[0] >= 0)
+ yyerror("%s duplicated", charname(i));
+ p->pri[0] = p->pri[1] = prim_pri++;
+ }
+ sec_pri = prim_pri;
+}
+ | '{' mixed_order_list '}' {
+ prim_pri = sec_pri;
+}
+ | '(' sec_order_list ')' {
+ prim_pri = sec_pri;
+}
+;
+mixed_order_list : mixed_sub_list {
+ sec_pri++;
+}
+ | mixed_order_list ';' mixed_sub_list {
+ sec_pri++;
+}
+;
+mixed_sub_list : mixed_sub_item
+ | mixed_sub_list ',' mixed_sub_item
+;
+sec_order_list : sec_sub_item
+ | sec_order_list ',' sec_sub_item
+;
+mixed_sub_item : CHAR {
+ struct __collate_st_char_pri *p = getpri($1);
+ if (p->pri[0] >= 0)
+ yyerror("%s duplicated", charname($1));
+ p->pri[0] = prim_pri;
+ p->pri[1] = sec_pri;
+}
+ | CHAR RANGE CHAR {
+ u_int i;
+ struct __collate_st_char_pri *p;
+
+ if ($3 <= $1)
+ yyerror("Illegal range %s -- %s",
+ charname($1), charname2($3));
+
+ for (i = $1; i <= $3; i++) {
+ p = getpri(i);
+ if (p->pri[0] >= 0)
+ yyerror("%s duplicated", charname(i));
+ p->pri[0] = prim_pri;
+ p->pri[1] = sec_pri;
+ }
+}
+ | chain {
+ struct __collate_st_chain_pri *c = getchain(curr_chain, NOTEXISTS);
+ c->pri[0] = prim_pri;
+ c->pri[1] = sec_pri;
+}
+sec_sub_item : CHAR {
+ struct __collate_st_char_pri *p = getpri($1);
+ if (p->pri[0] >= 0)
+ yyerror("%s duplicated", charname($1));
+ p->pri[0] = prim_pri;
+ p->pri[1] = sec_pri++;
+}
+ | CHAR RANGE CHAR {
+ u_int i;
+ struct __collate_st_char_pri *p;
+
+ if ($3 <= $1)
+ yyerror("Illegal range %s -- %s",
+ charname($1), charname2($3));
+
+ for (i = $1; i <= $3; i++) {
+ p = getpri(i);
+ if (p->pri[0] >= 0)
+ yyerror("%s duplicated", charname(i));
+ p->pri[0] = prim_pri;
+ p->pri[1] = sec_pri++;
+ }
+}
+ | chain {
+ struct __collate_st_chain_pri *c = getchain(curr_chain, NOTEXISTS);
+ c->pri[0] = prim_pri;
+ c->pri[1] = sec_pri++;
+}
+;
+%%
+int
+main(int ac, char **av)
+{
+ int ch, z;
+
+ if ((charmapdb = dbopen(NULL, O_CREAT | O_RDWR, 0600, DB_HASH, NULL)) == NULL)
+ err(1, "dbopen charmapdb");
+ if ((charmapdb2 = dbopen(NULL, O_CREAT | O_RDWR, 0600, DB_HASH, NULL)) == NULL)
+ err(1, "dbopen charmapdb");
+ if ((largemapdb = dbopen(NULL, O_CREAT | O_RDWR, 0600, DB_HASH, NULL)) == NULL)
+ err(1, "dbopen largemapdb");
+ if ((substdb[0] = dbopen(NULL, O_CREAT | O_RDWR, 0600, DB_HASH, NULL)) == NULL)
+ err(1, "dbopen substdb[0]");
+ if ((chaindb = dbopen(NULL, O_CREAT | O_RDWR, 0600, DB_HASH, NULL)) == NULL)
+ err(1, "dbopen chaindb");
+ /* -1 means an undefined priority, which we adjust after parsing */
+ for (ch = 0; ch <= UCHAR_MAX; ch++)
+ for(z = 0; z < COLL_WEIGHTS_MAX; z++)
+ __collate_char_pri_table[ch].pri[z] = PRI_UNDEFINED;
+#ifdef COLLATE_DEBUG
+ while((ch = getopt(ac, av, ":do:I:")) != -1) {
+#else
+ while((ch = getopt(ac, av, ":o:I:")) != -1) {
+#endif
+ switch (ch)
+ {
+#ifdef COLLATE_DEBUG
+ case 'd':
+ debug++;
+ break;
+#endif
+ case 'o':
+ out_file = optarg;
+ break;
+
+ case 'I':
+ strlcpy(map_name, optarg, sizeof(map_name));
+ break;
+
+ default:
+ usage();
+ }
+ }
+ ac -= optind;
+ av += optind;
+ if (ac > 0) {
+ if ((yyin = fopen(*av, "r")) == NULL)
+ err(EX_UNAVAILABLE, "can't open source file %s", *av);
+ }
+ yyparse();
+ return 0;
+}
+
+static struct __collate_st_char_pri *
+getpri(int32_t c)
+{
+ DBT key, val;
+ struct __collate_st_char_pri *p;
+ int ret;
+
+ if (c <= UCHAR_MAX)
+ return &__collate_char_pri_table[c];
+ key.data = &c;
+ key.size = sizeof(int32_t);
+ if ((ret = largemapdb->get(largemapdb, &key, &val, 0)) < 0)
+ err(1, "getpri: Error getting %s", charname(c));
+ if (ret != 0) {
+ struct __collate_st_char_pri *pn;
+ int z;
+ if ((pn = (struct __collate_st_char_pri *)malloc(sizeof(struct __collate_st_char_pri))) == NULL)
+ err(1, "getpri: malloc");
+ for(z = 0; z < COLL_WEIGHTS_MAX; z++)
+ pn->pri[z] = PRI_UNDEFINED;
+ val.data = &pn;
+ val.size = sizeof(struct __collate_st_char_pri *);
+ if (largemapdb->put(largemapdb, &key, &val, 0) < 0)
+ err(1, "getpri: Error storing %s", charname(c));
+ nlargemap++;
+ }
+ memcpy(&p, val.data, sizeof(struct __collate_st_char_pri *));
+ return p;
+}
+
+static struct __collate_st_char_pri *
+haspri(int32_t c)
+{
+ DBT key, val;
+ struct __collate_st_char_pri *p;
+ int ret;
+
+ if (c <= UCHAR_MAX)
+ return &__collate_char_pri_table[c];
+ key.data = &c;
+ key.size = sizeof(int32_t);
+ if ((ret = largemapdb->get(largemapdb, &key, &val, 0)) < 0)
+ err(1, "haspri: Error getting %s", charname(c));
+ if (ret != 0)
+ return NULL;
+ memcpy(&p, val.data, sizeof(struct __collate_st_char_pri *));
+ return p;
+}
+
+static struct __collate_st_chain_pri *
+getchain(const wchar_t *wcs, int exists)
+{
+ DBT key, val;
+ struct __collate_st_chain_pri *p;
+ int ret;
+
+ key.data = (void *)wcs;
+ key.size = __collate_wcsnlen(wcs, STR_LEN) * sizeof(wchar_t);
+ if ((ret = chaindb->get(chaindb, &key, &val, 0)) < 0)
+ err(1, "getchain: Error getting \"%s\"", showwcs(wcs, STR_LEN));
+ if (ret != 0) {
+ struct __collate_st_chain_pri *pn;
+ int z;
+ if (exists > 0)
+ errx(1, "getchain: \"%s\" is not defined", showwcs(wcs, STR_LEN));
+ if ((pn = (struct __collate_st_chain_pri *)malloc(sizeof(struct __collate_st_chain_pri))) == NULL)
+ err(1, "getchain: malloc");
+ for(z = 0; z < COLL_WEIGHTS_MAX; z++)
+ pn->pri[z] = PRI_UNDEFINED;
+ bzero(pn->str, sizeof(pn->str));
+ wcsncpy(pn->str, wcs, STR_LEN);
+ val.data = &pn;
+ val.size = sizeof(struct __collate_st_chain_pri *);
+ if (chaindb->put(chaindb, &key, &val, 0) < 0)
+ err(1, "getchain: Error storing \"%s\"", showwcs(wcs, STR_LEN));
+ nchain++;
+ } else if (exists == 0)
+ errx(1, "getchain: \"%s\" already exists", showwcs(wcs, STR_LEN));
+ memcpy(&p, val.data, sizeof(struct __collate_st_chain_pri *));
+ return p;
+}
+
+struct symbol *
+getsymbol(const wchar_t *wcs, int exists)
+{
+ DBT key, val;
+ struct symbol *p;
+ int ret;
+
+ key.data = (void *)wcs;
+ key.size = wcslen(wcs) * sizeof(wchar_t);
+ if ((ret = charmapdb->get(charmapdb, &key, &val, 0)) < 0)
+ err(1, "getsymbol: Error getting \"%s\"", showwcs(wcs, CHARMAP_SYMBOL_LEN));
+ if (ret != 0) {
+ struct symbol *pn;
+ if (exists > 0)
+ errx(1, "getsymbol: \"%s\" is not defined", showwcs(wcs, CHARMAP_SYMBOL_LEN));
+ if ((pn = (struct symbol *)malloc(sizeof(struct symbol))) == NULL)
+ err(1, "getsymbol: malloc");
+ pn->val = PRI_UNDEFINED;
+ wcsncpy(pn->name, wcs, CHARMAP_SYMBOL_LEN);
+ val.data = &pn;
+ val.size = sizeof(struct symbol *);
+ if (charmapdb->put(charmapdb, &key, &val, 0) < 0)
+ err(1, "getsymbol: Error storing \"%s\"", showwcs(wcs, CHARMAP_SYMBOL_LEN));
+ } else if (exists == 0)
+ errx(1, "getsymbol: \"%s\" already exists", showwcs(wcs, CHARMAP_SYMBOL_LEN));
+ memcpy(&p, val.data, sizeof(struct symbol *));
+ return p;
+}
+
+static struct symbol *
+getsymbolbychar(wchar_t wc)
+{
+ DBT key, val;
+ struct symbol *p;
+ int ret;
+
+ key.data = &wc;
+ key.size = sizeof(wchar_t);
+ if ((ret = charmapdb2->get(charmapdb2, &key, &val, 0)) < 0)
+ err(1, "getsymbolbychar: Error getting Char 0x%02x", wc);
+ if (ret != 0)
+ errx(1, "getsymbolbychar: Char 0x%02x is not defined", wc);
+ memcpy(&p, val.data, sizeof(struct symbol *));
+ return p;
+}
+
+static struct symbol *
+hassymbolbychar(wchar_t wc)
+{
+ DBT key, val;
+ struct symbol *p;
+ int ret;
+
+ key.data = &wc;
+ key.size = sizeof(wchar_t);
+ if ((ret = charmapdb2->get(charmapdb2, &key, &val, 0)) < 0)
+ err(1, "hassymbolbychar: Error getting Char 0x%02x", wc);
+ if (ret != 0)
+ return NULL;
+ memcpy(&p, val.data, sizeof(struct symbol *));
+ return p;
+}
+
+static void
+setsymbolbychar(struct symbol *s)
+{
+ DBT key, val;
+ struct symbol *p;
+ int ret;
+
+ key.data = &s->u.wc;
+ key.size = sizeof(wchar_t);
+ val.data = &s;
+ val.size = sizeof(struct symbol *);
+ if (charmapdb2->put(charmapdb2, &key, &val, 0) < 0)
+ err(1, "setsymbolbychar: Error storing <%s>", showwcs(s->name, CHARMAP_SYMBOL_LEN));
+}
+
+struct symbol *
+getstring(const wchar_t *wcs)
+{
+ DBT key, val;
+ struct symbol *p;
+ int ret;
+
+ key.data = (void *)wcs;
+ key.size = wcslen(wcs) * sizeof(wchar_t);
+ if ((ret = stringdb->get(stringdb, &key, &val, 0)) < 0)
+ err(1, "getstring: Error getting \"%s\"", showwcs(wcs, STR_LEN));
+ if (ret != 0) {
+ struct symbol *pn;
+ if ((pn = (struct symbol *)malloc(sizeof(struct symbol))) == NULL)
+ err(1, "getstring: malloc");
+ pn->type = SYMBOL_STRING;
+ pn->val = prim_pri++;
+ wcsncpy(pn->u.str, wcs, STR_LEN);
+ val.data = &pn;
+ val.size = sizeof(struct symbol *);
+ if (stringdb->put(stringdb, &key, &val, 0) < 0)
+ err(1, "getstring: Error storing \"%s\"", showwcs(wcs, STR_LEN));
+ }
+ memcpy(&p, val.data, sizeof(struct symbol *));
+ return p;
+}
+
+static void
+makeforwardref(int i, const struct symbol *from, const struct symbol * to)
+{
+}
+
+static void
+putsubst(int32_t c, int i, const wchar_t *str)
+{
+ DBT key, val;
+ int ret;
+ wchar_t clean[STR_LEN];
+
+ if (!substdb[i])
+ if ((substdb[i] = dbopen(NULL, O_CREAT | O_RDWR, 0600, DB_HASH, NULL)) == NULL)
+ err(1, "dbopen substdb[%d]", i);
+ key.data = &c;
+ key.size = sizeof(int32_t);
+ bzero(clean, sizeof(clean));
+ wcsncpy(clean, str, STR_LEN);
+ val.data = clean;
+ val.size = sizeof(clean);
+ if ((ret = substdb[i]->put(substdb[i], &key, &val, R_NOOVERWRITE)) < 0)
+ err(1, "putsubst: Error on %s", charname(c));
+ if (ret != 0)
+ errx(1, "putsubst: Duplicate substitution of %s", charname(c));
+ nsubst[i]++;
+}
+
+static int
+hassubst(int32_t c, int i)
+{
+ DBT key, val;
+ int ret;
+
+ if (!substdb[i])
+ return 0;
+ key.data = &c;
+ key.size = sizeof(int32_t);
+ if ((ret = substdb[i]->get(substdb[i], &key, &val, 0)) < 0)
+ err(1, "hassubst: Error getting %s", charname(c));
+ return (ret == 0);
+}
+
+static int
+chainpricompar(const void *a, const void *b)
+{
+ return wcsncmp(((struct __collate_st_chain_pri *)a)->str, ((struct __collate_st_chain_pri *)b)->str, STR_LEN);
+}
+
+static int
+charpricompar(const void *a, const void *b)
+{
+ return ((struct __collate_st_large_char_pri *)a)->val - ((struct __collate_st_large_char_pri *)b)->val;
+}
+
+static int
+substcompar(const void *a, const void *b)
+{
+ return ((struct __collate_st_subst *)a)->val - ((struct __collate_st_subst *)b)->val;
+}
+
+static const wchar_t *
+__collate_wcsnchr(const wchar_t *s, wchar_t c, int len)
+{
+ while (*s && len > 0) {
+ if (*s == c)
+ return s;
+ s++;
+ len--;
+ }
+ return NULL;
+}
+
+static int
+__collate_wcsnlen(const wchar_t *s, int len)
+{
+ int n = 0;
+ while (*s && n < len) {
+ s++;
+ n++;
+ }
+ return n;
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: colldef [-o out_file] [-I map_dir] [filename]\n");
+ exit(EX_USAGE);
+}
+
+void
+yyerror(const char *fmt, ...)
+{
+ va_list ap;
+ char msg[128];
+
+ va_start(ap, fmt);
+ vsnprintf(msg, sizeof(msg), fmt, ap);
+ va_end(ap);
+ errx(EX_UNAVAILABLE, "%s, near line %d", msg, line_no);
+}
+
+char *
+showwcs(const wchar_t *t, int len)
+{
+ static char buf[8* CHARMAP_SYMBOL_LEN];
+ char *cp = buf;
+
+ for(; *t && len > 0; len--, t++) {
+ if (*t >=32 && *t <= 126)
+ *cp++ = *t;
+ else {
+ sprintf(cp, "\\x{%02x}", *t);
+ cp += strlen(cp);
+ }
+ }
+ *cp = 0;
+ return buf;
+}
+
+static char *
+charname(wchar_t wc)
+{
+ static char buf[CHARMAP_SYMBOL_LEN + 1];
+ struct symbol *s = hassymbolbychar(wc);
+
+ if (s)
+ strcpy(buf, showwcs(s->name, CHARMAP_SYMBOL_LEN));
+ else
+ sprintf(buf, "Char 0x%02x", wc);
+ return buf;
+}
+
+static char *
+charname2(wchar_t wc)
+{
+ static char buf[CHARMAP_SYMBOL_LEN + 1];
+ struct symbol *s = hassymbolbychar(wc);
+
+ if (s)
+ strcpy(buf, showwcs(s->name, CHARMAP_SYMBOL_LEN));
+ else
+ sprintf(buf, "Char 0x%02x", wc);
+ return buf;
+}
+
+#ifdef COLLATE_DEBUG
+static char *
+show(int c)
+{
+ static char buf[5];
+
+ if (c >=32 && c <= 126)
+ sprintf(buf, "'%c' ", c);
+ else
+ sprintf(buf, "\\x{%02x}", c);
+ return buf;
+}
+
+static void
+collate_print_tables(void)
+{
+ int i, z;
+
+ printf("Info: p=%d s=%d f=0x%02x m=%d dc=%d up=%d us=%d pc=%d sc=%d cc=%d lc=%d\n",
+ info.directive[0], info.directive[1],
+ info.flags, info.chain_max_len,
+ info.directive_count,
+ info.undef_pri[0], info.undef_pri[1],
+ info.subst_count[0], info.subst_count[1],
+ info.chain_count, info.large_pri_count);
+ for(z = 0; z < info.directive_count; z++) {
+ if (info.subst_count[z] > 0) {
+ struct __collate_st_subst *p2 = __collate_substitute_table[z];
+ if (z == 0 && (info.flags & COLLATE_SUBST_DUP))
+ printf("Both substitute tables:\n");
+ else
+ printf("Substitute table %d:\n", z);
+ for (i = info.subst_count[z]; i-- > 0; p2++)
+ printf("\t%s --> \"%s\"\n",
+ show(p2->val),
+ showwcs(p2->str, STR_LEN));
+ }
+ }
+ if (info.chain_count > 0) {
+ printf("Chain priority table:\n");
+ struct __collate_st_chain_pri *p2 = __collate_chain_pri_table;
+ for (i = info.chain_count; i-- > 0; p2++) {
+ printf("\t\"%s\" :", showwcs(p2->str, STR_LEN));
+ for(z = 0; z < info.directive_count; z++)
+ printf(" %d", p2->pri[z]);
+ putchar('\n');
+ }
+ }
+ printf("Char priority table:\n");
+ {
+ struct __collate_st_char_pri *p2 = __collate_char_pri_table;
+ for (i = 0; i < UCHAR_MAX + 1; i++, p2++) {
+ printf("\t%s :", show(i));
+ for(z = 0; z < info.directive_count; z++)
+ printf(" %d", p2->pri[z]);
+ putchar('\n');
+ }
+ }
+ if (info.large_pri_count > 0) {
+ struct __collate_st_large_char_pri *p2 = __collate_large_char_pri_table;
+ printf("Large priority table:\n");
+ for (i = info.large_pri_count; i-- > 0; p2++) {
+ printf("\t%s :", show(p2->val));
+ for(z = 0; z < info.directive_count; z++)
+ printf(" %d", p2->pri.pri[z]);
+ putchar('\n');
+ }
+ }
+}
+#endif
diff --git a/adv_cmds/colldef/scan.l b/adv_cmds/colldef/scan.l
new file mode 100644
index 0000000..ce14492
--- /dev/null
+++ b/adv_cmds/colldef/scan.l
@@ -0,0 +1,398 @@
+%x string s_name charmap defn nchar subs subs2 ldef elem
+%{
+/*-
+ * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
+ * at Electronni Visti IA, Kiev, Ukraine.
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/colldef/scan.l,v 1.19 2002/08/23 04:18:26 ache Exp $");
+
+#include <ctype.h>
+#include <err.h>
+#include <limits.h>
+#include <unistd.h>
+#include <string.h>
+#include <wchar.h>
+#include <sysexits.h>
+#include <sys/types.h>
+#include "collate.h"
+#include "common.h"
+#include "y.tab.h"
+
+int line_no = 1, save_no, fromsubs;
+wchar_t buf0[BUFSIZE], *ptr;
+wchar_t *buf = buf0;
+wchar_t bufstr[BUFSIZE], *ptrsave;
+FILE *map_fp;
+YY_BUFFER_STATE main_buf, map_buf;
+#ifdef FLEX_DEBUG
+YYSTYPE yylval;
+#endif /* FLEX_DEBUG */
+int yylex(void);
+static int localedefmode = 0;
+static orderpass = 0;
+%}
+%%
+<INITIAL,charmap,nchar,subs,subs2,ldef>[ \t]+ ;
+<subs2,ldef>\" { ptr = buf; BEGIN(string); }
+<string>\< {
+ if(localedefmode) {
+ ptrsave = ptr;
+ ptr = buf = bufstr;
+ BEGIN(s_name);
+ } else {
+ if(ptr >= buf + BUFSIZE - 1)
+ errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character '<'",
+ line_no);
+ *ptr++ = '<';
+ }
+}
+<subs>\< { ptr = buf; fromsubs = 1; BEGIN(s_name); }
+<ldef>[,;] return *yytext;
+<ldef>forward { yylval.ch = DIRECTIVE_FORWARD; return ORDER_DIRECTIVE; }
+<ldef>backward { yylval.ch = DIRECTIVE_BACKWARD; return ORDER_DIRECTIVE; }
+<ldef>position { yylval.ch = DIRECTIVE_POSITION; return ORDER_DIRECTIVE; }
+<ldef>collating[-_]element return COLLATING_ELEMENT;
+<ldef>collating[-_]symbol return COLLATING_SYMBOL;
+<ldef>from return FROM;
+<ldef>\.\.\. return ELLIPSIS;
+<ldef>IGNORE return IGNORE;
+<ldef>UNDEFINED return UNDEFINED;
+<ldef>order[-_]start return ORDER_START;
+<ldef>order[-_]end {
+ char line[YY_BUF_SIZE];
+ if (orderpass)
+ return ORDER_END;
+ /* The first pass only defined the left-most symbol. We reread the
+ * order lines, and forward references should now be resolved. */
+ orderpass++;
+ YY_FLUSH_BUFFER;
+ rewind(yyin);
+ for(;;) {
+ if (fgets(line, sizeof(line), yyin) == NULL)
+ errx(EX_UNAVAILABLE, "EOF rescanning for order_start");
+ if (*line == '#')
+ continue;
+ if (strstr(line, "order_start") != NULL)
+ break;
+ }
+ return ORDER_SECOND_PASS;
+}
+<ldef>END[ \t]+LC_COLLATE return END_LC_COLLATE;
+<ldef>\n {
+ line_no++;
+ return '\n';
+}
+<ldef>\< { ptr = buf; BEGIN(elem); }
+<INITIAL>\< { ptr = buf; fromsubs = 0; BEGIN(s_name); }
+<*>^#.*\n line_no++;
+^\n line_no++;
+<INITIAL>\\\n line_no++;
+<INITIAL,nchar,subs>\\t { yylval.ch = '\t'; return CHAR; }
+<INITIAL,nchar,subs>\\n { yylval.ch = '\n'; return CHAR; }
+<INITIAL,nchar,subs>\\b { yylval.ch = '\b'; return CHAR; }
+<INITIAL,nchar,subs>\\f { yylval.ch = '\f'; return CHAR; }
+<INITIAL,nchar,subs>\\v { yylval.ch = '\v'; return CHAR; }
+<INITIAL,nchar,subs>\\r { yylval.ch = '\r'; return CHAR; }
+<INITIAL,nchar,subs>\\a { yylval.ch = '\a'; return CHAR; }
+<subs2>\n {
+ line_no++;
+ BEGIN(INITIAL);
+ return '\n';
+}
+<INITIAL,nchar>\n {
+ line_no++;
+ if (map_fp != NULL) {
+ ptr = buf;
+ BEGIN(defn);
+ }
+ return '\n';
+}
+<INITIAL>[;,{}()] return *yytext;
+<INITIAL>substitute { BEGIN(subs); return SUBSTITUTE; }
+<INITIAL>LC_COLLATE { BEGIN(ldef); localedefmode++; return START_LC_COLLATE; }
+<subs>with { BEGIN(subs2); return WITH; }
+<INITIAL>order return ORDER;
+<INITIAL,ldef>charmap BEGIN(charmap);
+<INITIAL>;[ \t]*\.\.\.[ \t]*; return RANGE;
+<INITIAL,nchar,subs>\\([0-7]{3}) {
+ u_int v;
+
+ sscanf(&yytext[1], "%o", &v);
+ yylval.ch = v;
+ return CHAR;
+}
+<INITIAL,nchar,subs>\\x\{([0-9a-fA-F]{2,8})\} {
+ u_int v;
+
+ sscanf(&yytext[3], "%x", &v);
+ yylval.ch = v;
+ return CHAR;
+}
+<INITIAL,nchar,subs>\\x([0-9a-fA-F]{2}) {
+ u_int v;
+
+ sscanf(&yytext[2], "%x", &v);
+ yylval.ch = v;
+ return CHAR;
+}
+<INITIAL,nchar,subs>\\. { yylval.ch = yytext[1]; return CHAR; }
+<INITIAL,nchar,subs>. { yylval.ch = *(u_char *)yytext; return CHAR; }
+<defn>^\n line_no++;
+<defn>[ \t]+ {
+ if (ptr == buf)
+ errx(EX_UNAVAILABLE, "map expected near line %u of %s",
+ line_no, map_name);
+ *ptr = 0;
+ if (localedefmode && *buf == '<' && ptr[-1] == '>') {
+ if (ptr == buf + 2)
+ errx(EX_UNAVAILABLE, "map expected near line %u of %s",
+ line_no, map_name);
+ *--ptr = 0;
+ wcscpy(yylval.str, buf + 1);
+ } else
+ wcscpy(yylval.str, buf);
+ BEGIN(nchar);
+ return DEFN;
+}
+<s_name,elem>\/\/ {
+ if(ptr >= buf + BUFSIZE - 1)
+ errx(EX_UNAVAILABLE, "name buffer overflow near line %u, character '/'",
+ line_no);
+ *ptr++ = '/';
+}
+<s_name,elem>\/\> {
+ if(ptr >= buf + BUFSIZE - 1)
+ errx(EX_UNAVAILABLE, "name buffer overflow near line %u, character '>'",
+ line_no);
+ *ptr++ = '>';
+}
+<string>\\\" {
+ if(ptr >= buf + BUFSIZE - 1)
+ errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character '\"'",
+ line_no);
+ *ptr++ = '"';
+}
+<elem>\> {
+ if (ptr == buf)
+ errx(EX_UNAVAILABLE, "non-empty name expected near line %u",
+ line_no);
+ *ptr = 0;
+ wcscpy(yylval.str, buf);
+ BEGIN(ldef);
+ return ELEM;
+}
+<s_name>\> {
+ struct symbol *s;
+
+ if (ptr == buf)
+ errx(EX_UNAVAILABLE, "non-empty name expected near line %u",
+ line_no);
+ *ptr = 0;
+ s = getsymbol(buf, EXISTS);
+ switch (s->type) {
+ case SYMBOL_CHAR:
+ break;
+ case SYMBOL_CHAIN:
+ errx(EX_UNAVAILABLE, "name <%s> is chain type near line %u",
+ showwcs(buf, CHARMAP_SYMBOL_LEN), line_no);
+ case SYMBOL_SYMBOL:
+ errx(EX_UNAVAILABLE, "name <%s> is symbol type near line %u",
+ showwcs(buf, CHARMAP_SYMBOL_LEN), line_no);
+ default:
+ errx(EX_UNAVAILABLE, "name <%s>: unknown symbol type (%d) near line %u",
+ showwcs(buf, CHARMAP_SYMBOL_LEN), s->type, line_no);
+ }
+ if (localedefmode) {
+ ptr = ptrsave;
+ buf = buf0;
+ if(ptr >= buf + BUFSIZE - 1)
+ errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character <%s>",
+ line_no, showwcs(bufstr, CHARMAP_SYMBOL_LEN));
+ *ptr++ = s->u.wc;
+ BEGIN(string);
+ } else {
+ yylval.ch = s->u.wc;
+ if (fromsubs)
+ BEGIN(subs);
+ else
+ BEGIN(INITIAL);
+ return CHAR;
+ }
+}
+<string>\" {
+ *ptr = 0;
+ wcscpy(yylval.str, buf);
+ if (localedefmode)
+ BEGIN(ldef);
+ else
+ BEGIN(subs2);
+ return STRING;
+}
+<s_name,defn,elem>. {
+ const char *s = (map_fp != NULL) ? map_name : "input";
+
+ if (!isascii(*yytext) || !isprint(*yytext))
+ errx(EX_UNAVAILABLE, "non-ASCII or non-printable character 0x%02x not allowed in the map/name near line %u of %s",
+ *yytext, line_no, s);
+ if(ptr >= buf + BUFSIZE - 1)
+ errx(EX_UNAVAILABLE, "map/name buffer overflow near line %u of %s, character '%c'",
+ line_no, s, *yytext);
+ *ptr++ = *yytext;
+}
+<string>\\t {
+ if(ptr >= buf + BUFSIZE - 1)
+ errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character '\\t'",
+ line_no);
+ *ptr++ = '\t';
+}
+<string>\\b {
+ if(ptr >= buf + BUFSIZE - 1)
+ errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character '\\b'",
+ line_no);
+ *ptr++ = '\b';
+}
+<string>\\f {
+ if(ptr >= buf + BUFSIZE - 1)
+ errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character '\\f'",
+ line_no);
+ *ptr++ = '\f';
+}
+<string>\\v {
+ if(ptr >= buf + BUFSIZE - 1)
+ errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character '\\v'",
+ line_no);
+ *ptr++ = '\v';
+}
+<string>\\n {
+ if(ptr >= buf + BUFSIZE - 1)
+ errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character '\\n'",
+ line_no);
+ *ptr++ = '\n';
+}
+<string>\\r {
+ if(ptr >= buf + BUFSIZE - 1)
+ errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character '\\r'",
+ line_no);
+ *ptr++ = '\r';
+}
+<string>\\a {
+ if(ptr >= buf + BUFSIZE - 1)
+ errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character '\\a'",
+ line_no);
+ *ptr++ = '\a';
+}
+<s_name,string,defn,elem>\n {
+ const char *s = (map_fp != NULL) ? map_name : "input";
+
+ errx(EX_UNAVAILABLE, "unterminated map/name/string near line %u of %s", line_no, s);
+}
+<s_name,string,nchar,elem><<EOF>> {
+ const char *s = (map_fp != NULL) ? map_name : "input";
+
+ errx(EX_UNAVAILABLE, "premature EOF in the name/string/char near line %u of %s", line_no, s);
+}
+<string>\\x\{([0-9a-f]{2,8})\} {
+ u_int v;
+
+ sscanf(&yytext[3], "%x", &v);
+ *ptr++ = v;
+}
+<string>\\x([0-9a-f]{2}) {
+ u_int v;
+
+ sscanf(&yytext[2], "%x", &v);
+ *ptr++ = v;
+}
+<string>\\([0-7]{3}) {
+ u_int v;
+
+ sscanf(&yytext[1], "%o", &v);
+ *ptr++ = v;
+}
+<string>\\. {
+ if(ptr >= buf + BUFSIZE - 1)
+ errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character '%c'",
+ line_no, yytext[1]);
+ *ptr++ = yytext[1];
+}
+<string>. {
+ if(ptr >= buf + BUFSIZE - 1)
+ errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character '%c'",
+ line_no, *yytext);
+ *ptr++ = *yytext;
+}
+<charmap>[^ \t\n]+ {
+ if(*yytext == '/')
+ strcpy(map_name, yytext);
+ else {
+ strcat(map_name, "/");
+ strcat(map_name, yytext);
+ }
+ if((map_fp = fopen(map_name, "r")) == NULL)
+ err(EX_UNAVAILABLE, "can't open 'charmap' file %s",
+ map_name);
+ save_no = line_no;
+ line_no = 1;
+ map_buf = yy_new_buffer(map_fp, YY_BUF_SIZE);
+ main_buf = YY_CURRENT_BUFFER;
+ yy_switch_to_buffer(map_buf);
+ ptr = buf;
+ BEGIN(defn);
+}
+<charmap>\n {
+ errx(EX_UNAVAILABLE, "'charmap' file name expected near line %u",
+ line_no);
+}
+<charmap><<EOF>> {
+ errx(EX_UNAVAILABLE, "'charmap' file name expected near line %u",
+ line_no);
+}
+<INITIAL,defn><<EOF>> {
+ if(map_fp != NULL) {
+ if (ptr != buf)
+ errx(EX_UNAVAILABLE, "premature EOF in the map near line %u of %s", line_no, map_name);
+ yy_switch_to_buffer(main_buf);
+ yy_delete_buffer(map_buf);
+ fclose(map_fp);
+ map_fp = NULL;
+ line_no = save_no;
+ if (localedefmode)
+ BEGIN(ldef);
+ else
+ BEGIN(INITIAL);
+ } else
+ yyterminate();
+}
+%%
+#ifdef FLEX_DEBUG
+main()
+{
+ while(yylex())
+ ;
+ return 0;
+}
+#endif /* FLEX_DEBUG */
diff --git a/adv_cmds/finger/extern.h b/adv_cmds/finger/extern.h
new file mode 100644
index 0000000..7b8f29c
--- /dev/null
+++ b/adv_cmds/finger/extern.h
@@ -0,0 +1,68 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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.
+ *
+ * @(#)extern.h 8.2 (Berkeley) 4/28/95
+ * $FreeBSD: src/usr.bin/finger/extern.h,v 1.10 2005/09/19 10:11:46 dds Exp $
+ */
+
+#ifndef _EXTERN_H_
+#define _EXTERN_H_
+
+extern char tbuf[1024]; /* Temp buffer for anybody. */
+extern int entries; /* Number of people. */
+extern DB *db; /* Database. */
+extern int d_first;
+extern sa_family_t family;
+extern int gflag;
+extern int lflag;
+extern time_t now;
+extern int oflag;
+extern int pplan; /* don't show .plan/.project */
+#ifndef __APPLE__
+extern int Tflag;
+#endif
+extern int invoker_root; /* Invoked by root */
+
+void enter_lastlog(PERSON *);
+PERSON *enter_person(struct passwd *);
+void enter_where(struct utmpx *, PERSON *);
+PERSON *find_person(const char *);
+int hide(struct passwd *);
+void lflag_print(void);
+int match(struct passwd *, const char *);
+void netfinger(char *);
+PERSON *palloc(void);
+char *prphone(char *);
+void sflag_print(void);
+int show_text(const char *, const char *, const char *);
+
+#endif /* !_EXTERN_H_ */
diff --git a/adv_cmds/finger/finger.1 b/adv_cmds/finger/finger.1
new file mode 100644
index 0000000..4fbdfeb
--- /dev/null
+++ b/adv_cmds/finger/finger.1
@@ -0,0 +1,257 @@
+.\" Copyright (c) 1989, 1990, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" 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.
+.\"
+.\" @(#)finger.1 8.3 (Berkeley) 5/5/94
+.\" $FreeBSD: src/usr.bin/finger/finger.1,v 1.31 2005/09/19 10:11:46 dds Exp $
+.\"
+.Dd July 17, 2004
+.Dt FINGER 1
+.Os
+.Sh NAME
+.Nm finger
+.Nd user information lookup program
+.Sh SYNOPSIS
+.Nm
+.Op Fl 46gklmpsho
+.Op Ar user ...\&
+.Op Ar user@host ...\&
+.Sh DESCRIPTION
+The
+.Nm
+utility displays information about the system users.
+.Pp
+Options are:
+.Bl -tag -width indent
+.It Fl 4
+Forces
+.Nm
+to use IPv4 addresses only.
+.It Fl 6
+Forces
+.Nm
+to use IPv6 addresses only.
+.It Fl g
+This option restricts the gecos output to only the users' real
+name.
+It also has the side-effect of restricting the output
+of the remote host when used in conjunction with the
+.Fl h
+option.
+.It Fl h
+When used in conjunction with the
+.Fl s
+option, the name of the remote host is displayed instead of the office
+location and office phone.
+.It Fl k
+Disable all use of
+.Xr utmpx 5 .
+.It Fl l
+Produce a multi-line format displaying all of the information
+described for the
+.Fl s
+option as well as the user's home directory, home phone number, login
+shell, mail status, and the contents of the files
+.Pa .forward ,
+.Pa .plan ,
+.Pa .project
+and
+.Pa .pubkey
+from the user's home directory.
+.Pp
+If idle time is at least a minute and less than a day, it is
+presented in the form ``hh:mm''.
+Idle times greater than a day are presented as ``d day[s]hh:mm''.
+.Pp
+Phone numbers specified as eleven digits are printed as ``+N-NNN-NNN-NNNN''.
+Numbers specified as ten or seven digits are printed as the appropriate
+subset of that string.
+Numbers specified as five digits are printed as ``xN-NNNN''.
+Numbers specified as four digits are printed as ``xNNNN''.
+.Pp
+If write permission is denied to the device, the phrase ``(messages off)''
+is appended to the line containing the device name.
+One entry per user is displayed with the
+.Fl l
+option; if a user is logged on multiple times, terminal information
+is repeated once per login.
+.Pp
+Mail status is shown as ``No Mail.'' if there is no mail at all, ``Mail
+last read DDD MMM ## HH:MM YYYY (TZ)'' if the person has looked at their
+mailbox since new mail arriving, or ``New mail received ...'', ``Unread
+since ...'' if they have new mail.
+.It Fl m
+Prevent matching of
+.Ar user
+names.
+.Ar User
+is usually a login name; however, matching will also be done on the
+users' real names, unless the
+.Fl m
+option is supplied.
+All name matching performed by
+.Nm
+is case insensitive.
+.It Fl o
+When used in conjunction with the
+.Fl s
+option, the office location and office phone information is displayed
+instead of the name of the remote host.
+.It Fl p
+Prevent
+the
+.Fl l
+option of
+.Nm
+from displaying the contents of the
+.Pa .forward ,
+.Pa .plan ,
+.Pa .project
+and
+.Pa .pubkey
+files.
+.It Fl s
+Display the user's login name, real name, terminal name and write
+status (as a ``*'' before the terminal name if write permission is
+denied), idle time, login time, and either office location and office
+phone number, or the remote host.
+If
+.Fl o
+is given, the office location and office phone number is printed
+(the default).
+If
+.Fl h
+is given, the remote host is printed instead.
+.Pp
+Idle time is in minutes if it is a single integer, hours and minutes
+if a ``:'' is present, or days if a ``d'' is present.
+If it is an
+.Dq * ,
+the login time indicates the time of last login.
+Login time is displayed as the day name if less than 6 days, else month, day;
+hours and minutes, unless more than six months ago, in which case the year
+is displayed rather than the hours and minutes.
+.Pp
+Unknown devices as well as nonexistent idle and login times are
+displayed as single asterisks.
+.El
+.Pp
+If no options are specified,
+.Nm
+defaults to the
+.Fl l
+style output if operands are provided, otherwise to the
+.Fl s
+style.
+Note that some fields may be missing, in either format, if information
+is not available for them.
+.Pp
+If no arguments are specified,
+.Nm
+will print an entry for each user currently logged into the system.
+.Pp
+The
+.Nm
+utility may be used to look up users on a remote machine.
+The format is to specify a
+.Ar user
+as
+.Dq Li user@host ,
+or
+.Dq Li @host ,
+where the default output
+format for the former is the
+.Fl l
+style, and the default output format for the latter is the
+.Fl s
+style.
+The
+.Fl l
+option is the only option that may be passed to a remote machine.
+.Pp
+If the file
+.Pa .nofinger
+exists in the user's home directory,
+and the program is not run with superuser privileges,
+.Nm
+behaves as if the user in question does not exist.
+.Pp
+The optional
+.Xr finger.conf 5
+configuration file can be used to specify aliases.
+Since
+.Nm
+is invoked by
+.Xr fingerd 8 ,
+aliases will work for both local and network queries.
+.Sh ENVIRONMENT
+The
+.Nm
+utility utilizes the following environment variable, if it exists:
+.Bl -tag -width Fl
+.It Ev FINGER
+This variable may be set with favored options to
+.Nm .
+.El
+.Sh FILES
+.Bl -tag -width /var/log/lastlog -compact
+.It Pa /etc/finger.conf
+alias definition data base
+.It Pa /var/log/lastlog
+last login data base
+.El
+.Sh SEE ALSO
+.Xr chpass 1 ,
+.Xr w 1 ,
+.Xr who 1 ,
+.Xr finger.conf 5 ,
+.Xr fingerd 8
+.Rs
+.%A D. Zimmerman
+.%T The Finger User Information Protocol
+.%R RFC 1288
+.%D December, 1991
+.Re
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 3.0 .
+.Sh BUGS
+The current FINGER protocol RFC requires that the client keep the connection
+fully open until the server closes.
+This prevents the use of the optimal
+three-packet T/TCP exchange.
+(Servers which depend on this requirement are
+bogus but have nonetheless been observed in the Internet at large.)
+.Pp
+The
+.Nm
+utility does not recognize multibyte characters.
diff --git a/adv_cmds/finger/finger.c b/adv_cmds/finger/finger.c
new file mode 100644
index 0000000..0cbb887
--- /dev/null
+++ b/adv_cmds/finger/finger.c
@@ -0,0 +1,416 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
+ *
+ * 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.
+ */
+
+/*
+ * Luke Mewburn <lm@rmit.edu.au> added the following on 940622:
+ * - mail status ("No Mail", "Mail read:...", or "New Mail ...,
+ * Unread since ...".)
+ * - 4 digit phone extensions (3210 is printed as x3210.)
+ * - host/office toggling in short format with -h & -o.
+ * - short day names (`Tue' printed instead of `Jun 21' if the
+ * login time is < 6 days.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)finger.c 8.5 (Berkeley) 5/4/95";
+#endif
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/finger/finger.c,v 1.36 2005/09/19 10:11:46 dds Exp $");
+
+/*
+ * Finger prints out information about users. It is not portable since
+ * certain fields (e.g. the full user name, office, and phone numbers) are
+ * extracted from the gecos field of the passwd file which other UNIXes
+ * may not have or may use for other things.
+ *
+ * There are currently two output formats; the short format is one line
+ * per user and displays login name, tty, login time, real name, idle time,
+ * and either remote host information (default) or office location/phone
+ * number, depending on if -h or -o is used respectively.
+ * The long format gives the same information (in a more legible format) as
+ * well as home directory, shell, mail info, and .plan/.project files.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <db.h>
+#include <err.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <utmpx.h>
+#include <locale.h>
+
+#include "finger.h"
+#include "pathnames.h"
+
+DB *db;
+time_t now;
+int entries, gflag, kflag, lflag, mflag, pplan, sflag, oflag, Tflag;
+sa_family_t family = PF_UNSPEC;
+int d_first = -1;
+char tbuf[1024];
+int invoker_root = 0;
+
+static void loginlist(void);
+static int option(int, char **);
+static void usage(void);
+static void userlist(int, char **);
+
+static int
+option(int argc, char **argv)
+{
+ int ch;
+
+ optind = 1; /* reset getopt */
+
+#ifdef __APPLE__
+ while ((ch = getopt(argc, argv, "46gklmpsho")) != -1)
+#else
+ while ((ch = getopt(argc, argv, "46gklmpshoT")) != -1)
+#endif
+ switch(ch) {
+ case '4':
+ family = AF_INET;
+ break;
+ case '6':
+ family = AF_INET6;
+ break;
+ case 'g':
+ gflag = 1;
+ break;
+ case 'k':
+ kflag = 1; /* keep going without utmpx */
+ break;
+ case 'l':
+ lflag = 1; /* long format */
+ break;
+ case 'm':
+ mflag = 1; /* force exact match of names */
+ break;
+ case 'p':
+ pplan = 1; /* don't show .plan/.project */
+ break;
+ case 's':
+ sflag = 1; /* short format */
+ break;
+ case 'h':
+ oflag = 0; /* remote host info */
+ break;
+ case 'o':
+ oflag = 1; /* office info */
+ break;
+#ifndef __APPLE__
+ case 'T':
+ Tflag = 1; /* disable T/TCP */
+ break;
+#endif
+ case '?':
+ default:
+ usage();
+ }
+
+ return optind;
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr,
+ "usage: finger [-46gklmpshoT] [user ...] [user@host ...]\n");
+ exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+ int envargc, argcnt;
+ char *envargv[3];
+ struct passwd *pw;
+ static char myname[] = "finger";
+
+ if (getuid() == 0 || geteuid() == 0) {
+ invoker_root = 1;
+ if ((pw = getpwnam(UNPRIV_NAME)) && pw->pw_uid > 0) {
+ setgid(pw->pw_gid);
+ setuid(pw->pw_uid);
+ } else {
+ setgid(UNPRIV_UGID);
+ setuid(UNPRIV_UGID);
+ }
+ }
+
+ (void) setlocale(LC_ALL, "");
+
+ /* remove this line to get remote host */
+ oflag = 1; /* default to old "office" behavior */
+
+ /*
+ * Process environment variables followed by command line arguments.
+ */
+ if ((envargv[1] = getenv("FINGER"))) {
+ envargc = 2;
+ envargv[0] = myname;
+ envargv[2] = NULL;
+ (void) option(envargc, envargv);
+ }
+
+ argcnt = option(argc, argv);
+ argc -= argcnt;
+ argv += argcnt;
+
+ (void)time(&now);
+ setpassent(1);
+ if (!*argv) {
+ /*
+ * Assign explicit "small" format if no names given and -l
+ * not selected. Force the -s BEFORE we get names so proper
+ * screening will be done.
+ */
+ if (!lflag)
+ sflag = 1; /* if -l not explicit, force -s */
+ loginlist();
+ if (entries == 0)
+ (void)printf("No one logged on.\n");
+ } else {
+ userlist(argc, argv);
+ /*
+ * Assign explicit "large" format if names given and -s not
+ * explicitly stated. Force the -l AFTER we get names so any
+ * remote finger attempts specified won't be mishandled.
+ */
+ if (!sflag)
+ lflag = 1; /* if -s not explicit, force -l */
+ }
+ if (entries) {
+ if (lflag)
+ lflag_print();
+ else
+ sflag_print();
+ }
+ return (0);
+}
+
+static void
+loginlist(void)
+{
+ PERSON *pn;
+ DBT data, key;
+ struct passwd *pw;
+ struct utmpx *user;
+ int r, sflag1;
+ char name[_UTX_USERSIZE + 1];
+
+ if (kflag)
+ errx(1, "can't list logins without reading utmpx");
+
+ setutxent();
+ name[_UTX_USERSIZE] = '\0';
+ while ((user = getutxent()) != NULL) {
+ if (!user->ut_user[0] || user->ut_type != USER_PROCESS)
+ continue;
+ if ((pn = find_person(user->ut_user)) == NULL) {
+ bcopy(user->ut_user, name, _UTX_USERSIZE);
+ if ((pw = getpwnam(name)) == NULL)
+ continue;
+ if (hide(pw))
+ continue;
+ pn = enter_person(pw);
+ }
+ enter_where(user, pn);
+ }
+ endutxent();
+ if (db && lflag)
+ for (sflag1 = R_FIRST;; sflag1 = R_NEXT) {
+ PERSON *tmp;
+
+ r = (*db->seq)(db, &key, &data, sflag1);
+ if (r == -1)
+ err(1, "db seq");
+ if (r == 1)
+ break;
+ memmove(&tmp, data.data, sizeof tmp);
+ enter_lastlog(tmp);
+ }
+}
+
+static void
+userlist(int argc, char **argv)
+{
+ PERSON *pn;
+ DBT data, key;
+ struct utmpx *user;
+ struct passwd *pw;
+ int r, sflag1, *used, *ip;
+ char **ap, **nargv, **np, **p;
+ FILE *conf_fp;
+ char conf_alias[LINE_MAX];
+ char *conf_realname;
+ int conf_length;
+
+ if ((nargv = malloc((argc+1) * sizeof(char *))) == NULL ||
+ (used = calloc(argc, sizeof(int))) == NULL)
+ err(1, NULL);
+
+ /* Pull out all network requests. */
+ for (ap = p = argv, np = nargv; *p; ++p)
+ if (index(*p, '@'))
+ *np++ = *p;
+ else
+ *ap++ = *p;
+
+ *np++ = NULL;
+ *ap++ = NULL;
+
+ if (!*argv)
+ goto net;
+
+ /*
+ * Mark any arguments beginning with '/' as invalid so that we
+ * don't accidently confuse them with expansions from finger.conf
+ */
+ for (p = argv, ip = used; *p; ++p, ++ip)
+ if (**p == '/') {
+ *ip = 1;
+ warnx("%s: no such user", *p);
+ }
+
+ /*
+ * Traverse the finger alias configuration file of the form
+ * alias:(user|alias), ignoring comment lines beginning '#'.
+ */
+ if ((conf_fp = fopen(_PATH_FINGERCONF, "r")) != NULL) {
+ while(fgets(conf_alias, sizeof(conf_alias), conf_fp) != NULL) {
+ conf_length = strlen(conf_alias);
+ if (*conf_alias == '#' || conf_alias[--conf_length] != '\n')
+ continue;
+ conf_alias[conf_length] = '\0'; /* Remove trailing LF */
+ if ((conf_realname = strchr(conf_alias, ':')) == NULL)
+ continue;
+ *conf_realname = '\0'; /* Replace : with NUL */
+ for (p = argv; *p; ++p) {
+ if (strcmp(*p, conf_alias) == 0) {
+ if ((*p = strdup(conf_realname+1)) == NULL) {
+ err(1, NULL);
+ }
+ }
+ }
+ }
+ (void)fclose(conf_fp);
+ }
+
+ /*
+ * Traverse the list of possible login names and check the login name
+ * and real name against the name specified by the user. If the name
+ * begins with a '/', try to read the file of that name instead of
+ * gathering the traditional finger information.
+ */
+ if (mflag)
+ for (p = argv, ip = used; *p; ++p, ++ip) {
+ if (**p != '/' || *ip == 1 || !show_text("", *p, "")) {
+ if (((pw = getpwnam(*p)) != NULL) && !hide(pw))
+ enter_person(pw);
+ else if (!*ip)
+ warnx("%s: no such user", *p);
+ }
+ }
+ else {
+ while ((pw = getpwent()) != NULL) {
+ for (p = argv, ip = used; *p; ++p, ++ip)
+ if (**p == '/' && *ip != 1
+ && show_text("", *p, ""))
+ *ip = 1;
+ else if (match(pw, *p) && !hide(pw)) {
+ enter_person(pw);
+ *ip = 1;
+ }
+ }
+ for (p = argv, ip = used; *p; ++p, ++ip)
+ if (!*ip)
+ warnx("%s: no such user", *p);
+ }
+
+ /* Handle network requests. */
+net: for (p = nargv; *p;) {
+ netfinger(*p++);
+ if (*p || entries)
+ printf("\n");
+ }
+
+ if (entries == 0)
+ return;
+
+ if (kflag)
+ return;
+
+ /*
+ * Scan thru the list of users currently logged in, saving
+ * appropriate data whenever a match occurs.
+ */
+ setutxent();
+ while ((user = getutxent()) != NULL) {
+ if (!user->ut_user && user->ut_type != USER_PROCESS)
+ continue;
+ if ((pn = find_person(user->ut_user)) == NULL)
+ continue;
+ enter_where(user, pn);
+ }
+ endutxent();
+ if (db)
+ for (sflag1 = R_FIRST;; sflag1 = R_NEXT) {
+ PERSON *tmp;
+
+ r = (*db->seq)(db, &key, &data, sflag1);
+ if (r == -1)
+ err(1, "db seq");
+ if (r == 1)
+ break;
+ memmove(&tmp, data.data, sizeof tmp);
+ enter_lastlog(tmp);
+ }
+}
diff --git a/adv_cmds/finger/finger.conf.5 b/adv_cmds/finger/finger.conf.5
new file mode 100644
index 0000000..83ebc5b
--- /dev/null
+++ b/adv_cmds/finger/finger.conf.5
@@ -0,0 +1,91 @@
+.\" Copyright (c) 2000 Mark Knight <markk@knigma.org>
+.\" All rights reserved.
+.\"
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+.\"
+.\" $FreeBSD: src/usr.bin/finger/finger.conf.5,v 1.6 2005/02/09 18:04:22 ru Exp $
+.\"
+.Dd August 16, 2000
+.Dt FINGER.CONF 5
+.Os
+.Sh NAME
+.Nm finger.conf
+.Nd
+.Xr finger 1
+alias configuration file
+.Sh DESCRIPTION
+The optional
+.Nm
+file is used to provide aliases that can be fingered by local
+and network users.
+This may be useful where a user's login name is not the same
+as their preferred mail address, or for providing virtual login names
+than can be fingered.
+.Pp
+Lines beginning with ``#'' are comments.
+Other lines must consist of an
+alias name and a target name separated by a colon.
+A target name should be either a user, a forward
+reference to another alias or the path of a world readable file.
+.Pp
+Where an alias points to a file, the contents of that file will be displayed
+when the alias is fingered.
+.Sh FILES
+.Bl -tag -width /etc/finger.conf -compact
+.It Pa /etc/finger.conf
+.Xr finger 1
+alias definition data base
+.El
+.Sh EXAMPLES
+.Bd -literal
+# /etc/finger.conf alias definition file
+#
+# Format alias:(user|alias)
+#
+# Individual aliases
+#
+markk:mkn
+john.smith:dev329
+john:dev329
+sue:/etc/finger/sue.txt
+#
+# Network status message
+#
+status:/usr/local/etc/status.txt
+#
+# Administrative redirects
+#
+root:admin
+postmaster:admin
+abuse:admin
+#
+# For the time being, 'sod' is sysadmin.
+#
+admin:sod
+.Ed
+.Sh SEE ALSO
+.Xr finger 1
+.Sh HISTORY
+Support for the
+.Nm
+file was submitted by Mark Knight <markk@knigma.org> and first appeared in
+.Fx 4.2 .
diff --git a/adv_cmds/finger/finger.h b/adv_cmds/finger/finger.h
new file mode 100644
index 0000000..19b30fb
--- /dev/null
+++ b/adv_cmds/finger/finger.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
+ *
+ * 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.
+ *
+ * @(#)finger.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD: src/usr.bin/finger/finger.h,v 1.5 2004/03/14 06:43:34 jmallett Exp $
+ */
+
+#ifndef _FINGER_H_
+#define _FINGER_H_
+
+typedef struct person {
+ uid_t uid; /* user id */
+ char *dir; /* user's home directory */
+ char *homephone; /* pointer to home phone no. */
+ char *name; /* login name */
+ char *office; /* pointer to office name */
+ char *officephone; /* pointer to office phone no. */
+ char *realname; /* pointer to full name */
+ char *shell; /* user's shell */
+ time_t mailread; /* last time mail was read */
+ time_t mailrecv; /* last time mail was received */
+ struct where *whead, *wtail; /* list of where user is or has been */
+} PERSON;
+
+enum status { LASTLOG, LOGGEDIN };
+
+typedef struct where {
+ struct where *next; /* next place user is or has been */
+ enum status info; /* type/status of request */
+ short writable; /* tty is writable */
+ time_t loginat; /* time of (last) login */
+ time_t idletime; /* how long idle (if logged in) */
+ char tty[_UTX_LINESIZE+1]; /* null terminated tty line */
+ char host[_UTX_HOSTSIZE+1]; /* null terminated remote host name */
+} WHERE;
+
+#define UNPRIV_NAME "nobody" /* Preferred privilege level */
+#define UNPRIV_UGID 32767 /* Default uid and gid */
+#define OUTPUT_MAX 100000 /* Do not keep listinging forever */
+#define TIME_LIMIT 360 /* Do not keep listinging forever */
+
+#define UT_NAMESIZE 8 /* old utmp.h value */
+
+#include "extern.h"
+
+#endif /* !_FINGER_H_ */
diff --git a/adv_cmds/finger/lprint.c b/adv_cmds/finger/lprint.c
new file mode 100644
index 0000000..6e9b42d
--- /dev/null
+++ b/adv_cmds/finger/lprint.c
@@ -0,0 +1,367 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
+ *
+ * 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.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)lprint.c 8.3 (Berkeley) 4/28/95";
+#endif
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/finger/lprint.c,v 1.25 2004/03/14 06:43:34 jmallett Exp $");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <ctype.h>
+#include <db.h>
+#include <err.h>
+#include <fcntl.h>
+#include <langinfo.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <utmpx.h>
+#include "finger.h"
+#include "pathnames.h"
+
+#define LINE_LEN 80
+#define TAB_LEN 8 /* 8 spaces between tabs */
+
+static int demi_print(char *, int);
+static void lprint(PERSON *);
+static void vputc(unsigned char);
+
+void
+lflag_print(void)
+{
+ PERSON *pn;
+ int sflag, r;
+ PERSON *tmp;
+ DBT data, key;
+
+ for (sflag = R_FIRST;; sflag = R_NEXT) {
+ r = (*db->seq)(db, &key, &data, sflag);
+ if (r == -1)
+ err(1, "db seq");
+ if (r == 1)
+ break;
+ memmove(&tmp, data.data, sizeof tmp);
+ pn = tmp;
+ if (sflag != R_FIRST)
+ putchar('\n');
+ lprint(pn);
+ if (!pplan) {
+ (void)show_text(pn->dir,
+ _PATH_FORWARD, "Mail forwarded to");
+ (void)show_text(pn->dir, _PATH_PROJECT, "Project");
+ if (!show_text(pn->dir, _PATH_PLAN, "Plan"))
+ (void)printf("No Plan.\n");
+ (void)show_text(pn->dir,
+ _PATH_PUBKEY, "Public key");
+ }
+ }
+}
+
+static void
+lprint(PERSON *pn)
+{
+ struct tm *delta;
+ WHERE *w;
+ int cpr, len, maxlen;
+ struct tm *tp;
+ int oddfield;
+ char t[80];
+
+ if (d_first < 0)
+ d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
+ /*
+ * long format --
+ * login name
+ * real name
+ * home directory
+ * shell
+ * office, office phone, home phone if available
+ * mail status
+ */
+ (void)printf("Login: %-15s\t\t\tName: %s\nDirectory: %-25s",
+ pn->name, pn->realname, pn->dir);
+ (void)printf("\tShell: %-s\n", *pn->shell ? pn->shell : _PATH_BSHELL);
+
+ if (gflag)
+ goto no_gecos;
+ /*
+ * try and print office, office phone, and home phone on one line;
+ * if that fails, do line filling so it looks nice.
+ */
+#define OFFICE_TAG "Office"
+#define OFFICE_PHONE_TAG "Office Phone"
+ oddfield = 0;
+ if (pn->office && pn->officephone &&
+ strlen(pn->office) + strlen(pn->officephone) +
+ sizeof(OFFICE_TAG) + 2 <= 5 * TAB_LEN) {
+ (void)snprintf(tbuf, sizeof(tbuf), "%s: %s, %s",
+ OFFICE_TAG, pn->office, prphone(pn->officephone));
+ oddfield = demi_print(tbuf, oddfield);
+ } else {
+ if (pn->office) {
+ (void)snprintf(tbuf, sizeof(tbuf), "%s: %s",
+ OFFICE_TAG, pn->office);
+ oddfield = demi_print(tbuf, oddfield);
+ }
+ if (pn->officephone) {
+ (void)snprintf(tbuf, sizeof(tbuf), "%s: %s",
+ OFFICE_PHONE_TAG, prphone(pn->officephone));
+ oddfield = demi_print(tbuf, oddfield);
+ }
+ }
+ if (pn->homephone) {
+ (void)snprintf(tbuf, sizeof(tbuf), "%s: %s", "Home Phone",
+ prphone(pn->homephone));
+ oddfield = demi_print(tbuf, oddfield);
+ }
+ if (oddfield)
+ putchar('\n');
+
+no_gecos:
+ /*
+ * long format con't:
+ * if logged in
+ * terminal
+ * idle time
+ * if messages allowed
+ * where logged in from
+ * if not logged in
+ * when last logged in
+ */
+ /* find out longest device name for this user for formatting */
+ for (w = pn->whead, maxlen = -1; w != NULL; w = w->next)
+ if ((len = strlen(w->tty)) > maxlen)
+ maxlen = len;
+ /* find rest of entries for user */
+ for (w = pn->whead; w != NULL; w = w->next) {
+ if (w->info == LOGGEDIN) {
+ tp = localtime(&w->loginat);
+ strftime(t, sizeof(t),
+ d_first ? "%a %e %b %R (%Z)" : "%a %b %e %R (%Z)",
+ tp);
+ cpr = printf("On since %s on %s", t, w->tty);
+ /*
+ * idle time is tough; if have one, print a comma,
+ * then spaces to pad out the device name, then the
+ * idle time. Follow with a comma if a remote login.
+ */
+ delta = gmtime(&w->idletime);
+ if (w->idletime != -1 && (delta->tm_yday ||
+ delta->tm_hour || delta->tm_min)) {
+ cpr += printf("%-*s idle ",
+ maxlen - (int)strlen(w->tty) + 1, ",");
+ if (delta->tm_yday > 0) {
+ cpr += printf("%d day%s ",
+ delta->tm_yday,
+ delta->tm_yday == 1 ? "" : "s");
+ }
+ cpr += printf("%d:%02d",
+ delta->tm_hour, delta->tm_min);
+ if (*w->host) {
+ putchar(',');
+ ++cpr;
+ }
+ }
+ if (!w->writable)
+ cpr += printf(" (messages off)");
+ } else if (w->loginat == 0) {
+ cpr = printf("Never logged in.");
+ } else {
+ tp = localtime(&w->loginat);
+ if (now - w->loginat > 86400 * 365 / 2) {
+ strftime(t, sizeof(t),
+ d_first ? "%a %e %b %R %Y (%Z)" :
+ "%a %b %e %R %Y (%Z)",
+ tp);
+ } else {
+ strftime(t, sizeof(t),
+ d_first ? "%a %e %b %R (%Z)" :
+ "%a %b %e %R (%Z)",
+ tp);
+ }
+ cpr = printf("Last login %s on %s", t, w->tty);
+ }
+ if (*w->host) {
+ if (LINE_LEN < (cpr + 6 + strlen(w->host)))
+ (void)printf("\n ");
+ (void)printf(" from %s", w->host);
+ }
+ putchar('\n');
+ }
+ if (pn->mailrecv == -1)
+ printf("No Mail.\n");
+ else if (pn->mailrecv > pn->mailread) {
+ tp = localtime(&pn->mailrecv);
+ strftime(t, sizeof(t),
+ d_first ? "%a %e %b %R %Y (%Z)" :
+ "%a %b %e %R %Y (%Z)",
+ tp);
+ printf("New mail received %s\n", t);
+ tp = localtime(&pn->mailread);
+ strftime(t, sizeof(t),
+ d_first ? "%a %e %b %R %Y (%Z)" :
+ "%a %b %e %R %Y (%Z)",
+ tp);
+ printf(" Unread since %s\n", t);
+ } else {
+ tp = localtime(&pn->mailread);
+ strftime(t, sizeof(t),
+ d_first ? "%a %e %b %R %Y (%Z)" :
+ "%a %b %e %R %Y (%Z)",
+ tp);
+ printf("Mail last read %s\n", t);
+ }
+}
+
+static int
+demi_print(char *str, int oddfield)
+{
+ static int lenlast;
+ int lenthis, maxlen;
+
+ lenthis = strlen(str);
+ if (oddfield) {
+ /*
+ * We left off on an odd number of fields. If we haven't
+ * crossed the midpoint of the screen, and we have room for
+ * the next field, print it on the same line; otherwise,
+ * print it on a new line.
+ *
+ * Note: we insist on having the right hand fields start
+ * no less than 5 tabs out.
+ */
+ maxlen = 5 * TAB_LEN;
+ if (maxlen < lenlast)
+ maxlen = lenlast;
+ if (((((maxlen / TAB_LEN) + 1) * TAB_LEN) +
+ lenthis) <= LINE_LEN) {
+ while(lenlast < (4 * TAB_LEN)) {
+ putchar('\t');
+ lenlast += TAB_LEN;
+ }
+ (void)printf("\t%s\n", str); /* force one tab */
+ } else {
+ (void)printf("\n%s", str); /* go to next line */
+ oddfield = !oddfield; /* this'll be undone below */
+ }
+ } else
+ (void)printf("%s", str);
+ oddfield = !oddfield; /* toggle odd/even marker */
+ lenlast = lenthis;
+ return(oddfield);
+}
+
+int
+show_text(const char *directory, const char *file_name, const char *header)
+{
+ struct stat sb;
+ FILE *fp;
+ int ch, cnt;
+ char *p, lastc;
+ int fd, nr;
+
+ lastc = '\0';
+
+ (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", directory, file_name);
+ if ((fd = open(tbuf, O_RDONLY)) < 0 || fstat(fd, &sb) ||
+ sb.st_size == 0)
+ return(0);
+
+ /* If short enough, and no newlines, show it on a single line.*/
+ if (sb.st_size <= LINE_LEN - strlen(header) - 5) {
+ nr = read(fd, tbuf, sizeof(tbuf));
+ if (nr <= 0) {
+ (void)close(fd);
+ return(0);
+ }
+ for (p = tbuf, cnt = nr; cnt--; ++p)
+ if (*p == '\n')
+ break;
+ if (cnt <= 1) {
+ if (*header != '\0')
+ (void)printf("%s: ", header);
+ for (p = tbuf, cnt = nr; cnt--; ++p)
+ if (*p != '\r')
+ vputc(lastc = *p);
+ if (lastc != '\n')
+ (void)putchar('\n');
+ (void)close(fd);
+ return(1);
+ }
+ else
+ (void)lseek(fd, 0L, SEEK_SET);
+ }
+ if ((fp = fdopen(fd, "r")) == NULL)
+ return(0);
+ if (*header != '\0')
+ (void)printf("%s:\n", header);
+ while ((ch = getc(fp)) != EOF)
+ if (ch != '\r')
+ vputc(lastc = ch);
+ if (lastc != '\n')
+ (void)putchar('\n');
+ (void)fclose(fp);
+ return(1);
+}
+
+static void
+vputc(unsigned char ch)
+{
+ int meta;
+
+ if (!isprint(ch) && !isascii(ch)) {
+ (void)putchar('M');
+ (void)putchar('-');
+ ch = toascii(ch);
+ meta = 1;
+ } else
+ meta = 0;
+ if (isprint(ch) || (!meta && (ch == ' ' || ch == '\t' || ch == '\n')))
+ (void)putchar(ch);
+ else {
+ (void)putchar('^');
+ (void)putchar(ch == '\177' ? '?' : ch | 0100);
+ }
+}
diff --git a/adv_cmds/finger/net.c b/adv_cmds/finger/net.c
new file mode 100644
index 0000000..cf0699d
--- /dev/null
+++ b/adv_cmds/finger/net.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
+ *
+ * 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.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)net.c 8.4 (Berkeley) 4/28/95";
+#endif
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/finger/net.c,v 1.23 2004/05/16 22:08:15 stefanf Exp $");
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <ctype.h>
+#include <db.h>
+#include <err.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <utmpx.h>
+#include "finger.h"
+
+static void cleanup(int sig);
+static int do_protocol(const char *name, const struct addrinfo *ai);
+static void trying(const struct addrinfo *ai);
+
+void
+netfinger(char *name)
+{
+ int error, multi;
+ char *host;
+ struct addrinfo *ai, *ai0;
+ static struct addrinfo hint;
+
+ host = strrchr(name, '@');
+ if (host == 0)
+ return;
+ *host++ = '\0';
+ signal(SIGALRM, cleanup);
+ alarm(TIME_LIMIT);
+
+ hint.ai_flags = AI_CANONNAME;
+ hint.ai_family = family;
+ hint.ai_socktype = SOCK_STREAM;
+
+ error = getaddrinfo(host, "finger", &hint, &ai0);
+ if (error) {
+ warnx("%s: %s", host, gai_strerror(error));
+ return;
+ }
+
+ multi = (ai0->ai_next) != 0;
+
+ /* ai_canonname may not be filled in if the user specified an IP. */
+ if (ai0->ai_canonname == 0)
+ printf("[%s]\n", host);
+ else
+ printf("[%s]\n", ai0->ai_canonname);
+
+ for (ai = ai0; ai != 0; ai = ai->ai_next) {
+ if (multi)
+ trying(ai);
+
+ error = do_protocol(name, ai);
+ if (!error)
+ break;
+ }
+ alarm(0);
+ freeaddrinfo(ai0);
+}
+
+static int
+do_protocol(const char *name, const struct addrinfo *ai)
+{
+ int cnt, line_len, s;
+ FILE *fp;
+ int c, lastc;
+ struct iovec iov[3];
+ struct msghdr msg;
+ static char slash_w[] = "/W ";
+ static char neteol[] = "\r\n";
+
+ s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+ if (s < 0) {
+ warn("socket(%d, %d, %d)", ai->ai_family, ai->ai_socktype,
+ ai->ai_protocol);
+ return -1;
+ }
+
+ msg.msg_name = (void *)ai->ai_addr;
+ msg.msg_namelen = ai->ai_addrlen;
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 0;
+ msg.msg_control = 0;
+ msg.msg_controllen = 0;
+ msg.msg_flags = 0;
+
+ /* -l flag for remote fingerd */
+ if (lflag) {
+ iov[msg.msg_iovlen].iov_base = slash_w;
+ iov[msg.msg_iovlen++].iov_len = 3;
+ }
+ /* send the name followed by <CR><LF> */
+ iov[msg.msg_iovlen].iov_base = strdup(name);
+ iov[msg.msg_iovlen++].iov_len = strlen(name);
+ iov[msg.msg_iovlen].iov_base = neteol;
+ iov[msg.msg_iovlen++].iov_len = 2;
+
+#ifdef __APPLE__
+ if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0) {
+#else
+ /*
+ * -T disables data-on-SYN: compatibility option to finger broken
+ * hosts. Also, the implicit-open API is broken on IPv6, so do
+ * the explicit connect there, too.
+ */
+ if ((Tflag || ai->ai_addr->sa_family == AF_INET6)
+ && connect(s, ai->ai_addr, ai->ai_addrlen) < 0) {
+#endif
+ warn("connect");
+ close(s);
+ return -1;
+ }
+
+ if (sendmsg(s, &msg, 0) < 0) {
+ warn("sendmsg");
+ close(s);
+ return -1;
+ }
+
+ /*
+ * Read from the remote system; once we're connected, we assume some
+ * data. If none arrives, we hang until the user interrupts.
+ *
+ * If we see a <CR> or a <CR> with the high bit set, treat it as
+ * a newline; if followed by a newline character, only output one
+ * newline.
+ *
+ * Otherwise, all high bits are stripped; if it isn't printable and
+ * it isn't a space, we can simply set the 7th bit. Every ASCII
+ * character with bit 7 set is printable.
+ */
+ lastc = 0;
+ if ((fp = fdopen(s, "r")) != NULL) {
+ cnt = 0;
+ line_len = 0;
+ while ((c = getc(fp)) != EOF) {
+ if (++cnt > OUTPUT_MAX) {
+ printf("\n\n Output truncated at %d bytes...\n",
+ cnt - 1);
+ break;
+ }
+ if (c == 0x0d) {
+ if (lastc == '\r') /* ^M^M - skip dupes */
+ continue;
+ c = '\n';
+ lastc = '\r';
+ } else {
+ if (!isprint(c) && !isspace(c)) {
+ c &= 0x7f;
+ c |= 0x40;
+ }
+ if (lastc != '\r' || c != '\n')
+ lastc = c;
+ else {
+ lastc = '\n';
+ continue;
+ }
+ }
+ putchar(c);
+ if (c != '\n' && ++line_len > _POSIX2_LINE_MAX) {
+ putchar('\\');
+ putchar('\n');
+ lastc = '\r';
+ }
+ if (lastc == '\n' || lastc == '\r')
+ line_len = 0;
+ }
+ if (ferror(fp)) {
+ /*
+ * Assume that whatever it was set errno...
+ */
+ warn("reading from network");
+ }
+ if (lastc != '\n')
+ putchar('\n');
+
+ fclose(fp);
+ }
+ return 0;
+}
+
+static void
+trying(const struct addrinfo *ai)
+{
+ char buf[NI_MAXHOST];
+
+ if (getnameinfo(ai->ai_addr, ai->ai_addrlen, buf, sizeof buf,
+ (char *)0, 0, NI_NUMERICHOST) != 0)
+ return; /* XXX can't happen */
+
+ printf("Trying %s...\n", buf);
+}
+
+void
+cleanup(int sig __unused)
+{
+#define ERRSTR "Timed out.\n"
+ write(STDERR_FILENO, ERRSTR, sizeof ERRSTR);
+ exit(1);
+}
+
diff --git a/adv_cmds/finger/pathnames.h b/adv_cmds/finger/pathnames.h
new file mode 100644
index 0000000..160252d
--- /dev/null
+++ b/adv_cmds/finger/pathnames.h
@@ -0,0 +1,41 @@
+/*-
+ * Copyright (c) 2000 Mark Knight <markk@knigma.org>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD: src/usr.bin/finger/pathnames.h,v 1.5 2001/07/30 16:50:47 yar Exp $
+ */
+
+#ifndef PATHNAMES_H
+
+#define _PATH_FORWARD ".forward"
+#define _PATH_NOFINGER ".nofinger"
+#define _PATH_PLAN ".plan"
+#define _PATH_PROJECT ".project"
+#define _PATH_PUBKEY ".pubkey"
+
+#ifndef _PATH_FINGERCONF
+#define _PATH_FINGERCONF "/etc/finger.conf"
+#endif /* _PATH_FINGERCONF */
+
+#endif /* PATHNAMES_H */
diff --git a/adv_cmds/finger/sprint.c b/adv_cmds/finger/sprint.c
new file mode 100644
index 0000000..8de1cba
--- /dev/null
+++ b/adv_cmds/finger/sprint.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
+ *
+ * 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.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)sprint.c 8.3 (Berkeley) 4/28/95";
+#endif
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/finger/sprint.c,v 1.22 2003/04/02 20:22:29 rwatson Exp $");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <db.h>
+#include <err.h>
+#include <langinfo.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <utmpx.h>
+#include "finger.h"
+
+static void stimeprint(WHERE *);
+
+void
+sflag_print(void)
+{
+ PERSON *pn;
+ WHERE *w;
+ int sflag, r, namelen;
+ char p[80];
+ PERSON *tmp;
+ DBT data, key;
+ struct tm *lc;
+
+ if (d_first < 0)
+ d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
+ /*
+ * short format --
+ * login name
+ * real name
+ * terminal name (the XX of ttyXX)
+ * if terminal writeable (add an '*' to the terminal name
+ * if not)
+ * if logged in show idle time and day logged in, else
+ * show last login date and time.
+ * If > 6 months, show year instead of time.
+ * if (-o)
+ * office location
+ * office phone
+ * else
+ * remote host
+ */
+#define MAXREALNAME 20
+#define MAXHOSTNAME 17 /* in reality, hosts are never longer than 16 */
+ (void)printf("%-*s %-*s%s %s\n", UT_NAMESIZE, "Login", MAXREALNAME,
+ "Name", " TTY Idle Login Time ", (gflag) ? "" :
+ oflag ? "Office Phone" : "Where");
+
+ for (sflag = R_FIRST;; sflag = R_NEXT) {
+ r = (*db->seq)(db, &key, &data, sflag);
+ if (r == -1)
+ err(1, "db seq");
+ if (r == 1)
+ break;
+ memmove(&tmp, data.data, sizeof tmp);
+ pn = tmp;
+
+ for (w = pn->whead; w != NULL; w = w->next) {
+ namelen = MAXREALNAME;
+ if (w->info == LOGGEDIN && !w->writable)
+ --namelen; /* leave space before `*' */
+ (void)printf("%-*.*s %-*.*s", UT_NAMESIZE, _UTX_USERSIZE,
+ pn->name, MAXREALNAME, namelen,
+ pn->realname ? pn->realname : "");
+ if (!w->loginat) {
+ (void)printf(" * * No logins ");
+ goto office;
+ }
+ (void)putchar(w->info == LOGGEDIN && !w->writable ?
+ '*' : ' ');
+ if (*w->tty)
+ (void)printf("%-3.3s ",
+ (strncmp(w->tty, "tty", 3)
+ && strncmp(w->tty, "cua", 3))
+ ? w->tty : w->tty + 3);
+ else
+ (void)printf(" ");
+ if (w->info == LOGGEDIN) {
+ stimeprint(w);
+ (void)printf(" ");
+ } else
+ (void)printf(" * ");
+ lc = localtime(&w->loginat);
+#define SECSPERDAY 86400
+#define DAYSPERWEEK 7
+#define DAYSPERNYEAR 365
+ if (now - w->loginat < SECSPERDAY * (DAYSPERWEEK - 1)) {
+ (void)strftime(p, sizeof(p), "%a", lc);
+ } else {
+ (void)strftime(p, sizeof(p),
+ d_first ? "%e %b" : "%b %e", lc);
+ }
+ (void)printf("%-6.6s", p);
+ if (now - w->loginat >= SECSPERDAY * DAYSPERNYEAR / 2) {
+ (void)strftime(p, sizeof(p), "%Y", lc);
+ } else {
+ (void)strftime(p, sizeof(p), "%R", lc);
+ }
+ (void)printf(" %-5.5s", p);
+office:
+ if (gflag)
+ goto no_gecos;
+ if (oflag) {
+ if (pn->office)
+ (void)printf(" %-7.7s", pn->office);
+ else if (pn->officephone)
+ (void)printf(" %-7.7s", " ");
+ if (pn->officephone)
+ (void)printf(" %-.9s",
+ prphone(pn->officephone));
+ } else
+ (void)printf(" %.*s", MAXHOSTNAME, w->host);
+no_gecos:
+ putchar('\n');
+ }
+ }
+}
+
+static void
+stimeprint(WHERE *w)
+{
+ struct tm *delta;
+
+ if (w->idletime == -1) {
+ (void)printf(" ");
+ return;
+ }
+
+ delta = gmtime(&w->idletime);
+ if (!delta->tm_yday)
+ if (!delta->tm_hour)
+ if (!delta->tm_min)
+ (void)printf(" ");
+ else
+ (void)printf("%5d", delta->tm_min);
+ else
+ (void)printf("%2d:%02d",
+ delta->tm_hour, delta->tm_min);
+ else
+ (void)printf("%4dd", delta->tm_yday);
+}
diff --git a/adv_cmds/finger/util.c b/adv_cmds/finger/util.c
new file mode 100644
index 0000000..6e7c925
--- /dev/null
+++ b/adv_cmds/finger/util.c
@@ -0,0 +1,419 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
+ *
+ * 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.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)util.c 8.3 (Berkeley) 4/28/95";
+#endif
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/finger/util.c,v 1.22 2005/09/19 10:11:47 dds Exp $");
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <db.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <utmpx.h>
+#include "finger.h"
+#include "pathnames.h"
+
+static void find_idle_and_ttywrite(WHERE *);
+static void userinfo(PERSON *, struct passwd *);
+static WHERE *walloc(PERSON *);
+
+int
+match(struct passwd *pw, const char *user)
+{
+ char *p, *t;
+ char name[1024];
+
+ if (!strcasecmp(pw->pw_name, user))
+ return(1);
+
+ /*
+ * XXX
+ * Why do we skip asterisks!?!?
+ */
+ (void)strncpy(p = tbuf, pw->pw_gecos, sizeof(tbuf));
+ tbuf[sizeof(tbuf) - 1] = '\0';
+ if (*p == '*')
+ ++p;
+
+ /* Ampersands get replaced by the login name. */
+ if ((p = strtok(p, ",")) == NULL)
+ return(0);
+
+ for (t = name; t < &name[sizeof(name) - 1] && (*t = *p) != '\0'; ++p) {
+ if (*t == '&') {
+ (void)strncpy(t, pw->pw_name,
+ sizeof(name) - (t - name));
+ name[sizeof(name) - 1] = '\0';
+ while (t < &name[sizeof(name) - 1] && *++t)
+ continue;
+ } else {
+ ++t;
+ }
+ }
+ *t = '\0';
+ for (t = name; (p = strtok(t, "\t ")) != NULL; t = NULL)
+ if (!strcasecmp(p, user))
+ return(1);
+ return(0);
+}
+
+void
+enter_lastlog(PERSON *pn)
+{
+ WHERE *w;
+ struct lastlogx l, *ll;
+ char doit = 0;
+
+ if ((ll = getlastlogxbyname(pn->name, &l)) == NULL) {
+ bzero(&l, sizeof(l));
+ ll = &l;
+ }
+ if ((w = pn->whead) == NULL)
+ doit = 1;
+ else if (ll->ll_tv.tv_sec != 0) {
+ /* if last login is earlier than some current login */
+ for (; !doit && w != NULL; w = w->next)
+ if (w->info == LOGGEDIN && w->loginat < ll->ll_tv.tv_sec)
+ doit = 1;
+ /*
+ * and if it's not any of the current logins
+ * can't use time comparison because there may be a small
+ * discrepancy since login calls time() twice
+ */
+ for (w = pn->whead; doit && w != NULL; w = w->next)
+ if (w->info == LOGGEDIN &&
+ strncmp(w->tty, ll->ll_line, _UTX_LINESIZE) == 0)
+ doit = 0;
+ }
+ if (doit) {
+ w = walloc(pn);
+ w->info = LASTLOG;
+ bcopy(ll->ll_line, w->tty, _UTX_LINESIZE);
+ w->tty[_UTX_LINESIZE] = 0;
+ bcopy(ll->ll_host, w->host, _UTX_HOSTSIZE);
+ w->host[_UTX_HOSTSIZE] = 0;
+ w->loginat = ll->ll_tv.tv_sec;
+ }
+}
+
+void
+enter_where(struct utmpx *ut, PERSON *pn)
+{
+ WHERE *w;
+
+ w = walloc(pn);
+ w->info = LOGGEDIN;
+ bcopy(ut->ut_line, w->tty, _UTX_LINESIZE);
+ w->tty[_UTX_LINESIZE] = 0;
+ bcopy(ut->ut_host, w->host, _UTX_HOSTSIZE);
+ w->host[_UTX_HOSTSIZE] = 0;
+ w->loginat = (time_t)ut->ut_tv.tv_sec;
+ find_idle_and_ttywrite(w);
+}
+
+PERSON *
+enter_person(struct passwd *pw)
+{
+ DBT data, key;
+ PERSON *pn;
+
+ if (db == NULL &&
+ (db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL)) == NULL)
+ err(1, NULL);
+
+ key.data = pw->pw_name;
+ key.size = strlen(pw->pw_name);
+
+ switch ((*db->get)(db, &key, &data, 0)) {
+ case 0:
+ memmove(&pn, data.data, sizeof pn);
+ return (pn);
+ default:
+ case -1:
+ err(1, "db get");
+ /* NOTREACHED */
+ case 1:
+ ++entries;
+ pn = palloc();
+ userinfo(pn, pw);
+ pn->whead = NULL;
+
+ data.size = sizeof(PERSON *);
+ data.data = &pn;
+ if ((*db->put)(db, &key, &data, 0))
+ err(1, "db put");
+ return (pn);
+ }
+}
+
+PERSON *
+find_person(const char *name)
+{
+ struct passwd *pw;
+
+ int cnt;
+ DBT data, key;
+ PERSON *p;
+ char buf[_UTX_USERSIZE + 1];
+
+ if (!db)
+ return(NULL);
+
+ if ((pw = getpwnam(name)) && hide(pw))
+ return(NULL);
+
+ /* Name may be only _UTX_USERSIZE long and not NUL terminated. */
+ for (cnt = 0; cnt < _UTX_USERSIZE && *name; ++name, ++cnt)
+ buf[cnt] = *name;
+ buf[cnt] = '\0';
+ key.data = buf;
+ key.size = cnt;
+
+ if ((*db->get)(db, &key, &data, 0))
+ return (NULL);
+ memmove(&p, data.data, sizeof p);
+ return (p);
+}
+
+PERSON *
+palloc(void)
+{
+ PERSON *p;
+
+ if ((p = malloc(sizeof(PERSON))) == NULL)
+ err(1, NULL);
+ return(p);
+}
+
+static WHERE *
+walloc(PERSON *pn)
+{
+ WHERE *w;
+
+ if ((w = malloc(sizeof(WHERE))) == NULL)
+ err(1, NULL);
+ if (pn->whead == NULL)
+ pn->whead = pn->wtail = w;
+ else {
+ pn->wtail->next = w;
+ pn->wtail = w;
+ }
+ w->next = NULL;
+ return(w);
+}
+
+char *
+prphone(char *num)
+{
+ char *p;
+ int len;
+ static char pbuf[20];
+
+ /* don't touch anything if the user has their own formatting */
+ for (p = num; *p; ++p)
+ if (!isdigit(*p))
+ return(num);
+ len = p - num;
+ p = pbuf;
+ switch(len) {
+ case 11: /* +0-123-456-7890 */
+ *p++ = '+';
+ *p++ = *num++;
+ *p++ = '-';
+ /* FALLTHROUGH */
+ case 10: /* 012-345-6789 */
+ *p++ = *num++;
+ *p++ = *num++;
+ *p++ = *num++;
+ *p++ = '-';
+ /* FALLTHROUGH */
+ case 7: /* 012-3456 */
+ *p++ = *num++;
+ *p++ = *num++;
+ *p++ = *num++;
+ break;
+ case 5: /* x0-1234 */
+ case 4: /* x1234 */
+ *p++ = 'x';
+ *p++ = *num++;
+ break;
+ default:
+ return(num);
+ }
+ if (len != 4) {
+ *p++ = '-';
+ *p++ = *num++;
+ }
+ *p++ = *num++;
+ *p++ = *num++;
+ *p++ = *num++;
+ *p = '\0';
+ return(pbuf);
+}
+
+static void
+find_idle_and_ttywrite(WHERE *w)
+{
+ struct stat sb;
+ time_t touched;
+ int error;
+
+ (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_DEV, w->tty);
+
+ error = stat(tbuf, &sb);
+ if (error < 0 && errno == ENOENT) {
+ /*
+ * The terminal listed is not actually a terminal (i.e.,
+ * ":0"). This is a failure, so we'll skip printing
+ * out the idle time, which is non-ideal but better
+ * than a bogus warning and idle time.
+ */
+ w->idletime = -1;
+ return;
+ } else if (error < 0) {
+ warn("%s", tbuf);
+ w->idletime = -1;
+ return;
+ }
+ touched = sb.st_atime;
+ if (touched < w->loginat) {
+ /* tty untouched since before login */
+ touched = w->loginat;
+ }
+ w->idletime = now < touched ? 0 : now - touched;
+
+#define TALKABLE 0220 /* tty is writable if 220 mode */
+ w->writable = ((sb.st_mode & TALKABLE) == TALKABLE);
+}
+
+static void
+userinfo(PERSON *pn, struct passwd *pw)
+{
+ char *p, *t;
+ char *bp, name[1024];
+ struct stat sb;
+
+ pn->realname = pn->office = pn->officephone = pn->homephone = NULL;
+
+ pn->uid = pw->pw_uid;
+ if ((pn->name = strdup(pw->pw_name)) == NULL)
+ err(1, "strdup failed");
+ if ((pn->dir = strdup(pw->pw_dir)) == NULL)
+ err(1, "strdup failed");
+ if ((pn->shell = strdup(pw->pw_shell)) == NULL)
+ err(1, "strdup failed");
+
+ /* why do we skip asterisks!?!? */
+ (void)strncpy(bp = tbuf, pw->pw_gecos, sizeof(tbuf));
+ tbuf[sizeof(tbuf) - 1] = '\0';
+ if (*bp == '*')
+ ++bp;
+
+ /* ampersands get replaced by the login name */
+ if (!(p = strsep(&bp, ",")))
+ return;
+ for (t = name; t < &name[sizeof(name) - 1] && (*t = *p) != '\0'; ++p) {
+ if (*t == '&') {
+ (void)strncpy(t, pw->pw_name,
+ sizeof(name) - (t - name));
+ name[sizeof(name) - 1] = '\0';
+ if (islower(*t))
+ *t = toupper(*t);
+ while (t < &name[sizeof(name) - 1] && *++t)
+ continue;
+ } else {
+ ++t;
+ }
+ }
+ *t = '\0';
+ if ((pn->realname = strdup(name)) == NULL)
+ err(1, "strdup failed");
+ pn->office = ((p = strsep(&bp, ",")) && *p) ?
+ strdup(p) : NULL;
+ pn->officephone = ((p = strsep(&bp, ",")) && *p) ?
+ strdup(p) : NULL;
+ pn->homephone = ((p = strsep(&bp, ",")) && *p) ?
+ strdup(p) : NULL;
+ (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pw->pw_name);
+ pn->mailrecv = -1; /* -1 == not_valid */
+ if (stat(tbuf, &sb) < 0) {
+ if (errno != ENOENT) {
+ warn("%s", tbuf);
+ return;
+ }
+ } else if (sb.st_size != 0) {
+ pn->mailrecv = sb.st_mtime;
+ pn->mailread = sb.st_atime;
+ }
+}
+
+/*
+ * Is this user hiding from finger?
+ * If ~<user>/.nofinger exists, return 1 (hide), else return 0 (nohide).
+ * Nobody can hide from root.
+ */
+
+int
+hide(struct passwd *pw)
+{
+ struct stat st;
+ char buf[MAXPATHLEN];
+
+ if (invoker_root || !pw->pw_dir)
+ return 0;
+
+ snprintf(buf, sizeof(buf), "%s/%s", pw->pw_dir, _PATH_NOFINGER);
+
+ if (stat(buf, &st) == 0)
+ return 1;
+
+ return 0;
+}
diff --git a/adv_cmds/gencat/gencat.1 b/adv_cmds/gencat/gencat.1
new file mode 100644
index 0000000..bcead36
--- /dev/null
+++ b/adv_cmds/gencat/gencat.1
@@ -0,0 +1,177 @@
+.\" $OpenBSD: gencat.1,v 1.3 1997/06/11 15:39:54 kstailey Exp $
+.\"
+.\" Copyright (c) 1997 Ken Stailey
+.\"
+.\" 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. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+.\"
+.\" $FreeBSD: src/usr.bin/gencat/gencat.1,v 1.9 2001/11/23 14:37:27 dd Exp $
+.\"
+.Dd June 11, 1997
+.Dt GENCAT 1
+.Os
+.Sh NAME
+.Nm gencat
+.Nd NLS catalog compiler
+.Sh SYNOPSIS
+.Nm
+.Ar "output-file"
+.Ar "input-files..."
+.Sh DESCRIPTION
+The
+.Nm
+utility merges the text NLS input files
+.Ar "input-files..."
+into a formatted message catalog file
+.Ar "output-file" .
+The file
+.Ar "output-file"
+will be created if it does not already exist. If
+.Ar "output-file"
+does exist, its messages will be included in the new
+.Ar "output-file" .
+If set and message numbers collide, the new message text defined in
+.Ar "input-files..."
+will replace the old message text currently contained in
+.Ar "output-file" .
+.Sh INPUT FILES
+The format of a message text source file is defined below. Note that
+the fields of a message text source line are separated by a single space
+character: any other space characters are considered to be part of the
+field contents.
+.Pp
+.Bl -tag -width 3n
+.It Li $set Ar n comment
+This line specifies the set identifier of the following messages until
+the next
+.Li $set
+or end-of-file appears. The argument
+.Ar n
+is the set identifier which is defined as a number in the range
+[1, (NL_SETMAX)]. Set identifiers must occur in ascending order within
+a single source file, but need not be contiguous. Any string following
+a space following the set identifier is treated as a comment. If no
+.Li $set
+directive is specified in a given source file, all messages will
+be located in the default message set NL_SETD.
+.It Li $del Ar n comment
+This line deletes messages from set
+.Ar n
+from a message catalog. The
+.Ar n
+specifies a set number. Any string following a space following the set
+number is treated as a comment.
+.It Li $ Ar comment
+A line beginning with
+.Li $
+followed by a space is treated as a comment.
+.It Ar m message-text
+A message line consists of a message identifier
+.Ar m
+in the range [1, (NL_MSGMAX)]. The
+.Ar message-text
+is stored in the message catalog with the set identifier specified by
+the last
+.Li $set
+directive, and the message identifier
+.Ar m .
+If the
+.Ar message-text
+is empty, and there is a space character following the message identifier,
+an empty string is stored in the message catalog. If the
+.Ar message-text
+is empty, and if there is no space character following the message
+identifier, then the existing message in the current set with the
+specified message identifier is deleted from the catalog. Message
+identifiers must be in ascending order within a single set, but
+need not be contiguous. The
+.Ar message-text
+length must be in the range [0, (NL_TEXTMAX)].
+.It Li $quote Ar c
+This line specifies an optional quote character
+.Ar c
+which can be used to surround
+.Ar message-text
+so that trailing space or empty messages are visible in message
+source files. By default, or if an empty
+.Li $quote
+directive is specified, no quoting of
+.Ar message-text
+will be recognized.
+.El
+.Pp
+Empty lines in message source files are ignored. The effect of lines
+beginning with any character other than those described above is
+undefined.
+.Pp
+Text strings can contain the following special characters and escape
+sequences. In addition, if a quote character is defined, it may be
+escaped as well to embed a literal quote character.
+.Pp
+.Bl -tag -width "\eooo" -offset indent -compact
+.It Li \en
+line feed
+.It Li \et
+horizontal tab
+.It Li \ev
+vertical tab
+.It Li \eb
+backspace
+.It Li \er
+carriage return
+.It Li \ef
+form feed
+.It Li \e\e
+backslash
+.It Li \eooo
+octal number in the range [000, 377]
+.El
+.Pp
+A backslash character immediately before the end of the line in a file
+is used to continue the line onto the next line, e.g.:
+.Pp
+.Dl 1 This line is continued \e
+.Dl on this line.
+.Pp
+If the character following the backslash is not one of those specified,
+the backslash is ignored.
+.Sh DIAGNOSTICS
+.Ex -std
+.Sh SEE ALSO
+.Xr catclose 3 ,
+.Xr catgets 3 ,
+.Xr catopen 3
+.Sh STANDARDS
+The
+.Nm
+utility is compliant with the
+.St -xpg4
+standard.
+.Sh AUTHORS
+.An -nosplit
+This manual page was originally written by
+.An Ken Stailey
+and later revised by
+.An Terry Lambert .
+.Sh BUGS
+A message catalog file created from a blank input file cannot be revised;
+it must be deleted and recreated.
diff --git a/adv_cmds/gencat/gencat.c b/adv_cmds/gencat/gencat.c
new file mode 100644
index 0000000..e0d00e3
--- /dev/null
+++ b/adv_cmds/gencat/gencat.c
@@ -0,0 +1,199 @@
+/***********************************************************
+Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that Alfalfa's name not be used in
+advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.
+
+ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+If you make any modifications, bugfixes or other changes to this software
+we'd appreciate it if you could send a copy to us so we can keep things
+up-to-date. Many thanks.
+ Kee Hinckley
+ Alfalfa Software, Inc.
+ 267 Allston St., #3
+ Cambridge, MA 02139 USA
+ nazgul@alfalfa.com
+
+******************************************************************/
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/gencat/gencat.c,v 1.9 2002/05/29 14:23:10 tjr Exp $");
+
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <err.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "gencat.h"
+
+/*
+ * The spec says the syntax is "gencat catfile msgfile...".
+ * We extend it to:
+ * gencat [-lang C|C++|ANSIC] catfile msgfile [-h <header-file>]...
+ * Flags are order dependent, we'll take whatever lang was most recently chosen
+ * and use it to generate the next header file. The header files are generated
+ * at the point in the command line they are listed. Thus the sequence:
+ * gencat -lang C foo.cat foo.mcs -h foo.h -lang C++ bar.mcs -h bar.H
+ * will put constants from foo.mcs into foo.h and constants from bar.mcs into
+ * bar.h. Constants are not saved in the catalog file, so nothing will come
+ * from that, even if things have been defined before. The constants in foo.h
+ * will be in C syntax, in bar.H in C++ syntax.
+ */
+
+static void writeIfChanged(char *, int, int);
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: gencat [-new] [-or] [-lang C|C++|ANSIC]\n"
+ " catfile msgfile [-h <header-file>]...\n");
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int ofd = -1, ifd, i;
+ char *catfile = NULL;
+ char *input = NULL;
+ int lang = MCLangC;
+ int new = FALSE;
+ int orConsts = FALSE;
+
+ for (i = 1; i < argc; ++i) {
+ if (argv[i][0] == '-') {
+ if (strcmp(argv[i], "-lang") == 0) {
+ ++i;
+ if (strcmp(argv[i], "C") == 0) lang = MCLangC;
+ else if (strcmp(argv[i], "C++") == 0) lang = MCLangCPlusPlus;
+ else if (strcmp(argv[i], "ANSIC") == 0) lang = MCLangANSIC;
+ else {
+ errx(1, "unrecognized language: %s", argv[i]);
+ }
+ } else if (strcmp(argv[i], "-h") == 0) {
+ if (!input)
+ errx(1, "can't write to a header before reading something");
+ ++i;
+ writeIfChanged(argv[i], lang, orConsts);
+ } else if (strcmp(argv[i], "-new") == 0) {
+ if (catfile)
+ errx(1, "you must specify -new before the catalog file name");
+ new = TRUE;
+ } else if (strcmp(argv[i], "-or") == 0) {
+ orConsts = ~orConsts;
+ } else {
+ usage();
+ }
+ } else {
+ if (!catfile) {
+ catfile = argv[i];
+ if (new) {
+ if ((ofd = open(catfile, O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0)
+ errx(1, "unable to create a new %s", catfile);
+ } else if ((ofd = open(catfile, O_RDONLY)) < 0) {
+ if ((ofd = open(catfile, O_WRONLY|O_CREAT, 0666)) < 0)
+ errx(1, "unable to create %s", catfile);
+ } else {
+ MCReadCat(ofd);
+ close(ofd);
+ if ((ofd = open(catfile, O_WRONLY|O_TRUNC)) < 0)
+ errx(1, "unable to truncate %s", catfile);
+ }
+ } else {
+ input = argv[i];
+ if ((ifd = open(input, O_RDONLY)) < 0)
+ errx(1, "unable to read %s", input);
+ MCParse(ifd);
+ close(ifd);
+ }
+ }
+ }
+ if (catfile) {
+ MCWriteCat(ofd);
+ exit(0);
+ } else {
+ usage();
+ }
+ return 0;
+}
+
+static void
+writeIfChanged(char *fname, int lang, int orConsts)
+{
+ char tmpname[] = _PATH_TMP"/gencat.XXXXXX";
+ char buf[BUFSIZ], tbuf[BUFSIZ], *cptr, *tptr;
+ int fd, tfd;
+ int diff = FALSE;
+ int len, tlen;
+ struct stat sbuf;
+
+ /* If it doesn't exist, just create it */
+ if (stat(fname, &sbuf)) {
+ if ((fd = open(fname, O_WRONLY|O_CREAT, 0666)) < 0)
+ errx(1, "unable to create header file %s", fname);
+ MCWriteConst(fd, lang, orConsts);
+ close(fd);
+ return;
+ }
+
+ /* If it does exist, create a temp file for now */
+ if ((tfd = mkstemp(tmpname)) < 0)
+ err(1, "mkstemp");
+ unlink(tmpname);
+
+ /* Write to the temp file and rewind */
+ MCWriteConst(tfd, lang, orConsts);
+
+ /* Open the real header file */
+ if ((fd = open(fname, O_RDONLY)) < 0)
+ errx(1, "unable to read header file: %s", fname);
+
+ /* Backup to the start of the temp file */
+ if (lseek(tfd, (off_t)0, L_SET) < 0)
+ errx(1, "unable to seek in tempfile: %s", tmpname);
+
+ /* Now compare them */
+ while ((tlen = read(tfd, tbuf, BUFSIZ)) > 0) {
+ if ((len = read(fd, buf, BUFSIZ)) != tlen) {
+ diff = TRUE;
+ goto done;
+ }
+ for (cptr = buf, tptr = tbuf; cptr < buf+len; ++cptr, ++tptr) {
+ if (*tptr != *cptr) {
+ diff = TRUE;
+ goto done;
+ }
+ }
+ }
+done:
+ if (diff) {
+ if (lseek(tfd, (off_t)0, L_SET) < 0)
+ errx(1, "unable to seek in tempfile: %s", tmpname);
+ close(fd);
+ if ((fd = open(fname, O_WRONLY|O_TRUNC)) < 0)
+ errx(1, "unable to truncate header file: %s", fname);
+ while ((len = read(tfd, buf, BUFSIZ)) > 0) {
+ if (write(fd, buf, (size_t)len) != len)
+ warnx("error writing to header file: %s", fname);
+ }
+ }
+ close(fd);
+ close(tfd);
+}
diff --git a/adv_cmds/gencat/gencat.h b/adv_cmds/gencat/gencat.h
new file mode 100644
index 0000000..5e7e459
--- /dev/null
+++ b/adv_cmds/gencat/gencat.h
@@ -0,0 +1,87 @@
+/* $FreeBSD: src/usr.bin/gencat/gencat.h,v 1.4 2002/03/26 12:39:08 charnier Exp $ */
+
+#ifndef GENCAT_H
+#define GENCAT_H
+
+/***********************************************************
+Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that Alfalfa's name not be used in
+advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.
+
+ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+If you make any modifications, bugfixes or other changes to this software
+we'd appreciate it if you could send a copy to us so we can keep things
+up-to-date. Many thanks.
+ Kee Hinckley
+ Alfalfa Software, Inc.
+ 267 Allston St., #3
+ Cambridge, MA 02139 USA
+ nazgul@alfalfa.com
+
+******************************************************************/
+
+/*
+ * $set n comment
+ * My extension: If the comment begins with # treat the next string
+ * as a constant identifier.
+ * $delset n comment
+ * n goes from 1 to NL_SETMAX
+ * Deletes a set from the MC
+ * $ comment
+ * My extension: If comment begins with # treat the next string as
+ * a constant identifier for the next message.
+ * m message-text
+ * m goes from 1 to NL_MSGMAX
+ * If message-text is empty, and a space or tab is present, put
+ * empty string in catalog.
+ * If message-text is empty, delete the message.
+ * Length of text is 0 to NL_TEXTMAX
+ * My extension: If '#' is used instead of a number, the number
+ * is generated automatically. A # followed by anything is an empty message.
+ * $quote c
+ * Optional quote character which can surround message-text to
+ * show where spaces are.
+ *
+ * Escape Characters
+ * \n (newline), \t (horiz tab), \v (vert tab), \b (backspace),
+ * \r (carriage return), \f (formfeed), \\ (backslash), \ddd (bitpattern
+ * in octal).
+ * Also, \ at end of line is a continuation.
+ *
+ */
+
+#define MCLangC 0
+#define MCLangCPlusPlus 1
+#define MCLangANSIC 2
+
+#define MAXTOKEN 1024
+
+#define TRUE 1
+#define FALSE 0
+
+extern void MCAddSet(int, char *);
+extern void MCDelSet(int);
+extern void MCAddMsg(int, const char *, char *);
+extern void MCDelMsg(int);
+extern void MCParse(int);
+extern void MCReadCat(int);
+extern void MCWriteConst(int, int, int);
+extern void MCWriteCat(int);
+extern long MCGetByteOrder(void);
+
+#endif /* GENCAT_H */
diff --git a/adv_cmds/gencat/genlib.c b/adv_cmds/gencat/genlib.c
new file mode 100644
index 0000000..42b7ae2
--- /dev/null
+++ b/adv_cmds/gencat/genlib.c
@@ -0,0 +1,836 @@
+/***********************************************************
+Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that Alfalfa's name not be used in
+advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.
+
+ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+If you make any modifications, bugfixes or other changes to this software
+we'd appreciate it if you could send a copy to us so we can keep things
+up-to-date. Many thanks.
+ Kee Hinckley
+ Alfalfa Software, Inc.
+ 267 Allston St., #3
+ Cambridge, MA 02139 USA
+ nazgul@alfalfa.com
+
+******************************************************************/
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/gencat/genlib.c,v 1.13 2002/12/24 07:40:10 davidxu Exp $");
+
+#include <ctype.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "msgcat.h"
+#include "gencat.h"
+#include <machine/endian.h>
+/* libkern/OSByteOrder is needed for the 64 bit byte swap */
+#include <libkern/OSByteOrder.h>
+
+#ifndef htonll
+#define htonll(x) OSSwapHostToBigInt64(x)
+#define ntohll(x) OSSwapBigToHostInt64(x)
+#endif
+
+static char *curline = NULL;
+static long lineno = 0;
+
+static void
+warning(char *cptr, const char *msg)
+{
+ warnx("%s on line %ld\n%s", msg, lineno, (curline == NULL ? "" : curline) );
+ if (cptr) {
+ char *tptr;
+ for (tptr = curline; tptr < cptr; ++tptr) putc(' ', stderr);
+ fprintf(stderr, "^\n");
+ }
+}
+
+static void
+error(char *cptr, const char *msg)
+{
+ warning(cptr, msg);
+ exit(1);
+}
+
+static void
+corrupt(void) {
+ error(NULL, "corrupt message catalog");
+}
+
+static void
+nomem(void) {
+ error(NULL, "out of memory");
+}
+
+static char *
+gencat_getline(int fd)
+{
+ static size_t curlen = BUFSIZ;
+ static char buf[BUFSIZ], *bptr = buf, *bend = buf;
+ char *cptr, *cend;
+ long buflen;
+
+ if (!curline) {
+ curline = (char *) malloc(curlen);
+ if (!curline) nomem();
+ }
+ ++lineno;
+
+ cptr = curline;
+ cend = curline + curlen;
+ while (TRUE) {
+ for (; bptr < bend && cptr < cend; ++cptr, ++bptr) {
+ if (*bptr == '\n') {
+ *cptr = '\0';
+ ++bptr;
+ return(curline);
+ } else *cptr = *bptr;
+ }
+ if (bptr == bend) {
+ buflen = read(fd, buf, BUFSIZ);
+ if (buflen <= 0) {
+ if (cptr > curline) {
+ *cptr = '\0';
+ return(curline);
+ }
+ return(NULL);
+ }
+ bend = buf + buflen;
+ bptr = buf;
+ }
+ if (cptr == cend) {
+ cptr = curline = (char *) realloc(curline, curlen *= 2);
+ if (!curline) nomem();
+ cend = curline + curlen;
+ }
+ }
+}
+
+static char *
+token(char *cptr)
+{
+ static char tok[MAXTOKEN+1];
+ char *tptr = tok;
+
+ while (*cptr && isspace((unsigned char)*cptr)) ++cptr;
+ while (*cptr && !isspace((unsigned char)*cptr)) *tptr++ = *cptr++;
+ *tptr = '\0';
+ return(tok);
+}
+
+static char *
+wskip(char *cptr)
+{
+ if (!*cptr || !isspace((unsigned char)*cptr)) {
+ warning(cptr, "expected a space");
+ return(cptr);
+ }
+ while (*cptr && isspace((unsigned char)*cptr)) ++cptr;
+ return(cptr);
+}
+
+static char *
+cskip(char *cptr)
+{
+ if (!*cptr || isspace((unsigned char)*cptr)) {
+ warning(cptr, "wasn't expecting a space");
+ return(cptr);
+ }
+ while (*cptr && !isspace((unsigned char)*cptr)) ++cptr;
+ return(cptr);
+}
+
+static char *
+getmsg(int fd, char *cptr, char quote)
+{
+ static char *msg = NULL;
+ static size_t msglen = 0;
+ size_t clen, i;
+ char *tptr;
+ int needq;
+
+ if (quote && *cptr == quote) {
+ needq = TRUE;
+ ++cptr;
+ } else needq = FALSE;
+
+ clen = strlen(cptr) + 1;
+ if (clen > msglen) {
+ if (msglen) msg = (char *) realloc(msg, clen);
+ else msg = (char *) malloc(clen);
+ if (!msg) nomem();
+ msglen = clen;
+ }
+ tptr = msg;
+
+ while (*cptr) {
+ if (quote && *cptr == quote) {
+ char *tmp;
+ tmp = cptr+1;
+ if (*tmp && (!isspace((unsigned char)*tmp) || *wskip(tmp))) {
+ warning(cptr, "unexpected quote character, ignoring");
+ *tptr++ = *cptr++;
+ } else {
+ *cptr = '\0';
+ }
+ } else if (*cptr == '\\') {
+ ++cptr;
+ switch (*cptr) {
+ case '\0':
+ cptr = gencat_getline(fd);
+ if (!cptr) error(NULL, "premature end of file");
+ msglen += strlen(cptr);
+ i = tptr - msg;
+ msg = (char *) realloc(msg, msglen);
+ if (!msg) nomem();
+ tptr = msg + i;
+ break;
+
+#define CASEOF(CS, CH) \
+ case CS: \
+ *tptr++ = CH; \
+ ++cptr; \
+ break;
+
+ CASEOF('n', '\n')
+ CASEOF('t', '\t')
+ CASEOF('v', '\v')
+ CASEOF('b', '\b')
+ CASEOF('r', '\r')
+ CASEOF('f', '\f')
+ CASEOF('"', '"')
+ CASEOF('\'', '\'')
+ CASEOF('\\', '\\')
+
+ default:
+ if (isdigit((unsigned char)*cptr)) {
+ *tptr = 0;
+ for (i = 0; i < 3; ++i) {
+ if (!isdigit((unsigned char)*cptr)) break;
+ if (*cptr > '7') warning(cptr, "octal number greater than 7?!");
+ *tptr *= 8;
+ *tptr += (*cptr - '0');
+ ++cptr;
+ }
+ ++tptr;
+ } else {
+ warning(cptr, "unrecognized escape sequence");
+ }
+ }
+ } else {
+ *tptr++ = *cptr++;
+ }
+ }
+ *tptr = '\0';
+ return(msg);
+}
+
+static char *
+dupstr(const char *ostr)
+{
+ char *nstr;
+
+ nstr = strdup(ostr);
+ if (!nstr) error(NULL, "unable to allocate storage");
+ return(nstr);
+}
+
+/*
+ * The Global Stuff
+ */
+
+typedef struct _msgT {
+ long msgId;
+ char *str;
+ char *hconst;
+ long offset;
+ struct _msgT *prev, *next;
+} msgT;
+
+typedef struct _setT {
+ long setId;
+ char *hconst;
+ msgT *first, *last;
+ struct _setT *prev, *next;
+} setT;
+
+typedef struct {
+ setT *first, *last;
+} catT;
+
+static setT *curSet;
+static catT *cat;
+
+/*
+ * Find the current byte order. There are of course some others, but
+ * this will do for now. Note that all we care about is "long".
+ */
+long
+MCGetByteOrder(void) {
+ long l = 0x00010203;
+ char *cptr = (char *) &l;
+
+ if (cptr[0] == 0 && cptr[1] == 1 && cptr[2] == 2 && cptr[3] == 3)
+ return MC68KByteOrder;
+ else return MCn86ByteOrder;
+}
+
+void
+MCParse(int fd)
+{
+ char *cptr, *str;
+ int setid = 1, msgid = 0;
+ char hconst[MAXTOKEN+1];
+ char quote = 0;
+
+ if (!cat) {
+ cat = (catT *) malloc(sizeof(catT));
+ if (!cat) nomem();
+ bzero(cat, sizeof(catT));
+ }
+
+ hconst[0] = '\0';
+
+ while ((cptr = gencat_getline(fd)) != NULL) {
+ if (*cptr == '$') {
+ ++cptr;
+ if (strncmp(cptr, "set", 3) == 0) {
+ cptr += 3;
+ cptr = wskip(cptr);
+ setid = atoi(cptr);
+ cptr = cskip(cptr);
+ if (*cptr) cptr = wskip(cptr);
+ if (*cptr == '#') {
+ ++cptr;
+ MCAddSet(setid, token(cptr));
+ } else MCAddSet(setid, NULL);
+ msgid = 0;
+ } else if (strncmp(cptr, "delset", 6) == 0) {
+ cptr += 6;
+ cptr = wskip(cptr);
+ setid = atoi(cptr);
+ MCDelSet(setid);
+ } else if (strncmp(cptr, "quote", 5) == 0) {
+ cptr += 5;
+ if (!*cptr) quote = 0;
+ else {
+ cptr = wskip(cptr);
+ if (!*cptr) quote = 0;
+ else quote = *cptr;
+ }
+ } else if (isspace((unsigned char)*cptr)) {
+ cptr = wskip(cptr);
+ if (*cptr == '#') {
+ ++cptr;
+ strcpy(hconst, token(cptr));
+ }
+ } else {
+ if (*cptr) {
+ cptr = wskip(cptr);
+ if (*cptr) warning(cptr, "unrecognized line");
+ }
+ }
+ } else {
+ if (!curSet) MCAddSet(setid, NULL);
+ if (isdigit((unsigned char)*cptr) || *cptr == '#') {
+ if (*cptr == '#') {
+ ++msgid;
+ ++cptr;
+ if (!*cptr) {
+ MCAddMsg(msgid, "", hconst);
+ hconst[0] = '\0';
+ continue;
+ }
+ if (!isspace((unsigned char)*cptr)) warning(cptr, "expected a space");
+ ++cptr;
+ if (!*cptr) {
+ MCAddMsg(msgid, "", hconst);
+ hconst[0] = '\0';
+ continue;
+ }
+ } else {
+ msgid = atoi(cptr);
+ cptr = cskip(cptr);
+ if (isspace(*cptr))
+ cptr++;
+ /* if (*cptr) ++cptr; */
+ }
+ if (!*cptr) {
+ if (isspace(cptr[-1])) {
+ MCAddMsg(msgid, "", hconst);
+ hconst[0] = '\0';
+ } else {
+ MCDelMsg(msgid);
+ }
+ } else {
+ str = getmsg(fd, cptr, quote);
+ MCAddMsg(msgid, str, hconst);
+ hconst[0] = '\0';
+ }
+ }
+ }
+ }
+}
+
+void
+MCReadCat(int fd)
+{
+ MCHeaderT mcHead;
+ MCMsgT mcMsg;
+ MCSetT mcSet;
+ msgT *msg;
+ setT *set;
+ int i;
+ char *data;
+
+ cat = (catT *) malloc(sizeof(catT));
+ if (!cat) nomem();
+ bzero(cat, sizeof(catT));
+
+ /* While we deal with read/write this in network byte order we do NOT
+ deal with struct member padding issues, or even sizeof(long) issues,
+ those are left for a future genneration to curse either me, or the
+ original author for */
+
+ if (read(fd, &mcHead, sizeof(mcHead)) != sizeof(mcHead)) corrupt();
+ if (strncmp(mcHead.magic, MCMagic, MCMagicLen) != 0) corrupt();
+ if (ntohl(mcHead.majorVer) != MCMajorVer) error(NULL, "unrecognized catalog version");
+ if ((ntohl(mcHead.flags) & MC68KByteOrder) == 0) error(NULL, "wrong byte order");
+
+ if (lseek(fd, ntohll(mcHead.firstSet), L_SET) == -1) corrupt();
+
+ while (TRUE) {
+ if (read(fd, &mcSet, sizeof(mcSet)) != sizeof(mcSet)) corrupt();
+ if (mcSet.invalid) continue;
+
+ set = (setT *) malloc(sizeof(setT));
+ if (!set) nomem();
+ bzero(set, sizeof(*set));
+ if (cat->first) {
+ cat->last->next = set;
+ set->prev = cat->last;
+ cat->last = set;
+ } else cat->first = cat->last = set;
+
+ set->setId = ntohl(mcSet.setId);
+
+ /* Get the data */
+ if (mcSet.dataLen) {
+ data = (char *) malloc((size_t)ntohl(mcSet.dataLen));
+ if (!data) nomem();
+ if (lseek(fd, ntohll(mcSet.data.off), L_SET) == -1) corrupt();
+ if (read(fd, data, (size_t)ntohl(mcSet.dataLen)) != ntohl(mcSet.dataLen)) corrupt();
+ if (lseek(fd, ntohll(mcSet.u.firstMsg), L_SET) == -1) corrupt();
+
+ for (i = 0; i < ntohl(mcSet.numMsgs); ++i) {
+ if (read(fd, &mcMsg, sizeof(mcMsg)) != sizeof(mcMsg)) corrupt();
+ if (mcMsg.invalid) {
+ --i;
+ continue;
+ }
+
+ msg = (msgT *) malloc(sizeof(msgT));
+ if (!msg) nomem();
+ bzero(msg, sizeof(*msg));
+ if (set->first) {
+ set->last->next = msg;
+ msg->prev = set->last;
+ set->last = msg;
+ } else set->first = set->last = msg;
+
+ msg->msgId = ntohl(mcMsg.msgId);
+ msg->str = dupstr((char *) (data + ntohll(mcMsg.msg.off)));
+ }
+ free(data);
+ }
+ if (!mcSet.nextSet) break;
+ if (lseek(fd, ntohll(mcSet.nextSet), L_SET) == -1) corrupt();
+ }
+}
+
+
+static void
+printS(int fd, const char *str)
+{
+ if (str)
+ write(fd, str, strlen(str));
+}
+
+static void
+printL(int fd, long l)
+{
+ char buf[32];
+ sprintf(buf, "%ld", l);
+ write(fd, buf, strlen(buf));
+}
+
+static void
+printLX(int fd, long l)
+{
+ char buf[32];
+ sprintf(buf, "%lx", l);
+ write(fd, buf, strlen(buf));
+}
+
+static void
+genconst(int fd, int type, char *setConst, char *msgConst, long val)
+{
+ switch (type) {
+ case MCLangC:
+ if (!msgConst) {
+ printS(fd, "\n#define ");
+ printS(fd, setConst);
+ printS(fd, "Set");
+ } else {
+ printS(fd, "#define ");
+ printS(fd, setConst);
+ printS(fd, msgConst);
+ }
+ printS(fd, "\t0x");
+ printLX(fd, val);
+ printS(fd, "\n");
+ break;
+ case MCLangCPlusPlus:
+ case MCLangANSIC:
+ if (!msgConst) {
+ printS(fd, "\nconst long ");
+ printS(fd, setConst);
+ printS(fd, "Set");
+ } else {
+ printS(fd, "const long ");
+ printS(fd, setConst);
+ printS(fd, msgConst);
+ }
+ printS(fd, "\t= ");
+ printL(fd, val);
+ printS(fd, ";\n");
+ break;
+ default:
+ error(NULL, "not a recognized (programming) language type");
+ }
+}
+
+void
+MCWriteConst(int fd, int type, int orConsts)
+{
+ msgT *msg;
+ setT *set;
+ long id;
+
+ if (orConsts && (type == MCLangC || type == MCLangCPlusPlus || type == MCLangANSIC)) {
+ printS(fd, "/* Use these Macros to compose and decompose setId's and msgId's */\n");
+ printS(fd, "#ifndef MCMakeId\n");
+ printS(fd, "# define MCMakeId(s,m)\t(unsigned long)(((unsigned short)s<<(sizeof(short)*8))\\\n");
+ printS(fd, "\t\t\t\t\t|(unsigned short)m)\n");
+ printS(fd, "# define MCSetId(id)\t(unsigned int) (id >> (sizeof(short) * 8))\n");
+ printS(fd, "# define MCMsgId(id)\t(unsigned int) ((id << (sizeof(short) * 8))\\\n");
+ printS(fd, "\t\t\t\t\t>> (sizeof(short) * 8))\n");
+ printS(fd, "#endif\n");
+ }
+
+ for (set = cat->first; set; set = set->next) {
+ if (set->hconst) genconst(fd, type, set->hconst, NULL, set->setId);
+
+ for (msg = set->first; msg; msg = msg->next) {
+ if (msg->hconst) {
+ if (orConsts) id = MCMakeId(set->setId, msg->msgId);
+ else id = msg->msgId;
+ genconst(fd, type, set->hconst, msg->hconst, id);
+ free(msg->hconst);
+ msg->hconst = NULL;
+ }
+ }
+ if (set->hconst) {
+ free(set->hconst);
+ set->hconst = NULL;
+ }
+ }
+}
+
+void
+MCWriteCat(int fd)
+{
+ MCHeaderT mcHead;
+ int cnt;
+ setT *set;
+ msgT *msg;
+ MCSetT mcSet;
+ MCMsgT mcMsg;
+ off_t pos;
+
+ bcopy(MCMagic, mcHead.magic, MCMagicLen);
+ mcHead.majorVer = htonl(MCMajorVer);
+ mcHead.minorVer = htonl(MCMinorVer);
+ mcHead.flags = htonl(MC68KByteOrder);
+ mcHead.firstSet = 0; /* We'll be back to set this in a minute */
+
+ if (cat == NULL)
+ error(NULL, "cannot write empty catalog set");
+
+ for (cnt = 0, set = cat->first; set; set = set->next) ++cnt;
+ mcHead.numSets = htonl(cnt);
+
+ /* I'm not inclined to mess with it, but it looks odd that we write
+ the header twice...and that we get the firstSet value from another
+ lseek rather then just 'sizeof(mcHead)' */
+
+ /* Also, this code doesn't seem to check returns from write! */
+
+ lseek(fd, (off_t)0L, L_SET);
+ write(fd, &mcHead, sizeof(mcHead));
+ mcHead.firstSet = htonll(lseek(fd, (off_t)0L, L_INCR));
+ lseek(fd, (off_t)0L, L_SET);
+ write(fd, &mcHead, sizeof(mcHead));
+
+ for (set = cat->first; set; set = set->next) {
+ bzero(&mcSet, sizeof(mcSet));
+
+ mcSet.setId = htonl(set->setId);
+ mcSet.invalid = FALSE;
+
+ /* The rest we'll have to come back and change in a moment */
+ pos = lseek(fd, (off_t)0L, L_INCR);
+ write(fd, &mcSet, sizeof(mcSet));
+
+ /* Now write all the string data */
+ mcSet.data.off = htonll(lseek(fd, (off_t)0L, L_INCR));
+ cnt = 0;
+ for (msg = set->first; msg; msg = msg->next) {
+ msg->offset = lseek(fd, (off_t)0L, L_INCR) - ntohll(mcSet.data.off);
+ mcSet.dataLen += write(fd, msg->str, strlen(msg->str) + 1);
+ ++cnt;
+ }
+ mcSet.u.firstMsg = htonll(lseek(fd, (off_t)0L, L_INCR));
+ mcSet.numMsgs = htonl(cnt);
+ mcSet.dataLen = htonl(mcSet.dataLen);
+
+ /* Now write the message headers */
+ for (msg = set->first; msg; msg = msg->next) {
+ mcMsg.msgId = htonl(msg->msgId);
+ mcMsg.msg.off = htonll(msg->offset);
+ mcMsg.invalid = FALSE;
+ write(fd, &mcMsg, sizeof(mcMsg));
+ }
+
+ /* Go back and fix things up */
+
+ if (set == cat->last) {
+ mcSet.nextSet = 0;
+ lseek(fd, pos, L_SET);
+ write(fd, &mcSet, sizeof(mcSet));
+ } else {
+ mcSet.nextSet = htonll(lseek(fd, (off_t)0L, L_INCR));
+ lseek(fd, pos, L_SET);
+ write(fd, &mcSet, sizeof(mcSet));
+ lseek(fd, ntohll(mcSet.nextSet), L_SET);
+ }
+ }
+}
+
+void
+MCAddSet(int setId, char *hconst)
+{
+ setT *set;
+
+ if (setId <= 0) {
+ error(NULL, "setId's must be greater than zero");
+ return;
+ }
+
+ if (hconst && !*hconst) hconst = NULL;
+ for (set = cat->first; set; set = set->next) {
+ if (set->setId == setId) {
+ if (set->hconst && hconst) free(set->hconst);
+ set->hconst = NULL;
+ break;
+ } else if (set->setId > setId) {
+ setT *newSet;
+
+ newSet = (setT *) malloc(sizeof(setT));
+ if (!newSet) nomem();
+ bzero(newSet, sizeof(setT));
+ newSet->prev = set->prev;
+ newSet->next = set;
+ if (set->prev) set->prev->next = newSet;
+ else cat->first = newSet;
+ set->prev = newSet;
+ set = newSet;
+ break;
+ }
+ }
+ if (!set) {
+ set = (setT *) malloc(sizeof(setT));
+ if (!set) nomem();
+ bzero(set, sizeof(setT));
+
+ if (cat->first) {
+ set->prev = cat->last;
+ set->next = NULL;
+ cat->last->next = set;
+ cat->last = set;
+ } else {
+ set->prev = set->next = NULL;
+ cat->first = cat->last = set;
+ }
+ }
+ set->setId = setId;
+ if (hconst) set->hconst = dupstr(hconst);
+ curSet = set;
+}
+
+void
+MCAddMsg(int msgId, const char *str, char *hconst)
+{
+ msgT *msg;
+
+ if (!curSet)
+ error(NULL, "can't specify a message when no set exists");
+
+ if (msgId <= 0) {
+ error(NULL, "msgId's must be greater than zero");
+ return;
+ }
+
+ if (hconst && !*hconst) hconst = NULL;
+ for (msg = curSet->first; msg; msg = msg->next) {
+ if (msg->msgId == msgId) {
+ if (msg->hconst && hconst) free(msg->hconst);
+ if (msg->str) free(msg->str);
+ msg->hconst = msg->str = NULL;
+ break;
+ } else if (msg->msgId > msgId) {
+ msgT *newMsg;
+
+ newMsg = (msgT *) malloc(sizeof(msgT));
+ if (!newMsg) nomem();
+ bzero(newMsg, sizeof(msgT));
+ newMsg->prev = msg->prev;
+ newMsg->next = msg;
+ if (msg->prev) msg->prev->next = newMsg;
+ else curSet->first = newMsg;
+ msg->prev = newMsg;
+ msg = newMsg;
+ break;
+ }
+ }
+ if (!msg) {
+ msg = (msgT *) malloc(sizeof(msgT));
+ if (!msg) nomem();
+ bzero(msg, sizeof(msgT));
+
+ if (curSet->first) {
+ msg->prev = curSet->last;
+ msg->next = NULL;
+ curSet->last->next = msg;
+ curSet->last = msg;
+ } else {
+ msg->prev = msg->next = NULL;
+ curSet->first = curSet->last = msg;
+ }
+ }
+ msg->msgId = msgId;
+ if (hconst) msg->hconst = dupstr(hconst);
+ msg->str = dupstr(str);
+}
+
+void
+MCDelSet(int setId)
+{
+ setT *set;
+ msgT *msg;
+
+ for (set = cat->first; set; set = set->next) {
+ if (set->setId == setId) {
+ for (msg = set->first; msg; msg = msg->next) {
+ if (msg->hconst) free(msg->hconst);
+ if (msg->str) free(msg->str);
+ free(msg);
+ }
+ if (set->hconst) free(set->hconst);
+
+ if (set->prev) set->prev->next = set->next;
+ else cat->first = set->next;
+
+ if (set->next) set->next->prev = set->prev;
+ else cat->last = set->prev;
+
+ free(set);
+ return;
+ } else if (set->setId > setId) break;
+ }
+ warning(NULL, "specified set doesn't exist");
+}
+
+void
+MCDelMsg(int msgId)
+{
+ msgT *msg;
+
+ if (!curSet)
+ error(NULL, "you can't delete a message before defining the set");
+
+ for (msg = curSet->first; msg; msg = msg->next) {
+ if (msg->msgId == msgId) {
+ if (msg->hconst) free(msg->hconst);
+ if (msg->str) free(msg->str);
+
+ if (msg->prev) msg->prev->next = msg->next;
+ else curSet->first = msg->next;
+
+ if (msg->next) msg->next->prev = msg->prev;
+ else curSet->last = msg->prev;
+
+ free(msg);
+ return;
+ } else if (msg->msgId > msgId) break;
+ }
+ warning(NULL, "specified msg doesn't exist");
+}
+
+#if 0 /* this function is unsed and looks like debug thing */
+
+void
+MCDumpcat(fp)
+FILE *fp;
+{
+ msgT *msg;
+ setT *set;
+
+ if (!cat)
+ errx(1, "no catalog open");
+
+ for (set = cat->first; set; set = set->next) {
+ fprintf(fp, "$set %ld", set->setId);
+ if (set->hconst)
+ fprintf(fp, " # %s", set->hconst);
+ fprintf(fp, "\n\n");
+
+ for (msg = set->first; msg; msg = msg->next) {
+ if (msg->hconst)
+ fprintf(fp, "# %s\n", msg->hconst);
+ fprintf(fp, "%ld\t%s\n", msg->msgId, msg->str);
+ }
+ fprintf(fp, "\n");
+ }
+
+}
+#endif /* 0 */
diff --git a/adv_cmds/last/last.1 b/adv_cmds/last/last.1
new file mode 100644
index 0000000..8ffd49d
--- /dev/null
+++ b/adv_cmds/last/last.1
@@ -0,0 +1,111 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" 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.
+.\"
+.\" @(#)last.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt LAST 1
+.Os BSD 4
+.Sh NAME
+.Nm last
+.Nd indicate last logins of users and ttys
+.Sh SYNOPSIS
+.Nm
+.Op Fl Ns Ar n
+.Op Fl h Ar host
+.Op Fl t Ar tty
+.Op user ...
+.Sh DESCRIPTION
+.Nm Last
+will list the sessions of specified
+.Ar users ,
+.Ar ttys ,
+and
+.Ar hosts ,
+in reverse time order. Each line of output contains
+the user name, the tty from which the session was conducted, any
+hostname, the start and stop times for the session, and the duration
+of the session. If the session is still continuing or was cut short by
+a crash or shutdown,
+.Nm
+will so indicate.
+.Pp
+.Bl -tag -width indent-two
+.It Fl Ns Ar n
+Limits the report to
+.Ar n
+lines.
+.It Fl h Ar host
+.Ar Host
+names may be names or internet numbers.
+.It Fl t Ar tty
+Specify the
+.Ar tty .
+Tty names may be given fully or abbreviated, for example,
+.Dq Li "last -t 03"
+is
+equivalent to
+.Dq Li "last -t tty03" .
+.El
+.Pp
+If
+multiple arguments are given, the information which applies to any of the
+arguments is printed, e.g.,
+.Dq Li "last root -t console"
+would list all of
+.Dq Li root Ns 's
+sessions as well as all sessions on the console terminal. If no
+users, hostnames or terminals are specified,
+.Nm
+prints a record of
+all logins and logouts.
+.Pp
+The pseudo-user
+.Ar reboot
+logs in at reboots of the system, thus
+.Dq Li last reboot
+will give an indication of mean time between reboot.
+.Pp
+If
+.Nm
+is interrupted, it indicates to what date the search has
+progressed. If interrupted with a quit signal
+.Nm
+indicates how
+far the search has progressed and then continues.
+.Sh SEE ALSO
+.Xr lastcomm 1 ,
+.Xr utmpx 5 ,
+.Xr ac 8
+.Sh HISTORY
+.Nm Last
+appeared in
+.Bx 3.0 .
diff --git a/adv_cmds/last/last.c b/adv_cmds/last/last.c
new file mode 100644
index 0000000..6439dd1
--- /dev/null
+++ b/adv_cmds/last/last.c
@@ -0,0 +1,419 @@
+/*
+ * Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved
+ *
+ * Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * The NEXTSTEP Software License Agreement specifies the terms
+ * and conditions for redistribution.
+ *
+ * @(#)last.c 8.2 (Berkeley) 4/2/94
+ */
+
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1987, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <tzfile.h>
+#include <unistd.h>
+#include <utmpx.h>
+#include <ctype.h>
+
+#define NO 0 /* false/no */
+#define YES 1 /* true/yes */
+
+static const struct utmpx *prev; /* previous utmpx structure */
+
+/* values from utmp.h, used for print formatting */
+#define UT_NAMESIZE 8 /* old utmp.h value */
+#define UT_LINESIZE 8
+#define UT_HOSTSIZE 16
+
+typedef struct arg {
+ const char *name; /* argument */
+#define HOST_TYPE -2
+#define TTY_TYPE -3
+#define USER_TYPE -4
+ int type; /* type of arg */
+ struct arg *next; /* linked list pointer */
+} ARG;
+ARG *arglist; /* head of linked list */
+
+typedef struct ttytab {
+ long logout; /* log out time */
+ char id[_UTX_IDSIZE]; /* terminal id */
+ pid_t pid;
+ struct ttytab *next; /* linked list pointer */
+} TTY;
+TTY *ttylist; /* head of linked list */
+
+static const char *crmsg; /* cause of last reboot */
+static long currentout, /* current logout value */
+ maxrec; /* records to display */
+time_t now;
+
+void addarg __P((int, const char *));
+TTY *addtty __P((const char *, pid_t));
+void hostconv __P((const char *));
+void onintr __P((int));
+const char *ttyconv __P((const char *));
+int want __P((struct utmpx *, int));
+void wtmp __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern int optind;
+ extern char *optarg;
+ int ch;
+ char *p;
+ char *myname = *argv;
+
+ if ((p = strrchr(myname, '/')) != NULL)
+ myname = p + 1;
+ maxrec = -1;
+ while ((ch = getopt(argc, argv, "0123456789f:h:t:")) != EOF)
+ switch (ch) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ /*
+ * kludge: last was originally designed to take
+ * a number after a dash.
+ */
+ if (maxrec == -1) {
+ p = argv[optind - 1];
+ if (p[0] == '-' && p[1] == ch && !p[2])
+ maxrec = atol(++p);
+ else
+ maxrec = atol(argv[optind] + 1);
+ if (!maxrec)
+ exit(0);
+ }
+ break;
+ case 'h':
+ hostconv(optarg);
+ addarg(HOST_TYPE, optarg);
+ break;
+ case 't':
+ addarg(TTY_TYPE, ttyconv(optarg));
+ break;
+ case 'f':
+ warnx("-f is unsupported");
+ break;
+ case '?':
+ default:
+ (void)fprintf(stderr,
+ "usage: last [-#] [-t tty] [-h hostname] [user ...]\n");
+ exit(1);
+ }
+
+ if (argc) {
+ setlinebuf(stdout);
+ for (argv += optind; *argv; ++argv) {
+#define COMPATIBILITY
+#ifdef COMPATIBILITY
+ /* code to allow "last p5" to work */
+ addarg(TTY_TYPE, ttyconv(*argv));
+#endif
+ addarg(USER_TYPE, *argv);
+ }
+ }
+ wtmp();
+ exit(0);
+}
+
+/*
+ * wtmp --
+ * read through the wtmp file
+ */
+
+void
+wtmp()
+{
+
+ struct utmpx *bp; /* current structure */
+ TTY *T; /* tty list entry */
+ long delta; /* time difference */
+ char *ct;
+
+ (void)time(&now);
+ (void)signal(SIGINT, onintr);
+ (void)signal(SIGQUIT, onintr);
+
+ setutxent_wtmp(0); /* zero means reverse chronological order */
+ while ((bp = getutxent_wtmp()) != NULL) {
+ prev = bp;
+ switch(bp->ut_type) {
+ case BOOT_TIME:
+ case SHUTDOWN_TIME:
+ /* everybody just logged out */
+ for (T = ttylist; T; T = T->next)
+ T->logout = -bp->ut_tv.tv_sec;
+ currentout = -bp->ut_tv.tv_sec;
+ crmsg = bp->ut_type == BOOT_TIME ? "crash" : "shutdown";
+ if (want(bp, NO)) {
+ ct = ctime(&bp->ut_tv.tv_sec);
+ printf("%-*s %-*s %-*.*s %10.10s %5.5s \n",
+ UT_NAMESIZE, bp->ut_type == BOOT_TIME ? "reboot" : "shutdown",
+ UT_LINESIZE, "~",
+ UT_HOSTSIZE, _UTX_HOSTSIZE,
+ bp->ut_host, ct, ct + 11);
+ if (maxrec != -1 && !--maxrec)
+ return;
+ }
+ continue;
+ case OLD_TIME:
+ case NEW_TIME:
+ if (want(bp, NO)) {
+ ct = ctime(&bp->ut_tv.tv_sec);
+ printf("%-*s %-*s %-*.*s %10.10s %5.5s \n",
+ UT_NAMESIZE, "date",
+ UT_LINESIZE, bp->ut_type == OLD_TIME ? "|" : "{",
+ UT_HOSTSIZE, _UTX_HOSTSIZE, bp->ut_host,
+ ct, ct + 11);
+ if (maxrec && !--maxrec)
+ return;
+ }
+ continue;
+ case USER_PROCESS:
+ case DEAD_PROCESS:
+ /* find associated tty */
+ for (T = ttylist;; T = T->next) {
+ if (!T) {
+ /* add new one */
+ T = addtty(bp->ut_id, bp->ut_pid);
+ break;
+ }
+ if (!memcmp(T->id, bp->ut_id, _UTX_IDSIZE) && T->pid == bp->ut_pid)
+ break;
+ }
+ if (bp->ut_type != DEAD_PROCESS && want(bp, YES)) {
+ ct = ctime(&bp->ut_tv.tv_sec);
+ printf("%-*.*s %-*.*s %-*.*s %10.10s %5.5s ",
+ UT_NAMESIZE, _UTX_USERSIZE, bp->ut_user,
+ UT_LINESIZE, _UTX_LINESIZE, bp->ut_line,
+ UT_HOSTSIZE, _UTX_HOSTSIZE, bp->ut_host,
+ ct, ct + 11);
+ if (!T->logout)
+ puts(" still logged in");
+ else {
+ if (T->logout < 0) {
+ T->logout = -T->logout;
+ printf("- %s", crmsg);
+ }
+ else
+ printf("- %5.5s",
+ ctime(&T->logout)+11);
+ delta = T->logout - bp->ut_tv.tv_sec;
+ if (delta < SECSPERDAY)
+ printf(" (%5.5s)\n",
+ asctime(gmtime(&delta))+11);
+ else
+ printf(" (%ld+%5.5s)\n",
+ delta / SECSPERDAY,
+ asctime(gmtime(&delta))+11);
+ }
+ if (maxrec != -1 && !--maxrec)
+ return;
+ }
+ T->logout = bp->ut_tv.tv_sec;
+ continue;
+ }
+ }
+ endutxent_wtmp();
+ ct = ctime(prev ? &prev->ut_tv.tv_sec : &now);
+ printf("\nwtmp begins %10.10s %5.5s \n", ct, ct + 11);
+}
+
+/*
+ * want --
+ * see if want this entry
+ */
+int
+want(bp, check)
+ struct utmpx *bp;
+ int check;
+{
+ ARG *step;
+
+ if (!arglist)
+ return (YES);
+
+ for (step = arglist; step; step = step->next)
+ switch(step->type) {
+ case HOST_TYPE:
+ if (!strncasecmp(step->name, bp->ut_host, _UTX_HOSTSIZE))
+ return (YES);
+ break;
+ case TTY_TYPE:
+ {
+ char *line = bp->ut_line;
+ if (check) {
+ /*
+ * when uucp and ftp log in over a network, the entry in
+ * the utmpx file is the name plus their process id. See
+ * etc/ftpd.c and usr.bin/uucp/uucpd.c for more information.
+ */
+ if (!strncmp(line, "ftp", sizeof("ftp") - 1))
+ line = "ftp";
+ else if (!strncmp(line, "uucp", sizeof("uucp") - 1))
+ line = "uucp";
+ }
+ if (!strncmp(step->name, line, _UTX_LINESIZE))
+ return (YES);
+ break;
+ }
+ case USER_TYPE:
+ if (bp->ut_type == BOOT_TIME && !strncmp(step->name, "reboot", _UTX_USERSIZE))
+ return (YES);
+ if (bp->ut_type == SHUTDOWN_TIME && !strncmp(step->name, "shutdown", _UTX_USERSIZE))
+ return (YES);
+ if (!strncmp(step->name, bp->ut_user, _UTX_USERSIZE))
+ return (YES);
+ break;
+ }
+ return (NO);
+}
+
+/*
+ * addarg --
+ * add an entry to a linked list of arguments
+ */
+void
+addarg(type, arg)
+ int type;
+ const char *arg;
+{
+ ARG *cur;
+
+ if (!(cur = (ARG *)malloc((u_int)sizeof(ARG))))
+ err(1, "malloc failure");
+ cur->next = arglist;
+ cur->type = type;
+ cur->name = arg;
+ arglist = cur;
+}
+
+/*
+ * addtty --
+ * add an entry to a linked list of ttys
+ */
+TTY *
+addtty(id, pid)
+ const char *id;
+ pid_t pid;
+{
+ TTY *cur;
+
+ if (!(cur = (TTY *)malloc((u_int)sizeof(TTY))))
+ err(1, "malloc failure");
+ cur->next = ttylist;
+ cur->logout = currentout;
+ memmove(cur->id, id, _UTX_IDSIZE);
+ cur->pid = pid;
+ return (ttylist = cur);
+}
+
+/*
+ * hostconv --
+ * convert the hostname to search pattern; if the supplied host name
+ * has a domain attached that is the same as the current domain, rip
+ * off the domain suffix since that's what login(1) does.
+ */
+void
+hostconv(arg)
+ const char *arg;
+{
+ static int first = 1;
+ static char *hostdot, name[MAXHOSTNAMELEN];
+ char *argdot;
+
+ if (!(argdot = strchr(arg, '.')))
+ return;
+ if (first) {
+ first = 0;
+ if (gethostname(name, sizeof(name)))
+ err(1, "gethostname");
+ hostdot = strchr(name, '.');
+ }
+ if (hostdot && !strcasecmp(hostdot, argdot))
+ *argdot = '\0';
+}
+
+/*
+ * ttyconv --
+ * convert tty to correct name.
+ */
+const char *
+ttyconv(arg)
+ const char *arg;
+{
+ char *mval;
+ int kludge = 0;
+ int len = strlen(arg);
+
+ /*
+ * kludge -- we assume that most tty's end with
+ * a two character suffix.
+ */
+ if (len == 2)
+ kludge = 8; /* either 6 for "ttyxx" or 8 for "console"; use largest */
+ /*
+ * kludge -- we assume cloning ptys names are "ttys" followed by
+ * more than one digit
+ */
+ else if (len > 2 && *arg == 's') {
+ const char *cp = arg + 1;
+ while(*cp && isdigit(*cp))
+ cp++;
+ if (*cp == 0)
+ kludge = len + sizeof("tty");
+ }
+ if (kludge) {
+ if (!(mval = malloc(kludge)))
+ err(1, "malloc failure");
+ if (!strcmp(arg, "co"))
+ (void)strcpy(mval, "console");
+ else {
+ (void)strcpy(mval, "tty");
+ (void)strcpy(mval + sizeof("tty") - 1, arg);
+ }
+ return (mval);
+ }
+ if (!strncmp(arg, _PATH_DEV, sizeof(_PATH_DEV) - 1))
+ return (arg + sizeof(_PATH_DEV) - 1);
+ return (arg);
+}
+
+/*
+ * onintr --
+ * on interrupt, we inform the user how far we've gotten
+ */
+void
+onintr(signo)
+ int signo;
+{
+ char *ct;
+
+ ct = ctime(prev ? &prev->ut_tv.tv_sec : &now);
+ printf("\ninterrupted %10.10s %5.5s \n", ct, ct + 11);
+ if (signo == SIGINT)
+ exit(1);
+ (void)fflush(stdout); /* fix required for rsh */
+}
diff --git a/adv_cmds/locale/locale.1 b/adv_cmds/locale/locale.1
new file mode 100644
index 0000000..e4df365
--- /dev/null
+++ b/adv_cmds/locale/locale.1
@@ -0,0 +1,101 @@
+.\"Modified from man(1) of FreeBSD, the NetBSD mdoc.template, and mdoc.samples.
+.\"See Also:
+.\"man mdoc.samples for a complete listing of options
+.\"man mdoc for the short list of editing options
+.\"/usr/share/misc/mdoc.template
+.Dd August 27, 2004
+.Dt LOCALE 1
+.Os Darwin
+.Sh NAME
+.Nm locale
+.Nd display locale settings
+.Sh SYNOPSIS
+.Nm
+.Op Fl a|m
+.Nm
+.Op Fl ck
+.Ar name
+.Op ...
+.Sh DESCRIPTION
+.Nm
+displays information about the current locale, or a list of all available
+locales.
+.Pp
+When
+.Nm
+is run with no arguments,
+it will display the current source of each locale category.
+.Pp
+When
+.Nm
+is given the name of a category,
+it acts as if it had been given each keyword in that category.
+For each keyword it is given, the current value
+is displayed.
+.Sh OPTIONS
+.Bl -tag -width -indent
+.It Fl a
+Lists all public locales.
+.It Fl c Ar name ...
+Lists the category name before each keyword,
+unless it is the same category as the previously displayed keyword.
+.It Fl k Ar name ...
+Displays the name of each keyword prior to its value.
+.It Fl m
+Lists all available public charmaps.
+Darwin locales do not support charmaps, so list all CODESETs instead.
+.El
+.Pp
+.Sh OPERANDS
+The following operand is supported:
+.Pp
+.Ar name
+is the name of a keyword or category to display. A list of all keywords
+and categories can be shown with the following command:
+.Bd -literal
+locale -ck LC_ALL
+.Ed
+.Pp
+.Sh ENVIRONMENT
+.Bl -tag -width "LC_MESSAGES"
+.It Ev LANG
+Used as a substitute for any unset
+.Ev LC_*
+variable. If
+.Ev LANG
+is unset, it will act as if set to "C". If any of
+.Ev LANG
+or
+.Ev LC_*
+are set to invalid values,
+.Nm
+acts as if they are all unset.
+.It Ev LC_ALL
+Will override the setting of all other
+.Ev LC_*
+variables.
+.It Ev LC_COLLATE
+Sets the locale for the LC_COLLATE category.
+.It Ev LC_CTYPE
+Sets the locale for the LC_CTYPE category.
+.It Ev LC_MESSAGES
+Sets the locale for the LC_MESSAGES category.
+.It Ev LC_MONETARY
+Sets the locale for the LC_MONETARY category.
+.It Ev LC_NUMERIC
+Sets the locale for the LC_NUMERIC category.
+.It Ev LC_TIME
+Sets the locale for the LC_TIME category.
+.El
+.Sh SEE ALSO
+.Xr localedef 1 ,
+.Xr localeconv 3 ,
+.Xr nl_langinfo 3 ,
+.Xr setlocale 3
+.Sh STANDARDS
+The
+.Nm
+utility conforms to IEEE Std 1003.1-2001 (``POSIX.1'').
+.Sh HISTORY
+.Nm
+appeared in Mac OS X 10.4
diff --git a/adv_cmds/locale/locale.cc b/adv_cmds/locale/locale.cc
new file mode 100644
index 0000000..88c7784
--- /dev/null
+++ b/adv_cmds/locale/locale.cc
@@ -0,0 +1,428 @@
+#include <iostream>
+#include <sstream>
+#include <map>
+#include <set>
+#include <vector>
+#include <algorithm>
+
+#include <unistd.h>
+#include <langinfo.h>
+#include <locale.h>
+#include <xlocale.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#define LAST(array) array + (sizeof(array) / sizeof(*array))
+
+#define LC_SPECIAL (LC_COLLATE+LC_CTYPE+LC_MESSAGES+LC_MONETARY+LC_NUMERIC+LC_TIME)
+
+using namespace std;
+
+enum vtype {
+ V_STR, V_NUM
+};
+
+template<typename T> string tostr(T val) {
+ ostringstream ss;
+ ss << val;
+ return ss.str();
+}
+
+string quote(string s) {
+ return '"' + s + '"';
+}
+
+class keyword {
+ public:
+ virtual string get_category() const { return category; }
+ virtual string get_keyword() const { return kword; }
+ virtual string get_value(bool show_quotes) const {
+ return (show_quotes && t == V_STR) ? quote(value) : value; }
+
+ virtual ~keyword() { }
+ protected:
+ keyword(int category_, string kword, string value, vtype t)
+ : kword(kword), value(value), t(t) {
+ switch(category_) {
+ case LC_COLLATE:
+ category = "LC_COLLATE";
+ break;
+ case LC_CTYPE:
+ category = "LC_CTYPE";
+ break;
+ case LC_MESSAGES:
+ category = "LC_MESSAGES";
+ break;
+ case LC_MONETARY:
+ category = "LC_MONETARY";
+ break;
+ case LC_NUMERIC:
+ category = "LC_NUMERIC";
+ break;
+ case LC_TIME:
+ category = "LC_TIME";
+ break;
+ case LC_SPECIAL:
+ category = "LC_SPECIAL";
+ break;
+ default:
+ {
+ ostringstream lc;
+ lc << "LC_" << category_;
+ category = lc.str();
+ }
+ break;
+ }
+ }
+
+ string category, kword, value;
+ vtype t;
+};
+
+struct keyword_cmp {
+ bool operator()(const keyword *a, const keyword *b) const {
+ return a->get_category() < b->get_category();
+ }
+};
+
+class li_keyword : public keyword {
+ public:
+ li_keyword(int category, string kword, int itemnum, vtype t = V_STR)
+ : keyword(category, kword, nl_langinfo(itemnum), t) { }
+};
+
+class lia_keyword : public keyword {
+ protected:
+ vector<string> values;
+ public:
+ virtual string get_value(bool show_quotes) const {
+ ostringstream ss;
+ vector<string>::const_iterator s(values.begin()), e(values.end()), i(s);
+
+ for(; i < e; ++i) {
+ if (i != s) {
+ ss << ';';
+ }
+ if (show_quotes && t == V_STR) {
+ ss << quote(*i);
+ } else {
+ ss << *i;
+ }
+ }
+
+ return ss.str();
+ }
+
+ lia_keyword(int category, string kword, int *s, int *e, vtype t = V_STR)
+ : keyword(category, kword, "", t) {
+ for(; s < e; ++s) {
+ values.push_back(nl_langinfo(*s));
+ }
+ }
+};
+
+class lc_keyword : public keyword {
+ public:
+ lc_keyword(int category, string kword, string value, vtype t = V_STR)
+ : keyword(category, kword, value, t) { }
+};
+
+void usage(char *argv0) {
+ clog << "usage: " << argv0 << "[-a|-m]\n or: "
+ << argv0 << " [-cCk] name..." << endl;
+}
+
+void list_all_valid_locales() {
+ string locale_dir("/usr/share/locale");
+ bool found_C = false, found_POSIX = false;
+ DIR *d = opendir(locale_dir.c_str());
+ struct dirent *de;
+ static string expected[] = { "LC_COLLATE", "LC_CTYPE", "LC_MESSAGES",
+ "LC_NUMERIC", "LC_TIME" };
+
+ for(de = readdir(d); de; de = readdir(d)) {
+ string lname(de->d_name, de->d_namlen);
+ string ldir(locale_dir + "/" + lname);
+ int cnt = 0;
+ DIR *ld = opendir(ldir.c_str());
+ if (ld) {
+ struct dirent *lde;
+ for(lde = readdir(ld); lde; lde = readdir(ld)) {
+ string fname(lde->d_name, lde->d_namlen);
+ if (LAST(expected) != find(expected, LAST(expected), fname)) {
+ cnt++;
+ }
+ }
+ closedir(ld);
+
+ if (cnt == LAST(expected) - expected) {
+ cout << lname << endl;
+ if (lname == "C") {
+ found_C = true;
+ }
+ if (lname == "POSIX") {
+ found_POSIX = true;
+ }
+ }
+ }
+ }
+ closedir(d);
+ if (!found_C) {
+ cout << "C" << endl;
+ }
+ if (!found_POSIX) {
+ cout << "POSIX" << endl;
+ }
+}
+
+void show_all_unique_codesets() {
+ string locale_dir("/usr/share/locale");
+ DIR *d = opendir(locale_dir.c_str());
+ struct dirent *de;
+ static string expected[] = { "LC_COLLATE", "LC_CTYPE", "LC_MESSAGES",
+ "LC_NUMERIC", "LC_TIME" };
+ set<string> codesets;
+ for(de = readdir(d); de; de = readdir(d)) {
+ string lname(de->d_name, de->d_namlen);
+ string ldir(locale_dir + "/" + lname);
+ int cnt = 0;
+ DIR *ld = opendir(ldir.c_str());
+ if (ld) {
+ struct dirent *lde;
+ for(lde = readdir(ld); lde; lde = readdir(ld)) {
+ string fname(lde->d_name, lde->d_namlen);
+ if (LAST(expected) != find(expected, LAST(expected), fname)) {
+ cnt++;
+ }
+ }
+ closedir(ld);
+
+ if (cnt == LAST(expected) - expected) {
+ locale_t xloc = newlocale(LC_ALL_MASK, lname.c_str(), NULL);
+ if (xloc) {
+ char *cs = nl_langinfo_l(CODESET, xloc);
+ if (cs && *cs && (codesets.find(cs) == codesets.end())) {
+ cout << cs << endl;
+ codesets.insert(cs);
+ }
+ freelocale(xloc);
+ }
+ }
+ }
+ }
+ closedir(d);
+}
+
+typedef map<string, keyword *> keywords_t;
+keywords_t keywords;
+
+typedef map<string, vector<keyword *> > catorgies_t;
+catorgies_t catoriges;
+
+void add_kw(keyword *k) {
+ keywords.insert(make_pair(k->get_keyword(), k));
+ catorgies_t::iterator c = catoriges.find(k->get_category());
+ if (c != catoriges.end()) {
+ c->second.push_back(k);
+ } else {
+ vector<keyword *> v;
+ v.push_back(k);
+ catoriges.insert(make_pair(k->get_category(), v));
+ }
+}
+
+string grouping(char *g) {
+ ostringstream ss;
+ if (*g == 0) {
+ ss << "0";
+ } else {
+ ss << static_cast<int>(*g);
+ while(*++g) {
+ ss << ";" << static_cast<int>(*g);
+ }
+ }
+ return ss.str();
+}
+
+void init_keywords() {
+ struct lconv *lc = localeconv();
+ if (lc) {
+ add_kw(new lc_keyword(LC_NUMERIC, "decimal_point", lc->decimal_point));
+ add_kw(new lc_keyword(LC_NUMERIC, "thousands_sep", lc->thousands_sep));
+ add_kw(new lc_keyword(LC_NUMERIC, "grouping", grouping(lc->grouping)));
+ add_kw(new lc_keyword(LC_MONETARY, "int_curr_symbol", lc->int_curr_symbol));
+ add_kw(new lc_keyword(LC_MONETARY, "currency_symbol", lc->currency_symbol));
+ add_kw(new lc_keyword(LC_MONETARY, "mon_decimal_point", lc->mon_decimal_point));
+ add_kw(new lc_keyword(LC_MONETARY, "mon_thousands_sep", lc->mon_thousands_sep));
+ add_kw(new lc_keyword(LC_MONETARY, "mon_grouping", grouping(lc->mon_grouping)));
+ add_kw(new lc_keyword(LC_MONETARY, "positive_sign", lc->positive_sign));
+ add_kw(new lc_keyword(LC_MONETARY, "negative_sign", lc->negative_sign));
+ add_kw(new lc_keyword(LC_MONETARY, "int_frac_digits", tostr((int)lc->int_frac_digits), V_NUM));
+ add_kw(new lc_keyword(LC_MONETARY, "frac_digits", tostr((int)lc->frac_digits), V_NUM));
+ add_kw(new lc_keyword(LC_MONETARY, "p_cs_precedes", tostr((int)lc->p_cs_precedes), V_NUM));
+ add_kw(new lc_keyword(LC_MONETARY, "p_sep_by_space", tostr((int)lc->p_sep_by_space), V_NUM));
+ add_kw(new lc_keyword(LC_MONETARY, "n_cs_precedes", tostr((int)lc->n_cs_precedes), V_NUM));
+ add_kw(new lc_keyword(LC_MONETARY, "n_sep_by_space", tostr((int)lc->n_sep_by_space), V_NUM));
+ add_kw(new lc_keyword(LC_MONETARY, "p_sign_posn", tostr((int)lc->p_sign_posn), V_NUM));
+ add_kw(new lc_keyword(LC_MONETARY, "n_sign_posn", tostr((int)lc->n_sign_posn), V_NUM));
+ add_kw(new lc_keyword(LC_MONETARY, "int_p_cs_precedes", tostr((int)lc->int_p_cs_precedes), V_NUM));
+ add_kw(new lc_keyword(LC_MONETARY, "int_n_cs_precedes", tostr((int)lc->int_n_cs_precedes), V_NUM));
+ add_kw(new lc_keyword(LC_MONETARY, "int_p_sep_by_space", tostr((int)lc->int_p_sep_by_space), V_NUM));
+ add_kw(new lc_keyword(LC_MONETARY, "int_n_sep_by_space", tostr((int)lc->int_n_sep_by_space), V_NUM));
+ add_kw(new lc_keyword(LC_MONETARY, "int_p_sign_posn", tostr((int)lc->int_p_sign_posn), V_NUM));
+ add_kw(new lc_keyword(LC_MONETARY, "int_n_sign_posn", tostr((int)lc->int_n_sign_posn), V_NUM));
+ }
+
+ int abdays[] = {ABDAY_1, ABDAY_2, ABDAY_3, ABDAY_4, ABDAY_5, ABDAY_6, ABDAY_7};
+ add_kw(new lia_keyword(LC_TIME, "ab_day", abdays, LAST(abdays)));
+ add_kw(new lia_keyword(LC_TIME, "abday", abdays, LAST(abdays)));
+
+ int days[] = {DAY_1, DAY_2, DAY_3, DAY_4, DAY_5, DAY_6, DAY_7};
+ add_kw(new lia_keyword(LC_TIME, "day", days, LAST(days)));
+
+ int abmons[] = {ABMON_1, ABMON_2, ABMON_3, ABMON_4, ABMON_5, ABMON_6, ABMON_7, ABMON_8, ABMON_9, ABMON_10, ABMON_11, ABMON_12};
+ add_kw(new lia_keyword(LC_TIME, "abmon", abmons, LAST(abmons)));
+
+ int mons[] = {MON_1, MON_2, MON_3, MON_4, MON_5, MON_6, MON_7, MON_8, MON_9, MON_10, MON_11, MON_12};
+ add_kw(new lia_keyword(LC_TIME, "mon", mons, LAST(mons)));
+
+ int am_pms[] = {AM_STR, PM_STR};
+ add_kw(new lia_keyword(LC_TIME, "am_pm", am_pms, LAST(am_pms)));
+
+ add_kw(new li_keyword(LC_TIME, "t_fmt_ampm", T_FMT_AMPM));
+ add_kw(new li_keyword(LC_TIME, "era", ERA));
+ add_kw(new li_keyword(LC_TIME, "era_d_fmt", ERA_D_FMT));
+ add_kw(new li_keyword(LC_TIME, "era_t_fmt", ERA_T_FMT));
+ add_kw(new li_keyword(LC_TIME, "era_d_t_fmt", ERA_D_T_FMT));
+ add_kw(new li_keyword(LC_TIME, "alt_digits", ALT_DIGITS));
+
+ add_kw(new li_keyword(LC_TIME, "d_t_fmt", D_T_FMT));
+ add_kw(new li_keyword(LC_TIME, "d_fmt", D_FMT));
+ add_kw(new li_keyword(LC_TIME, "t_fmt", T_FMT));
+
+ add_kw(new li_keyword(LC_MESSAGES, "yesexpr", YESEXPR));
+ add_kw(new li_keyword(LC_MESSAGES, "noexpr", NOEXPR));
+ add_kw(new li_keyword(LC_MESSAGES, "yesstr", YESSTR));
+ add_kw(new li_keyword(LC_MESSAGES, "nostr", NOSTR));
+
+ add_kw(new li_keyword(LC_CTYPE, "charmap", CODESET));
+ add_kw(new lc_keyword(LC_SPECIAL, "categories", "LC_COLLATE LC_CTYPE LC_MESSAGES LC_MONETARY LC_NUMERIC LC_TIME"));
+
+ // add_kw: CRNCYSTR D_MD_ORDER CODESET RADIXCHAR THOUSEP
+}
+
+void show_keyword(string &last_cat, bool sw_categories, bool sw_keywords,
+ keyword *k) {
+ if (sw_categories && last_cat != k->get_category()) {
+ last_cat = k->get_category();
+ cout << last_cat << endl;
+ }
+ if (sw_keywords) {
+ cout << k->get_keyword() << "=";
+ }
+ cout << k->get_value(sw_keywords) << endl;
+}
+
+int main(int argc, char *argv[]) {
+ int sw;
+ bool sw_all_locales = false, sw_categories = false, sw_keywords = false,
+ sw_charmaps = false;
+
+ while(-1 != (sw = getopt(argc, argv, "ackm"))) {
+ switch(sw) {
+ case 'a':
+ sw_all_locales = true;
+ break;
+ case 'c':
+ sw_categories = true;
+ break;
+ case 'k':
+ sw_keywords = true;
+ break;
+ case 'm':
+ sw_charmaps = true;
+ break;
+ default:
+ usage(argv[0]);
+ exit(1);
+ }
+ }
+
+ if ((sw_all_locales && sw_charmaps)
+ || ((sw_all_locales || sw_charmaps) && (sw_keywords || sw_categories))
+ ) {
+ usage(argv[0]);
+ exit(1);
+ }
+
+ setlocale(LC_ALL, "");
+
+ if (!(sw_all_locales || sw_categories || sw_keywords || sw_charmaps)
+ && argc == optind) {
+ char *lang = getenv("LANG");
+ cout << "LANG=" << quote(lang ? lang : "") << endl;
+ cout << "LC_COLLATE=" << quote(setlocale(LC_COLLATE, NULL)) << endl;
+ cout << "LC_CTYPE=" << quote(setlocale(LC_CTYPE, NULL)) << endl;
+ cout << "LC_MESSAGES=" << quote(setlocale(LC_MESSAGES, NULL)) << endl;
+ cout << "LC_MONETARY=" << quote(setlocale(LC_MONETARY, NULL)) << endl;
+ cout << "LC_NUMERIC=" << quote(setlocale(LC_NUMERIC, NULL)) << endl;
+ cout << "LC_TIME=" << quote(setlocale(LC_TIME, NULL)) << endl;
+ if (getenv("LC_ALL")) {
+ cout << "LC_ALL=" << quote(setlocale(LC_ALL, NULL)) << endl;
+ } else {
+ cout << "LC_ALL=" << endl;
+ }
+
+ return 0;
+ }
+
+ if (sw_all_locales) {
+ list_all_valid_locales();
+ return 0;
+ }
+
+ if (sw_charmaps) {
+ show_all_unique_codesets();
+ return 0;
+ }
+
+ init_keywords();
+ string last_cat("");
+ int exit_val = 0;
+ for(int i = optind; i < argc; ++i) {
+ keywords_t::iterator ki = keywords.find(argv[i]);
+ if (ki != keywords.end()) {
+ show_keyword(last_cat, sw_categories, sw_keywords, ki->second);
+ } else {
+ catorgies_t::iterator ci = catoriges.find(argv[i]);
+ if (ci != catoriges.end()) {
+ vector<keyword *>::iterator vi(ci->second.begin()),
+ ve(ci->second.end());
+ for(; vi != ve; ++vi) {
+ show_keyword(last_cat, sw_categories, sw_keywords, *vi);
+ }
+ } else if (argv[i] == string("LC_ALL")) {
+ ki = keywords.begin();
+ keywords_t::iterator ke = keywords.end();
+ for(; ki != ke; ++ki) {
+ show_keyword(last_cat, sw_categories, sw_keywords, ki->second);
+ }
+ } else {
+ if (argv[i] == string("LC_CTYPE")
+ || argv[i] == string("LC_COLLATE")) {
+ // It would be nice to print a warning,
+ // but we aren't allowed (locale.ex test#14)
+ if (sw_categories) {
+ cout << argv[i] << endl;
+ }
+ } else {
+ clog << "unknown keyword "
+ << argv[i] << endl;
+ exit_val = 1;
+ }
+ }
+ }
+ }
+
+ return exit_val;
+}
diff --git a/adv_cmds/localedef/charmap.p-1 b/adv_cmds/localedef/charmap.p-1
new file mode 100644
index 0000000..3901dd9
--- /dev/null
+++ b/adv_cmds/localedef/charmap.p-1
@@ -0,0 +1,23 @@
+CHARMAP
+<space> \x20
+<dollar> \x24
+<A> \101
+<a> \141
+<A-acute> \346
+<a-acute> \365
+<A-grave> \300
+<a-grave> \366
+<b> \142
+<B> \102
+<C> \103
+<c> \143
+<c-cedilla> \347
+<d> \x64
+<E> \x65
+<H> \110
+<h> \150
+<eszet> \xb7
+<s> \x73
+<z> \x7a
+<e> \x65
+END CHARMAP
diff --git a/adv_cmds/localedef/charmap.p-2 b/adv_cmds/localedef/charmap.p-2
new file mode 100644
index 0000000..75a3fdf
--- /dev/null
+++ b/adv_cmds/localedef/charmap.p-2
@@ -0,0 +1,115 @@
+CHARMAP
+<NUL> \000
+<alert> \007
+<backspace> \010
+<tab> \011
+<newline> \012
+<vertical-tab> \013
+<form-feed> \014
+<carriage-return> \015
+<space> \040
+<exclamation-mark> \041
+<quotation-mark> \042
+<number-sign> \043
+<dollar-sign> \044
+<percent-sign> \045
+<ampersand> \046
+<apostrophe> \047
+<left-parenthesis> \050
+<right-parenthesis> \051
+<asterisk> \052
+<plus-sign> \053
+<comma> \054
+<hyphen> \055
+<hyphen-minus> \055
+<period> \056
+<full-stop> \056
+<slash> \057
+<solidus> \057
+<zero> \060
+<one> \061
+<two> \062
+<three> \063
+<four> \064
+<five> \065
+<six> \066
+<seven> \067
+<eight> \070
+<nine> \071
+<colon> \072
+<semicolon> \073
+<less-then-sign> \074
+<equals-sign> \075
+<greater-then-sign> \076
+<question-mark> \077
+<commercial-at> \100
+<A> \101
+<B> \102
+<C> \103
+<D> \104
+<E> \105
+<F> \106
+<G> \107
+<H> \110
+<I> \111
+<J> \112
+<K> \113
+<L> \114
+<M> \115
+<N> \116
+<O> \117
+<P> \120
+<Q> \121
+<R> \122
+<S> \123
+<T> \124
+<U> \125
+<V> \126
+<W> \127
+<X> \130
+<Y> \131
+<Z> \132
+<left-square-bracket> \133
+<backslash> \134
+<reverse-solidus> \134
+<right-square-bracket> \135
+<circumflex> \136
+<circumflex-accent> \136
+<underscore> \137
+<underline> \137
+<low-line> \137
+<grave-accent> \140
+<a> \141
+<b> \142
+<c> \143
+<d> \144
+<e> \145
+<f> \146
+<g> \147
+<h> \150
+<i> \151
+<j> \152
+<k> \153
+<l> \154
+<m> \155
+<n> \156
+<o> \157
+<p> \160
+<q> \161
+<r> \162
+<s> \163
+<t> \164
+<u> \165
+<v> \166
+<w> \167
+<x> \170
+<y> \171
+<z> \172
+<left-brace> \173
+<left-curly-bracket> \173
+<vertical-line> \174
+<right-brace> \175
+<right-curly-bracket> \175
+<tilde> \176
+<DEL> \177
+END CHARMAP
diff --git a/adv_cmds/localedef/charmap.test b/adv_cmds/localedef/charmap.test
new file mode 100644
index 0000000..fd40463
--- /dev/null
+++ b/adv_cmds/localedef/charmap.test
@@ -0,0 +1,38 @@
+CHARMAP
+<mb_cur_max> 2
+<mb_cur_min> 2
+
+<acute-accent> \047
+<grave-accent> \140
+
+<A> \x41
+<B> \102
+<C> C
+<D> \104
+<E> "E"
+<F> \d70
+
+<backslash> \\
+<double-E> "<E><E>"
+
+<A-grave> \x60\x41
+<A-acute> \x27\x41
+<a-grave> \x60\x61
+<a-acute> \x27\x61
+
+<j0101>...<j0104> \x12\x34
+END CHARMAP
+
+WIDTH
+<A>...<D> 1
+<j0101>...<j0104> 2
+<no-such-symbol> 27
+
+<A-grave> 2
+<A-acute> 2
+<a-grave> 2
+<a-acute> 2
+
+WIDTH_DEFAULT 1
+
+END WIDTH
diff --git a/adv_cmds/localedef/def.a55 b/adv_cmds/localedef/def.a55
new file mode 100644
index 0000000..386e1c1
--- /dev/null
+++ b/adv_cmds/localedef/def.a55
@@ -0,0 +1,6 @@
+LC_COLLATE
+order_start forward
+order_start forward;forward;forward
+<a>
+order_end
+END LC_COLLATE
diff --git a/adv_cmds/localedef/def.p-1 b/adv_cmds/localedef/def.p-1
new file mode 100644
index 0000000..adef476
--- /dev/null
+++ b/adv_cmds/localedef/def.p-1
@@ -0,0 +1,157 @@
+#
+LC_CTYPE
+lower <a>;<b>;<c>;<c-cedilla>;<d>;...;<z>
+upper A;B;C;C;...;Z
+space \x20;\x09;\x0a;\x0b;\x0c;\x0d
+blank \040;\011
+toupper (<a>,<A>);(b,B);(c,C);(c,C);(d,D);(z,Z)
+digit 3;2
+END LC_CTYPE
+#
+LC_COLLATE
+#
+# The following example of collation is based on the proposed
+# Canadian standard Z243.4.1-1990, "Canadian Alphanumeric
+# Ordering Standard For Character sets of CSA Z234.4 Standard".
+# (Other parts of this example locale definition file do not
+# purport to relate to Canada, or to any other real culture.)
+# The proposed standard defines a 4-weight collation, such that
+# in the first pass, characters are compared without regard to
+# case or accents; in second pass, backwards compare without
+# regard to case; in the third pass, forward compare without
+# regard to diacriticals. In the 3 first passes, non-alphabetic
+# characters are ignored; in the fourth pass, only special
+# characters are considered, such that "The string that has a
+# special character in the lowest position comes first. If two
+# strings have a special character in the same position, the
+# collation value of the special character determines ordering.
+#
+# Only a subset of the character set is used here; mostly to
+# illustrate the set-up.
+#
+#
+collating-symbol <LOW_VALUE>
+collating-symbol <LOWER-CASE>
+collating-symbol <SUBSCRIPT-LOWER>
+collating-symbol <SUPERSCRIPT-LOWER>
+collating-symbol <UPPER-CASE>
+collating-symbol <NO-ACCENT>
+collating-symbol <PECULIAR>
+collating-symbol <LIGATURE>
+collating-symbol <ACUTE>
+collating-symbol <GRAVE>
+collating-symbol <RING-ABOVE>
+collating-symbol <DIAERESIS>
+collating-symbol <TILDE>
+# Further collating-symbols follow.
+#
+# Properly, the standard does not include any multi-character
+# collating elements; the one below is added for completeness.
+#
+collating_element <ch> from "<c><h>"
+collating_element <CH> from "<C><H>"
+collating_element <Ch> from "<C><h>"
+collating_element <AE> from "<A><E>"
+collating_element <ae> from "<a><e>"
+#
+order_start forward;backward;forward;forward,position
+#
+# Collating symbols are specified first in the sequence to allocate
+# basic collation values to them, lower than that of any character.
+<LOW_VALUE>
+<LOWER-CASE>
+<SUBSCRIPT-LOWER>
+<SUPERSCRIPT-LOWER>
+<UPPER-CASE>
+<NO-ACCENT>
+<PECULIAR>
+<LIGATURE>
+<ACUTE>
+<GRAVE>
+<RING-ABOVE>
+<DIAERESIS>
+<TILDE>
+# Further collating symbols are given a basic collating value here.
+#
+# Here follow special characters.
+<space> IGNORE;IGNORE;IGNORE;<space>
+# Other special characters follow here.
+#
+# Here follow the regular characters.
+<a> <a>;<NO-ACCENT>;<LOWER-CASE>;IGNORE
+<A> <a>;<NO-ACCENT>;<UPPER-CASE>;IGNORE
+<a-acute> <a>;<ACUTE>;<LOWER-CASE>;IGNORE
+<A-acute> <a>;<ACUTE>;<UPPER-CASE>;IGNORE
+<a-grave> <a>;<GRAVE>;<LOWER-CASE>;IGNORE
+<A-grave> <a>;<GRAVE>;<UPPER-CASE>;IGNORE
+<ae> "<a><e>";"<LIGATURE><LIGATURE>";\
+ "<LOWER-CASE><LOWER-CASE>";IGNORE
+<AE> "<a><e>";"<LIGATURE><LIGATURE>";\
+ "<UPPER-CASE><UPPER-CASE>";IGNORE
+<b> <b>;<NO-ACCENT>;<LOWER-CASE>;IGNORE
+... ...;<NO-ACCENT>;<LOWER-CASE>;IGNORE
+<z> ...;<NO-ACCENT>;<LOWER-CASE>;IGNORE
+<B> <b>;<NO-ACCENT>;<UPPER-CASE>;IGNORE
+<c> <c>;<NO-ACCENT>;<LOWER-CASE>;IGNORE
+<C> <c>;<NO-ACCENT>;<UPPER-CASE>;IGNORE
+<ch> <ch>;<NO-ACCENT>;<LOWER-CASE>;IGNORE
+<Ch> <ch>;<NO-ACCENT>;<PECULIAR>;IGNORE
+<CH> <ch>;<NO-ACCENT>;<UPPER-CASE>;IGNORE
+#
+# As an example, the strings "Bach" and "bach" could be encoded (for
+# compare purposes) as:
+# "Bach" <b>;<a>;<ch>;<LOW_VALUE>;<NO_ACCENT>;<NO_ACCENT>;\
+# <NO_ACCENT>;<LOW_VALUE>;<UPPER>;<LOWER>;<LOWER>;<NULL>
+# "bach" <b>;<a>;<ch>;<LOW_VALUE>;<NO_ACCENT>;<NO_ACCENT>;\
+# <NO_ACCENT>;<LOW_VALUE>;<LOWER>;<LOWER>;<LOWER>;<NULL>
+#
+# The two strings are equal in pass 1 and 2, but differ in pass 3.
+#
+# Further characters follow.
+#
+UNDEFINED IGNORE;IGNORE;IGNORE;IGNORE
+#
+order_end
+#
+END LC_COLLATE
+#
+LC_MONETARY
+int_curr_symbol "USD "
+currency_symbol "$"
+mon_decimal_point "."
+mon_grouping 3;0
+positive_sign ""
+negative_sign "-"
+p_cs_precedes 1
+n_sign_posn 0
+END LC_MONETARY
+#
+LC_NUMERIC
+copy "US_en.ASCII"
+decimal_point .
+thousands_sep \,
+grouping 3;3
+END LC_NUMERIC
+#
+LC_TIME
+abday "Sun";"Mon";"Tue";"Wed";"Thu";"Fri";"Sat"
+#
+day "Sunday";"Monday";"Tuesday";"Wednesday";\
+ "Thursday";"Friday";"Saturday"
+#
+abmon "Jan";"Feb";"Mar";"Apr";"May";"Jun";\
+ "Jul";"Aug";"Sep";"Oct";"Nov";"Dec"
+#
+mon "January";"February";"March";"April";\
+ "May";"June";"July";"August";"September";\
+ "October";"November";"December"
+#
+d_t_fmt "%a %b %d %T %Z %Y\n"
+am_pm "Am";"Pm"
+END LC_TIME
+#
+LC_MESSAGES
+yesexpr "^([yY][[:alpha:]]*)|(OK)"
+#
+noexpr "^[nN][[:alpha:]]*"
+END LC_MESSAGES
diff --git a/adv_cmds/localedef/def.p-2 b/adv_cmds/localedef/def.p-2
new file mode 100644
index 0000000..9b6ee15
--- /dev/null
+++ b/adv_cmds/localedef/def.p-2
@@ -0,0 +1,280 @@
+LC_CTYPE
+# The following is the POSIX locale LC_CTYPE.
+# "alpha" is by default "upper" and "lower"
+# "alnum" is by definition "alpha" and "digit"
+# "print" is by default "alnum", "punct" and the <space> character
+# "graph" is by default "alnum" and "punct"
+#
+upper <A>;<B>;<C>;<D>;<E>;<F>;<G>;<H>;<I>;<J>;<K>;<L>;<M>;\
+ <N>;<O>;<P>;<Q>;<R>;<S>;<T>;<U>;<V>;<W>;<X>;<Y>;<Z>
+#
+lower <a>;<b>;<c>;<d>;<e>;<f>;<g>;<h>;<i>;<j>;<k>;<l>;<m>;\
+ <n>;<o>;<p>;<q>;<r>;<s>;<t>;<u>;<v>;<w>;<x>;<y>;<z>
+#
+digit <zero>;<one>;<two>;<three>;<four>;<five>;<six>;\
+ <seven>;<eight>;<nine>
+#
+space <tab>;<newline>;<vertical-tab>;<form-feed>;\
+ <carriage-return>;<space>
+#
+cntrl <alert>;<backspace>;<tab>;<newline>;<vertical-tab>;\
+ <form-feed>;<carriage-return>;\
+ <NUL>;<SOH>;<STX>;<ETX>;<EOT>;<ENQ>;<ACK>;<SO>;\
+ <SI>;<DLE>;<DC1>;<DC2>;<DC3>;<DC4>;<NAK>;<SYN>;\
+ <ETB>;<CAN>;<EM>;<SUB>;<ESC>;<IS4>;<IS3>;<IS2>;\
+ <IS1>;<DEL>
+#
+punct <exclamation-mark>;<quotation-mark>;<number-sign>;\
+ <dollar-sign>;<percent-sign>;<ampersand>;<apostrophe>;\
+ <left-parenthesis>;<right-parenthesis>;<asterisk>;\
+ <plus-sign>;<comma>;<hyphen>;<period>;<slash>;\
+ <colon>;<semicolon>;<less-than-sign>;<equals-sign>;\
+ <greater-than-sign>;<question-mark>;<commercial-at>;\
+ <left-square-bracket>;<backslash>;<right-square-bracket>;\
+ <circumflex>;<underscore>;<grave-accent>;<left-curly-bracket>;\
+ <vertical-line>;<right-curly-bracket>;<tilde>
+#
+xdigit <zero>;<one>;<two>;<three>;<four>;<five>;<six>;<seven>;\
+ <eight>;<nine>;<A>;<B>;<C>;<D>;<E>;<F>;<a>;<b>;<c>;<d>;<e>;<f>
+#
+blank <space>;<tab>
+#
+toupper (<a>,<A>);(<b>,<B>);(<c>,<C>);(<d>,<D>);(<e>,<E>);\
+ (<f>,<F>);(<g>,<G>);(<h>,<H>);(<i>,<I>);(<j>,<J>);\
+ (<k>,<K>);(<l>,<L>);(<m>,<M>);(<n>,<N>);(<o>,<O>);\
+ (<p>,<P>);(<q>,<Q>);(<r>,<R>);(<s>,<S>);(<t>,<T>);\
+ (<u>,<U>);(<v>,<V>);(<w>,<W>);(<x>,<X>);(<y>,<Y>);(<z>,<Z>)
+#
+tolower (<A>,<a>);(<B>,<b>);(<C>,<c>);(<D>,<d>);(<E>,<e>);\
+ (<F>,<f>);(<G>,<g>);(<H>,<h>);(<I>,<i>);(<J>,<j>);\
+ (<K>,<k>);(<L>,<l>);(<M>,<m>);(<N>,<n>);(<O>,<o>);\
+ (<P>,<p>);(<Q>,<q>);(<R>,<r>);(<S>,<s>);(<T>,<t>);\
+ (<U>,<u>);(<V>,<v>);(<W>,<w>);(<X>,<x>);(<Y>,<y>);(<Z>,<z>)
+END LC_CTYPE
+LC_COLLATE
+# This is the POSIX locale definition for the LC_COLLATE category.
+# The order is the same as in the ASCII codeset.
+order_start forward
+<NUL>
+<SOH>
+<STX>
+<ETX>
+<EOT>
+<ENQ>
+<ACK>
+<alert>
+<backspace>
+<tab>
+<newline>
+<vertical-tab>
+<form-feed>
+<carriage-return>
+<SO>
+<SI>
+<DLE>
+<DC1>
+<DC2>
+<DC3>
+<DC4>
+<NAK>
+<SYN>
+<ETB>
+<CAN>
+<EM>
+<SUB>
+<ESC>
+<IS4>
+<IS3>
+<IS2>
+<IS1>
+<space>
+<exclamation-mark>
+<quotation-mark>
+<number-sign>
+<dollar-sign>
+<percent-sign>
+<ampersand>
+<apostrophe>
+<left-parenthesis>
+<right-parenthesis>
+<asterisk>
+<plus-sign>
+<comma>
+<hyphen>
+<period>
+<slash>
+<zero>
+<one>
+<two>
+<three>
+<four>
+<five>
+<six>
+<seven>
+<eight>
+<nine>
+<colon>
+<semicolon>
+<less-than-sign>
+<equals-sign>
+<greater-than-sign>
+<question-mark>
+<commercial-at>
+<A>
+<B>
+<C>
+<D>
+<E>
+<F>
+<G>
+<H>
+<I>
+<J>
+<K>
+<L>
+<M>
+<N>
+<O>
+<P>
+<Q>
+<R>
+<S>
+<T>
+<U>
+<V>
+<W>
+<X>
+<Y>
+<Z>
+<left-square-bracket>
+<backslash>
+<right-square-bracket>
+<circumflex>
+<underscore>
+<grave-accent>
+<a>
+<b>
+<c>
+<d>
+<e>
+<f>
+<g>
+<h>
+<i>
+<j>
+<k>
+<l>
+<m>
+<n>
+<o>
+<p>
+<q>
+<r>
+<s>
+<t>
+<u>
+<v>
+<w>
+<x>
+<y>
+<z>
+<left-curly-bracket>
+<vertical-line>
+<right-curly-bracket>
+<tilde>
+<DEL>
+order_end
+#
+END LC_COLLATE
+LC_MONETARY
+# This is the POSIX locale definition for
+# the LC_MONETARY category.
+#
+int_curr_symbol ""
+currency_symbol ""
+mon_decimal_point ""
+mon_thousands_sep ""
+mon_grouping -1
+positive_sign ""
+negative_sign ""
+int_frac_digits -1
+p_cs_precedes -1
+p_sep_by_space -1
+n_cs_precedes -1
+n_sep_by_space -1
+p_sign_posn -1
+n_sign_posn -1
+#
+END LC_MONETARY
+LC_NUMERIC
+# This is the POSIX locale definition for
+# the LC_NUMERIC category.
+#
+decimal_point "<period>"
+thousands_sep ""
+grouping -1
+#
+END LC_NUMERIC
+LC_TIME
+# This is the POSIX locale definition for
+# the LC_TIME category.
+#
+# Abbreviated weekday names (%a)
+abday "<S><u><n>";"<M><o><n>";"<T><u><e>";"<W><e><d>";\
+ "<T><h><u>";"<F><r><i>";"<S><a><t>"
+#
+# Full weekday names (%A)
+day "<S><u><n><d><a><y>";"<M><o><n><d><a><y>";\
+ "<T><u><e><s><d><a><y>";"<W><e><d><n><e><s><d><a><y>";\
+ "<T><h><u><r><s><d><a><y>";"<F><r><i><d><a><y>";\
+ "<S><a><t><u><r><d><a><y>"
+#
+# Abbreviated month names (%b)
+abmon "<J><a><n>";"<F><e><b>";"<M><a><r>";\
+ "<A><p><r>";"<M><a><y>";"<J><u><n>";\
+ "<J><u><l>";"<A><u><g>";"<S><e><p>";\
+ "<O><c><t>";"<N><o><v>";"<D><e><c>"
+#
+# Full month names (%B)
+mon "<J><a><n><u><a><r><y>";"<F><e><b><r><u><a><r><y>";\
+ "<M><a><r><c><h>";"<A><p><r><i><l>";\
+ "<M><a><y>";"<J><u><n><e>";\
+ "<J><u><l><y>";"<A><u><g><u><s><t>";\
+ "<S><e><p><t><e><m><b><e><r>";"<O><c><t><o><b><e><r>";\
+ "<N><o><v><e><m><b><e><r>";"<D><e><c><e><m><b><e><r>"
+#
+# Equivalent of AM/PM (%p) "AM";"PM"
+am_pm "<A><M>";"<P><M>"
+#
+# Appropriate date and time representation (%c)
+# "%a %b %e %H:%M:%S %Y"
+d_t_fmt "<percent-sign><a><space><percent-sign><b>\
+ <space><percent-sign><e><space><percent-sign><H>\
+ <colon><percent-sign><M><colon><percent-sign><S>\
+ <space><percent-sign><Y>"
+#
+# Appropriate date representation (%x) "%m/%d/%y"
+d_fmt "<percent-sign><m><slash><percent-sign><d>\
+ <slash><percent-sign><y>"
+#
+# Appropriate time representation (%X) "%H:%M:%S"
+t_fmt "<percent-sign><H><colon><percent-sign><M>\
+ <colon><percent-sign><S>"
+#
+# Appropriate 12-hour time representation (%r) "%I:%M:%S %p"
+t_fmt_ampm "<percent-sign><I><colon><percent-sign><M><colon>\
+ <percent-sign><S> <percent-sign><p>"
+#
+END LC_TIME
+LC_MESSAGES
+# This is the POSIX locale definition for
+# the LC_MESSAGES category.
+#
+yesexpr "<circumflex><left-square-bracket><y><Y><right-square-bracket>"
+#
+noexpr "<circumflex><left-square-bracket><n><N><right-square-bracket>"
+#
+yesstr "yes"
+nostr "no"
+END LC_MESSAGES
+
diff --git a/adv_cmds/localedef/localedef.1 b/adv_cmds/localedef/localedef.1
new file mode 100644
index 0000000..c8f3907
--- /dev/null
+++ b/adv_cmds/localedef/localedef.1
@@ -0,0 +1,122 @@
+.\"Modified from man(1) of FreeBSD, the NetBSD mdoc.template, and mdoc.samples.
+.Dd September 9, 2004
+.Dt LOCALEDEF 1
+.Os Darwin
+.Sh NAME
+.Nm localedef
+.Nd define locale environment
+.Sh SYNOPSIS
+.Nm
+.Op Fl c
+.Op Fl f Ar charmap
+.Op Fl i Ar sourcefile
+.Ar name
+." localedef [-c][-f charmap][-i sourcefile] name
+.Sh DESCRIPTION
+The
+.Nm
+utility reads source definitions for one or more locale categories
+belonging to the same locale from the file named in the
+.Fl i
+option (if specified) or from standard input.
+.Pp
+The
+.Ar name
+operand identifies the target locale. The
+.Nm
+utility supports
+the creation of public, or generally accessible locales, as well
+as private, or restricted-access locales.
+.Pp
+Each category source definition is identified by the corresponding
+environment variable name and terminated by an END category-name
+statement.
+.Pp
+.Bl -tag -width "LC_MONETARY" -compact -offset indent
+.It LC_CTYPE
+Defines character classification and case conversion.
+.It LC_COLLATE
+Defines collation rules.
+.It LC_MONETARY
+Defines the format and symbols used in formatting of monetary information.
+.It LC_NUMERIC
+Defines the decimal delimiter, grouping, and grouping symbol for non-monetary numeric editing.
+.It LC_TIME
+Defines the format and content of date and time information.
+.It LC_MESSAGES
+Defines the format and values of affirmative and negative responses.
+.El
+.Sh OPTIONS
+The following options are supported:
+.Pp
+.Bl -tag -width -indent
+.It Fl c
+Create permanent output even if warning messages have been issued.
+.It Fl f Ar charmap
+Specify the pathname of a file containing a mapping of character symbols and collating element symbols to actual character encodings.
+.It Fl i Ar sourcefile
+The pathname of a file containing the source definitions. If this option is not present, source definitions will be read from standard input.
+.El
+.Sh OPERANDS
+The following operand is supported:
+.Bl -tag -width -indent
+.It Ar name
+Identifies the locale.
+If the name contains one or more slash characters,
+.Ar name
+will be interpreted as a pathname
+where the created locale definitions will be stored.
+If
+.Ar name
+does not contain any slash characters,
+the locale will be public.
+This capability is restricted to users with appropriate privileges.
+(As a consequence of specifying one name,
+although several categories can be processed in one execution,
+only categories belonging to the same locale can be processed.)
+.El
+.Sh ENVIRONMENT
+The following environment variables affect the execution of
+.Nm :
+.Bl -tag -width "LC_COLLATE"
+.It Ev LANG
+Provide a default value for the internationalization variables
+that are unset or null.
+If LANG is unset or null,
+the corresponding value from the implementation-dependent default locale
+will be used.
+If any of the internationalization variables contains an invalid setting,
+the utility will behave as if none of the variables had been defined.
+.It Ev LC_ALL
+If set to a non-empty string value, override the values of all the other internationalization variables.
+.It Ev LC_COLLATE
+(This variable has no effect on
+.Nm ;
+the POSIX locale will be used for this category.)
+.It Ev LC_CTYPE
+Determine the locale for the interpretation of sequences of bytes
+of text data as characters
+(for example, single- as opposed to multi-byte characters
+in arguments and input files).
+This variable has no effect on the processing of
+.Nm
+input data;
+the POSIX locale is used for this purpose,
+regardless of the value of this variable.
+.It Ev LC_MESSAGES
+Determine the locale that should be used to affect the format and contents of diagnostic messages written to standard error.
+.It Ev NLSPATH
+Determine the location of message catalogues for the processing of LC_MESSAGES.
+.El
+.Sh EXIT STATUS
+The following exit values are returned:
+.Bl -tag -width -indent
+.It 0
+No errors occurred and the locales were successfully created.
+.It 1
+Warnings occurred and the locales were successfully created.
+.It 2
+The locale specification exceeded implementation limits or the coded character set or sets used were not supported by the implementation, and no locale was created.
+.It >2
+Warnings or errors occurred and no output was created.
+.El
diff --git a/adv_cmds/localedef/localedef.pl b/adv_cmds/localedef/localedef.pl
new file mode 100644
index 0000000..222eda0
--- /dev/null
+++ b/adv_cmds/localedef/localedef.pl
@@ -0,0 +1,1166 @@
+#!/usr/bin/perl -w
+
+use strict;
+use Getopt::Std;
+use Fcntl qw(O_TRUNC O_CREAT O_WRONLY SEEK_SET);
+use File::Temp qw(tempfile);
+use IO::File;
+
+my %opt;
+getopts("cf:u:i:", \%opt);
+
+my $comment_char = "#";
+my $escape_char = "\\";
+my $val_match = undef; # set in set_escape
+my %sym = ();
+my %width = ();
+my %ctype_classes = (
+ # there are the charactors that get automagically included, there is no
+ # standard way to avoid them. XXX even if you have a charset without
+ # some of these charactors defined!
+
+ # They are accessable in a regex via [:classname:], and libc has a
+ # isX() for most of these.
+ upper => {map { ($_, 1); } qw(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z)},
+ lower => {map { ($_, 1); } qw(a b c d e f g h i j k l m n o p q r s t u v w x y z)},
+ alpha => {},
+ #alnum => {},
+ digit => {map { ($_, 1); } qw(0 1 2 3 4 5 6 7 8 9)},
+ space => {},
+ cntrl => {},
+ punct => {},
+ graph => {},
+ print => {},
+ xdigit => {map { ($_, 1); } qw(0 1 2 3 4 5 6 7 8 9 A B C D E F a b c d e f)},
+ blank => {" " => 1, "\t" => 1},
+
+ toupper => {map { ($_, "\U$_"); } qw(a b c d e f g h i j k l m n o p q r s t u v w x y z)},
+ tolower => {map { ($_, "\L$_"); } qw(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z)},
+);
+
+my %cele = (
+ # collating-elements -- these are a lot like %sym that only works
+ # in LC_COLLATE, can also be accessed in a regex via [.element.]
+);
+
+my %csym = (
+ # collating-symbols -- these are used to define a set of charactors
+ # that compare as equals (in one or more passes), can also be accessed
+ # in a regex via [=symbol=]
+);
+
+my @corder = (); # collating order
+my @corder_weights = (); # collating directions (forward, backward, position)
+
+my @colldef = ();
+
+my(%monetary, %numeric, %time, %messages);
+
+# This is the default charmap, unlike %ctype_classes you _can_ avoid this
+# merely by having your own charmap definition file
+my $default_charmap = <<EOT;
+CHARMAP
+<NUL> \\000
+<alert> \\007
+<backspace> \\010
+<tab> \\011
+<newline> \\012
+<vertical-tab> \\013
+<form-feed> \\014
+<carriage-return> \\015
+<space> \\040
+<exclamation-mark> \\041
+<quotation-mark> \\042
+<number-sign> \\043
+<dollar-sign> \\044
+<percent-sign> \\045
+<ampersand> \\046
+<apostrophe> \\047
+<left-parenthesis> \\050
+<right-parenthesis> \\051
+<asterisk> \\052
+<plus-sign> \\053
+<comma> \\054
+<hyphen> \\055
+<hyphen-minus> \\055
+<period> \\056
+<full-stop> \\056
+<slash> \\057
+<solidus> \\057
+<zero> \\060
+<one> \\061
+<two> \\062
+<three> \\063
+<four> \\064
+<five> \\065
+<six> \\066
+<seven> \\067
+<eight> \\070
+<nine> \\071
+<colon> \\072
+<semicolon> \\073
+<less-then-sign> \\074
+<less-than-sign> \\074
+<equals-sign> \\075
+<greater-then-sign> \\076
+<greater-than-sign> \\076
+<question-mark> \\077
+<commercial-at> \\100
+<A> \\101
+<B> \\102
+<C> \\103
+<D> \\104
+<E> \\105
+<F> \\106
+<G> \\107
+<H> \\110
+<I> \\111
+<J> \\112
+<K> \\113
+<L> \\114
+<M> \\115
+<N> \\116
+<O> \\117
+<P> \\120
+<Q> \\121
+<R> \\122
+<S> \\123
+<T> \\124
+<U> \\125
+<V> \\126
+<W> \\127
+<X> \\130
+<Y> \\131
+<Z> \\132
+<left-square-bracket> \\133
+<backslash> \\134
+<reverse-solidus> \\134
+<right-square-bracket> \\135
+<circumflex> \\136
+<circumflex-accent> \\136
+<underscore> \\137
+<underline> \\137
+<low-line> \\137
+<grave-accent> \\140
+<a> \\141
+<b> \\142
+<c> \\143
+<d> \\144
+<e> \\145
+<f> \\146
+<g> \\147
+<h> \\150
+<i> \\151
+<j> \\152
+<k> \\153
+<l> \\154
+<m> \\155
+<n> \\156
+<o> \\157
+<p> \\160
+<q> \\161
+<r> \\162
+<s> \\163
+<t> \\164
+<u> \\165
+<v> \\166
+<w> \\167
+<x> \\170
+<y> \\171
+<z> \\172
+<left-brace> \\173
+<left-curly-bracket> \\173
+<vertical-line> \\174
+<right-brace> \\175
+<right-curly-bracket> \\175
+<tilde> \\176
+<DEL> \\177
+
+<SOH> \\x01
+<STX> \\x02
+<ETX> \\x03
+<EOT> \\x04
+<ENQ> \\x05
+<ACK> \\x06
+<BEL> \\x07
+<BS> \\x08
+<HT> \\x09
+<NL> \\x0a
+<VT> \\x0b
+<NP> \\x0c
+<CR> \\x0d
+<SO> \\x0e
+<SI> \\x0f
+<DLE> \\x10
+<DC1> \\x11
+<DC2> \\x12
+<DC3> \\x13
+<DC4> \\x14
+<NAK> \\x15
+<SYN> \\x16
+<ETB> \\x17
+<CAN> \\x18
+<EM> \\x19
+<SUB> \\x1a
+<ESC> \\x1b
+<FS> \\x1c
+<IS4> \\x1c
+<GS> \\x1d
+<IS3> \\x1d
+<RS> \\x1e
+<IS2> \\x1e
+<US> \\x1f
+<IS1> \\x1f
+END CHARMAP
+EOT
+
+&set_escape($escape_char);
+
+use strict qw(vars);
+
+if (@ARGV != 1) {
+ &exit(4, "usage: $0 [-c] [-f charmap-file] [-u codesetname] [-i localdef-file] LOCALENAME\n");
+}
+
+my $locale_dir = $ARGV[0];
+$locale_dir = "/usr/share/locale/$locale_dir" unless ($locale_dir =~ m{/});
+
+my $CMAP;
+if (defined($opt{'f'})) {
+ # Using new IO::File $opt{'f'}, "r" runs into problems with long path names
+ sysopen(CMAP_KLUDGE, $opt{'f'}, O_RDONLY) || &exit(4, "Can't open $opt{f}: $!\n");
+ $CMAP = new IO::Handle;
+ $CMAP->fdopen(fileno(CMAP_KLUDGE), "r") || &exit(4, "Can't fdopen $opt{f}: $!\n");
+} else {
+ # er, not everyone gets IO::Scalar, so use an unamed tmp file
+ # $CMAP = new IO::Scalar \$default_charmap;
+ $CMAP = new_tmpfile IO::File;
+ print $CMAP $default_charmap;
+ seek $CMAP, 0, SEEK_SET;
+}
+
+while(<$CMAP>) {
+ if (m/^\s*CHARMAP\s*$/) {
+ &parse_charmaps();
+ } elsif (m/^\s*WIDTH\s*$/) {
+ &parse_widths();
+ } elsif (m/^\s*($comment_char.*)?$/) {
+ } else {
+ chomp;
+ &exit(4, "syntax error on line $. ($_)");
+ }
+}
+&parse_widths() if (0 == %width);
+
+if (defined($opt{'i'})) {
+ sysopen(STDIN, $opt{'i'}, 0) || &exit(4, "Can't open localdef file $opt{i}: $!");
+} else {
+ $opt{'i'} = "/dev/stdin";
+}
+
+my %LC_parsers = (
+ NONE => [\&parse_LC_NONE, qr/^\s*((escape|comment)_char\s+$val_match\s*)?$/],
+ CTYPE => [\&parse_LC_CTYPE, qr/^\s*(\S+)\s+(\S+.*?)\s*$/],
+ COLLATE => [\&parse_LC_COLLATE, qr/^\s*(<[^>\s]+>|order_end|END|(\S*)\s+(\S+.*?)|collating[_-]element\s*<[^>]+>\s+from\s+$val_match)\s*$/, 1],
+ TIME => [\&parse_LC_TIME, qr/^\s*(ab_?day|day|abmon|mon|d_t_fmt|d_fmt|t_fmt|am_pm|t_fmt_ampm|era|era_d_fmt|era_t_fmt|era_d_t_fmt|alt_digits|copy|END)\s+(\S+.*?)\s*$/],
+ NUMERIC => [\&parse_LC_NUMERIC, qr/^\s*(decimal_point|thousands_sep|grouping|END|copy)\s+(\S+.*?)\s*$/],
+ MONETARY => [\&parse_LC_MONETARY, qr/^\s*(int_curr_symbol|currency_symbol|mon_decimal_point|mon_thousands_sep|mon_grouping|positive_sign|negative_sign|int_frac_digits|frac_digits|p_cs_precedes|p_sep_by_space|n_cs_precedes|n_sep_by_space|p_sign_posn|n_sign_posn|int_p_cs_precedes|int_n_cs_precedes|int_p_sep_by_space|int_n_sep_by_space|int_p_sign_posn|int_n_sign_posn|copy|END)\s+(\S+.*?)\s*$/],
+ MESSAGES => [\&parse_LC_MESSAGES, qr/^\s*(END|yesexpr|noexpr|yesstr|nostr|copy)\s+(\S+.*?)\s*$/],
+ "COLLATE order" => [\&parse_collate_order, qr/^\s*(order_end|(<[^>\s]+>|UNDEFINED|\Q...\E)(\s+\S+.*)?)\s*$/],
+);
+my($current_LC, $parse_func, $validate_line, $call_parse_on_END)
+ = ("NONE", $LC_parsers{"NONE"}->[0], $LC_parsers{"NONE"}->[1], undef);
+
+while(<STDIN>) {
+ next if (m/^\s*($comment_char.*)?\s*$/);
+ if (m/\Q$escape_char\E$/) {
+ chomp;
+ chop;
+ my $tmp = <STDIN>;
+ if (!defined($tmp)) {
+ &exit(4, "Syntax error, last line ($.) of $opt{i} is marked as a continued line\n");
+ }
+ $tmp =~ s/^\s*//;
+ $_ .= $tmp;
+ redo;
+ }
+
+ if ($current_LC eq "NONE" && m/^\s*LC_([A-Z]+)\s*$/) {
+ &set_parser($1);
+ next;
+ }
+
+ unless (m/$validate_line/) {
+ &exit(4, "Syntax error on line $. of $opt{i}\n");
+ }
+
+ my($action, $args);
+ if (m/^\s*(\S*)(\s+(\S+.*?))?\s*$/) {
+ ($action, $args) = ($1, $3);
+ } else {
+ $action = $_;
+ chomp $action;
+ }
+
+ if ($action eq "END") {
+ if ($args ne "LC_$current_LC" || $current_LC eq "NONE") {
+ &exit(4, "Syntax error on line $. of $opt{i} attempting to end $args when LC_$current_LC is open\n");
+ }
+ if ($call_parse_on_END) {
+ &{$parse_func}($action, $args);
+ }
+ &set_parser("NONE");
+ } else {
+ &{$parse_func}($action, $args);
+ }
+}
+
+mkdir($locale_dir);
+&run_mklocale();
+&write_lc_money();
+&write_lc_time();
+&write_lc_messages();
+&write_lc_numeric();
+&write_lc_collate();
+exit 0;
+
+sub parse_charmaps {
+ while(<$CMAP>) {
+ # XXX need to parse out <code_set_name>, <mb_cur_max>, <mb_cur_min>,
+ # <escape_char>, and <comment_char> before the generic "<sym> val"
+ if (m/^\s*<([\w\-]+)>\s+($val_match+)\s*$/) {
+ my($sym, $val) = ($1, $2);
+ $val = &parse_value_double_backwhack($val);
+ $sym{$sym} = $val;
+ } elsif (m/^\s*<([\w\-]*\d)>\s*\Q...\E\s*<([\w\-]*\d)>\s+($val_match+)\s*$/) {
+ # We don't deal with $se < $ss, or overflow of the last byte of $vs
+ # then again the standard doesn't say anything in particular needs
+ # to happen for those cases
+ my($ss, $se, $vs) = ($1, $2, $3);
+ $vs = &parse_value_double_backwhack($vs);
+ my $vlast = length($vs) -1;
+ for(my($s, $v) = ($ss, $vs); $s cmp $se; $s++) {
+ $sym{$s} = $v;
+ substr($v, $vlast) = chr(ord(substr($v, $vlast)) +1)
+ }
+ } elsif (m/^\s*END\s+CHARMAP\s*$/) {
+ return;
+ } elsif (m/^\s*($comment_char.*)?$/) {
+ } else {
+ &exit(4, "syntax error on line $.");
+ }
+ }
+}
+
+sub parse_widths {
+ my $default = 1;
+ my @syms;
+
+ while(<$CMAP>) {
+ if (m/^\s*<([\w\-]+)>\s+(\d+)\s*$/) {
+ my($sym, $w) = ($1, $2);
+ print "$sym width $w\n";
+ if (!defined($sym{$sym})) {
+ warn "localedef: can't set width of unknown symbol $sym on line $.\n";
+ } else {
+ $width{$sym} = $w;
+ }
+ } elsif (m/^\s*<([\w\-]+)>\s*\Q...\E\s*<([\w\-]+)>\s+(\d+)\s*$/) {
+ my($ss, $se, $w) = ($1, $2, $3);
+ if (!@syms) {
+ @syms = sort { $a cmp $b } keys(%sym);
+ }
+
+ # Yes, we could do a binary search for find $ss in @syms
+ foreach my $s (@syms) {
+ if (($s cmp $ss) >= 0) {
+ last if (($s cmp $se) > 0);
+ }
+ }
+ } elsif (m/^\s*WIDTH_DEFAULT\s+(\d+)\s*$/) {
+ $default = $1;
+ } elsif (m/^\s*END\s+WIDTH\s*$/) {
+ last;
+ } elsif (m/^\s*($comment_char.*)?$/) {
+ } else {
+ &exit(4, "syntax error on line $.");
+ }
+ }
+
+ foreach my $s (keys(%sym)) {
+ if (!defined($width{$s})) {
+ $width{$s} = $default;
+ }
+ }
+}
+
+# This parses a single value in any of the 7 forms it can appear in,
+# returns [0] the parsed value and [1] the remander of the string
+sub parse_value_return_extra {
+ my $val = "";
+ local($_) = $_[0];
+
+ while(1) {
+ $val .= &unsym($1), next
+ if (m/\G"((?:[^"\Q$escape_char\E]+|\Q$escape_char\E.)*)"/gc);
+ $val .= chr(oct($1)), next
+ if (m/\G\Q$escape_char\E([0-7]+)/gc);
+ $val .= chr(0+$1), next
+ if (m/\G\Q$escape_char\Ed([0-9]+)/gc);
+ $val .= pack("H*", $1), next
+ if (m/\G\Q$escape_char\Ex([0-9a-fA-F]+)/gc);
+ $val .= $1, next
+ if (m/\G([^,;<>\s\Q$escape_char()\E])/gc);
+ $val .= $1
+ if (m/\G(?:\Q$escape_char\E)([,;<>\Q$escape_char()\E])/gc);
+ $val .= &unsym($1), next
+ if (m/\G(<[^>]+>)/gc);
+
+ m/\G(.*)$/;
+
+ return ($val, $1);
+ }
+}
+
+# Parse one value, if there is more then one value alert the media
+sub parse_value {
+ my ($ret, $err) = &parse_value_return_extra($_[0]);
+ if ($err ne "") {
+ &exit(4, "Syntax error, unexpected '$err' in value (after '$ret') on line $.\n");
+ }
+
+ return $ret;
+}
+
+sub parse_value_double_backwhack {
+ my($val) = @_;
+
+ my ($ret, $err) = &parse_value_return_extra($val);
+ return $ret if ($err eq "");
+
+ $val =~ s{\\\\}{\\}g;
+ ($ret, $err) = &parse_value_return_extra($val);
+ if ($err ne "") {
+ &exit(4, "Syntax error, unexpected '$err' in value (after '$ret') on line $.\n");
+ }
+
+ return $ret;
+}
+# $values is the string to parse, $dot_expand is a function ref that will
+# return an array to insert when "X;...;Y" is parsed (undef means that
+# construct is a syntax error), $nest is true if parens indicate a nested
+# value string should be parsed and put in an array ref, $return_extra
+# is true if any unparsable trailing junk should be returned as the last
+# element (otherwise it is a syntax error). Any text matching the regex
+# $specials is returned as an hash.
+sub parse_values {
+ my($values, $sep, $dot_expand, $nest, $return_extra, $specials) = @_;
+ my(@ret, $live_dots);
+
+ while($values ne "") {
+ if (defined($specials) && $values =~ s/^($specials)($sep|$)//) {
+ push(@ret, { $1, undef });
+ next;
+ }
+ if ($nest && $values =~ s/^\(//) {
+ my @subret = &parse_values($values, ',', $dot_expand, $nest, 1, $specials);
+ $values = pop(@subret);
+ push(@ret, [@subret]);
+ unless ($values =~ s/^\)($sep)?//) {
+ &exit(4, "Syntax error, unmatched open paren on line $. of $opt{i}\n");
+ }
+ next;
+ }
+
+ my($v, $l) = &parse_value_return_extra($values);
+ $values = $l;
+
+ if ($live_dots) {
+ splice(@ret, -1, 1, &{$dot_expand}($ret[$#ret], $v));
+ $live_dots = 0;
+ } else {
+ push(@ret, $v);
+ }
+
+ if (defined($dot_expand) && $values =~ s/^$sep\Q...\E$sep//) {
+ $live_dots = 1;
+ } elsif($values =~ s/^$sep//) {
+ # Normal case
+ } elsif($values =~ m/^$/) {
+ last;
+ } else {
+ last if ($return_extra);
+ &exit(4, "Syntax error parsing arguments on line $. of $opt{i}\n");
+ }
+ }
+
+ if ($live_dots) {
+ splice(@ret, -1, 1, &{$dot_expand}($ret[$#ret], undef));
+ }
+ if ($return_extra) {
+ push(@ret, $values);
+ }
+
+ return @ret;
+}
+
+sub parse_LC_NONE {
+ my($cmd, $arg) = @_;
+
+ if ($cmd eq "comment_char") {
+ $comment_char = &parse_value($arg);
+ } elsif($cmd eq "escape_char") {
+ &set_escape_char(&parse_value($arg));
+ } elsif($cmd eq "") {
+ } else {
+ &exit(4, "Syntax error on line $. of $opt{i}\n");
+ }
+}
+
+sub parse_LC_CTYPE {
+ my($cmd, $arg) = @_;
+
+ my $ctype_classes = join("|", keys(%ctype_classes));
+ if ($cmd eq "copy") {
+ # XXX -- the locale command line utility doesn't currently
+ # output any LC_CTYPE info, so there isn't much of a way
+ # to implent copy yet
+ &exit(2, "copy not supported on line $. of $opt{i}\n");
+ } elsif($cmd eq "charclass") {
+ my $cc = &parse_value($arg);
+ if (!defined($ctype_classes{$cc})) {
+ $ctype_classes{$cc} = [];
+ } else {
+ warn "charclass $cc defined more then once\n";
+ }
+ } elsif($cmd =~ m/^to(upper|lower)$/) {
+ my @arg = &parse_values($arg, ';', undef, 1);
+ foreach my $p (@arg) {
+ &exit(4, "Syntax error on line $. of $opt{i} ${cmd}'s arguments must be character pairs like (a,A);(b,B)\n") if ("ARRAY" ne ref $p || 2 != @$p);
+ }
+ foreach my $pair (@arg) {
+ $ctype_classes{$cmd}{$pair->[0]} = $pair->[1];
+ }
+ } elsif($cmd =~ m/^($ctype_classes)$/) {
+ my @arg = &parse_values($arg, ';', \&dot_expand, 0);
+ foreach my $c (@arg) {
+ $ctype_classes{$1}->{$c} = 1;
+ }
+ } elsif($cmd =~ "END") {
+ &add_to_ctype_class('alpha', keys(%{$ctype_classes{'lower'}}));
+ &add_to_ctype_class('alpha', keys(%{$ctype_classes{'upper'}}));
+ foreach my $c (qw(alpha lower upper)) {
+ foreach my $d (qw(cntrl digit punct space)) {
+ &deny_in_ctype_class($c, $d, keys(%{$ctype_classes{$d}}));
+ }
+ }
+
+ &add_to_ctype_class('space', keys(%{$ctype_classes{'blank'}}));
+ foreach my $d (qw(upper lower alpha digit graph xdigit)) {
+ &deny_in_ctype_class('space', $d, keys(%{$ctype_classes{$d}}));
+ }
+
+ foreach my $d (qw(upper lower alpha digit punct graph print xdigit)) {
+ &deny_in_ctype_class('cntrl', $d, keys(%{$ctype_classes{$d}}));
+ }
+
+ foreach my $d (qw(upper lower alpha digit cntrl xdigit space)) {
+ &deny_in_ctype_class('punct', $d, keys(%{$ctype_classes{$d}}));
+ }
+
+ foreach my $c (qw(graph print)) {
+ foreach my $a (qw(upper lower alpha digit xdigit punct)) {
+ &add_to_ctype_class($c, keys(%{$ctype_classes{$a}}));
+ }
+ foreach my $d (qw(cntrl)) {
+ &deny_in_ctype_class($c, $d, keys(%{$ctype_classes{$d}}));
+ }
+ }
+ &add_to_ctype_class('print', keys(%{$ctype_classes{'space'}}));
+
+ # Yes, this is a requirment of the standard
+ &exit(2, "The digit class must have exactly 10 elements\n") if (10 != values(%{$ctype_classes{'digit'}}));
+ foreach my $d (values %{$ctype_classes{'digit'}}) {
+ if (!defined $ctype_classes{'xdigits'}->{$d}) {
+ &exit(4, "$d isn't in class xdigits, but all digits must appaer in xdigits\n");
+ }
+ }
+
+ $ctype_classes{'alnum'} = {} unless defined $ctype_classes{'alnum'};
+ foreach my $a (qw(alpha digit)) {
+ &add_to_ctype_class('alnum', keys(%{$ctype_classes{$a}}));
+ }
+
+ } else {
+ &exit(4, "Syntax error on line $. of $opt{i}\n");
+ }
+}
+
+sub parse_LC_COLLATE {
+ my ($cmd, $arg) = @_;
+ if (defined($arg) && $arg ne "") {
+ push(@colldef, "$cmd $arg");
+ } else {
+ push(@colldef, "$cmd");
+ }
+}
+
+sub parse_collate_order {
+ my($cmd, $arg) = @_;
+
+ if ($cmd =~ m/order[-_]end/) {
+ # restore the parent parser
+ &set_parser("COLLATE");
+ my $undef_at;
+ for(my $i = 0; $i <= $#corder; ++$i) {
+ next unless "ARRAY" eq ref($corder[$i]);
+ # If ... appears as the "key" for a order entry it means the
+ # rest of the line is duplicated once for everything in the
+ # open ended range (key-pev-line, key-next-line). Any ...
+ # in the weight fields are delt with by &fixup_collate_order_args
+ if ($corder[$i]->[0] eq "...") {
+ my(@sym, $from, $to);
+
+ my @charset = sort { $sym{$a} cmp $sym{$b} } keys(%sym);
+ if ($i != 0) {
+ $from = $corder[$i -1]->[0];
+ } else {
+ $from = $charset[0];
+ }
+ if ($i != $#corder) {
+ $to = $corder[$i +1]->[0];
+ } else {
+ $to = $charset[$#charset];
+ }
+
+ my @expand;
+ my($s, $e) = (&parse_value($from), &parse_value($to));
+ foreach my $c (@charset) {
+ if (($sym{$c} cmp $s) > 0) {
+ last if (($sym{$c} cmp $e) >= 0);
+ my @entry = @{$corder[$i]};
+ $entry[0] = "<$c>";
+ push(@expand, \@entry);
+ }
+ }
+ splice(@corder, $i, 1, @expand);
+ } elsif($corder[$i]->[0] eq "UNDEFINED") {
+ $undef_at = $i;
+ next;
+ }
+ &fixup_collate_order_args($corder[$i]);
+ }
+
+ if ($undef_at) {
+ my @insert;
+ my %cused = map { ("ARRAY" eq ref $_) ? ($_->[0], undef) : () } @corder;
+ foreach my $s (keys(%sym)) {
+ next if (exists $cused{"<$s>"});
+ my @entry = @{$corder[$undef_at]};
+ $entry[0] = "<$s>";
+ &fixup_collate_order_args(\@entry);
+ push(@insert, \@entry);
+ }
+ splice(@corder, $undef_at, 1, @insert);
+ }
+ } elsif((!defined $arg) || $arg eq "") {
+ if (!exists($csym{$cmd})) {
+ my($decode, $was_sym) = &unsym_with_check($cmd);
+ if ($was_sym) {
+ my %dots = ( "..." => undef );
+ my @dots = (\%dots) x (0+@corder_weights);
+ push(@corder, [$cmd, @dots]);
+ } else {
+ warn "Undefined collation symbol $cmd used on line $. of $opt{i}\n";
+ }
+ } else {
+ push(@corder, $cmd);
+ }
+ } else {
+ unless (defined($cele{$cmd} || defined $sym{$cmd})) {
+ warn "Undefined collation element or charset sym $cmd used on line $. of $opt{i}\n";
+ } else {
+ # This expands all the symbols (but not colating elements), which
+ # makes life easier for dealing with ..., but harder for
+ # outputing the actual table at the end where we end up
+ # converting literal sequences back into symbols in some cases
+ my @args = &parse_values($arg, ';', undef, 0, 0,
+ qr/IGNORE|\Q...\E/);
+
+ if (@args != @corder_weights) {
+ if (@args < @corder_weights) {
+ &exit(4, "Only " . (0 + @args)
+ . " weights supplied on line $. of $opt{i}, needed "
+ . (0 + @corder_weights)
+ . "\n");
+ } else {
+ &exit(4, "Too many weights supplied on line $. of $opt{i},"
+ . " wanted " . (0 + @corder_weights) . " but had "
+ . (0 + @args)
+ . "\n");
+ }
+ }
+
+ push(@corder, [$cmd, @args]);
+ }
+ }
+}
+
+sub parse_LC_MONETARY {
+ my($cmd, $arg) = @_;
+
+ if ($cmd eq "copy") {
+ &do_copy(&parse_value($arg));
+ } elsif($cmd eq "END") {
+ } elsif($cmd eq "mon_grouping") {
+ my @v = &parse_values($arg, ';', undef, 0);
+ $monetary{$cmd} = \@v;
+ } else {
+ my $v = &parse_value($arg);
+ $monetary{$cmd} = $v;
+ }
+}
+
+sub parse_LC_MESSAGES {
+ my($cmd, $arg) = @_;
+
+ if ($cmd eq "copy") {
+ &do_copy(&parse_value($arg));
+ } elsif($cmd eq "END") {
+ } else {
+ my $v = &parse_value($arg);
+ $messages{$cmd} = $v;
+ }
+}
+
+sub parse_LC_NUMERIC {
+ my($cmd, $arg) = @_;
+
+ if ($cmd eq "copy") {
+ &do_copy(&parse_value($arg));
+ } elsif($cmd eq "END") {
+ } elsif($cmd eq "grouping") {
+ my @v = &parse_values($arg, ';', undef, 0);
+ $numeric{$cmd} = \@v;
+ } else {
+ my $v = &parse_value($arg);
+ $numeric{$cmd} = $v;
+ }
+}
+
+sub parse_LC_TIME {
+ my($cmd, $arg) = @_;
+
+ $cmd =~ s/^ab_day$/abday/;
+
+ if ($cmd eq "copy") {
+ &do_copy(&parse_value($arg));
+ } elsif($cmd eq "END") {
+ } elsif($cmd =~ m/abday|day|mon|abmon|am_pm|alt_digits/) {
+ my @v = &parse_values($arg, ';', undef, 0);
+ $time{$cmd} = \@v;
+ } elsif($cmd eq "era") {
+ my @v = &parse_values($arg, ':', undef, 0);
+ $time{$cmd} = \@v;
+ } else {
+ my $v = &parse_value($arg);
+ $time{$cmd} = $v;
+ }
+}
+
+
+###############################################################################
+
+sub run_mklocale {
+ my $L = (new IO::File "|/usr/bin/mklocale -o $locale_dir/LC_CTYPE") || &exit(5, "$0: Can't start mklocale $!\n");
+ if (defined($opt{'u'})) {
+ $L->print(qq{ENCODING "$opt{u}"\n});
+ } else {
+ if ($ARGV[0] =~ m/(big5|euc|gb18030|gb2312|gbk|mskanji|utf-8)/i) {
+ my $enc = uc($1);
+ $L->print(qq{ENCODING "$enc"\n});
+ } elsif($ARGV[0] =~ m/utf8/) {
+ $L->print(qq{ENCODING "UTF-8"\n});
+ } else {
+ $L->print(qq{ENCODING "NONE"\n});
+ }
+ }
+ foreach my $class (keys(%ctype_classes)) {
+ unless ($class =~ m/^(tolower|toupper|alpha|control|digit|grah|lower|space|upper|xdigit|blank|print|ideogram|special|phonogram)$/) {
+ $L->print("# skipping $class\n");
+ next;
+ }
+
+ if (!%{$ctype_classes{$class}}) {
+ $L->print("# Nothing in \U$class\n");
+ next;
+ }
+
+ if ($class =~ m/^to/) {
+ my $t = $class;
+ $t =~ s/^to/map/;
+ $L->print("\U$t ");
+
+ foreach my $from (keys(%{$ctype_classes{$class}})) {
+ $L->print("[", &hexchars($from), " ",
+ &hexchars($ctype_classes{$class}->{$from}), "] ");
+ }
+ } else {
+ $L->print("\U$class ");
+
+ foreach my $rune (keys(%{$ctype_classes{$class}})) {
+ $L->print(&hexchars($rune), " ");
+ }
+ }
+ $L->print("\n");
+ }
+
+ my @width;
+ foreach my $s (keys(%width)) {
+ my $w = $width{$s};
+ $w = 3 if ($w > 3);
+ push(@{$width[$w]}, &hexchars($sym{$s}));
+ }
+ for(my $w = 0; $w <= $#width; ++$w) {
+ next if (!defined $width[$w]);
+ next if (0 == @{$width[$w]});
+ $L->print("SWIDTH$w ", join(" ", @{$width[$w]}), "\n");
+ }
+
+ if (!$L->close()) {
+ if (0 == $!) {
+ &exit(5, "Bad return from mklocale $?");
+ } else {
+ &exit(5, "Couldn't close mklocale pipe: $!");
+ }
+ }
+}
+
+###############################################################################
+
+sub hexchars {
+ my($str) = $_[0];
+ my($ret);
+
+ $ret = unpack "H*", $str;
+ &exit(2, "Rune >4 bytes ($ret; for $str)") if (length($ret) > 8);
+
+ return "0x" . $ret;
+}
+
+sub hexseq {
+ my($str) = $_[0];
+ my($ret);
+
+ $ret = unpack "H*", $str;
+ $ret =~ s/(..)/\\x$1/g;
+
+ return $ret;
+}
+
+# dot_expand in the target charset
+sub dot_expand {
+ my($s, $e) = @_;
+ my(@ret);
+
+ my @charset = sort { $a cmp $b } values(%sym);
+ foreach my $c (@charset) {
+ if (($c cmp $s) >= 0) {
+ last if (($c cmp $e) > 0);
+ push(@ret, $c);
+ }
+ }
+
+ return @ret;
+}
+
+# Convert symbols into literal values
+sub unsym {
+ my @ret = &unsym_with_check(@_);
+ return $ret[0];
+}
+
+# Convert symbols into literal values (return[0]), and a count of how
+# many symbols were converted (return[1]).
+sub unsym_with_check {
+ my($str) = $_[0];
+
+ my $rx = join("|", keys(%sym));
+ return ($str, 0) if ($rx eq "");
+ my $found = $str =~ s/<($rx)>/$sym{$1}/eg;
+
+ return ($str, $found);
+}
+
+# Convert a string of literals back into symbols. It is an error
+# for there to be literal values that can't be mapped back. The
+# converter uses a gredy algo. It is likely this could be done
+# more efficently with a regex ctrated at runtime. It would also be
+# a good idea to only create %rsym if %sym changes, but that isn't
+# the simplest thing to do in perl5.
+sub resym {
+ my($str) = $_[0];
+ my(%rsym, $k, $v);
+ my $max_len = 0;
+ my $ret = "";
+
+ while(($k, $v) = each(%sym)) {
+ # Collisions in $v are ok, we merely need a mapping, not the
+ # identical mapping
+ $rsym{$v} = $k;
+ $max_len = length($v) if (length($v) > $max_len);
+ }
+
+ SYM: while("" ne $str) {
+ foreach my $l ($max_len .. 1) {
+ next if ($l > length($str));
+ my $s = substr($str, 0, $l);
+ if (defined($rsym{$s})) {
+ $ret .= "<" . $rsym{$s} . ">";
+ substr($str, 0, $l) = "";
+ next SYM;
+ }
+ }
+ &exit(4, "Can't convert $str ($_[0]) back into symbolic form\n");
+ }
+
+ return $ret;
+}
+
+sub set_escape {
+ $escape_char = $_[0];
+ $val_match = qr/"(?:[^"\Q$escape_char\E]+|\Q$escape_char\E")+"|(?:\Q$escape_char\E(?:[0-7]+|d[0-9]+|x[0-9a-fA-F]+))|[^,;<>\s\Q$escape_char\E]|(?:\Q$escape_char\E)[,;<>\Q$escape_char\E]/;
+}
+
+sub set_parser {
+ my $section = $_[0];
+ ($current_LC, $parse_func, $validate_line, $call_parse_on_END)
+ = ($section, $LC_parsers{$section}->[0], $LC_parsers{$section}->[1],
+ $LC_parsers{$section}->[2]);
+ unless (defined $parse_func) {
+ &exit(4, "Unknown section name LC_$section on line $. of $opt{i}\n");
+ }
+}
+
+sub do_copy {
+ my($from) = @_;
+ local($ENV{LC_ALL}) = $from;
+
+ my $C = (new IO::File "/usr/bin/locale -k LC_$current_LC |") || &exit(5, "can't fork locale during copy of LC_$current_LC");
+ while(<$C>) {
+ if (s/=\s*$/ ""/ || s/=/ /) {
+ if (m/$validate_line/ && m/^\s*(\S*)(\s+(\S+.*?))?\s*$/) {
+ my($action, $args) = ($1, $3);
+ &{$parse_func}($action, $args);
+ } else {
+ &exit(4, "Syntax error on line $. of locale -k output"
+ . " during copy $current_LC\n");
+ }
+ } else {
+ &exit(4, "Ill-formed line $. from locale -k during copy $current_LC\n");
+ }
+ }
+ $C->close() || &exit(5, "copying LC_$current_LC from $from failed");
+}
+
+sub fixup_collate_order_args {
+ my $co = $_[0];
+
+ foreach my $s (@{$co}[1..$#{$co}]) {
+ if ("HASH" eq ref($s) && exists($s->{"..."})) {
+ $s = $co->[0];
+ }
+ }
+}
+
+sub add_to_ctype_class {
+ my($class, @runes) = @_;
+
+ my $c = $ctype_classes{$class};
+ foreach my $r (@runes) {
+ $c->{$r} = 2 unless exists $c->{$r};
+ }
+}
+
+sub deny_in_ctype_class {
+ my($class, $deny_reason, @runes) = @_;
+
+ my $c = $ctype_classes{$class};
+ foreach my $r (@runes) {
+ next unless exists $c->{$r};
+ $deny_reason =~ s/^(\S+)$/can't belong in class $class and in class $1 at the same time/;
+ &exit(4, &hexchars($r) . " " . $deny_reason . "\n");
+ }
+}
+
+# write_lc_{money,time,messages} all use the existing Libc format, which
+# is raw text with each record terminated by a newline, and records
+# in a predetermined order.
+
+sub write_lc_money {
+ my $F = (new IO::File "$locale_dir/LC_MONETARY", O_TRUNC|O_WRONLY|O_CREAT, 0666) || &exit(4, "$0 can't create $locale_dir/LC_MONETARY: $!");
+ foreach my $s (qw(int_curr_symbol currency_symbol mon_decimal_point mon_thousands_sep mon_grouping positive_sign negative_sign int_frac_digits frac_digits p_cs_precedes p_sep_by_space n_cs_precedes n_sep_by_space p_sign_posn n_sign_posn int_p_cs_precedes int_n_cs_precedes int_p_sep_by_space int_n_sep_by_space int_p_sign_posn int_n_sign_posn)) {
+ if (exists $monetary{$s}) {
+ my $v = $monetary{$s};
+ if ("ARRAY" eq ref $v) {
+ $F->print(join(";", @$v), "\n");
+ } else {
+ $F->print("$v\n");
+ }
+ } else {
+ if ($s =~ m/^(int_curr_symbol|currency_symbol|mon_decimal_point|mon_thousands_sep|positive_sign|negative_sign)$/) {
+ $F->print("\n");
+ } else {
+ $F->print("-1\n");
+ }
+ }
+ }
+}
+
+sub write_lc_time {
+ my $F = (new IO::File "$locale_dir/LC_TIME", O_TRUNC|O_WRONLY|O_CREAT, 0666) || &exit(4, "$0 can't create $locale_dir/LC_TIME: $!");
+ my %array_cnt = (abmon => 12, mon => 12, abday => 7, day => 7, alt_month => 12, am_pm => 2);
+
+ $time{"md_order"} = "md" unless defined $time{"md_order"};
+
+ foreach my $s (qw(abmon mon abday day t_fmt d_fmt d_t_fmt am_pm d_t_fmt mon md_order t_fmt_ampm)) {
+ my $cnt = $array_cnt{$s};
+ my $v = $time{$s};
+
+ if (defined $v) {
+ if (defined $cnt) {
+ my @a = @{$v};
+ &exit(4, "$0: $s has " . (0 + @a)
+ . " elements, it needs to have exactly $cnt\n")
+ unless (@a == $cnt);
+ $F->print(join("\n", @a), "\n");
+ } else {
+ $F->print("$v\n");
+ }
+ } else {
+ $cnt = 1 if !defined $cnt;
+ $F->print("\n" x $cnt);
+ }
+ }
+}
+
+sub write_lc_messages {
+ mkdir("$locale_dir/LC_MESSAGES");
+ my $F = (new IO::File "$locale_dir/LC_MESSAGES/LC_MESSAGES", O_TRUNC|O_WRONLY|O_CREAT, 0666) || &exit(4, "$0 can't create $locale_dir/LC_MESSAGES/LC_MESSAGES: $!");
+
+ foreach my $s (qw(yesexpr noexpr yesstr nostr)) {
+ my $v = $messages{$s};
+
+ if (defined $v) {
+ $F->print("$v\n");
+ } else {
+ $F->print("\n");
+ }
+ }
+}
+
+sub write_lc_numeric {
+ my $F = (new IO::File "$locale_dir/LC_NUMERIC", O_TRUNC|O_WRONLY|O_CREAT, 0666) || &exit(4, "$0 can't create $locale_dir/LC_NUMERIC: $!");
+
+ foreach my $s (qw(decimal_point thousands_sep grouping)) {
+ if (exists $numeric{$s}) {
+ my $v = $numeric{$s};
+ if ("ARRAY" eq ref $v) {
+ $F->print(join(";", @$v), "\n");
+ } else {
+ $F->print("$v\n");
+ }
+ } else {
+ $F->print("\n");
+ }
+ }
+}
+
+sub bylenval {
+ return 0 if ("ARRAY" ne ref $a || "ARRAY" ne ref $b);
+
+ my($aval, $af) = &unsym_with_check($a->[0]);
+ $aval = $cele{$a->[0]} unless $af;
+ my($bval, $bf) = &unsym_with_check($b->[0]);
+ $bval = $cele{$b->[0]} unless $bf;
+
+ my $r = length($aval) - length($bval);
+ return $r if $r;
+ return $aval cmp $bval;
+}
+
+sub write_lc_collate {
+ return unless @colldef;
+
+ # colldef doesn't parse the whole glory of SuSv3 charmaps, and we
+ # already have, so we cna spit out a simplifyed one; unfortunitly
+ # it doesn't like "/dev/fd/N" so we need a named tmp file
+ my($CMAP, $cmapname) = tempfile(DIR => "/tmp");
+ foreach my $s (keys(%sym)) {
+ $CMAP->print("<$s>\t", sprintf "\\x%02x\n", ord($sym{$s}));
+ }
+ $CMAP->flush();
+ unshift(@colldef, qq{charmap $cmapname});
+ unshift(@colldef, "LC_COLLATE");
+ $colldef[$#colldef] = "END LC_COLLATE";
+
+ # Can't just use /dev/stdin, colldef appears to use seek,
+ # and even seems to need a named temp file (re-open?)
+ my($COL, $colname) = tempfile(DIR => "/tmp");
+ $COL->print(join("\n", @colldef), "\n");
+ $COL->flush();
+
+ my $rc = system(
+ "/usr/bin/colldef -o $locale_dir/LC_COLLATE $colname");
+ unlink $colname, $cmapname;
+ if ($rc) {
+ &exit(1, "Bad return from colldef $rc");
+ }
+}
+
+# Pack an int of unknown size into a series of bytes, each of which
+# contains 7 bits of data, and the top bit is clear on the last
+# byte of data. Also works on arrays -- does not encode the size of
+# the array. This format is great for data that tends to have fewer
+# then 21 bits.
+sub pack_p_int {
+ if (@_ > 1) {
+ my $ret = "";
+ foreach my $v (@_) {
+ $ret .= &pack_p_int($v);
+ }
+
+ return $ret;
+ }
+
+ my $v = $_[0];
+ my $b;
+
+ &exit(4, "pack_p_int only works on positive values") if ($v < 0);
+ if ($v < 128) {
+ $b = chr($v);
+ } else {
+ $b = chr(($v & 0x7f) | 0x80);
+ $b .= pack_p_int($v >> 7);
+ }
+ return $b;
+}
+
+sub strip_angles {
+ my $s = $_[0];
+ $s =~ s/^<(.*)>$/$1/;
+ return $s;
+}
+
+# For localedef
+# xc=0 "no warnings, locale defined"
+# xc=1 "warnings, locale defined"
+# xc=2 "implmentation limits or unsupported charactor sets, no locale defined"
+# xc=3 "can't create new locales"
+# xc=4+ "wornings or errors, no locale defined"
+sub exit {
+ my($xc, $message) = @_;
+
+ print STDERR $message;
+ exit $xc;
+}
diff --git a/adv_cmds/lsvfs/lsvfs.1 b/adv_cmds/lsvfs/lsvfs.1
new file mode 100644
index 0000000..411ea17
--- /dev/null
+++ b/adv_cmds/lsvfs/lsvfs.1
@@ -0,0 +1,67 @@
+.\" Copyright (c) 1998-2003 Apple Computer, Inc. All rights reserved.
+.\"
+.\" @APPLE_LICENSE_HEADER_START@
+.\"
+.\" The contents of this file constitute Original Code as defined in and
+.\" are subject to the Apple Public Source License Version 1.1 (the
+.\" "License"). You may not use this file except in compliance with the
+.\" License. Please obtain a copy of the License at
+.\" http://www.apple.com/publicsource and read it before using this file.
+.\"
+.\" This Original Code and all software distributed under the License are
+.\" distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+.\" License for the specific language governing rights and limitations
+.\" under the License.
+.\"
+.\" @APPLE_LICENSE_HEADER_END@
+.\"
+.Dd January 4, 2003
+.Dt LSVFS 1
+.Os
+.Sh NAME
+.Nm lsvfs
+.Nd list known virtual file systems
+.Sh SYNOPSIS
+.Nm
+.Op Ar vfsname Ar ...
+.Sh DESCRIPTION
+The
+.Nm
+command lists information about the currently loaded virtual filesystem
+modules.
+When
+.Ar vfsname
+arguments are given,
+.Nm
+lists information about the specified VFS modules.
+Otherwise,
+.Nm
+lists all currently loaded modules.
+The information is as follows:
+.Pp
+.Bl -tag -compact -width Filesystem
+.It Filesystem
+the name of the filesystem, as would be used in the
+.Ar type
+parameter to
+.Xr mount 2
+and the
+.Fl t
+option to
+.Xr mount 8
+.It Refs
+the number of references to this VFS; i.e., the number of currently
+mounted filesystems of this type
+.It Flags
+flag bits
+.El
+.Sh SEE ALSO
+.Xr mount 2 ,
+.Xr mount 8
+.Sh HISTORY
+The command from which this tool was derived, as well as this manual,
+originally appeared in
+.Fx 2.0 .
diff --git a/adv_cmds/lsvfs/lsvfs.c b/adv_cmds/lsvfs/lsvfs.c
new file mode 100644
index 0000000..73f4135
--- /dev/null
+++ b/adv_cmds/lsvfs/lsvfs.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 1998-2003 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <sys/mount.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#define FMT "%-32.32s %5d %s\n"
+#define HDRFMT "%-32.32s %5.5s %s\n"
+#define DASHES "-------------------------------- ----- ---------------\n"
+
+static const char *fmt_flags(int flags);
+
+int
+main(int argc, char *argv[])
+{
+ struct vfsconf vfc;
+ int mib[4], max, x;
+ size_t len;
+
+ printf(HDRFMT, "Filesystem", "Refs", "Flags");
+ fputs(DASHES, stdout);
+
+ if (argc > 1) {
+ for (x = 1; x < argc; x++)
+ if (getvfsbyname(argv[x], &vfc) == 0)
+ printf(FMT, vfc.vfc_name, vfc.vfc_refcount,
+ fmt_flags(vfc.vfc_flags));
+ else
+ warnx("VFS %s unknown or not loaded", argv[x]);
+ } else {
+ mib[0] = CTL_VFS;
+ mib[1] = VFS_GENERIC;
+ mib[2] = VFS_MAXTYPENUM;
+ len = sizeof(int);
+ if (sysctl(mib, 3, &max, &len, NULL, 0) != 0)
+ errx(1, "sysctl");
+ mib[2] = VFS_CONF;
+
+ len = sizeof(vfc);
+ for (x = 0; x < max; x++) {
+ mib[3] = x;
+ if (sysctl(mib, 4, &vfc, &len, NULL, 0) != 0) {
+ if (errno != ENOTSUP)
+ errx(1, "sysctl");
+ } else {
+ printf(FMT, vfc.vfc_name, vfc.vfc_refcount,
+ fmt_flags(vfc.vfc_flags));
+ }
+ }
+ }
+
+ return 0;
+}
+
+static const char *
+fmt_flags(int flags)
+{
+ static char buf[sizeof "local, dovolfs"];
+ int comma = 0;
+
+ buf[0] = '\0';
+
+ if(flags & MNT_LOCAL) {
+ if(comma++) strcat(buf, ", ");
+ strcat(buf, "local");
+ }
+
+ if(flags & MNT_DOVOLFS) {
+ if(comma++) strcat(buf, ", ");
+ strcat(buf, "dovolfs");
+ }
+
+ return buf;
+}
diff --git a/adv_cmds/mklocale/extern.h b/adv_cmds/mklocale/extern.h
new file mode 100644
index 0000000..f2037dd
--- /dev/null
+++ b/adv_cmds/mklocale/extern.h
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * 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.
+ *
+ * $FreeBSD: src/usr.bin/mklocale/extern.h,v 1.1 2002/04/28 12:34:54 markm Exp $
+ */
+
+int yylex(void);
+int yyparse(void);
diff --git a/adv_cmds/mklocale/ldef.h b/adv_cmds/mklocale/ldef.h
new file mode 100644
index 0000000..da9e015
--- /dev/null
+++ b/adv_cmds/mklocale/ldef.h
@@ -0,0 +1,68 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * 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.
+ *
+ * @(#)ldef.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD: src/usr.bin/mklocale/ldef.h,v 1.5 2007/11/07 14:46:22 rafan Exp $
+ */
+
+#include <sys/types.h>
+#ifdef __APPLE__
+#include <inttypes.h>
+#include <limits.h>
+#endif /* __APPLE__ */
+#include "runefile.h"
+
+/*
+ * This should look a LOT like a _RuneEntry
+ */
+typedef struct rune_list {
+ int32_t min;
+ int32_t max;
+ int32_t map;
+ uint32_t *types;
+ struct rune_list *next;
+} rune_list;
+
+typedef struct rune_map {
+ uint32_t map[_CACHED_RUNES];
+ rune_list *root;
+} rune_map;
+
+#ifdef __APPLE__
+typedef struct {
+ char name[CHARCLASS_NAME_MAX];
+ uint32_t mask;
+} rune_charclass;
+#endif /* __APPLE__ */
diff --git a/adv_cmds/mklocale/lex.l b/adv_cmds/mklocale/lex.l
new file mode 100644
index 0000000..9ffbaca
--- /dev/null
+++ b/adv_cmds/mklocale/lex.l
@@ -0,0 +1,179 @@
+%{
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * 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
+#if 0
+static char sccsid[] = "@(#)lex.l 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/mklocale/lex.l,v 1.9 2005/02/26 21:47:54 ru Exp $");
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "ldef.h"
+#include "y.tab.h"
+#include "extern.h"
+%}
+
+ODIGIT [0-7]
+DIGIT [0-9]
+XDIGIT [0-9a-fA-F]
+W [\t\n\r ]
+
+%%
+\'.\' { yylval.rune = (unsigned char)yytext[1];
+ return(RUNE); }
+
+'\\a' { yylval.rune = '\a';
+ return(RUNE); }
+'\\b' { yylval.rune = '\b';
+ return(RUNE); }
+'\\f' { yylval.rune = '\f';
+ return(RUNE); }
+'\\n' { yylval.rune = '\n';
+ return(RUNE); }
+'\\r' { yylval.rune = '\r';
+ return(RUNE); }
+'\\t' { yylval.rune = '\t';
+ return(RUNE); }
+'\\v' { yylval.rune = '\v';
+ return(RUNE); }
+
+0x{XDIGIT}+ { yylval.rune = strtol(yytext, 0, 16);
+ return(RUNE); }
+0{ODIGIT}+ { yylval.rune = strtol(yytext, 0, 8);
+ return(RUNE); }
+{DIGIT}+ { yylval.rune = strtol(yytext, 0, 10);
+ return(RUNE); }
+
+
+MAPLOWER { return(MAPLOWER); }
+MAPUPPER { return(MAPUPPER); }
+TODIGIT { return(DIGITMAP); }
+INVALID { return(INVALID); }
+
+ALPHA { yylval.i = _CTYPE_A|_CTYPE_R|_CTYPE_G;
+ return(LIST); }
+CONTROL { yylval.i = _CTYPE_C;
+ return(LIST); }
+DIGIT { yylval.i = _CTYPE_D|_CTYPE_R|_CTYPE_G;
+ return(LIST); }
+GRAPH { yylval.i = _CTYPE_G|_CTYPE_R;
+ return(LIST); }
+LOWER { yylval.i = _CTYPE_L|_CTYPE_R|_CTYPE_G;
+ return(LIST); }
+PUNCT { yylval.i = _CTYPE_P|_CTYPE_R|_CTYPE_G;
+ return(LIST); }
+SPACE { yylval.i = _CTYPE_S;
+ return(LIST); }
+UPPER { yylval.i = _CTYPE_U|_CTYPE_R|_CTYPE_G;
+ return(LIST); }
+XDIGIT { yylval.i = _CTYPE_X|_CTYPE_R|_CTYPE_G;
+ return(LIST); }
+BLANK { yylval.i = _CTYPE_B;
+ return(LIST); }
+PRINT { yylval.i = _CTYPE_R;
+ return(LIST); }
+IDEOGRAM { yylval.i = _CTYPE_I|_CTYPE_R|_CTYPE_G;
+ return(LIST); }
+SPECIAL { yylval.i = _CTYPE_T|_CTYPE_R|_CTYPE_G;
+ return(LIST); }
+PHONOGRAM { yylval.i = _CTYPE_Q|_CTYPE_R|_CTYPE_G;
+ return(LIST); }
+SWIDTH0 { yylval.i = _CTYPE_SW0; return(LIST); }
+SWIDTH1 { yylval.i = _CTYPE_SW1; return(LIST); }
+SWIDTH2 { yylval.i = _CTYPE_SW2; return(LIST); }
+SWIDTH3 { yylval.i = _CTYPE_SW3; return(LIST); }
+
+VARIABLE[\t ] { static char vbuf[1024];
+ char *v = vbuf;
+ while ((*v = input()) && *v != '\n')
+ ++v;
+ if (*v) {
+ unput(*v);
+ *v = 0;
+ }
+ yylval.str = vbuf;
+ return(VARIABLE);
+ }
+
+ENCODING { return(ENCODING); }
+
+CHARCLASS { return(CHARCLASS); }
+
+\".*\" { char *e = yytext + 1;
+ yylval.str = e;
+ while (*e && *e != '"')
+ ++e;
+ *e = 0;
+ return(STRING); }
+
+\<|\(|\[ { return(LBRK); }
+
+\>|\)|\] { return(RBRK); }
+
+\- { return(THRU); }
+\.\.\. { return(THRU); }
+
+\: { return(':'); }
+
+{W}+ ;
+
+^\#.*\n ;
+\/\* { char lc = 0;
+ do {
+ while ((lc) != '*')
+ if ((lc = input()) == 0)
+ break;
+ } while((lc = input()) != '/');
+ }
+
+\\$ ;
+. { printf("Lex is skipping '%s'\n", yytext); }
+%%
+
+#if !defined(yywrap)
+int
+yywrap()
+{
+ return(1);
+}
+#endif
diff --git a/adv_cmds/mklocale/mklocale.1 b/adv_cmds/mklocale/mklocale.1
new file mode 100644
index 0000000..8f2ec0e
--- /dev/null
+++ b/adv_cmds/mklocale/mklocale.1
@@ -0,0 +1,308 @@
+.\" Copyright (c) 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Paul Borman at Krystal Technologies.
+.\"
+.\" 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.
+.\"
+.\" @(#)mklocale.1 8.2 (Berkeley) 4/18/94
+.\" $FreeBSD: src/usr.bin/mklocale/mklocale.1,v 1.28 2008/01/22 00:04:50 ache Exp $
+.\"
+.Dd October 17, 2004
+.Dt MKLOCALE 1
+.Os
+.Sh NAME
+.Nm mklocale
+.Nd make LC_CTYPE locale files
+.Sh SYNOPSIS
+.Nm
+.Op Fl d
+.Ar "< src-file"
+.Ar "> language/LC_CTYPE"
+.Nm
+.Op Fl d
+.Fl o
+.Ar language/LC_CTYPE
+.Ar src-file
+.Sh DESCRIPTION
+The
+.Nm
+utility reads a
+.Dv LC_CTYPE
+source file from standard input and produces a
+.Dv LC_CTYPE
+binary file on standard output suitable for placement in
+.Pa /usr/share/locale/ Ns Ar language Ns Pa /LC_CTYPE .
+.Pp
+The format of
+.Ar src-file
+is quite simple.
+It consists of a series of lines which start with a keyword and have
+associated data following.
+C style comments are used
+to place comments in the file.
+.Pp
+Following options are available:
+.Bl -tag -width indent
+.It Fl d
+Turns on debugging messages.
+.It Fl o
+Specify output file.
+.El
+.Pp
+Besides the keywords which will be listed below,
+the following are valid tokens in
+.Ar src-file :
+.Bl -tag -width ".Ar literal"
+.It Dv RUNE
+A
+.Dv RUNE
+may be any of the following:
+.Bl -tag -width ".Ar 0x[0-9a-z]*"
+.It Ar 'x'
+The ASCII character
+.Ar x .
+.It Ar '\ex'
+The ANSI C character
+.Ar \ex
+where
+.Ar \ex
+is one of
+.Dv \ea ,
+.Dv \eb ,
+.Dv \ef ,
+.Dv \en ,
+.Dv \er ,
+.Dv \et ,
+or
+.Dv \ev .
+.It Ar 0x[0-9a-z]*
+A hexadecimal number representing a rune code.
+.It Ar 0[0-7]*
+An octal number representing a rune code.
+.It Ar [1-9][0-9]*
+A decimal number representing a rune code.
+.El
+.It Dv STRING
+A string enclosed in double quotes (").
+.It Dv THRU
+Either
+.Dv ...
+or
+.Dv - .
+Used to indicate ranges.
+.It Ar literal
+The follow characters are taken literally:
+.Bl -tag -width ".Dv <\|\|(\|\|["
+.It Dv "<\|(\|["
+Used to start a mapping.
+All are equivalent.
+.It Dv ">\|\^)\|]"
+Used to end a mapping.
+All are equivalent.
+.It Dv :
+Used as a delimiter in mappings.
+.El
+.El
+.Pp
+Key words which should only appear once are:
+.Bl -tag -width ".Dv PHONOGRAM"
+.It Dv ENCODING
+Followed by a
+.Dv STRING
+which indicates the encoding mechanism to be used for this locale.
+The current encodings are:
+.Bl -tag -width ".Dv MSKanji"
+.It Dv ASCII
+American Standard Code for Information Interchange.
+.It Dv BIG5
+The
+.Dq Big5
+encoding of Chinese.
+.It Dv EUC
+.Dv EUC
+encoding as used by several
+vendors of
+.Ux
+systems.
+.It Dv GB18030
+PRC national standard for encoding of Chinese text.
+.It Dv GB2312
+Older PRC national standard for encoding Chinese text.
+.It Dv GBK
+A widely used encoding method for Chinese text,
+backwards compatible with GB\ 2312-1980.
+.It Dv MSKanji
+The method of encoding Japanese used by Microsoft,
+loosely based on JIS.
+Also known as
+.Dq "Shift JIS"
+and
+.Dq SJIS .
+.It Dv NONE
+No translation and the default.
+.It Dv UTF-8
+The
+.Dv UTF-8
+transformation format of
+.Tn ISO
+10646
+as defined by RFC 2279.
+.El
+.It Dv VARIABLE
+This keyword must be followed by a single tab or space character,
+after which encoding specific data is placed.
+Currently only the
+.Dv "EUC"
+encoding requires variable data.
+See
+.Xr euc 5
+for further details.
+.It Dv INVALID
+(obsolete)
+A single
+.Dv RUNE
+follows and is used as the invalid rune for this locale.
+.El
+.Pp
+The following keywords may appear multiple times and have the following
+format for data:
+.Bl -tag -width ".Dv <RUNE1 THRU RUNEn : RUNE2>" -offset indent
+.It Dv <RUNE1 RUNE2>
+.Dv RUNE1
+is mapped to
+.Dv RUNE2 .
+.It Dv <RUNE1 THRU RUNEn : RUNE2>
+Runes
+.Dv RUNE1
+through
+.Dv RUNEn
+are mapped to
+.Dv RUNE2
+through
+.Dv RUNE2
++ n-1.
+.El
+.Bl -tag -width ".Dv PHONOGRAM"
+.It Dv MAPLOWER
+Defines the tolower mappings.
+.Dv RUNE2
+is the lower case representation of
+.Dv RUNE1 .
+.It Dv MAPUPPER
+Defines the toupper mappings.
+.Dv RUNE2
+is the upper case representation of
+.Dv RUNE1 .
+.It Dv TODIGIT
+Defines a map from runes to their digit value.
+.Dv RUNE2
+is the integer value represented by
+.Dv RUNE1 .
+For example, the ASCII character
+.Ql 0
+would map to the decimal value 0.
+Only values up to 255
+are allowed.
+.El
+.Pp
+The following keywords may appear multiple times and have the following
+format for data:
+.Bl -tag -width ".Dv RUNE1 THRU RUNEn" -offset indent
+.It Dv RUNE
+This rune has the property defined by the keyword.
+.It Dv "RUNE1 THRU RUNEn"
+All the runes between and including
+.Dv RUNE1
+and
+.Dv RUNEn
+have the property defined by the keyword.
+.El
+.Bl -tag -width ".Dv PHONOGRAM"
+.It Dv ALPHA
+Defines runes which are alphabetic, printable and graphic.
+.It Dv CONTROL
+Defines runes which are control characters.
+.It Dv DIGIT
+Defines runes which are decimal digits, printable and graphic.
+.It Dv GRAPH
+Defines runes which are graphic and printable.
+.It Dv LOWER
+Defines runes which are lower case, printable and graphic.
+.It Dv PUNCT
+Defines runes which are punctuation, printable and graphic.
+.It Dv SPACE
+Defines runes which are spaces.
+.It Dv UPPER
+Defines runes which are upper case, printable and graphic.
+.It Dv XDIGIT
+Defines runes which are hexadecimal digits, printable and graphic.
+.It Dv BLANK
+Defines runes which are blank.
+.It Dv PRINT
+Defines runes which are printable.
+.It Dv IDEOGRAM
+Defines runes which are ideograms, printable and graphic.
+.It Dv SPECIAL
+Defines runes which are special characters, printable and graphic.
+.It Dv PHONOGRAM
+Defines runes which are phonograms, printable and graphic.
+.It Dv SWIDTH0
+Defines runes with display width 0.
+.It Dv SWIDTH1
+Defines runes with display width 1.
+.It Dv SWIDTH2
+Defines runes with display width 2.
+.It Dv SWIDTH3
+Defines runes with display width 3.
+.El
+.Pp
+If no display width explicitly defined, width 1 assumed
+for printable runes by default.
+.Sh SEE ALSO
+.Xr colldef 1 ,
+.Xr setlocale 3 ,
+.Xr wcwidth 3 ,
+.Xr big5 5 ,
+.Xr euc 5 ,
+.Xr gb18030 5 ,
+.Xr gb2312 5 ,
+.Xr gbk 5 ,
+.Xr mskanji 5 ,
+.Xr utf8 5
+.Sh HISTORY
+The
+.Nm
+utility first appeared in
+.Bx 4.4 .
+.Sh BUGS
+The
+.Nm
+utility is overly simplistic.
diff --git a/adv_cmds/mklocale/runefile.h b/adv_cmds/mklocale/runefile.h
new file mode 100644
index 0000000..6b3f9f7
--- /dev/null
+++ b/adv_cmds/mklocale/runefile.h
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 2005 Ruslan Ermilov
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD: src/lib/libc/locale/runefile.h,v 1.1 2005/05/16 09:32:41 ru Exp $
+ */
+
+#ifndef _RUNEFILE_H_
+#define _RUNEFILE_H_
+
+#include <sys/types.h>
+
+#ifndef _CACHED_RUNES
+#define _CACHED_RUNES (1 << 8)
+#endif
+
+typedef struct {
+ int32_t min;
+ int32_t max;
+ int32_t map;
+#ifdef __APPLE__
+ int32_t __types_fake;
+#endif /* __APPLE__ */
+} _FileRuneEntry;
+
+typedef struct {
+ char magic[8];
+ char encoding[32];
+
+#ifdef __APPLE__
+ int32_t __sgetrune_fake;
+ int32_t __sputrune_fake;
+ int32_t __invalid_rune;
+#endif /* __APPLE__ */
+
+ uint32_t runetype[_CACHED_RUNES];
+ int32_t maplower[_CACHED_RUNES];
+ int32_t mapupper[_CACHED_RUNES];
+
+ int32_t runetype_ext_nranges;
+#ifdef __APPLE__
+ int32_t __runetype_ext_ranges_fake;
+#endif /* __APPLE__ */
+ int32_t maplower_ext_nranges;
+#ifdef __APPLE__
+ int32_t __maplower_ext_ranges_fake;
+#endif /* __APPLE__ */
+ int32_t mapupper_ext_nranges;
+#ifdef __APPLE__
+ int32_t __mapupper_ext_ranges_fake;
+#endif /* __APPLE__ */
+
+#ifdef __APPLE__
+ int32_t __variable_fake;
+#endif /* __APPLE__ */
+ int32_t variable_len;
+
+#ifdef __APPLE__
+ int32_t ncharclasses;
+ int32_t __charclasses_fake;
+#endif /* __APPLE__ */
+} _FileRuneLocale;
+
+#define _FILE_RUNE_MAGIC_1 "RuneMag1"
+
+#endif /* !_RUNEFILE_H_ */
diff --git a/adv_cmds/mklocale/yacc.y b/adv_cmds/mklocale/yacc.y
new file mode 100644
index 0000000..f76498d
--- /dev/null
+++ b/adv_cmds/mklocale/yacc.y
@@ -0,0 +1,929 @@
+%{
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * 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
+#if 0
+static char sccsid[] = "@(#)yacc.y 8.1 (Berkeley) 6/6/93";
+#endif /* 0 */
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/mklocale/yacc.y,v 1.28 2008/01/22 00:04:50 ache Exp $");
+
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ldef.h"
+#include "extern.h"
+#include "runefile.h"
+
+#define MAX_CHARCLASS 4
+#define CHARCLASSBIT 4
+
+static void *xmalloc(unsigned int sz);
+static uint32_t *xlalloc(unsigned int sz);
+void yyerror(const char *s);
+static uint32_t *xrelalloc(uint32_t *old, unsigned int sz);
+static void dump_tables(void);
+static void cleanout(void);
+
+const char *locale_file = "<stdout>";
+
+rune_map maplower = { { 0 }, NULL };
+rune_map mapupper = { { 0 }, NULL };
+rune_map types = { { 0 }, NULL };
+
+_FileRuneLocale new_locale = { "", "", 0, 0, 0, {}, {}, {}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+char *variable = NULL;
+
+rune_charclass charclasses[MAX_CHARCLASS];
+int charclass_index = 0;
+
+void set_map(rune_map *, rune_list *, uint32_t);
+void set_digitmap(rune_map *, rune_list *);
+void add_map(rune_map *, rune_list *, uint32_t);
+static void usage(void);
+%}
+
+%union {
+ int32_t rune;
+ int i;
+ char *str;
+
+ rune_list *list;
+}
+
+%token <rune> RUNE
+%token LBRK
+%token RBRK
+%token THRU
+%token MAPLOWER
+%token MAPUPPER
+%token DIGITMAP
+%token CHARCLASS
+%token <i> LIST
+%token <str> VARIABLE
+%token ENCODING
+%token INVALID
+%token <str> STRING
+
+%type <list> list
+%type <list> map
+
+
+%%
+
+locale : /* empty */
+ | table
+ { dump_tables(); }
+ ;
+
+table : entry
+ | table entry
+ ;
+
+entry : ENCODING STRING
+ { if (strcmp($2, "NONE") &&
+ strcmp($2, "ASCII") &&
+ strcmp($2, "UTF-8") &&
+ strcmp($2, "EUC") &&
+ strcmp($2, "GBK") &&
+ strcmp($2, "GB18030") &&
+ strcmp($2, "GB2312") &&
+ strcmp($2, "BIG5") &&
+ strcmp($2, "MSKanji") &&
+ strcmp($2, "UTF2"))
+ warnx("ENCODING %s is not supported by libc", $2);
+ strncpy(new_locale.encoding, $2,
+ sizeof(new_locale.encoding)); }
+ | VARIABLE
+ { new_locale.variable_len = strlen($1) + 1;
+ variable = xmalloc(new_locale.variable_len);
+ strcpy(variable, $1);
+ }
+ | INVALID RUNE
+ { warnx("the INVALID keyword is deprecated"); }
+ | LIST list
+ { set_map(&types, $2, $1); }
+ | MAPLOWER map
+ { set_map(&maplower, $2, 0); }
+ | MAPUPPER map
+ { set_map(&mapupper, $2, 0); }
+ | DIGITMAP map
+ {
+ if (($2->map >= 0) && ($2->map <= 255)) { /* Data corruption otherwise */
+ set_digitmap(&types, $2);
+ }
+ }
+ | CHARCLASS STRING list
+ {
+ int i;
+ if (strlen($2) > CHARCLASS_NAME_MAX)
+ errx(1, "Exceeded maximum charclass name size (%d) \"%s\"", CHARCLASS_NAME_MAX, $2);
+ for(i = 0; i < charclass_index; i++)
+ if (strncmp(charclasses[i].name, $2, CHARCLASS_NAME_MAX) == 0)
+ break;
+ if (i >= charclass_index) {
+ if (charclass_index >= MAX_CHARCLASS)
+ errx(1, "Exceeded maximum number of charclasses (%d)", MAX_CHARCLASS);
+ strncpy(charclasses[charclass_index].name, $2, CHARCLASS_NAME_MAX);
+ charclasses[charclass_index].mask = (1 << (charclass_index + CHARCLASSBIT));
+ charclass_index++;
+ }
+ set_map(&types, $3, charclasses[i].mask);
+ }
+ ;
+
+list : RUNE
+ {
+ $$ = (rune_list *)xmalloc(sizeof(rune_list));
+ $$->min = $1;
+ $$->max = $1;
+ $$->next = 0;
+ }
+ | RUNE THRU RUNE
+ {
+ $$ = (rune_list *)xmalloc(sizeof(rune_list));
+ $$->min = $1;
+ $$->max = $3;
+ $$->next = 0;
+ }
+ | list RUNE
+ {
+ $$ = (rune_list *)xmalloc(sizeof(rune_list));
+ $$->min = $2;
+ $$->max = $2;
+ $$->next = $1;
+ }
+ | list RUNE THRU RUNE
+ {
+ $$ = (rune_list *)xmalloc(sizeof(rune_list));
+ $$->min = $2;
+ $$->max = $4;
+ $$->next = $1;
+ }
+ ;
+
+map : LBRK RUNE RUNE RBRK
+ {
+ $$ = (rune_list *)xmalloc(sizeof(rune_list));
+ $$->min = $2;
+ $$->max = $2;
+ $$->map = $3;
+ $$->next = 0;
+ }
+ | map LBRK RUNE RUNE RBRK
+ {
+ $$ = (rune_list *)xmalloc(sizeof(rune_list));
+ $$->min = $3;
+ $$->max = $3;
+ $$->map = $4;
+ $$->next = $1;
+ }
+ | LBRK RUNE THRU RUNE ':' RUNE RBRK
+ {
+ $$ = (rune_list *)xmalloc(sizeof(rune_list));
+ $$->min = $2;
+ $$->max = $4;
+ $$->map = $6;
+ $$->next = 0;
+ }
+ | map LBRK RUNE THRU RUNE ':' RUNE RBRK
+ {
+ $$ = (rune_list *)xmalloc(sizeof(rune_list));
+ $$->min = $3;
+ $$->max = $5;
+ $$->map = $7;
+ $$->next = $1;
+ }
+ ;
+%%
+
+int debug;
+FILE *fp;
+
+static void
+cleanout(void)
+{
+ if (fp != NULL)
+ unlink(locale_file);
+}
+
+int
+main(int ac, char *av[])
+{
+ int x;
+
+ fp = stdout;
+
+ while ((x = getopt(ac, av, "do:")) != -1) {
+ switch(x) {
+ case 'd':
+ debug = 1;
+ break;
+ case 'o':
+ locale_file = optarg;
+ if ((fp = fopen(locale_file, "w")) == NULL)
+ err(1, "%s: fopen", locale_file);
+ atexit(cleanout);
+ break;
+ default:
+ usage();
+ }
+ }
+
+ switch (ac - optind) {
+ case 0:
+ break;
+ case 1:
+ if (freopen(av[optind], "r", stdin) == 0)
+ err(1, "%s: freopen", av[optind]);
+ break;
+ default:
+ usage();
+ }
+ for (x = 0; x < _CACHED_RUNES; ++x) {
+ mapupper.map[x] = x;
+ maplower.map[x] = x;
+ }
+ memcpy(new_locale.magic, _RUNE_MAGIC_A, sizeof(new_locale.magic));
+
+ yyparse();
+
+ return(0);
+}
+
+static void
+usage()
+{
+ fprintf(stderr, "usage: mklocale [-d] [-o output] [source]\n");
+ exit(1);
+}
+
+void
+yyerror(s)
+ const char *s;
+{
+ fprintf(stderr, "%s\n", s);
+}
+
+static void *
+xmalloc(sz)
+ unsigned int sz;
+{
+ void *r = malloc(sz);
+ if (!r)
+ errx(1, "xmalloc");
+ return(r);
+}
+
+static uint32_t *
+xlalloc(sz)
+ unsigned int sz;
+{
+ uint32_t *r = (uint32_t *)malloc(sz * sizeof(uint32_t));
+ if (!r)
+ errx(1, "xlalloc");
+ return(r);
+}
+
+static uint32_t *
+xrelalloc(old, sz)
+ uint32_t *old;
+ unsigned int sz;
+{
+ uint32_t *r = (uint32_t *)realloc((char *)old,
+ sz * sizeof(uint32_t));
+ if (!r)
+ errx(1, "xrelalloc");
+ return(r);
+}
+
+void
+set_map(map, list, flag)
+ rune_map *map;
+ rune_list *list;
+ uint32_t flag;
+{
+ while (list) {
+ rune_list *nlist = list->next;
+ add_map(map, list, flag);
+ list = nlist;
+ }
+}
+
+void
+set_digitmap(map, list)
+ rune_map *map;
+ rune_list *list;
+{
+ int32_t i;
+
+ while (list) {
+ rune_list *nlist = list->next;
+ for (i = list->min; i <= list->max; ++i) {
+ if (list->map + (i - list->min)) {
+ rune_list *tmp = (rune_list *)xmalloc(sizeof(rune_list));
+ tmp->min = i;
+ tmp->max = i;
+ add_map(map, tmp, list->map + (i - list->min));
+ }
+ }
+ free(list);
+ list = nlist;
+ }
+}
+
+void
+add_map(map, list, flag)
+ rune_map *map;
+ rune_list *list;
+ uint32_t flag;
+{
+ int32_t i;
+ rune_list *lr = 0;
+ rune_list *r;
+ int32_t run;
+
+ while (list->min < _CACHED_RUNES && list->min <= list->max) {
+ if (flag)
+ map->map[list->min++] |= flag;
+ else
+ map->map[list->min++] = list->map++;
+ }
+
+ if (list->min > list->max) {
+ free(list);
+ return;
+ }
+
+ run = list->max - list->min + 1;
+
+ if (!(r = map->root) || (list->max < r->min - 1)
+ || (!flag && list->max == r->min - 1)) {
+ if (flag) {
+ list->types = xlalloc(run);
+ for (i = 0; i < run; ++i)
+ list->types[i] = flag;
+ }
+ list->next = map->root;
+ map->root = list;
+ return;
+ }
+
+ for (r = map->root; r && r->max + 1 < list->min; r = r->next)
+ lr = r;
+
+ if (!r) {
+ /*
+ * We are off the end.
+ */
+ if (flag) {
+ list->types = xlalloc(run);
+ for (i = 0; i < run; ++i)
+ list->types[i] = flag;
+ }
+ list->next = 0;
+ lr->next = list;
+ return;
+ }
+
+ if (list->max < r->min - 1) {
+ /*
+ * We come before this range and we do not intersect it.
+ * We are not before the root node, it was checked before the loop
+ */
+ if (flag) {
+ list->types = xlalloc(run);
+ for (i = 0; i < run; ++i)
+ list->types[i] = flag;
+ }
+ list->next = lr->next;
+ lr->next = list;
+ return;
+ }
+
+ /*
+ * At this point we have found that we at least intersect with
+ * the range pointed to by `r', we might intersect with one or
+ * more ranges beyond `r' as well.
+ */
+
+ if (!flag && list->map - list->min != r->map - r->min) {
+ /*
+ * There are only two cases when we are doing case maps and
+ * our maps needn't have the same offset. When we are adjoining
+ * but not intersecting.
+ */
+ if (list->max + 1 == r->min) {
+ lr->next = list;
+ list->next = r;
+ return;
+ }
+ if (list->min - 1 == r->max) {
+ list->next = r->next;
+ r->next = list;
+ return;
+ }
+ errx(1, "error: conflicting map entries");
+ }
+
+ if (list->min >= r->min && list->max <= r->max) {
+ /*
+ * Subset case.
+ */
+
+ if (flag) {
+ for (i = list->min; i <= list->max; ++i)
+ r->types[i - r->min] |= flag;
+ }
+ free(list);
+ return;
+ }
+ if (list->min <= r->min && list->max >= r->max) {
+ /*
+ * Superset case. Make him big enough to hold us.
+ * We might need to merge with the guy after him.
+ */
+ if (flag) {
+ list->types = xlalloc(list->max - list->min + 1);
+
+ for (i = list->min; i <= list->max; ++i)
+ list->types[i - list->min] = flag;
+
+ for (i = r->min; i <= r->max; ++i)
+ list->types[i - list->min] |= r->types[i - r->min];
+
+ free(r->types);
+ r->types = list->types;
+ } else {
+ r->map = list->map;
+ }
+ r->min = list->min;
+ r->max = list->max;
+ free(list);
+ } else if (list->min < r->min) {
+ /*
+ * Our tail intersects his head.
+ */
+ if (flag) {
+ list->types = xlalloc(r->max - list->min + 1);
+
+ for (i = r->min; i <= r->max; ++i)
+ list->types[i - list->min] = r->types[i - r->min];
+
+ for (i = list->min; i < r->min; ++i)
+ list->types[i - list->min] = flag;
+
+ for (i = r->min; i <= list->max; ++i)
+ list->types[i - list->min] |= flag;
+
+ free(r->types);
+ r->types = list->types;
+ } else {
+ r->map = list->map;
+ }
+ r->min = list->min;
+ free(list);
+ return;
+ } else {
+ /*
+ * Our head intersects his tail.
+ * We might need to merge with the guy after him.
+ */
+ if (flag) {
+ r->types = xrelalloc(r->types, list->max - r->min + 1);
+
+ for (i = list->min; i <= r->max; ++i)
+ r->types[i - r->min] |= flag;
+
+ for (i = r->max+1; i <= list->max; ++i)
+ r->types[i - r->min] = flag;
+ }
+ r->max = list->max;
+ free(list);
+ }
+
+ /*
+ * Okay, check to see if we grew into the next guy(s)
+ */
+ while ((lr = r->next) && r->max >= lr->min) {
+ if (flag) {
+ if (r->max >= lr->max) {
+ /*
+ * Good, we consumed all of him.
+ */
+ for (i = lr->min; i <= lr->max; ++i)
+ r->types[i - r->min] |= lr->types[i - lr->min];
+ } else {
+ /*
+ * "append" him on to the end of us.
+ */
+ r->types = xrelalloc(r->types, lr->max - r->min + 1);
+
+ for (i = lr->min; i <= r->max; ++i)
+ r->types[i - r->min] |= lr->types[i - lr->min];
+
+ for (i = r->max+1; i <= lr->max; ++i)
+ r->types[i - r->min] = lr->types[i - lr->min];
+
+ r->max = lr->max;
+ }
+ } else {
+ if (lr->max > r->max)
+ r->max = lr->max;
+ }
+
+ r->next = lr->next;
+
+ if (flag)
+ free(lr->types);
+ free(lr);
+ }
+}
+
+static void
+dump_tables()
+{
+ int x, first_d, curr_d;
+ rune_list *list;
+
+ /*
+ * See if we can compress some of the istype arrays
+ */
+ for(list = types.root; list; list = list->next) {
+ list->map = list->types[0];
+ for (x = 1; x < list->max - list->min + 1; ++x) {
+ if ((int32_t)list->types[x] != list->map) {
+ list->map = 0;
+ break;
+ }
+ }
+ }
+
+ first_d = curr_d = -1;
+ for (x = 0; x < _CACHED_RUNES; ++x) {
+ uint32_t r = types.map[x];
+
+ if (r & _CTYPE_D) {
+ if (first_d < 0)
+ first_d = curr_d = x;
+ else if (x != curr_d + 1)
+ errx(1, "error: DIGIT range is not contiguous");
+ else if (x - first_d > 9)
+ errx(1, "error: DIGIT range is too big");
+ else
+ curr_d++;
+ if (!(r & _CTYPE_X))
+ errx(1,
+ "error: DIGIT range is not a subset of XDIGIT range");
+ }
+ }
+ if (first_d < 0)
+ errx(1, "error: no DIGIT range defined in the single byte area");
+ else if (curr_d - first_d < 9)
+ errx(1, "error: DIGIT range is too small in the single byte area");
+
+ new_locale.ncharclasses = htonl(charclass_index);
+
+ /*
+ * Fill in our tables. Do this in network order so that
+ * diverse machines have a chance of sharing data.
+ * (Machines like Crays cannot share with little machines due to
+ * word size. Sigh. We tried.)
+ */
+ for (x = 0; x < _CACHED_RUNES; ++x) {
+ new_locale.runetype[x] = htonl(types.map[x]);
+ new_locale.maplower[x] = htonl(maplower.map[x]);
+ new_locale.mapupper[x] = htonl(mapupper.map[x]);
+ }
+
+ /*
+ * Count up how many ranges we will need for each of the extents.
+ */
+ list = types.root;
+
+ while (list) {
+ new_locale.runetype_ext_nranges++;
+ list = list->next;
+ }
+ new_locale.runetype_ext_nranges =
+ htonl(new_locale.runetype_ext_nranges);
+
+ list = maplower.root;
+
+ while (list) {
+ new_locale.maplower_ext_nranges++;
+ list = list->next;
+ }
+ new_locale.maplower_ext_nranges =
+ htonl(new_locale.maplower_ext_nranges);
+
+ list = mapupper.root;
+
+ while (list) {
+ new_locale.mapupper_ext_nranges++;
+ list = list->next;
+ }
+ new_locale.mapupper_ext_nranges =
+ htonl(new_locale.mapupper_ext_nranges);
+
+ new_locale.variable_len = htonl(new_locale.variable_len);
+
+ /*
+ * Okay, we are now ready to write the new locale file.
+ */
+
+ /*
+ * PART 1: The _FileRuneLocale structure
+ */
+ if (fwrite((char *)&new_locale, sizeof(new_locale), 1, fp) != 1) {
+ err(1, "%s: _FileRuneLocale structure", locale_file);
+ }
+ /*
+ * PART 2: The runetype_ext structures (not the actual tables)
+ */
+ list = types.root;
+
+ while (list) {
+ _FileRuneEntry re;
+
+ re.min = htonl(list->min);
+ re.max = htonl(list->max);
+ re.map = htonl(list->map);
+#ifdef __APPLE__
+ re.__types_fake = 0;
+#endif
+
+ if (fwrite((char *)&re, sizeof(re), 1, fp) != 1) {
+ err(1, "%s: runetype_ext structures", locale_file);
+ }
+
+ list = list->next;
+ }
+ /*
+ * PART 3: The maplower_ext structures
+ */
+ list = maplower.root;
+
+ while (list) {
+ _FileRuneEntry re;
+
+ re.min = htonl(list->min);
+ re.max = htonl(list->max);
+ re.map = htonl(list->map);
+#ifdef __APPLE__
+ re.__types_fake = 0;
+#endif
+
+ if (fwrite((char *)&re, sizeof(re), 1, fp) != 1) {
+ err(1, "%s: maplower_ext structures", locale_file);
+ }
+
+ list = list->next;
+ }
+ /*
+ * PART 4: The mapupper_ext structures
+ */
+ list = mapupper.root;
+
+ while (list) {
+ _FileRuneEntry re;
+
+ re.min = htonl(list->min);
+ re.max = htonl(list->max);
+ re.map = htonl(list->map);
+#ifdef __APPLE__
+ re.__types_fake = 0;
+#endif
+
+ if (fwrite((char *)&re, sizeof(re), 1, fp) != 1) {
+ err(1, "%s: mapupper_ext structures", locale_file);
+ }
+
+ list = list->next;
+ }
+ /*
+ * PART 5: The runetype_ext tables
+ */
+ list = types.root;
+
+ while (list) {
+ for (x = 0; x < list->max - list->min + 1; ++x)
+ list->types[x] = htonl(list->types[x]);
+
+ if (!list->map) {
+ if (fwrite((char *)list->types,
+ (list->max - list->min + 1) * sizeof(uint32_t),
+ 1, fp) != 1) {
+ err(1, "%s: runetype_ext tables", locale_file);
+ }
+ }
+ list = list->next;
+ }
+ /*
+ * PART 6: The charclass names table
+ */
+ for (x = 0; x < charclass_index; ++x) {
+ charclasses[x].mask = ntohl(charclasses[x].mask);
+ if (fwrite((char *)&charclasses[x], sizeof(rune_charclass), 1, fp) != 1) {
+ err(1, "%s: charclass names tables", locale_file);
+ }
+ }
+ /*
+ * PART 7: And finally the variable data
+ * SUSv3 says fwrite returns zero when either size or nitems is zero.
+ */
+ if (ntohl(new_locale.variable_len) > 0 && fwrite(variable,
+ ntohl(new_locale.variable_len), 1, fp) != 1) {
+ err(1, "%s: variable data", locale_file);
+ }
+ if (fclose(fp) != 0) {
+ err(1, "%s: fclose", locale_file);
+ }
+ fp = NULL;
+
+ if (!debug)
+ return;
+
+ if (new_locale.encoding[0])
+ fprintf(stderr, "ENCODING %s\n", new_locale.encoding);
+ if (variable)
+ fprintf(stderr, "VARIABLE %s\n", variable);
+
+ fprintf(stderr, "\nMAPLOWER:\n\n");
+
+ for (x = 0; x < _CACHED_RUNES; ++x) {
+ if (isprint(maplower.map[x]))
+ fprintf(stderr, " '%c'", (int)maplower.map[x]);
+ else if (maplower.map[x])
+ fprintf(stderr, "%04x", maplower.map[x]);
+ else
+ fprintf(stderr, "%4x", 0);
+ if ((x & 0xf) == 0xf)
+ fprintf(stderr, "\n");
+ else
+ fprintf(stderr, " ");
+ }
+ fprintf(stderr, "\n");
+
+ for (list = maplower.root; list; list = list->next)
+ fprintf(stderr, "\t%04x - %04x : %04x\n", list->min, list->max, list->map);
+
+ fprintf(stderr, "\nMAPUPPER:\n\n");
+
+ for (x = 0; x < _CACHED_RUNES; ++x) {
+ if (isprint(mapupper.map[x]))
+ fprintf(stderr, " '%c'", (int)mapupper.map[x]);
+ else if (mapupper.map[x])
+ fprintf(stderr, "%04x", mapupper.map[x]);
+ else
+ fprintf(stderr, "%4x", 0);
+ if ((x & 0xf) == 0xf)
+ fprintf(stderr, "\n");
+ else
+ fprintf(stderr, " ");
+ }
+ fprintf(stderr, "\n");
+
+ for (list = mapupper.root; list; list = list->next)
+ fprintf(stderr, "\t%04x - %04x : %04x\n", list->min, list->max, list->map);
+
+
+ fprintf(stderr, "\nTYPES:\n\n");
+
+ for (x = 0; x < _CACHED_RUNES; ++x) {
+ uint32_t r = types.map[x];
+
+ if (r) {
+ if (isprint(x))
+ fprintf(stderr, " '%c': %2d", x, (int)(r & 0xff));
+ else
+ fprintf(stderr, "%04x: %2d", x, (int)(r & 0xff));
+
+ fprintf(stderr, " %4s", (r & _CTYPE_A) ? "alph" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_C) ? "ctrl" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_D) ? "dig" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_G) ? "graf" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_L) ? "low" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_P) ? "punc" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_S) ? "spac" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_U) ? "upp" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_X) ? "xdig" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_B) ? "blnk" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_R) ? "prnt" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_I) ? "ideo" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_T) ? "spec" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_Q) ? "phon" : "");
+ fprintf(stderr, "\n");
+ }
+ }
+
+ for (list = types.root; list; list = list->next) {
+ if (list->map && list->min + 3 < list->max) {
+ uint32_t r = list->map;
+
+ fprintf(stderr, "%04x: %2d",
+ (uint32_t)list->min, (int)(r & 0xff));
+
+ fprintf(stderr, " %4s", (r & _CTYPE_A) ? "alph" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_C) ? "ctrl" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_D) ? "dig" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_G) ? "graf" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_L) ? "low" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_P) ? "punc" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_S) ? "spac" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_U) ? "upp" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_X) ? "xdig" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_B) ? "blnk" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_R) ? "prnt" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_I) ? "ideo" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_T) ? "spec" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_Q) ? "phon" : "");
+ fprintf(stderr, "\n...\n");
+
+ fprintf(stderr, "%04x: %2d",
+ (uint32_t)list->max, (int)(r & 0xff));
+
+ fprintf(stderr, " %4s", (r & _CTYPE_A) ? "alph" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_C) ? "ctrl" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_D) ? "dig" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_G) ? "graf" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_L) ? "low" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_P) ? "punc" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_S) ? "spac" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_U) ? "upp" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_X) ? "xdig" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_B) ? "blnk" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_R) ? "prnt" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_I) ? "ideo" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_T) ? "spec" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_Q) ? "phon" : "");
+ fprintf(stderr, "\n");
+ } else
+ for (x = list->min; x <= list->max; ++x) {
+ uint32_t r = ntohl(list->types[x - list->min]);
+
+ if (r) {
+ fprintf(stderr, "%04x: %2d", x, (int)(r & 0xff));
+
+ fprintf(stderr, " %4s", (r & _CTYPE_A) ? "alph" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_C) ? "ctrl" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_D) ? "dig" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_G) ? "graf" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_L) ? "low" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_P) ? "punc" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_S) ? "spac" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_U) ? "upp" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_X) ? "xdig" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_B) ? "blnk" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_R) ? "prnt" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_I) ? "ideo" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_T) ? "spec" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_Q) ? "phon" : "");
+ fprintf(stderr, "\n");
+ }
+ }
+ }
+}
diff --git a/adv_cmds/pkill/entitlements.plist b/adv_cmds/pkill/entitlements.plist
new file mode 100644
index 0000000..b0a6726
--- /dev/null
+++ b/adv_cmds/pkill/entitlements.plist
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.sysmond.client</key>
+ <true/>
+</dict>
+</plist>
diff --git a/adv_cmds/pkill/pkill.1 b/adv_cmds/pkill/pkill.1
new file mode 100644
index 0000000..672b185
--- /dev/null
+++ b/adv_cmds/pkill/pkill.1
@@ -0,0 +1,232 @@
+.\" $NetBSD: pkill.1,v 1.8 2003/02/14 15:59:18 grant Exp $
+.\"
+.\" $FreeBSD: src/bin/pkill/pkill.1,v 1.8 2010/07/12 01:58:46 brian Exp $
+.\"
+.\" Copyright (c) 2002 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Andrew Doran.
+.\"
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+.\"
+.Dd February 11, 2010
+.Dt PKILL 1
+.Os
+.Sh NAME
+.Nm pgrep , pkill
+.Nd find or signal processes by name
+.Sh SYNOPSIS
+.Nm pgrep
+.Op Fl Lafilnoqvx
+.Op Fl F Ar pidfile
+.Op Fl G Ar gid
+.Op Fl P Ar ppid
+.Op Fl U Ar uid
+.Op Fl d Ar delim
+.Op Fl g Ar pgrp
+.Op Fl t Ar tty
+.Op Fl u Ar euid
+.Ar pattern ...
+.Nm pkill
+.Op Fl Ar signal
+.Op Fl ILafilnovx
+.Op Fl F Ar pidfile
+.Op Fl G Ar gid
+.Op Fl P Ar ppid
+.Op Fl U Ar uid
+.Op Fl g Ar pgrp
+.Op Fl t Ar tty
+.Op Fl u Ar euid
+.Ar pattern ...
+.Sh DESCRIPTION
+The
+.Nm pgrep
+command searches the process table on the running system and prints the
+process IDs of all processes that match the criteria given on the command
+line.
+.Pp
+The
+.Nm pkill
+command searches the process table on the running system and signals all
+processes that match the criteria given on the command line.
+.Pp
+The following options are available:
+.Bl -tag -width ".Fl F Ar pidfile"
+.It Fl F Ar pidfile
+Restrict matches to a process whose PID is stored in the
+.Ar pidfile
+file.
+.It Fl G Ar gid
+Restrict matches to processes with a real group ID in the comma-separated
+list
+.Ar gid .
+.It Fl I
+Request confirmation before attempting to signal each process.
+.It Fl L
+The
+.Ar pidfile
+file given for the
+.Fl F
+option must be locked with the
+.Xr flock 2
+syscall or created with
+.Xr pidfile 3 .
+.It Fl P Ar ppid
+Restrict matches to processes with a parent process ID in the
+comma-separated list
+.Ar ppid .
+.It Fl U Ar uid
+Restrict matches to processes with a real user ID in the comma-separated
+list
+.Ar uid .
+.It Fl d Ar delim
+Specify a delimiter to be printed between each process ID.
+The default is a newline.
+This option can only be used with the
+.Nm pgrep
+command.
+.It Fl a
+Include process ancestors in the match list.
+By default, the current
+.Nm pgrep
+or
+.Nm pkill
+process and all of its ancestors are excluded (unless
+.Fl v
+is used).
+.It Fl f
+Match against full argument lists.
+The default is to match against process names.
+.It Fl g Ar pgrp
+Restrict matches to processes with a process group ID in the comma-separated
+list
+.Ar pgrp .
+The value zero is taken to mean the process group ID of the running
+.Nm pgrep
+or
+.Nm pkill
+command.
+.It Fl i
+Ignore case distinctions in both the process table and the supplied pattern.
+.It Fl l
+Long output.
+For
+.Nm pgrep ,
+print the process name in addition to the process ID for each matching
+process.
+If used in conjunction with
+.Fl f ,
+print the process ID and the full argument list for each matching process.
+For
+.Nm pkill ,
+display the kill command used for each process killed.
+.It Fl n
+Select only the newest (most recently started) of the matching processes.
+.It Fl o
+Select only the oldest (least recently started) of the matching processes.
+.It Fl q
+Do not write anything to standard output.
+.It Fl t Ar tty
+Restrict matches to processes associated with a terminal in the
+comma-separated list
+.Ar tty .
+Terminal names may be of the form
+.Pa tty Ns Ar xx
+or the shortened form
+.Ar xx .
+A single dash
+.Pq Ql -
+matches processes not associated with a terminal.
+.It Fl u Ar euid
+Restrict matches to processes with an effective user ID in the
+comma-separated list
+.Ar euid .
+.It Fl v
+Reverse the sense of the matching; display processes that do not match the
+given criteria.
+.It Fl x
+Require an exact match of the process name, or argument list if
+.Fl f
+is given.
+The default is to match any substring.
+.It Fl Ns Ar signal
+A non-negative decimal number or symbolic signal name specifying the signal
+to be sent instead of the default
+.Dv TERM .
+This option is valid only when given as the first argument to
+.Nm pkill .
+.El
+.Pp
+If any
+.Ar pattern
+operands are specified, they are used as regular expressions to match
+the command name or full argument list of each process.
+.Pp
+Note that a running
+.Nm pgrep
+or
+.Nm pkill
+process will never consider itself as
+a potential match.
+.Sh EXIT STATUS
+The
+.Nm pgrep
+and
+.Nm pkill
+utilities
+return one of the following values upon exit:
+.Bl -tag -width indent
+.It 0
+One or more processes were matched.
+.It 1
+No processes were matched.
+.It 2
+Invalid options were specified on the command line.
+.It 3
+An internal error occurred.
+.El
+.Sh SEE ALSO
+.Xr kill 1 ,
+.Xr killall 1 ,
+.Xr ps 1 ,
+.Xr flock 2 ,
+.Xr kill 2 ,
+.Xr sigaction 2 ,
+.Xr pidfile 3 ,
+.Xr re_format 7
+.\" Xr signal 7
+.Sh HISTORY
+The
+.Nm pkill
+and
+.Nm pgrep
+utilities
+first appeared in
+.Nx 1.6 .
+They are modelled after utilities of the same name that appeared in Sun
+Solaris 7.
+They made their first appearance in
+.Fx 5.3 .
+.Sh AUTHORS
+.An Andrew Doran
+.Aq ad@NetBSD.org
diff --git a/adv_cmds/pkill/pkill.c b/adv_cmds/pkill/pkill.c
new file mode 100644
index 0000000..668d656
--- /dev/null
+++ b/adv_cmds/pkill/pkill.c
@@ -0,0 +1,1111 @@
+/* $NetBSD: pkill.c,v 1.16 2005/10/10 22:13:20 kleink Exp $ */
+
+/*-
+ * Copyright (c) 2002 The NetBSD Foundation, Inc.
+ * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Andrew Doran.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/pkill/pkill.c,v 1.12 2011/02/04 16:40:50 jilles Exp $");
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/proc.h>
+#include <sys/queue.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/user.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <paths.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <regex.h>
+#include <ctype.h>
+#include <fcntl.h>
+#ifndef __APPLE__
+#include <kvm.h>
+#endif
+#include <err.h>
+#include <pwd.h>
+#include <grp.h>
+#include <errno.h>
+#include <locale.h>
+
+#ifdef __APPLE__
+#include <xpc/xpc.h>
+#include <sys/proc_info.h>
+#include <os/assumes.h>
+#include <sysmon.h>
+#endif
+
+#define STATUS_MATCH 0
+#define STATUS_NOMATCH 1
+#define STATUS_BADUSAGE 2
+#define STATUS_ERROR 3
+
+#define MIN_PID 5
+#define MAX_PID 99999
+
+#ifdef __APPLE__
+/* Ignore system processes and myself. */
+#define PSKIP(kp) ((pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)) == mypid || \
+ ((xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_FLAGS)) & PROC_FLAG_SYSTEM) != 0))
+#else
+/* Ignore system-processes (if '-S' flag is not specified) and myself. */
+#define PSKIP(kp) ((kp)->ki_pid == mypid || \
+ (!kthreads && ((kp)->ki_flag & P_KTHREAD) != 0))
+#endif
+
+enum listtype {
+ LT_GENERIC,
+ LT_USER,
+ LT_GROUP,
+ LT_TTY,
+ LT_PGRP,
+#ifndef __APPLE__
+ LT_JID,
+#endif
+ LT_SID
+};
+
+struct list {
+ SLIST_ENTRY(list) li_chain;
+ long li_number;
+};
+
+SLIST_HEAD(listhead, list);
+
+#ifdef __APPLE__
+static sysmon_table_t plist;
+#else
+static struct kinfo_proc *plist;
+#endif
+static char *selected;
+static const char *delim = "\n";
+static int nproc;
+static int pgrep;
+static int signum = SIGTERM;
+static int newest;
+static int oldest;
+static int interactive;
+static int inverse;
+static int longfmt;
+static int matchargs;
+static int fullmatch;
+#ifndef __APPLE__
+static int kthreads;
+#endif
+static int cflags = REG_EXTENDED;
+static int quiet;
+#ifndef __APPLE__
+static kvm_t *kd;
+#endif
+static pid_t mypid;
+
+static struct listhead euidlist = SLIST_HEAD_INITIALIZER(euidlist);
+static struct listhead ruidlist = SLIST_HEAD_INITIALIZER(ruidlist);
+static struct listhead rgidlist = SLIST_HEAD_INITIALIZER(rgidlist);
+static struct listhead pgrplist = SLIST_HEAD_INITIALIZER(pgrplist);
+static struct listhead ppidlist = SLIST_HEAD_INITIALIZER(ppidlist);
+static struct listhead tdevlist = SLIST_HEAD_INITIALIZER(tdevlist);
+#ifndef __APPLE__
+static struct listhead sidlist = SLIST_HEAD_INITIALIZER(sidlist);
+static struct listhead jidlist = SLIST_HEAD_INITIALIZER(jidlist);
+#endif
+
+static void usage(void) __attribute__((__noreturn__));
+#ifdef __APPLE__
+static int killact(const sysmon_row_t);
+static int grepact(const sysmon_row_t);
+#else
+static int killact(const struct kinfo_proc *);
+static int grepact(const struct kinfo_proc *);
+#endif
+static void makelist(struct listhead *, enum listtype, char *);
+static int takepid(const char *, int);
+
+#ifdef __APPLE__
+static sysmon_table_t
+copy_process_info(void)
+{
+ dispatch_semaphore_t sema;
+ sysmon_request_t request;
+ __block sysmon_table_t result = NULL;
+
+ sema = dispatch_semaphore_create(0);
+ request = sysmon_request_create_with_error(SYSMON_REQUEST_TYPE_PROCESS, ^(sysmon_table_t table, const char *error_str) {
+ if (table) {
+ result = sysmon_retain(table);
+ } else {
+ fprintf(stderr, "sysmon request failed with error: %s\n", error_str);
+ }
+ dispatch_semaphore_signal(sema);
+ });
+ sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_PID);
+ sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_FLAGS);
+ sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_UID);
+ sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_COMM);
+ sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_ARGUMENTS);
+ sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_RUID);
+ sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_RGID);
+ sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_PPID);
+ sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_PGID);
+ sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_TDEV);
+ sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_START);
+ sysmon_request_execute(request);
+ dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
+ dispatch_release(sema);
+ sysmon_release(request);
+
+ return result;
+}
+#endif /* __APPLE__ */
+
+int
+main(int argc, char **argv)
+{
+#ifdef __APPLE__
+ char buf[_POSIX2_LINE_MAX], *bufp, *mstr, *p, *q, *pidfile;
+ xpc_object_t pargv;
+#else
+ char buf[_POSIX2_LINE_MAX], *mstr, **pargv, *p, *q, *pidfile;
+ const char *execf, *coref;
+#endif
+ int ancestors, debug_opt, did_action;
+ int i, ch, bestidx, rv, criteria, pidfromfile, pidfilelock;
+#ifdef __APPLE__
+ __block size_t jsz;
+ int (*action)(const sysmon_row_t);
+ sysmon_row_t kp;
+#else
+ size_t jsz;
+ int (*action)(const struct kinfo_proc *);
+ struct kinfo_proc *kp;
+#endif
+ struct list *li;
+#ifdef __APPLE__
+ int64_t best_tval;
+#else
+ struct timeval best_tval;
+#endif
+ regex_t reg;
+ regmatch_t regmatch;
+ pid_t pid;
+
+ setlocale(LC_ALL, "");
+
+ if (strcmp(getprogname(), "pgrep") == 0) {
+ action = grepact;
+ pgrep = 1;
+ } else {
+ action = killact;
+ p = argv[1];
+
+ if (argc > 1 && p[0] == '-') {
+ p++;
+ i = (int)strtol(p, &q, 10);
+ if (*q == '\0') {
+ signum = i;
+ argv++;
+ argc--;
+ } else {
+ if (strncasecmp(p, "SIG", 3) == 0)
+ p += 3;
+ for (i = 1; i < NSIG; i++)
+ if (strcasecmp(sys_signame[i], p) == 0)
+ break;
+ if (i != NSIG) {
+ signum = i;
+ argv++;
+ argc--;
+ }
+ }
+ }
+ }
+
+ ancestors = 0;
+ criteria = 0;
+ debug_opt = 0;
+ pidfile = NULL;
+ pidfilelock = 0;
+ quiet = 0;
+#ifndef __APPLE__
+ execf = NULL;
+ coref = _PATH_DEVNULL;
+#endif
+
+#ifdef __APPLE__
+ while ((ch = getopt(argc, argv, "DF:G:ILP:U:ad:fg:ilnoqt:u:vx")) != -1)
+#else
+ while ((ch = getopt(argc, argv, "DF:G:ILM:N:P:SU:ad:fg:ij:lnoqs:t:u:vx")) != -1)
+#endif
+ switch (ch) {
+ case 'D':
+ debug_opt++;
+ break;
+ case 'F':
+ pidfile = optarg;
+ criteria = 1;
+ break;
+ case 'G':
+ makelist(&rgidlist, LT_GROUP, optarg);
+ criteria = 1;
+ break;
+ case 'I':
+ if (pgrep)
+ usage();
+ interactive = 1;
+ break;
+ case 'L':
+ pidfilelock = 1;
+ break;
+#ifndef __APPLE__
+ case 'M':
+ coref = optarg;
+ break;
+ case 'N':
+ execf = optarg;
+ break;
+#endif
+ case 'P':
+ makelist(&ppidlist, LT_GENERIC, optarg);
+ criteria = 1;
+ break;
+#ifndef __APPLE__
+ case 'S':
+ if (!pgrep)
+ usage();
+ kthreads = 1;
+ break;
+#endif
+ case 'U':
+ makelist(&ruidlist, LT_USER, optarg);
+ criteria = 1;
+ break;
+ case 'a':
+ ancestors++;
+ break;
+ case 'd':
+ if (!pgrep)
+ usage();
+ delim = optarg;
+ break;
+ case 'f':
+ matchargs = 1;
+ break;
+ case 'g':
+ makelist(&pgrplist, LT_PGRP, optarg);
+ criteria = 1;
+ break;
+ case 'i':
+ cflags |= REG_ICASE;
+ break;
+#ifndef __APPLE__
+ case 'j':
+ makelist(&jidlist, LT_JID, optarg);
+ criteria = 1;
+ break;
+#endif
+ case 'l':
+ longfmt = 1;
+ break;
+ case 'n':
+ newest = 1;
+ criteria = 1;
+ break;
+ case 'o':
+ oldest = 1;
+ criteria = 1;
+ break;
+ case 'q':
+ if (!pgrep)
+ usage();
+ quiet = 1;
+ break;
+#ifndef __APPLE__
+ case 's':
+ makelist(&sidlist, LT_SID, optarg);
+ criteria = 1;
+ break;
+#endif /* !__APPLE__ */
+ case 't':
+ makelist(&tdevlist, LT_TTY, optarg);
+ criteria = 1;
+ break;
+ case 'u':
+ makelist(&euidlist, LT_USER, optarg);
+ criteria = 1;
+ break;
+ case 'v':
+ inverse = 1;
+ break;
+ case 'x':
+ fullmatch = 1;
+ break;
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+
+ argc -= optind;
+ argv += optind;
+ if (argc != 0)
+ criteria = 1;
+ if (!criteria)
+ usage();
+ if (newest && oldest)
+ errx(STATUS_ERROR, "Options -n and -o are mutually exclusive");
+ if (pidfile != NULL)
+ pidfromfile = takepid(pidfile, pidfilelock);
+ else {
+ if (pidfilelock) {
+ errx(STATUS_ERROR,
+ "Option -L doesn't make sense without -F");
+ }
+ pidfromfile = -1;
+ }
+
+ mypid = getpid();
+
+#ifdef __APPLE__
+ plist = copy_process_info();
+ if (plist == NULL) {
+ errx(STATUS_ERROR, "Cannot get process list");
+ }
+ nproc = sysmon_table_get_count(plist);
+#else
+ /*
+ * Retrieve the list of running processes from the kernel.
+ */
+ kd = kvm_openfiles(execf, coref, NULL, O_RDONLY, buf);
+ if (kd == NULL)
+ errx(STATUS_ERROR, "Cannot open kernel files (%s)", buf);
+
+ /*
+ * Use KERN_PROC_PROC instead of KERN_PROC_ALL, since we
+ * just want processes and not individual kernel threads.
+ */
+ plist = kvm_getprocs(kd, KERN_PROC_PROC, 0, &nproc);
+ if (plist == NULL) {
+ errx(STATUS_ERROR, "Cannot get process list (%s)",
+ kvm_geterr(kd));
+ }
+#endif
+
+ /*
+ * Allocate memory which will be used to keep track of the
+ * selection.
+ */
+ if ((selected = malloc(nproc)) == NULL) {
+ err(STATUS_ERROR, "Cannot allocate memory for %d processes",
+ nproc);
+ }
+ memset(selected, 0, nproc);
+
+ /*
+ * Refine the selection.
+ */
+ for (; *argv != NULL; argv++) {
+ if ((rv = regcomp(&reg, *argv, cflags)) != 0) {
+ regerror(rv, &reg, buf, sizeof(buf));
+ errx(STATUS_BADUSAGE,
+ "Cannot compile regular expression `%s' (%s)",
+ *argv, buf);
+ }
+
+#ifdef __APPLE__
+ for (i = 0; i < nproc; i++) {
+ kp = sysmon_table_get_row(plist, i);
+#else
+ for (i = 0, kp = plist; i < nproc; i++, kp++) {
+#endif
+ if (PSKIP(kp)) {
+ if (debug_opt > 0)
+ fprintf(stderr, "* Skipped %5d %3d %s\n",
+#ifdef __APPLE__
+ (pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)),
+ (uid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_UID)),
+ xpc_string_get_string_ptr(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_COMM)));
+#else
+ kp->ki_pid, kp->ki_uid, kp->ki_comm);
+#endif
+ continue;
+ }
+
+#ifdef __APPLE__
+ if (matchargs &&
+ (pargv = sysmon_row_get_value(kp, SYSMON_ATTR_PROC_ARGUMENTS)) != NULL) {
+ jsz = 0;
+ os_assert(sizeof(buf) == _POSIX2_LINE_MAX);
+ bufp = buf;
+ xpc_array_apply(pargv, ^(size_t index, xpc_object_t value) {
+ if (jsz >= _POSIX2_LINE_MAX) {
+ return (bool)false;
+ }
+ jsz += snprintf(bufp + jsz,
+ _POSIX2_LINE_MAX - jsz,
+ index < xpc_array_get_count(pargv) - 1 ? "%s " : "%s",
+ xpc_string_get_string_ptr(value));
+ return (bool)true;
+ });
+#else
+ if (matchargs &&
+ (pargv = kvm_getargv(kd, kp, 0)) != NULL) {
+ jsz = 0;
+ while (jsz < sizeof(buf) && *pargv != NULL) {
+ jsz += snprintf(buf + jsz,
+ sizeof(buf) - jsz,
+ pargv[1] != NULL ? "%s " : "%s",
+ pargv[0]);
+ pargv++;
+ }
+#endif
+ mstr = buf;
+ } else
+#ifdef __APPLE__
+ {
+ /*
+ * comm is limited to 15 bytes (MAXCOMLEN - 1).
+ * Try to use argv[0] (trimmed) if available.
+ */
+ mstr = NULL;
+ pargv = sysmon_row_get_value(kp, SYSMON_ATTR_PROC_ARGUMENTS);
+ if (pargv != NULL && xpc_array_get_count(pargv) > 0) {
+ const char *tmp = xpc_array_get_string(pargv, 0);
+ if (tmp != NULL) {
+ mstr = strrchr(tmp, '/');
+ if (mstr != NULL) {
+ mstr++;
+ } else {
+ mstr = (char *)tmp;
+ }
+ }
+ }
+
+ /* Fall back to "comm" if we failed to get argv[0]. */
+ if (mstr == NULL || *mstr == '\0') {
+ mstr = (char *)xpc_string_get_string_ptr(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_COMM));
+ }
+
+ /* Couldn't find process name, it probably exited. */
+ if (mstr == NULL) {
+ continue;
+ }
+ }
+#else
+ mstr = kp->ki_comm;
+#endif
+
+ rv = regexec(&reg, mstr, 1, &regmatch, 0);
+ if (rv == 0) {
+ if (fullmatch) {
+ if (regmatch.rm_so == 0 &&
+ regmatch.rm_eo ==
+ (off_t)strlen(mstr))
+ selected[i] = 1;
+ } else
+ selected[i] = 1;
+ } else if (rv != REG_NOMATCH) {
+ regerror(rv, &reg, buf, sizeof(buf));
+ errx(STATUS_ERROR,
+ "Regular expression evaluation error (%s)",
+ buf);
+ }
+ if (debug_opt > 1) {
+ const char *rv_res = "NoMatch";
+ if (selected[i])
+ rv_res = "Matched";
+ fprintf(stderr, "* %s %5d %3d %s\n", rv_res,
+#ifdef __APPLE__
+ (pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)),
+ (uid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_UID)),
+ mstr);
+#else
+ kp->ki_pid, kp->ki_uid, mstr);
+#endif
+ }
+ }
+
+ regfree(&reg);
+ }
+
+#ifdef __APPLE__
+ for (i = 0; i < nproc; i++) {
+ kp = sysmon_table_get_row(plist, i);
+#else
+ for (i = 0, kp = plist; i < nproc; i++, kp++) {
+#endif
+ if (PSKIP(kp))
+ continue;
+
+#ifdef __APPLE__
+ if (pidfromfile >= 0 && (pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)) != pidfromfile) {
+#else
+ if (pidfromfile >= 0 && kp->ki_pid != pidfromfile) {
+#endif
+ selected[i] = 0;
+ continue;
+ }
+
+ SLIST_FOREACH(li, &ruidlist, li_chain)
+#ifdef __APPLE__
+ if ((uid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_RUID)) == (uid_t)li->li_number)
+#else
+ if (kp->ki_ruid == (uid_t)li->li_number)
+#endif
+ break;
+ if (SLIST_FIRST(&ruidlist) != NULL && li == NULL) {
+ selected[i] = 0;
+ continue;
+ }
+
+ SLIST_FOREACH(li, &rgidlist, li_chain)
+#ifdef __APPLE__
+ if ((gid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_RGID)) == (gid_t)li->li_number)
+#else
+ if (kp->ki_rgid == (gid_t)li->li_number)
+#endif
+ break;
+ if (SLIST_FIRST(&rgidlist) != NULL && li == NULL) {
+ selected[i] = 0;
+ continue;
+ }
+
+ SLIST_FOREACH(li, &euidlist, li_chain)
+#ifdef __APPLE__
+ if ((uid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_UID)) == (uid_t)li->li_number)
+#else
+ if (kp->ki_uid == (uid_t)li->li_number)
+#endif
+ break;
+ if (SLIST_FIRST(&euidlist) != NULL && li == NULL) {
+ selected[i] = 0;
+ continue;
+ }
+
+ SLIST_FOREACH(li, &ppidlist, li_chain)
+#ifdef __APPLE__
+ if ((pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PPID)) == (pid_t)li->li_number)
+#else
+ if (kp->ki_ppid == (pid_t)li->li_number)
+#endif
+ break;
+ if (SLIST_FIRST(&ppidlist) != NULL && li == NULL) {
+ selected[i] = 0;
+ continue;
+ }
+
+ SLIST_FOREACH(li, &pgrplist, li_chain)
+#ifdef __APPLE__
+ if ((pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PGID)) == (pid_t)li->li_number)
+#else
+ if (kp->ki_pgid == (pid_t)li->li_number)
+#endif
+ break;
+ if (SLIST_FIRST(&pgrplist) != NULL && li == NULL) {
+ selected[i] = 0;
+ continue;
+ }
+
+ SLIST_FOREACH(li, &tdevlist, li_chain) {
+ if (li->li_number == -1 &&
+#ifdef __APPLE__
+ (xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_FLAGS)) & PROC_FLAG_CONTROLT) == 0)
+#else
+ (kp->ki_flag & P_CONTROLT) == 0)
+#endif
+ break;
+#ifdef __APPLE__
+ if ((dev_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_TDEV)) == (dev_t)li->li_number)
+#else
+ if (kp->ki_tdev == (dev_t)li->li_number)
+#endif
+ break;
+ }
+ if (SLIST_FIRST(&tdevlist) != NULL && li == NULL) {
+ selected[i] = 0;
+ continue;
+ }
+
+#ifndef __APPLE__
+ SLIST_FOREACH(li, &sidlist, li_chain)
+ if (kp->ki_sid == (pid_t)li->li_number)
+ break;
+ if (SLIST_FIRST(&sidlist) != NULL && li == NULL) {
+ selected[i] = 0;
+ continue;
+ }
+
+ SLIST_FOREACH(li, &jidlist, li_chain) {
+ /* A particular jail ID, including 0 (not in jail) */
+ if (kp->ki_jid == (int)li->li_number)
+ break;
+ /* Any jail */
+ if (kp->ki_jid > 0 && li->li_number == -1)
+ break;
+ }
+ if (SLIST_FIRST(&jidlist) != NULL && li == NULL) {
+ selected[i] = 0;
+ continue;
+ }
+#endif /* !__APPLE__ */
+
+ if (argc == 0)
+ selected[i] = 1;
+ }
+
+ if (!ancestors) {
+ pid = mypid;
+ while (pid) {
+#ifdef __APPLE__
+ for (i = 0; i < nproc; i++) {
+ kp = sysmon_table_get_row(plist, i);
+#else
+ for (i = 0, kp = plist; i < nproc; i++, kp++) {
+#endif
+ if (PSKIP(kp))
+ continue;
+#ifdef __APPLE__
+ if ((pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)) == pid) {
+ selected[i] = 0;
+ pid = (pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PPID));
+ break;
+ }
+#else
+ if (kp->ki_pid == pid) {
+ selected[i] = 0;
+ pid = kp->ki_ppid;
+ break;
+ }
+#endif
+ }
+ if (i == nproc) {
+ if (pid == mypid)
+ pid = getppid();
+ else
+ break; /* Maybe we're in a jail ? */
+ }
+ }
+ }
+
+ if (newest || oldest) {
+#ifdef __APPLE__
+ best_tval = 0;
+#else
+ best_tval.tv_sec = 0;
+ best_tval.tv_usec = 0;
+#endif
+ bestidx = -1;
+
+#ifdef __APPLE__
+ for (i = 0; i < nproc; i++) {
+ kp = sysmon_table_get_row(plist, i);
+#else
+ for (i = 0, kp = plist; i < nproc; i++, kp++) {
+#endif
+ if (!selected[i])
+ continue;
+ if (bestidx == -1) {
+ /* The first entry of the list which matched. */
+ ;
+#ifdef __APPLE__
+ } else if (xpc_date_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_START)) > best_tval) {
+#else
+ } else if (timercmp(&kp->ki_start, &best_tval, >)) {
+#endif
+ /* This entry is newer than previous "best". */
+ if (oldest) /* but we want the oldest */
+ continue;
+ } else {
+ /* This entry is older than previous "best". */
+ if (newest) /* but we want the newest */
+ continue;
+ }
+ /* This entry is better than previous "best" entry. */
+#ifdef __APPLE__
+ best_tval = xpc_date_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_START));
+#else
+ best_tval.tv_sec = kp->ki_start.tv_sec;
+ best_tval.tv_usec = kp->ki_start.tv_usec;
+#endif
+ bestidx = i;
+ }
+
+ memset(selected, 0, nproc);
+ if (bestidx != -1)
+ selected[bestidx] = 1;
+ }
+
+ /*
+ * Take the appropriate action for each matched process, if any.
+ */
+ did_action = 0;
+#ifdef __APPLE__
+ for (i = 0, rv = 0; i < nproc; i++) {
+ kp = sysmon_table_get_row(plist, i);
+#else
+ for (i = 0, rv = 0, kp = plist; i < nproc; i++, kp++) {
+#endif
+ if (PSKIP(kp))
+ continue;
+ if (selected[i]) {
+ if (longfmt && !pgrep) {
+ did_action = 1;
+#ifdef __APPLE__
+ printf("kill -%d %d\n", signum, (int)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)));
+#else
+ printf("kill -%d %d\n", signum, kp->ki_pid);
+#endif
+ }
+ if (inverse)
+ continue;
+ } else if (!inverse)
+ continue;
+ rv |= (*action)(kp);
+ }
+ if (!did_action && !pgrep && longfmt)
+ fprintf(stderr,
+ "No matching processes belonging to you were found\n");
+
+ exit(rv ? STATUS_MATCH : STATUS_NOMATCH);
+}
+
+static void
+usage(void)
+{
+ const char *ustr;
+
+ if (pgrep)
+#ifdef __APPLE__
+ ustr = "[-Lfilnoqvx] [-d delim]";
+#else
+ ustr = "[-LSfilnoqvx] [-d delim]";
+#endif
+ else
+ ustr = "[-signal] [-ILfilnovx]";
+
+ fprintf(stderr,
+#ifdef __APPLE__
+ "usage: %s %s [-F pidfile] [-G gid]\n"
+ " [-P ppid] [-U uid] [-g pgrp]\n"
+#else
+ "usage: %s %s [-F pidfile] [-G gid] [-M core] [-N system]\n"
+ " [-P ppid] [-U uid] [-g pgrp] [-j jid] [-s sid]\n"
+#endif
+ " [-t tty] [-u euid] pattern ...\n", getprogname(),
+ ustr);
+
+ exit(STATUS_BADUSAGE);
+}
+
+static void
+#ifdef __APPLE__
+show_process(const sysmon_row_t kp)
+#else
+show_process(const struct kinfo_proc *kp)
+#endif
+{
+#ifdef __APPLE__
+ xpc_object_t argv;
+#else
+ char **argv;
+#endif
+
+ if (quiet) {
+ assert(pgrep);
+ return;
+ }
+#ifdef __APPLE__
+ if ((longfmt || !pgrep) && matchargs &&
+ (argv = sysmon_row_get_value(kp, SYSMON_ATTR_PROC_ARGUMENTS)) != NULL) {
+ printf("%d ", (int)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)));
+ (void)xpc_array_apply(argv, ^(size_t index, xpc_object_t value) {
+ printf("%s", xpc_string_get_string_ptr(value));
+ if (index < xpc_array_get_count(argv) - 1)
+ putchar(' ');
+ return (bool)true;
+ });
+ } else if (longfmt || !pgrep)
+ printf("%d %s",
+ (int)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)),
+ xpc_string_get_string_ptr(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_COMM)));
+ else
+ printf("%d", (int)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)));
+#else
+ if ((longfmt || !pgrep) && matchargs &&
+ (argv = kvm_getargv(kd, kp, 0)) != NULL) {
+ printf("%d ", (int)kp->ki_pid);
+ for (; *argv != NULL; argv++) {
+ printf("%s", *argv);
+ if (argv[1] != NULL)
+ putchar(' ');
+ }
+ } else if (longfmt || !pgrep)
+ printf("%d %s", (int)kp->ki_pid, kp->ki_comm);
+ else
+ printf("%d", (int)kp->ki_pid);
+#endif
+}
+
+static int
+#ifdef __APPLE__
+killact(const sysmon_row_t kp)
+#else
+killact(const struct kinfo_proc *kp)
+#endif
+{
+ int ch, first;
+
+ if (interactive) {
+ /*
+ * Be careful, ask before killing.
+ */
+ printf("kill ");
+ show_process(kp);
+ printf("? ");
+ fflush(stdout);
+ first = ch = getchar();
+ while (ch != '\n' && ch != EOF)
+ ch = getchar();
+ if (first != 'y' && first != 'Y')
+ return (1);
+ }
+#ifdef __APPLE__
+ if (kill((pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)), signum) == -1) {
+#else
+ if (kill(kp->ki_pid, signum) == -1) {
+#endif
+ /*
+ * Check for ESRCH, which indicates that the process
+ * disappeared between us matching it and us
+ * signalling it; don't issue a warning about it.
+ */
+ if (errno != ESRCH)
+#ifdef __APPLE__
+ warn("signalling pid %d", (int)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)));
+#else
+ warn("signalling pid %d", (int)kp->ki_pid);
+#endif
+ /*
+ * Return 0 to indicate that the process should not be
+ * considered a match, since we didn't actually get to
+ * signal it.
+ */
+ return (0);
+ }
+ return (1);
+}
+
+static int
+#ifdef __APPLE__
+grepact(const sysmon_row_t kp)
+#else
+grepact(const struct kinfo_proc *kp)
+#endif
+{
+
+ show_process(kp);
+ if (!quiet)
+ printf("%s", delim);
+ return (1);
+}
+
+static void
+makelist(struct listhead *head, enum listtype type, char *src)
+{
+ struct list *li;
+ struct passwd *pw;
+ struct group *gr;
+ struct stat st;
+ const char *cp;
+ char *sp, *ep, buf[MAXPATHLEN];
+ int empty;
+
+ empty = 1;
+
+ while ((sp = strsep(&src, ",")) != NULL) {
+ if (*sp == '\0')
+ usage();
+
+ if ((li = malloc(sizeof(*li))) == NULL) {
+ err(STATUS_ERROR, "Cannot allocate %zu bytes",
+ sizeof(*li));
+ }
+
+ SLIST_INSERT_HEAD(head, li, li_chain);
+ empty = 0;
+
+ li->li_number = (uid_t)strtol(sp, &ep, 0);
+ if (*ep == '\0') {
+ switch (type) {
+ case LT_PGRP:
+ if (li->li_number == 0)
+ li->li_number = getpgrp();
+ break;
+#ifndef __APPLE__
+ case LT_SID:
+ if (li->li_number == 0)
+ li->li_number = getsid(mypid);
+ break;
+ case LT_JID:
+ if (li->li_number < 0)
+ errx(STATUS_BADUSAGE,
+ "Negative jail ID `%s'", sp);
+ /* For compatibility with old -j */
+ if (li->li_number == 0)
+ li->li_number = -1; /* any jail */
+ break;
+#endif /* !__APPLE__ */
+ case LT_TTY:
+ if (li->li_number < 0)
+ errx(STATUS_BADUSAGE,
+ "Negative /dev/pts tty `%s'", sp);
+ snprintf(buf, sizeof(buf), _PATH_DEV "pts/%s",
+ sp);
+ if (stat(buf, &st) != -1)
+ goto foundtty;
+ if (errno == ENOENT)
+ errx(STATUS_BADUSAGE, "No such tty: `"
+ _PATH_DEV "pts/%s'", sp);
+ err(STATUS_ERROR, "Cannot access `"
+ _PATH_DEV "pts/%s'", sp);
+ break;
+ default:
+ break;
+ }
+ continue;
+ }
+
+ switch (type) {
+ case LT_USER:
+ if ((pw = getpwnam(sp)) == NULL)
+ errx(STATUS_BADUSAGE, "Unknown user `%s'", sp);
+ li->li_number = pw->pw_uid;
+ break;
+ case LT_GROUP:
+ if ((gr = getgrnam(sp)) == NULL)
+ errx(STATUS_BADUSAGE, "Unknown group `%s'", sp);
+ li->li_number = gr->gr_gid;
+ break;
+ case LT_TTY:
+ if (strcmp(sp, "-") == 0) {
+ li->li_number = -1;
+ break;
+ } else if (strcmp(sp, "co") == 0) {
+ cp = "console";
+ } else {
+ cp = sp;
+ }
+
+ snprintf(buf, sizeof(buf), _PATH_DEV "%s", cp);
+ if (stat(buf, &st) != -1)
+ goto foundtty;
+
+ snprintf(buf, sizeof(buf), _PATH_DEV "tty%s", cp);
+ if (stat(buf, &st) != -1)
+ goto foundtty;
+
+ if (errno == ENOENT)
+ errx(STATUS_BADUSAGE, "No such tty: `%s'", sp);
+ err(STATUS_ERROR, "Cannot access `%s'", sp);
+
+foundtty: if ((st.st_mode & S_IFCHR) == 0)
+ errx(STATUS_BADUSAGE, "Not a tty: `%s'", sp);
+
+ li->li_number = st.st_rdev;
+ break;
+#ifndef __APPLE__
+ case LT_JID:
+ if (strcmp(sp, "none") == 0)
+ li->li_number = 0;
+ else if (strcmp(sp, "any") == 0)
+ li->li_number = -1;
+ else if (*ep != '\0')
+ errx(STATUS_BADUSAGE,
+ "Invalid jail ID `%s'", sp);
+ break;
+#endif /* !__APPLE__ */
+ default:
+ usage();
+ }
+ }
+
+ if (empty)
+ usage();
+}
+
+static int
+takepid(const char *pidfile, int pidfilelock)
+{
+ char *endp, line[BUFSIZ];
+ FILE *fh;
+ long rval;
+
+ fh = fopen(pidfile, "r");
+ if (fh == NULL)
+ err(STATUS_ERROR, "Cannot open pidfile `%s'", pidfile);
+
+ if (pidfilelock) {
+ /*
+ * If we can lock pidfile, this means that daemon is not
+ * running, so would be better not to kill some random process.
+ */
+ if (flock(fileno(fh), LOCK_EX | LOCK_NB) == 0) {
+ (void)fclose(fh);
+ errx(STATUS_ERROR, "File '%s' can be locked", pidfile);
+ } else {
+ if (errno != EWOULDBLOCK) {
+ errx(STATUS_ERROR,
+ "Error while locking file '%s'", pidfile);
+ }
+ }
+ }
+
+ if (fgets(line, sizeof(line), fh) == NULL) {
+ if (feof(fh)) {
+ (void)fclose(fh);
+ errx(STATUS_ERROR, "Pidfile `%s' is empty", pidfile);
+ }
+ (void)fclose(fh);
+ err(STATUS_ERROR, "Cannot read from pid file `%s'", pidfile);
+ }
+ (void)fclose(fh);
+
+ rval = strtol(line, &endp, 10);
+ if (*endp != '\0' && !isspace((unsigned char)*endp))
+ errx(STATUS_ERROR, "Invalid pid in file `%s'", pidfile);
+ else if (rval < MIN_PID || rval > MAX_PID)
+ errx(STATUS_ERROR, "Invalid pid in file `%s'", pidfile);
+ return (rval);
+}
diff --git a/adv_cmds/ps/entitlements.plist b/adv_cmds/ps/entitlements.plist
new file mode 100644
index 0000000..eaaf1de
--- /dev/null
+++ b/adv_cmds/ps/entitlements.plist
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.system-task-ports</key>
+ <true/>
+ <key>task_for_pid-allow</key>
+ <true/>
+</dict>
+</plist>
diff --git a/adv_cmds/ps/extern.h b/adv_cmds/ps/extern.h
new file mode 100644
index 0000000..d3f6503
--- /dev/null
+++ b/adv_cmds/ps/extern.h
@@ -0,0 +1,98 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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.
+ * 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.
+ *
+ * @(#)extern.h 8.3 (Berkeley) 4/2/94
+ * $FreeBSD: extern.h,v 1.8 1998/05/25 05:07:17 steve Exp $
+ */
+
+struct kinfo;
+struct nlist;
+struct var;
+struct varent;
+
+extern fixpt_t ccpu;
+extern int cflag, eval, fscale, nlistread, rawcpu;
+#ifdef __APPLE__
+extern uint64_t mempages;
+#else
+extern unsigned long mempages;
+#endif
+extern time_t now;
+extern int showthreads, sumrusage, termwidth, totwidth;
+extern STAILQ_HEAD(velisthead, varent) varlist;
+
+__BEGIN_DECLS
+int get_task_info(KINFO *);
+void command(KINFO *, VARENT *);
+void just_command(KINFO *, VARENT *);
+void args(KINFO *, VARENT *);
+int s_command(KINFO *);
+int s_just_command(KINFO *);
+int s_args(KINFO *);
+void cputime(KINFO *, VARENT *);
+void pstime(KINFO *, VARENT *);
+void p_etime(KINFO *, VARENT *);
+int s_etime(KINFO *);
+void putime(KINFO *, VARENT *);
+int donlist(void);
+void evar(KINFO *, VARENT *);
+VARENT *find_varentry(VAR *);
+const char *fmt_argv(char **, char *, size_t);
+int getpcpu(KINFO *);
+double getpmem(KINFO *);
+void logname(KINFO *, VARENT *);
+void longtname(KINFO *, VARENT *);
+void lstarted(KINFO *, VARENT *);
+void maxrss(KINFO *, VARENT *);
+void nlisterr(struct nlist *);
+void p_rssize(KINFO *, VARENT *);
+void pagein(KINFO *, VARENT *);
+void parsefmt(const char *, int);
+void pcpu(KINFO *, VARENT *);
+void pmem(KINFO *, VARENT *);
+void pri(KINFO *, VARENT *);
+void rtprior(KINFO *, VARENT *);
+void printheader(void);
+void pvar(KINFO *, VARENT *);
+void runame(KINFO *, VARENT *);
+void rvar(KINFO *, VARENT *);
+int s_runame(KINFO *);
+int s_uname(KINFO *);
+void showkey(void);
+void started(KINFO *, VARENT *);
+void state(KINFO *, VARENT *);
+void tdev(KINFO *, VARENT *);
+void tname(KINFO *, VARENT *);
+void tsize(KINFO *, VARENT *);
+void ucomm(KINFO *, VARENT *);
+void uname(KINFO *, VARENT *);
+void uvar(KINFO *, VARENT *);
+void vsize(KINFO *, VARENT *);
+void wchan(KINFO *, VARENT *);
+void wq(KINFO *, VARENT *);
+__END_DECLS
diff --git a/adv_cmds/ps/fmt.c b/adv_cmds/ps/fmt.c
new file mode 100644
index 0000000..26ba3dc
--- /dev/null
+++ b/adv_cmds/ps/fmt.c
@@ -0,0 +1,132 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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.
+ * 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.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)fmt.c 8.4 (Berkeley) 4/15/94";
+#endif
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/ps/fmt.c,v 1.34 2004/06/22 02:18:29 gad Exp $");
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <err.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <vis.h>
+
+#include "ps.h"
+
+static char *cmdpart(char *);
+static char *shquote(char **);
+
+static char *
+shquote(char **argv)
+{
+ long arg_max;
+ static size_t buf_size;
+ size_t len;
+ char **p, *dst, *src;
+ static char *buf = NULL;
+
+ if (buf == NULL) {
+ if ((arg_max = sysconf(_SC_ARG_MAX)) == -1)
+ errx(1, "sysconf _SC_ARG_MAX failed");
+ if (arg_max >= LONG_MAX / 4 || arg_max >= (long)(SIZE_MAX / 4))
+ errx(1, "sysconf _SC_ARG_MAX preposterously large");
+ buf_size = 4 * arg_max + 1;
+ if ((buf = malloc(buf_size)) == NULL)
+ errx(1, "malloc failed");
+ }
+
+ if (*argv == NULL) {
+ buf[0] = '\0';
+ return (buf);
+ }
+ dst = buf;
+ for (p = argv; (src = *p++) != NULL; ) {
+ if (*src == '\0')
+ continue;
+ len = (buf_size - 1 - (dst - buf)) / 4;
+ strvisx(dst, src, strlen(src) < len ? strlen(src) : len,
+ VIS_NL | VIS_CSTYLE);
+ while (*dst != '\0')
+ dst++;
+ if ((buf_size - 1 - (dst - buf)) / 4 > 0)
+ *dst++ = ' ';
+ }
+ /* Chop off trailing space */
+ if (dst != buf && dst[-1] == ' ')
+ dst--;
+ *dst = '\0';
+ return (buf);
+}
+
+static char *
+cmdpart(char *arg0)
+{
+ char *cp;
+
+ return ((cp = strrchr(arg0, '/')) != NULL ? cp + 1 : arg0);
+}
+
+const char *
+fmt_argv(char **argv, char *cmd, size_t maxlen)
+{
+ size_t len;
+ char *ap, *cp;
+
+ if (argv == NULL || argv[0] == NULL) {
+ if (cmd == NULL)
+ return ("");
+ ap = NULL;
+ len = maxlen + 3;
+ } else {
+ ap = shquote(argv);
+ len = strlen(ap) + maxlen + 4;
+ }
+ cp = malloc(len);
+ if (cp == NULL)
+ errx(1, "malloc failed");
+ if (ap == NULL)
+ sprintf(cp, "[%.*s]", (int)maxlen, cmd);
+ else if (strncmp(cmdpart(argv[0]), cmd, maxlen) != 0)
+ sprintf(cp, "%s (%.*s)", ap, (int)maxlen, cmd);
+ else
+ strcpy(cp, ap);
+ return (cp);
+}
diff --git a/adv_cmds/ps/keyword.c b/adv_cmds/ps/keyword.c
new file mode 100644
index 0000000..ff311b4
--- /dev/null
+++ b/adv_cmds/ps/keyword.c
@@ -0,0 +1,340 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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.
+ * 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.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)keyword.c 8.5 (Berkeley) 4/2/94";
+#else
+static const char rcsid[] =
+ "$FreeBSD: keyword.c,v 1.23 1999/01/26 02:38:09 julian Exp $";
+#endif /* not lint */
+#endif
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/proc.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+
+#include <err.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ps.h"
+
+VAR *findvar(char *, int, char **header);
+static int vcmp(const void *, const void *);
+
+/* Compute offset in common structures. */
+#define POFF(x) offsetof(struct extern_proc, x)
+#define EOFF(x) offsetof(struct eproc, x)
+#define UOFF(x) offsetof(struct usave, x)
+#define ROFF(x) offsetof(struct rusage, x)
+
+#define EMULLEN 13 /* enough for "FreeBSD ELF32" */
+#define LWPFMT "d"
+#define LWPLEN 6
+#define NLWPFMT "d"
+#define NLWPLEN 4
+#ifdef __APPLE__
+#define UIDFMT "d"
+#else
+#define UIDFMT "u"
+#endif
+#define UIDLEN 5
+#define PIDFMT "d"
+#define PIDLEN 5
+#define USERLEN 16
+
+/* PLEASE KEEP THE TABLE BELOW SORTED ALPHABETICALLY!!! */
+static VAR var[] = {
+ /* 4133537: 5 characters to accomodate 100% or more */
+ {"%cpu", "%CPU", NULL, 0, pcpu, NULL, 5, 0, CHAR, NULL, 0},
+ {"%mem", "%MEM", NULL, 0, pmem, NULL, 4},
+ {"acflag", "ACFLG",
+ NULL, 0, pvar, NULL, 3, POFF(p_acflag), USHORT, "x"},
+ {"acflg", "", "acflag"},
+ {"args", "ARGS", NULL, COMM|LJUST|USER|DSIZ, args, s_args, 64},
+ {"blocked", "", "sigmask"},
+ {"caught", "", "sigcatch"},
+ {"comm", "COMM", NULL, COMM|LJUST|USER|DSIZ, just_command, s_just_command, 16},
+ {"command", "COMMAND", NULL, COMM|LJUST|USER|DSIZ, command, s_command, 16},
+ {"cpu", "CPU", NULL, 0, pvar, NULL, 3, POFF(p_estcpu), UINT, "d"},
+ {"cputime", "", "time"},
+ {"etime", "ELAPSED", NULL, USER|DSIZ, p_etime, s_etime, 20},
+ /* 5861775: Make F column 8 characters. */
+ {"f", "F", NULL, 0, pvar, NULL, 8, POFF(p_flag), INT, "x"},
+ {"flags", "", "f"},
+ {"gid", "GID", NULL, 0, evar, NULL, UIDLEN, EOFF(e_ucred.cr_gid),
+ UINT, UIDFMT},
+ {"group", "GROUP", "gid"},
+ {"ignored", "", "sigignore"},
+ {"inblk", "INBLK",
+ NULL, USER, rvar, NULL, 4, ROFF(ru_inblock), LONG, "ld"},
+ {"inblock", "", "inblk"},
+ {"jobc", "JOBC", NULL, 0, evar, NULL, 4, EOFF(e_jobc), SHORT, "d"},
+ {"ktrace", "KTRACE",
+ NULL, 0, pvar, NULL, 8, POFF(p_traceflag), INT, "x"},
+ {"ktracep", "KTRACEP",
+ NULL, 0, pvar, NULL, 8, POFF(p_tracep), LONG, "lx"},
+ {"lim", "LIM", NULL, 0, maxrss, NULL, 5},
+ {"login", "LOGIN", NULL, LJUST, logname, NULL, MAXLOGNAME-1},
+ {"logname", "", "login"},
+ {"lstart", "STARTED", NULL, LJUST|USER, lstarted, NULL, 28},
+ {"majflt", "MAJFLT",
+ NULL, USER, rvar, NULL, 4, ROFF(ru_majflt), LONG, "ld"},
+ {"minflt", "MINFLT",
+ NULL, USER, rvar, NULL, 4, ROFF(ru_minflt), LONG, "ld"},
+ {"msgrcv", "MSGRCV",
+ NULL, USER, rvar, NULL, 4, ROFF(ru_msgrcv), LONG, "ld"},
+ {"msgsnd", "MSGSND",
+ NULL, USER, rvar, NULL, 4, ROFF(ru_msgsnd), LONG, "ld"},
+ {"ni", "", "nice"},
+ {"nice", "NI", NULL, 0, pvar, NULL, 2, POFF(p_nice), CHAR, "d"},
+ {"nivcsw", "NIVCSW",
+ NULL, USER, rvar, NULL, 5, ROFF(ru_nivcsw), LONG, "ld"},
+ {"nsignals", "", "nsigs"},
+ {"nsigs", "NSIGS",
+ NULL, USER, rvar, NULL, 4, ROFF(ru_nsignals), LONG, "ld"},
+ {"nswap", "NSWAP",
+ NULL, USER, rvar, NULL, 4, ROFF(ru_nswap), LONG, "ld"},
+ {"nvcsw", "NVCSW",
+ NULL, USER, rvar, NULL, 5, ROFF(ru_nvcsw), LONG, "ld"},
+ {"nwchan", "WCHAN", NULL, 0, pvar, NULL, 6, POFF(p_wchan), KPTR, "lx"},
+ {"oublk", "OUBLK",
+ NULL, USER, rvar, NULL, 4, ROFF(ru_oublock), LONG, "ld"},
+ {"oublock", "", "oublk"},
+ {"p_ru", "P_RU", NULL, 0, pvar, NULL, 6, POFF(p_ru), KPTR, "lx"},
+ {"paddr", "PADDR", NULL, 0, evar, NULL, sizeof(void *) * 2, EOFF(e_paddr), KPTR, "lx"},
+ {"pagein", "PAGEIN", NULL, USER, pagein, NULL, 6},
+ {"pcpu", "", "%cpu"},
+ {"pending", "", "sig"},
+ {"pgid", "PGID",
+ NULL, 0, evar, NULL, PIDLEN, EOFF(e_pgid), UINT, PIDFMT},
+ {"pid", "PID", NULL, 0, pvar, NULL, PIDLEN, POFF(p_pid), UINT, PIDFMT},
+ {"pmem", "", "%mem"},
+ {"ppid", "PPID",
+ NULL, 0, evar, NULL, PIDLEN, EOFF(e_ppid), UINT, PIDFMT},
+ {"pri", "PRI", NULL, 0, pri, NULL, 3},
+ {"pstime", "", "stime"},
+ {"putime", "", "utime"},
+ {"re", "RE", NULL, 0, pvar, NULL, 3, POFF(p_swtime), UINT, "d"},
+ {"rgid", "RGID", NULL, 0, evar, NULL, UIDLEN, EOFF(e_pcred.p_rgid),
+ UINT, UIDFMT},
+ {"rgroup", "RGROUP", "rgid"},
+ {"rss", "RSS", NULL, 0, p_rssize, NULL, 6},
+#if FIXME
+ {"rtprio", "RTPRIO", NULL, 0, rtprior, NULL, 7, POFF(p_rtprio)},
+#endif /* FIXME */
+ {"ruid", "RUID", NULL, 0, evar, NULL, UIDLEN, EOFF(e_pcred.p_ruid),
+ UINT, UIDFMT},
+ {"ruser", "RUSER", NULL, LJUST|DSIZ, runame, s_runame, USERLEN},
+ {"sess", "SESS", NULL, 0, evar, NULL, 6, EOFF(e_sess), KPTR, "lx"},
+ {"sig", "PENDING", NULL, 0, pvar, NULL, 8, POFF(p_siglist), INT, "x"},
+#if FIXME
+ {"sigcatch", "CAUGHT",
+ NULL, 0, evar, NULL, 8, EOFF(e_procsig.ps_sigcatch), UINT, "x"},
+ {"sigignore", "IGNORED",
+ NULL, 0, evar, NULL, 8, EOFF(e_procsig.ps_sigignore), UINT, "x"},
+#endif /* FIXME */
+ {"sigmask", "BLOCKED",
+ NULL, 0, pvar, NULL, 8, POFF(p_sigmask), UINT, "x"},
+ {"sl", "SL", NULL, 0, pvar, NULL, 3, POFF(p_slptime), UINT, "d"},
+ {"start", "STARTED", NULL, LJUST|USER, started, NULL, 7},
+ {"stat", "", "state"},
+ {"state", "STAT", NULL, 0, state, NULL, 4},
+ {"stime", "STIME", NULL, USER, pstime, NULL, 9},
+ {"svgid", "SVGID", NULL, 0,
+ evar, NULL, UIDLEN, EOFF(e_pcred.p_svgid), UINT, UIDFMT},
+ {"svuid", "SVUID", NULL, 0,
+ evar, NULL, UIDLEN, EOFF(e_pcred.p_svuid), UINT, UIDFMT},
+ {"tdev", "TDEV", NULL, 0, tdev, NULL, 4},
+ {"time", "TIME", NULL, USER, cputime, NULL, 9},
+ {"tpgid", "TPGID",
+ NULL, 0, evar, NULL, 4, EOFF(e_tpgid), UINT, PIDFMT},
+ {"tsess", "TSESS", NULL, 0, evar, NULL, 6, EOFF(e_tsess), KPTR, "lx"},
+ {"tsiz", "TSIZ", NULL, 0, tsize, NULL, 8},
+ {"tt", "TT ", NULL, 0, tname, NULL, 5},
+ {"tty", "TTY", NULL, LJUST, longtname, NULL, 8},
+ {"ucomm", "UCOMM", NULL, LJUST, ucomm, NULL, MAXCOMLEN},
+ {"uid", "UID", NULL, 0, evar, NULL, UIDLEN, EOFF(e_ucred.cr_uid),
+ UINT, UIDFMT},
+ {"upr", "UPR", NULL, 0, pvar, NULL, 3, POFF(p_usrpri), CHAR, "d"},
+ {"user", "USER", NULL, LJUST|DSIZ, uname, s_uname, USERLEN},
+ {"usrpri", "", "upr"},
+ {"utime", "UTIME", NULL, USER, putime, NULL, 9},
+ {"vsize", "", "vsz"},
+ {"vsz", "VSZ", NULL, 0, vsize, NULL, 8},
+ {"wchan", "WCHAN", NULL, LJUST, wchan, NULL, 6},
+ {"wq", "WQ", NULL, 0, wq, NULL, 4, 0, CHAR, NULL, 0},
+ {"wqb", "WQB", NULL, 0, wq, NULL, 4, 0, CHAR, NULL, 0},
+ {"wql", "WQL", NULL, 0, wq, NULL, 3, 0, CHAR, NULL, 0},
+ {"wqr", "WQR", NULL, 0, wq, NULL, 4, 0, CHAR, NULL, 0},
+ {"xstat", "XSTAT", NULL, 0, pvar, NULL, 4, POFF(p_xstat), USHORT, "x"},
+ {""},
+};
+
+void
+showkey(void)
+{
+ VAR *v;
+ int i;
+ const char *p, *sep;
+
+ i = 0;
+ sep = "";
+ for (v = var; *(p = v->name); ++v) {
+ int len = strlen(p);
+ if (termwidth && (i += len + 1) > termwidth) {
+ i = len;
+ sep = "\n";
+ }
+ (void) printf("%s%s", sep, p);
+ sep = " ";
+ }
+ (void) printf("\n");
+}
+
+void
+parsefmt(const char *p, int user)
+{
+ char *tempstr, *tempstr1;
+
+#define FMTSEP " \t,\n"
+ tempstr1 = tempstr = strdup(p);
+ while (tempstr && *tempstr) {
+ char *cp, *hp;
+ VAR *v;
+ struct varent *vent;
+
+#ifndef __APPLE__
+ /*
+ * If an item contains an equals sign, it specifies a column
+ * header, may contain embedded separator characters and
+ * is always the last item.
+ */
+ if (tempstr[strcspn(tempstr, "="FMTSEP)] != '=')
+#endif /* !__APPLE__ */
+ while ((cp = strsep(&tempstr, FMTSEP)) != NULL &&
+ *cp == '\0')
+ /* void */;
+#ifndef __APPLE__
+ else {
+ cp = tempstr;
+ tempstr = NULL;
+ }
+#endif /* !__APPLE__ */
+ if (cp == NULL || !(v = findvar(cp, user, &hp)))
+ continue;
+ if (!user) {
+ /*
+ * If the user is NOT adding this field manually,
+ * get on with our lives if this VAR is already
+ * represented in the list.
+ */
+ vent = find_varentry(v);
+ if (vent != NULL)
+ continue;
+ }
+ if ((vent = malloc(sizeof(struct varent))) == NULL)
+ errx(1, "malloc failed");
+ vent->header = v->header;
+ if (hp) {
+ hp = strdup(hp);
+ if (hp)
+ vent->header = hp;
+ }
+ vent->var = malloc(sizeof(*vent->var));
+ if (vent->var == NULL)
+ errx(1, "malloc failed");
+ memcpy(vent->var, v, sizeof(*vent->var));
+ STAILQ_INSERT_TAIL(&varlist, vent, next_ve);
+ }
+ free(tempstr1);
+ if (STAILQ_EMPTY(&varlist)) {
+ warnx("no valid keywords; valid keywords:");
+ showkey();
+ exit(1);
+ }
+}
+
+VAR *
+findvar(char *p, int user, char **header)
+{
+ size_t rflen;
+ VAR *v, key;
+ char *hp, *realfmt;
+
+ hp = strchr(p, '=');
+ if (hp)
+ *hp++ = '\0';
+
+ key.name = p;
+ v = bsearch(&key, var, sizeof(var)/sizeof(VAR) - 1, sizeof(VAR), vcmp);
+
+ if (v && v->alias) {
+ /*
+ * If the user specified an alternate-header for this
+ * (aliased) format-name, then we need to copy that
+ * alternate-header when making the recursive call to
+ * process the alias.
+ */
+ if (hp == NULL)
+ parsefmt(v->alias, user);
+ else {
+ /*
+ * XXX - This processing will not be correct for
+ * any alias which expands into a list of format
+ * keywords. Presently there are no aliases
+ * which do that.
+ */
+ rflen = strlen(v->alias) + strlen(hp) + 2;
+ realfmt = malloc(rflen);
+ snprintf(realfmt, rflen, "%s=%s", v->alias, hp);
+ parsefmt(realfmt, user);
+ }
+ return ((VAR *)NULL);
+ }
+ if (!v) {
+ warnx("%s: keyword not found", p);
+ eval = 1;
+ }
+ if (header)
+ *header = hp;
+ return (v);
+}
+
+static int
+vcmp(const void *a, const void *b)
+{
+ return (strcmp(((const VAR *)a)->name, ((const VAR *)b)->name));
+}
diff --git a/adv_cmds/ps/nlist.c b/adv_cmds/ps/nlist.c
new file mode 100644
index 0000000..90a2303
--- /dev/null
+++ b/adv_cmds/ps/nlist.c
@@ -0,0 +1,86 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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.
+ * 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.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)nlist.c 8.4 (Berkeley) 4/2/94";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/ps/nlist.c,v 1.21 2004/04/06 20:06:49 markm Exp $");
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#ifdef __APPLE__
+#include <sys/resource.h>
+#endif
+
+#include <stddef.h>
+
+#include "ps.h"
+
+fixpt_t ccpu; /* kernel _ccpu variable */
+int nlistread; /* if nlist already read. */
+#ifdef __APPLE__
+uint64_t mempages; /* number of pages of phys. memory */
+#else
+unsigned long mempages; /* number of pages of phys. memory */
+#endif
+int fscale; /* kernel _fscale variable */
+
+int
+donlist(void)
+{
+#ifdef __APPLE__
+ int mib[2];
+#endif
+ size_t oldlen;
+
+#ifdef __APPLE__
+ mib[0] = CTL_HW;
+ mib[1] = HW_MEMSIZE;
+ oldlen = sizeof(mempages);
+ if (sysctl(mib, 2, &mempages, &oldlen, NULL, 0) == -1)
+ return (1);
+ fscale = 100;
+#else
+ oldlen = sizeof(ccpu);
+ if (sysctlbyname("kern.ccpu", &ccpu, &oldlen, NULL, 0) == -1)
+ return (1);
+ oldlen = sizeof(fscale);
+ if (sysctlbyname("kern.fscale", &fscale, &oldlen, NULL, 0) == -1)
+ return (1);
+ oldlen = sizeof(mempages);
+ if (sysctlbyname("hw.availpages", &mempages, &oldlen, NULL, 0) == -1)
+ return (1);
+#endif
+ nlistread = 1;
+ return (0);
+}
diff --git a/adv_cmds/ps/print.c b/adv_cmds/ps/print.c
new file mode 100644
index 0000000..103ba48
--- /dev/null
+++ b/adv_cmds/ps/print.c
@@ -0,0 +1,1225 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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
+#if 0
+static char sccsid[] = "@(#)print.c 8.6 (Berkeley) 4/16/94";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: print.c,v 1.33 1998/11/25 09:34:00 dfr Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/ucred.h>
+#include <sys/proc.h>
+#include <sys/stat.h>
+
+#include <sys/ucred.h>
+#include <sys/user.h>
+#include <sys/sysctl.h>
+#include <sys/cdefs.h>
+
+#if FIXME
+#include <vm/vm.h>
+#endif /* FIXME */
+#include <err.h>
+#include <langinfo.h>
+#include <libproc.h>
+#include <math.h>
+#include <nlist.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <vis.h>
+#include <pwd.h>
+
+#include "ps.h"
+
+extern int mflg, print_all_thread, print_thread_num;
+
+void
+printheader(void)
+{
+ VAR *v;
+ struct varent *vent;
+
+ STAILQ_FOREACH(vent, &varlist, next_ve)
+ if (*vent->header != '\0')
+ break;
+ if (!vent)
+ return;
+
+ STAILQ_FOREACH(vent, &varlist, next_ve) {
+ v = vent->var;
+ if (v->flag & LJUST) {
+ if (STAILQ_NEXT(vent, next_ve) == NULL) /* last one */
+ (void)printf("%s", vent->header);
+ else
+ (void)printf("%-*s", v->width, vent->header);
+ } else
+ (void)printf("%*s", v->width, vent->header);
+ if (STAILQ_NEXT(vent, next_ve) != NULL)
+ (void)putchar(' ');
+ }
+ (void)putchar('\n');
+}
+
+/*
+ * Get command and arguments.
+ *
+ * If the global variable eflg is non-zero and the user has permission to view
+ * the process's environment, the environment is included.
+ *
+ * on return argvlen is the length of the extracted string, argv0len is
+ * the length of the command (same as argvlen if show_args is true)
+ */
+static void
+getproclline(KINFO *k, char **command_name, int *argvlen, int *argv0len,
+ int show_args)
+{
+ int mib[3], argmax, nargs, c = 0;
+ size_t size;
+ char *procargs, *sp, *np, *cp;
+ extern int eflg;
+
+ /* Get the maximum process arguments size. */
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_ARGMAX;
+
+ size = sizeof(argmax);
+ if (sysctl(mib, 2, &argmax, &size, NULL, 0) == -1) {
+ goto ERROR_A;
+ }
+
+ /* Allocate space for the arguments. */
+ procargs = (char *)malloc(argmax);
+ if (procargs == NULL) {
+ goto ERROR_A;
+ }
+
+ /*
+ * Make a sysctl() call to get the raw argument space of the process.
+ * The layout is documented in start.s, which is part of the Csu
+ * project. In summary, it looks like:
+ *
+ * /---------------\ 0x00000000
+ * : :
+ * : :
+ * |---------------|
+ * | argc |
+ * |---------------|
+ * | arg[0] |
+ * |---------------|
+ * : :
+ * : :
+ * |---------------|
+ * | arg[argc - 1] |
+ * |---------------|
+ * | 0 |
+ * |---------------|
+ * | env[0] |
+ * |---------------|
+ * : :
+ * : :
+ * |---------------|
+ * | env[n] |
+ * |---------------|
+ * | 0 |
+ * |---------------| <-- Beginning of data returned by sysctl() is here.
+ * | argc |
+ * |---------------|
+ * | exec_path |
+ * |:::::::::::::::|
+ * | |
+ * | String area. |
+ * | |
+ * |---------------| <-- Top of stack.
+ * : :
+ * : :
+ * \---------------/ 0xffffffff
+ */
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROCARGS2;
+ mib[2] = KI_PROC(k)->p_pid;
+
+ size = (size_t)argmax;
+ if (sysctl(mib, 3, procargs, &size, NULL, 0) == -1) {
+ goto ERROR_B;
+ }
+
+ memcpy(&nargs, procargs, sizeof(nargs));
+ cp = procargs + sizeof(nargs);
+
+ /* Skip the saved exec_path. */
+ for (; cp < &procargs[size]; cp++) {
+ if (*cp == '\0') {
+ /* End of exec_path reached. */
+ break;
+ }
+ }
+ if (cp == &procargs[size]) {
+ goto ERROR_B;
+ }
+
+ /* Skip trailing '\0' characters. */
+ for (; cp < &procargs[size]; cp++) {
+ if (*cp != '\0') {
+ /* Beginning of first argument reached. */
+ break;
+ }
+ }
+ if (cp == &procargs[size]) {
+ goto ERROR_B;
+ }
+ /* Save where the argv[0] string starts. */
+ sp = cp;
+
+ /*
+ * Iterate through the '\0'-terminated strings and convert '\0' to ' '
+ * until a string is found that has a '=' character in it (or there are
+ * no more strings in procargs). There is no way to deterministically
+ * know where the command arguments end and the environment strings
+ * start, which is why the '=' character is searched for as a heuristic.
+ */
+ for (np = NULL; c < nargs && cp < &procargs[size]; cp++) {
+ if (*cp == '\0') {
+ c++;
+ if (np != NULL) {
+ /* Convert previous '\0'. */
+ *np = ' ';
+ } else {
+ *argv0len = cp - sp;
+ }
+ /* Note location of current '\0'. */
+ np = cp;
+
+ if (!show_args) {
+ /*
+ * Don't convert '\0' characters to ' '.
+ * However, we needed to know that the
+ * command name was terminated, which we
+ * now know.
+ */
+ break;
+ }
+ }
+ }
+
+ /*
+ * If eflg is non-zero, continue converting '\0' characters to ' '
+ * characters until no more strings that look like environment settings
+ * follow.
+ */
+ if ( show_args && (eflg != 0) && ( (getuid() == 0) || (KI_EPROC(k)->e_pcred.p_ruid == getuid()) ) ) {
+ for (; cp < &procargs[size]; cp++) {
+ if (*cp == '\0') {
+ if (np != NULL) {
+ if (&np[1] == cp) {
+ /*
+ * Two '\0' characters in a row.
+ * This should normally only
+ * happen after all the strings
+ * have been seen, but in any
+ * case, stop parsing.
+ */
+ break;
+ }
+ /* Convert previous '\0'. */
+ *np = ' ';
+ }
+ /* Note location of current '\0'. */
+ np = cp;
+ }
+ }
+ }
+
+ /*
+ * sp points to the beginning of the arguments/environment string, and
+ * np should point to the '\0' terminator for the string.
+ */
+ if (np == NULL || np == sp) {
+ /* Empty or unterminated string. */
+ goto ERROR_B;
+ }
+
+ /* Make a copy of the string. */
+ *argvlen = asprintf(command_name, "%s", sp);
+
+ /* Clean up. */
+ free(procargs);
+ return;
+
+ ERROR_B:
+ free(procargs);
+ ERROR_A:
+ *argv0len = *argvlen
+ = asprintf(command_name, "(%s)", KI_PROC(k)->p_comm);
+}
+
+/* Return value is malloc'ed, please free it */
+char *
+get_command_and_or_args(KINFO *k, int show_cmd, int show_args)
+{
+ char *vis_args;
+
+ char *rawcmd, *cmd;
+ int cmdlen, argv0len = 0;
+
+
+ if(!mflg || (print_all_thread && (print_thread_num== 0))) {
+ getproclline(k, &rawcmd, &cmdlen, &argv0len, show_args);
+
+ if (cflag) {
+ /* Ignore the path in cmd, if any. */
+ for (cmd = &rawcmd[cmdlen - 1]; cmd > rawcmd; cmd--) {
+ if (*cmd == '/') {
+ cmd++;
+ break;
+ }
+ }
+ } else {
+ cmd = rawcmd;
+ }
+
+ if (!show_cmd) {
+ cmd += argv0len;
+ if (*cmd) {
+ cmd++;
+ }
+ }
+
+ if ((vis_args = malloc(strlen(cmd) * 4 + 1)) == NULL)
+ err(1, NULL);
+ strvis(vis_args, cmd, VIS_TAB | VIS_NL | VIS_NOSLASH);
+ free(rawcmd);
+ return vis_args;
+ } else {
+ return strdup("");
+ }
+}
+
+int
+s_command_and_or_args(KINFO *k, int show_cmd, int show_args)
+{
+ char *s = get_command_and_or_args(k, show_cmd, show_args);
+ int sz = strlen(s);
+ free(s);
+
+ return sz;
+}
+
+void
+p_command_and_or_args(KINFO *k, VARENT *ve, int show_cmd, int show_args,
+ int no_trunc)
+{
+ VAR *v = ve->var;
+ char *s = get_command_and_or_args(k, show_cmd, show_args);
+
+ if (STAILQ_NEXT(ve, next_ve) == NULL) {
+ /* last field */
+ if (termwidth == UNLIMITED) {
+ fputs(s, stdout);
+ } else {
+ int left;
+ char *cp;
+
+ left = termwidth - (totwidth - v->width);
+ if (left < 1 || no_trunc) {
+ /* already wrapped, just use std * width */
+ left = v->width;
+ }
+ for(cp = s; --left >= 0 && *cp;) {
+ (void)putchar(*cp++);
+ }
+ }
+ } else {
+ /* XXX env? */
+ (void)printf("%-*.*s", v->width, v->width, s);
+ }
+
+ free(s);
+}
+
+int s_command(KINFO *k) {
+ return s_command_and_or_args(k, 1, !cflag);
+}
+
+int s_args(KINFO *k) {
+ return s_command_and_or_args(k, 1, 1);
+}
+
+int s_just_command(KINFO *k) {
+ return s_command_and_or_args(k, 1, 0);
+}
+
+void command(KINFO *k, VARENT *ve) {
+ p_command_and_or_args(k, ve, 1, !cflag, 0);
+}
+
+void args(KINFO *k, VARENT *ve) {
+ p_command_and_or_args(k, ve, 1, 1, 1);
+}
+
+void just_command(KINFO *k, VARENT *ve) {
+ p_command_and_or_args(k, ve, 1, 0, 0);
+}
+
+void
+ucomm(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+
+ v = ve->var;
+ (void)printf("%-*s", v->width, KI_PROC(k)->p_comm);
+}
+
+char *getname(uid)
+ uid_t uid;
+{
+ register struct passwd *pw;
+ struct passwd *getpwuid();
+
+ pw = getpwuid((short)uid);
+ if (pw == NULL) {
+ return( "UNKNOWN" );
+ }
+ return( pw->pw_name );
+}
+
+void
+logname(KINFO *k, VARENT *ve)
+{
+ VAR *v;
+ char *s;
+
+ v = ve->var;
+ (void)printf("%-*s", v->width, (s = getname(KI_EPROC(k)->e_ucred.cr_uid), *s) ? s : "-");
+}
+
+extern int mach_state_order();
+void
+state(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ struct extern_proc *p;
+ int flag,j;
+ char *cp;
+ VAR *v;
+ char buf[16];
+ extern char mach_state_table[];
+
+ v = ve->var;
+ p = KI_PROC(k);
+ flag = p->p_flag;
+ cp = buf;
+
+ if(!mflg ) {
+ switch (p->p_stat) {
+
+ case SSTOP:
+ *cp = 'T';
+ break;
+
+ case SZOMB:
+ *cp = 'Z';
+ break;
+
+ default:
+ *cp = mach_state_table[k->state];
+ }
+ cp++;
+ if (p->p_nice < 0)
+ *cp++ = '<';
+ else if (p->p_nice > 0)
+ *cp++ = 'N';
+ if (flag & P_TRACED)
+ *cp++ = 'X';
+ if (flag & P_WEXIT && p->p_stat != SZOMB)
+ *cp++ = 'E';
+ if (flag & P_PPWAIT)
+ *cp++ = 'V';
+ if (flag & (P_SYSTEM | P_NOSWAP | P_PHYSIO))
+ *cp++ = 'L';
+ if (KI_EPROC(k)->e_flag & EPROC_SLEADER)
+ *cp++ = 's';
+ if ((flag & P_CONTROLT) && KI_EPROC(k)->e_pgid == KI_EPROC(k)->e_tpgid)
+ *cp++ = '+';
+ *cp = '\0';
+ (void)printf("%-*s", v->width, buf);
+ } else if (print_all_thread) {
+ j = mach_state_order(k->thval[print_thread_num].tb.run_state,
+ k->thval[print_thread_num].tb.sleep_time);
+ *cp++ = mach_state_table[j];
+ *cp++='\0';
+ (void)printf("%-*s", v->width, buf);
+ } else {
+ (void)printf("%-*s", v->width, " ");
+ }
+
+}
+
+void
+pri(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+ int j=0;
+ char c = '?';
+
+ v = ve->var;
+ if (!mflg ) {
+ (void)printf("%*d", v->width, k->curpri);
+ } else if (print_all_thread) {
+ switch(k->thval[print_thread_num].tb.policy) {
+ case POLICY_TIMESHARE :
+ j = k->thval[print_thread_num].schedinfo.tshare.cur_priority;
+ c = 'T';
+ break;
+ case POLICY_FIFO :
+ j = k->thval[print_thread_num].schedinfo.fifo.base_priority;
+ c = 'F';
+ break;
+ case POLICY_RR :
+ j = k->thval[print_thread_num].schedinfo.rr.base_priority;
+ c = 'R';
+ break;
+ default :
+ j = 0;
+ }
+ (void)printf("%*d%c", v->width - 1, j, c);
+ }else {
+ j=0;
+ (void)printf("%*d", v->width, j);
+
+ }
+}
+
+void
+uname(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+
+ v = ve->var;
+ if(!mflg || (print_all_thread && (print_thread_num== 0)))
+ (void)printf("%-*s",
+ (int)v->width,
+ user_from_uid(KI_EPROC(k)->e_ucred.cr_uid, 0));
+ else
+ (void)printf("%-*s", (int)v->width, " ");
+}
+
+int
+s_uname(KINFO *k)
+{
+ return (strlen(user_from_uid(KI_EPROC(k)->e_ucred.cr_uid, 0)));
+}
+
+void
+runame(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+
+ v = ve->var;
+ (void)printf("%-*s",
+ (int)v->width, user_from_uid(KI_EPROC(k)->e_pcred.p_ruid, 0));
+}
+
+int
+s_runame(KINFO *k)
+{
+ return (strlen(user_from_uid(KI_EPROC(k)->e_pcred.p_ruid, 0)));
+}
+
+void
+tdev(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+ dev_t dev;
+ char buff[16];
+
+ v = ve->var;
+ dev = KI_EPROC(k)->e_tdev;
+ if (dev == NODEV)
+ (void)printf("%*s", v->width, "??");
+ else {
+ (void)snprintf(buff, sizeof(buff),
+ "%d/%d", major(dev), minor(dev));
+ (void)printf("%*s", v->width, buff);
+ }
+}
+
+void
+tname(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+ dev_t dev;
+ char *ttname;
+
+ v = ve->var;
+
+ if(!mflg || (print_all_thread && (print_thread_num== 0))) {
+ dev = KI_EPROC(k)->e_tdev;
+ if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL)
+ (void)printf("%*s ", v->width-1, "??");
+ else {
+ if (strncmp(ttname, "tty", 3) == 0 ||
+ strncmp(ttname, "cua", 3) == 0)
+ ttname += 3;
+ (void)printf("%*.*s%c", v->width-1, v->width-1, ttname,
+ KI_EPROC(k)->e_flag & EPROC_CTTY ? ' ' : '-');
+ }
+ }
+ else {
+ (void)printf("%*s ", v->width-1, " ");
+ }
+}
+
+void
+longtname(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+ dev_t dev;
+ char *ttname;
+
+ v = ve->var;
+ dev = KI_EPROC(k)->e_tdev;
+ if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL)
+ (void)printf("%-*s", v->width, "??");
+ else
+ (void)printf("%-*s", v->width, ttname);
+}
+
+void
+started(KINFO *k, VARENT *ve)
+{
+ VAR *v;
+ time_t then;
+ struct tm *tp;
+ static int use_ampm = -1;
+ char buf[100];
+
+ v = ve->var;
+ if (use_ampm < 0)
+ use_ampm = (*nl_langinfo(T_FMT_AMPM) != '\0');
+ then = KI_PROC(k)->p_starttime.tv_sec;
+ tp = localtime(&then);
+ if (now - KI_PROC(k)->p_starttime.tv_sec < 24 * 3600) {
+ (void)strftime(buf, sizeof(buf),
+ use_ampm ? "%l:%M%p" : "%k:%M ", tp);
+ } else if (now - KI_PROC(k)->p_starttime.tv_sec < 7 * 86400) {
+ (void)strftime(buf, sizeof(buf),
+ use_ampm ? "%a%I%p" : "%a%H ", tp);
+ } else
+ (void)strftime(buf, sizeof(buf), "%e%b%y", tp);
+ (void)printf("%-*s", v->width, buf);
+}
+
+void
+lstarted(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+ time_t then;
+ char buf[100];
+
+ v = ve->var;
+ then = KI_PROC(k)->p_starttime.tv_sec;
+ (void)strftime(buf, sizeof(buf) -1, "%c", localtime(&then));
+ (void)printf("%-*s", v->width, buf);
+}
+
+char *get_etime(KINFO *k) {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ long e = tv.tv_sec - KI_PROC(k)->p_starttime.tv_sec;
+
+ char *ret;
+
+ if (e > 100*60*60*24) {
+ asprintf(&ret, "%ld-%02ld:%02ld:%02ld",
+ e / (60*60*24),
+ (e / (60*60)) % 24,
+ (e / 60) % 60,
+ e % 60);
+ } else if (e > 60*60*24) {
+ asprintf(&ret, "%02ld-%02ld:%02ld:%02ld",
+ e / (60*60*24),
+ (e / (60*60)) % 24,
+ (e / 60) % 60,
+ e % 60);
+ } else if (e > 60*60) {
+ asprintf(&ret, "%02ld:%02ld:%02ld",
+ (e / (60*60)),
+ (e / 60) % 60,
+ e % 60);
+ } else {
+ asprintf(&ret, "%02ld:%02ld",
+ (e / 60),
+ e % 60);
+ }
+
+ return ret;
+}
+
+void p_etime(KINFO *k, VARENT *ve) {
+ char *str = get_etime(k);
+ printf("%*s", ve->var->width, str);
+ free(str);
+}
+
+int s_etime(KINFO *k) {
+ char *str = get_etime(k);
+ int sz = strlen(str);
+ free(str);
+ return sz;
+}
+
+void
+wchan(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+
+ v = ve->var;
+ if (KI_PROC(k)->p_wchan) {
+ if (KI_PROC(k)->p_wmesg)
+ (void)printf("%-*.*s", v->width, v->width,
+ KI_EPROC(k)->e_wmesg);
+ else
+#if FIXME
+ (void)printf("%-*lx", v->width,
+ (long)KI_PROC(k)->p_wchan &~ KERNBASE);
+#else /* FIXME */
+ (void)printf("%-*lx", v->width,
+ (long)KI_PROC(k)->p_wchan);
+#endif /* FIXME */
+ } else
+ (void)printf("%-*s", v->width, "-");
+}
+
+#define pgtok(a) (((a)*getpagesize())/1024)
+
+void
+vsize(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+
+ v = ve->var;
+#if FIXME
+ (void)printf("%*d", v->width,
+ (KI_EPROC(k)->e_vm.vm_map.size/1024));
+#else /* FIXME */
+ (void)printf("%*lu", v->width,
+ (u_long)((k)->tasks_info.virtual_size)/1024);
+#endif /* FIXME */
+}
+
+void
+p_rssize(k, ve) /* doesn't account for text */
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+/* FIXME LATER */
+ v = ve->var;
+ /* (void)printf("%*ld", v->width, "-"); */
+ (void)printf("%*lu", v->width,
+ (u_long)((k)->tasks_info.resident_size)/1024);
+}
+
+void
+cputime(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+ long secs;
+ long psecs; /* "parts" of a second. first micro, then centi */
+ char obuff[128];
+ time_value_t total_time, system_time;
+ v = ve->var;
+#if FIXME
+ if (KI_PROC(k)->p_stat == SZOMB || !k->ki_u.u_valid) {
+ secs = 0;
+ psecs = 0;
+ } else {
+ /*
+ * This counts time spent handling interrupts. We could
+ * fix this, but it is not 100% trivial (and interrupt
+ * time fractions only work on the sparc anyway). XXX
+ */
+#if FIXME
+ secs = KI_PROC(k)->p_runtime / 1000000;
+ psecs = KI_PROC(k)->p_runtime % 1000000;
+#endif /* FIXME */
+ if (sumrusage) {
+ secs += k->ki_u.u_cru.ru_utime.tv_sec +
+ k->ki_u.u_cru.ru_stime.tv_sec;
+ psecs += k->ki_u.u_cru.ru_utime.tv_usec +
+ k->ki_u.u_cru.ru_stime.tv_usec;
+ }
+ /*
+ * round and scale to 100's
+ */
+ psecs = (psecs + 5000) / 10000;
+ secs += psecs / 100;
+ psecs = psecs % 100;
+ }
+#else /* FIXME */
+ total_time = k->tasks_info.user_time;
+ system_time = k->tasks_info.system_time;
+
+ time_value_add(&total_time, &k->times.user_time);
+ time_value_add(&system_time, &k->times.system_time);
+ time_value_add(&total_time, &system_time);
+
+ secs = total_time.seconds;
+ psecs = total_time.microseconds;
+ /*
+ * round and scale to 100's
+ */
+ psecs = (psecs + 5000) / 10000;
+ secs += psecs / 100;
+ psecs = psecs % 100;
+#endif /* FIXME */
+ (void)snprintf(obuff, sizeof(obuff),
+ "%3ld:%02ld.%02ld", secs/60, secs%60, psecs);
+ (void)printf("%*s", v->width, obuff);
+}
+
+void
+putime(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+ long secs;
+ long psecs; /* "parts" of a second. first micro, then centi */
+ char obuff[128];
+ time_value_t user_time;
+
+
+ v = ve->var;
+ if (!mflg) {
+ user_time = k->tasks_info.user_time;
+ time_value_add(&user_time, &k->times.user_time);
+ } else if (print_all_thread) {
+ user_time = k->thval[print_thread_num].tb.user_time;
+ } else {
+ user_time.seconds =0;
+ user_time.microseconds =0;
+ }
+
+ secs = user_time.seconds;
+ psecs = user_time.microseconds;
+ /*
+ * round and scale to 100's
+ */
+ psecs = (psecs + 5000) / 10000;
+ secs += psecs / 100;
+ psecs = psecs % 100;
+
+ (void)snprintf(obuff, sizeof(obuff),
+ "%3ld:%02ld.%02ld", secs/60, secs%60, psecs);
+ (void)printf("%*s", v->width, obuff);
+}
+
+void
+pstime(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+ long secs;
+ long psecs; /* "parts" of a second. first micro, then centi */
+ char obuff[128];
+ time_value_t system_time;
+
+ v = ve->var;
+ if (!mflg) {
+ system_time = k->tasks_info.system_time;
+ time_value_add(&system_time, &k->times.system_time);
+ } else if (print_all_thread) {
+ system_time = k->thval[print_thread_num].tb.system_time;
+ } else {
+ system_time.seconds =0;
+ system_time.microseconds =0;
+ }
+ secs = system_time.seconds;
+ psecs = system_time.microseconds;
+ /*
+ * round and scale to 100's
+ */
+ psecs = (psecs + 5000) / 10000;
+ secs += psecs / 100;
+ psecs = psecs % 100;
+
+ (void)snprintf(obuff, sizeof(obuff),
+ "%3ld:%02ld.%02ld", secs/60, secs%60, psecs);
+ (void)printf("%*s", v->width, obuff);
+
+}
+
+int
+getpcpu(k)
+ KINFO *k;
+{
+#if FIXME
+ struct proc *p;
+ static int failure;
+
+ if (!nlistread)
+ failure = donlist();
+ if (failure)
+ return (0.0);
+ p = KI_PROC(k);
+#define fxtofl(fixpt) ((double)(fixpt) / fscale)
+
+ /* XXX - I don't like this */
+ if (p->p_swtime == 0 || (p->p_flag & P_INMEM) == 0)
+ return (0.0);
+ if (rawcpu)
+ return (100.0 * fxtofl(p->p_pctcpu));
+ return (100.0 * fxtofl(p->p_pctcpu) /
+ (1.0 - exp(p->p_swtime * log(fxtofl(ccpu)))));
+#else
+ return (k->cpu_usage);
+#endif /* FIXME */
+}
+
+#ifndef TH_USAGE_SCALE
+#define TH_USAGE_SCALE 1000
+#endif /* !TH_USAGE_SCALE */
+
+void
+pcpu(KINFO *k, VARENT *ve)
+{
+ VAR *v;
+ int cp;
+
+ if (!mflg) {
+ cp = getpcpu(k);
+ } else if (print_all_thread) {
+ cp = k->thval[print_thread_num].tb.cpu_usage;
+ } else {
+ cp = 0;
+ }
+
+ v = ve->var;
+ (void)printf("%*.1f", v->width, ((double)cp) * 100.0 / ((double)TH_USAGE_SCALE));
+}
+
+double
+getpmem(k)
+ KINFO *k;
+{
+ static int failure;
+ double fracmem;
+
+ if (!nlistread)
+ failure = donlist();
+ if (failure)
+ return (0.0);
+#if FIXME
+ p = KI_PROC(k);
+ e = KI_EPROC(k);
+ if ((p->p_flag & P_INMEM) == 0)
+ return (0.0);
+ /* XXX want pmap ptpages, segtab, etc. (per architecture) */
+ szptudot = UPAGES;
+ /* XXX don't have info about shared */
+ fracmem = ((float)e->e_vm.vm_rssize + szptudot)/mempages;
+ return (100.0 * fracmem);
+#else /* FIXME */
+ fracmem = ((float)k->tasks_info.resident_size)/(double)mempages;
+ return (100.0 * fracmem);
+#endif /* FIXME */
+}
+
+void
+pmem(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+
+ v = ve->var;
+ (void)printf("%*.1f", v->width, getpmem(k));
+}
+
+void
+pagein(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+
+ v = ve->var;
+ (void)printf("%*ld", v->width,
+ k->ki_u.u_valid ? k->ki_u.u_ru.ru_majflt : 0);
+}
+
+void
+maxrss(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+
+ v = ve->var;
+ /* XXX not yet */
+ (void)printf("%*s", v->width, "-");
+}
+
+void
+tsize(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+ int dummy=0;
+
+ v = ve->var;
+#if 0
+ (void)printf("%*ld", v->width, (long)pgtok(KI_EPROC(k)->e_vm.vm_tsize));
+#else
+ (void)printf("%*ld", v->width, (long)dummy);
+#endif
+}
+
+void
+rtprior(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+#if FIXME
+
+ VAR *v;
+ struct rtprio *prtp;
+ char str[8];
+ unsigned prio, type;
+
+ v = ve->var;
+ prtp = (struct rtprio *) ((char *)KI_PROC(k) + v->off);
+ prio = prtp->prio;
+ type = prtp->type;
+ switch (type) {
+ case RTP_PRIO_REALTIME:
+ snprintf(str, sizeof(str), "real:%u", prio);
+ break;
+ case RTP_PRIO_NORMAL:
+ strncpy(str, "normal", sizeof(str));
+ break;
+ case RTP_PRIO_IDLE:
+ snprintf(str, sizeof(str), "idle:%u", prio);
+ break;
+ default:
+ snprintf(str, sizeof(str), "%u:%u", type, prio);
+ break;
+ }
+ str[sizeof(str) - 1] = '\0';
+ (void)printf("%*s", v->width, str);
+#endif /* FIXME */
+}
+
+/*
+ * Generic output routines. Print fields from various prototype
+ * structures.
+ */
+static void
+printval(void *bp, VAR *v)
+{
+ static char ofmt[32] = "%";
+ const char *fcp;
+ char *cp;
+
+ cp = ofmt + 1;
+ fcp = v->fmt;
+ if (v->flag & LJUST)
+ *cp++ = '-';
+ *cp++ = '*';
+ while ((*cp++ = *fcp++));
+
+ switch (v->type) {
+ case CHAR:
+ (void)printf(ofmt, v->width, *(char *)bp);
+ break;
+ case UCHAR:
+ (void)printf(ofmt, v->width, *(u_char *)bp);
+ break;
+ case SHORT:
+ (void)printf(ofmt, v->width, *(short *)bp);
+ break;
+ case USHORT:
+ (void)printf(ofmt, v->width, *(u_short *)bp);
+ break;
+ case INT:
+ (void)printf(ofmt, v->width, *(int *)bp);
+ break;
+ case UINT:
+ (void)printf(ofmt, v->width, *(u_int *)bp);
+ break;
+ case LONG:
+ (void)printf(ofmt, v->width, *(long *)bp);
+ break;
+ case ULONG:
+ (void)printf(ofmt, v->width, *(u_long *)bp);
+ break;
+ case KPTR:
+#if FIXME
+ (void)printf(ofmt, v->width, *(u_long *)bp &~ KERNBASE);
+#else /* FIXME */
+ (void)printf(ofmt, v->width, *(u_long *)bp);
+#endif /* FIXME */
+ break;
+ default:
+ errx(1, "unknown type %d", v->type);
+ }
+}
+
+void
+pvar(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+
+ v = ve->var;
+ printval((char *)((char *)KI_PROC(k) + v->off), v);
+}
+
+void
+evar(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+
+ v = ve->var;
+ printval((char *)((char *)KI_EPROC(k) + v->off), v);
+}
+
+void
+uvar(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+
+ v = ve->var;
+ if (k->ki_u.u_valid)
+ printval((char *)((char *)&k->ki_u + v->off), v);
+ else
+ (void)printf("%*s", v->width, "-");
+}
+
+void
+rvar(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+
+ v = ve->var;
+ if (k->ki_u.u_valid)
+ printval((char *)((char *)(&k->ki_u.u_ru) + v->off), v);
+ else
+ (void)printf("%*s", v->width, "-");
+}
+
+void
+wq(KINFO *k, VARENT *ve)
+{
+ VAR *v;
+ struct proc_workqueueinfo wqinfo;
+ int len;
+ int ret;
+ uint32_t nthreads;
+
+ len = sizeof(wqinfo);
+ ret = proc_pidinfo(KI_PROC(k)->p_pid, PROC_PIDWORKQUEUEINFO, 0, &wqinfo, len);
+
+ v = ve->var;
+
+ if (len == ret && len == PROC_PIDWORKQUEUEINFO_SIZE) {
+ if (strcmp(v->name, "wql") == 0) {
+ char *s;
+ switch (wqinfo.pwq_state & (WQ_EXCEEDED_CONSTRAINED_THREAD_LIMIT | WQ_EXCEEDED_TOTAL_THREAD_LIMIT)) {
+ case 0:
+ s = "-";
+ break;
+ case WQ_EXCEEDED_CONSTRAINED_THREAD_LIMIT:
+ s = "C";
+ break;
+ case WQ_EXCEEDED_TOTAL_THREAD_LIMIT:
+ s = "T";
+ break;
+ default:
+ s = "CT";
+ break;
+ }
+ printf("%*s", v->width, s);
+ return;
+ }
+ if (strcmp(v->name, "wqr") == 0)
+ nthreads = wqinfo.pwq_runthreads;
+ else if (strcmp(v->name, "wqb") == 0)
+ nthreads = wqinfo.pwq_blockedthreads;
+ else
+ nthreads = wqinfo.pwq_nthreads;
+ printf("%*d", v->width, nthreads);
+ } else
+ printf("%*s", v->width, "-");
+}
diff --git a/adv_cmds/ps/ps.1 b/adv_cmds/ps/ps.1
new file mode 100644
index 0000000..20eed1c
--- /dev/null
+++ b/adv_cmds/ps/ps.1
@@ -0,0 +1,663 @@
+.\"-
+.\" Copyright (c) 1980, 1990, 1991, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)ps.1 8.3 (Berkeley) 4/18/94
+.\" $FreeBSD: src/bin/ps/ps.1,v 1.86 2005/04/29 11:10:27 maxim Exp $
+.\"
+.Dd March 20, 2005
+.Dt PS 1
+.Os
+.Sh NAME
+.Nm ps
+.Nd process status
+.Sh SYNOPSIS
+.Nm
+.Op Fl AaCcEefhjlMmrSTvwXx
+.Op Fl O Ar fmt | Fl o Ar fmt
+.Op Fl G Ar gid Ns Op , Ns Ar gid Ns Ar ...
+.Op Fl g Ar grp Ns Op , Ns Ar grp Ns Ar ...
+.Op Fl u Ar uid Ns Op , Ns Ar uid Ns Ar ...
+.Op Fl p Ar pid Ns Op , Ns Ar pid Ns Ar ...
+.Op Fl t Ar tty Ns Op , Ns Ar tty Ns Ar ...
+.Op Fl U Ar user Ns Op , Ns Ar user Ns Ar ...
+.Nm
+.Op Fl L
+.Sh DESCRIPTION
+The
+.Nm
+utility
+displays a header line, followed by lines containing information about
+all of your
+processes that have controlling terminals.
+.Pp
+A different set of processes can be selected for display by using any
+combination of the
+.Fl a , G , g , p , T , t , U ,
+and
+.Fl u
+options.
+If more than one of these options are given, then
+.Nm
+will select all processes which are matched by at least one of the
+given options.
+.Pp
+For the processes which have been selected for display,
+.Nm
+will usually display one line per process.
+The
+.Fl M
+option may result in multiple output lines (one line per thread) for
+some processes.
+By default all of these output lines are sorted first by controlling
+terminal, then by process ID.
+The
+.Fl m , r ,
+and
+.Fl v
+options will change the sort order.
+If more than one sorting option was given, then the selected processes
+will be sorted by the last sorting option which was specified.
+.Pp
+For the processes which have been selected for display, the information
+to display is selected based on a set of keywords (see the
+.Fl L , O ,
+and
+.Fl o
+options).
+The default output format includes, for each process, the process' ID,
+controlling terminal, CPU time (including both user and system time),
+state, and associated command.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl A
+Display information about other users' processes,
+including those without controlling terminals.
+.It Fl a
+Display information about other users' processes as well as your own.
+This will skip any processes which do not have a controlling terminal,
+unless the
+.Fl x
+option is also specified.
+.It Fl C
+Change the way the CPU percentage is calculated by using a
+.Dq raw
+CPU calculation that ignores
+.Dq resident
+time (this normally has
+no effect).
+.It Fl c
+Change the
+.Dq command
+column output to just contain the executable name,
+rather than the full command line.
+.It Fl d
+Like
+.Fl A ,
+but excludes session leaders.
+.It Fl E
+Display the environment as well.
+This does not reflect changes in the environment after process launch.
+.It Fl e
+Identical to
+.Fl A .
+.It Fl f
+Display the uid, pid, parent pid, recent CPU usage, process start time,
+controlling tty, elapsed CPU usage, and the associated command.
+If the
+.Fl u
+option is also used, display the user name rather then the numeric uid.
+When
+.Fl o
+or
+.Fl O
+is used to add to the display following
+.Fl f ,
+the command field is not truncated as severely as it is in other formats.
+.It Fl G
+Display information about processes
+which are running with the specified real group IDs.
+.It Fl g
+Display information about processes with the specified
+process group leaders.
+.It Fl h
+Repeat the information header as often as necessary
+to guarantee one header per page of information.
+.It Fl j
+Print information associated with the following keywords:
+.Cm user , pid , ppid , pgid , sess , jobc , state , tt , time ,
+and
+.Cm command .
+.It Fl L
+List the set of keywords available for the
+.Fl O
+and
+.Fl o
+options.
+.It Fl l
+Display information associated with the following keywords:
+.Cm uid , pid , ppid , flags , cpu , pri , nice , vsz=SZ , rss ,
+.Cm wchan , state=S , paddr=ADDR , tty , time ,
+and
+.Cm command=CMD .
+.It Fl M
+Print the threads corresponding to each task.
+.It Fl m
+Sort by memory usage, instead of the combination of controlling
+terminal and process ID.
+.It Fl O
+Add the information associated with the space or comma separated list
+of keywords specified, after the process ID,
+in the default information
+display.
+Keywords may be appended with an equals
+.Pq Ql =
+sign and a string.
+This causes the printed header to use the specified string instead of
+the standard header.
+.It Fl o
+Display information associated with the space or comma separated
+list of keywords specified.
+Multiple keywords may also be given in the form of more than one
+.Fl o
+option.
+Keywords may be appended with an equals
+.Pq Ql =
+sign and a string.
+This causes the printed header to use the specified string instead of
+the standard header.
+If all keywords have empty header texts, no header line is written.
+.It Fl p
+Display information about processes which match the specified process IDs.
+.It Fl r
+Sort by current CPU usage, instead of the combination of controlling
+terminal and process ID.
+.It Fl S
+Change the way the process time is calculated by summing all exited
+children to their parent process.
+.It Fl T
+Display information about processes attached to the device associated
+with the standard input.
+.It Fl t
+Display information about processes attached to the specified terminal
+devices.
+.It Fl U
+Display the processes belonging to the specified real user IDs.
+.It Fl u
+Display the processes belonging to the specified usernames.
+.It Fl v
+Display information associated with the following keywords:
+.Cm pid , state , time , sl , re , pagein , vsz , rss , lim , tsiz ,
+.Cm %cpu , %mem ,
+and
+.Cm command .
+The
+.Fl v
+option implies the
+.Fl m
+option.
+.It Fl w
+Use 132 columns to display information, instead of the default which
+is your window size.
+If the
+.Fl w
+option is specified more than once,
+.Nm
+will use as many columns as necessary without regard for your window size.
+When output is not to a terminal, an unlimited number of columns are
+always used.
+.It Fl X
+When displaying processes matched by other options, skip any processes
+which do not have a controlling terminal.
+.It Fl x
+When displaying processes matched by other options, include processes
+which do not have a controlling terminal.
+This is the opposite of the
+.Fl X
+option.
+If both
+.Fl X
+and
+.Fl x
+are specified in the same command, then
+.Nm
+will use the one which was specified last.
+.El
+.Pp
+A complete list of the available keywords is given below.
+Some of these keywords are further specified as follows:
+.Bl -tag -width lockname
+.It Cm %cpu
+The CPU utilization of the process;
+this is a decaying average over up to a minute of previous (real) time.
+Because the time base over which this is computed varies
+(some processes may be very young),
+it is possible for the sum of all
+.Cm %cpu
+fields to exceed 100%.
+.It Cm %mem
+The percentage of real memory used by this process.
+.It Cm flags
+The flags associated with the process as in
+the include file
+.In sys/proc.h :
+.Bl -column P_STOPPED_SINGLE 0x4000000
+.It Dv "P_ADVLOCK" Ta No "0x00001 Process may hold a POSIX advisory lock"
+.It Dv "P_CONTROLT" Ta No "0x00002 Has a controlling terminal"
+.It Dv "P_LP64" Ta No "0x00004 Process is LP64"
+.It Dv "P_NOCLDSTOP" Ta No "0x00008 No SIGCHLD when children stop"
+.It Dv "P_PPWAIT" Ta No "0x00010 Parent is waiting for child to exec/exit"
+.It Dv "P_PROFIL" Ta No "0x00020 Has started profiling"
+.It Dv "P_SELECT" Ta No "0x00040 Selecting; wakeup/waiting danger"
+.It Dv "P_CONTINUED" Ta No "0x00080 Process was stopped and continued"
+.It Dv "P_SUGID" Ta No "0x00100 Had set id privileges since last exec"
+.It Dv "P_SYSTEM" Ta No "0x00200 System proc: no sigs, stats or swapping"
+.It Dv "P_TIMEOUT" Ta No "0x00400 Timing out during sleep"
+.It Dv "P_TRACED" Ta No "0x00800 Debugged process being traced"
+.It Dv "P_WAITED" Ta No "0x01000 Debugging process has waited for child"
+.It Dv "P_WEXIT" Ta No "0x02000 Working on exiting"
+.It Dv "P_EXEC" Ta No "0x04000 Process called exec"
+.It Dv "P_OWEUPC" Ta No "0x08000 Owe process an addupc() call at next ast"
+.It Dv "P_WAITING" Ta No "0x40000 Process has a wait() in progress"
+.It Dv "P_KDEBUG" Ta No "0x80000 Kdebug tracing on for this process"
+.El
+.It Cm lim
+The soft limit on memory used, specified via a call to
+.Xr setrlimit 2 .
+.It Cm lstart
+The exact time the command started, using the
+.Ql %c
+format described in
+.Xr strftime 3 .
+.It Cm nice
+The process scheduling increment (see
+.Xr setpriority 2 ) .
+.It Cm rss
+the real memory (resident set) size of the process (in 1024 byte units).
+.It Cm start
+The time the command started.
+If the command started less than 24 hours ago, the start time is
+displayed using the
+.Dq Li %l:ps.1p
+format described in
+.Xr strftime 3 .
+If the command started less than 7 days ago, the start time is
+displayed using the
+.Dq Li %a6.15p
+format.
+Otherwise, the start time is displayed using the
+.Dq Li %e%b%y
+format.
+.It Cm state
+The state is given by a sequence of characters, for example,
+.Dq Li RWNA .
+The first character indicates the run state of the process:
+.Pp
+.Bl -tag -width indent -compact
+.It Li I
+Marks a process that is idle (sleeping for longer than about 20 seconds).
+.It Li R
+Marks a runnable process.
+.It Li S
+Marks a process that is sleeping for less than about 20 seconds.
+.It Li T
+Marks a stopped process.
+.It Li U
+Marks a process in uninterruptible wait.
+.It Li Z
+Marks a dead process (a
+.Dq zombie ) .
+.El
+.Pp
+Additional characters after these, if any, indicate additional state
+information:
+.Pp
+.Bl -tag -width indent -compact
+.It Li +
+The process is in the foreground process group of its control terminal.
+.It Li <
+The process has raised CPU scheduling priority.
+.It Li >
+The process has specified a soft limit on memory requirements and is
+currently exceeding that limit; such a process is (necessarily) not
+swapped.
+.It Li A
+the process has asked for random page replacement
+.Pf ( Dv VA_ANOM ,
+from
+.Xr vadvise 2 ,
+for example,
+.Xr lisp 1
+in a garbage collect).
+.It Li E
+The process is trying to exit.
+.It Li L
+The process has pages locked in core (for example, for raw
+.Tn I/O ) .
+.It Li N
+The process has reduced CPU scheduling priority (see
+.Xr setpriority 2 ) .
+.It Li S
+The process has asked for
+.Tn FIFO
+page replacement
+.Pf ( Dv VA_SEQL ,
+from
+.Xr vadvise 2 ,
+for example, a large image processing program using virtual memory to
+sequentially address voluminous data).
+.It Li s
+The process is a session leader.
+.It Li V
+The process is suspended during a
+.Xr vfork 2 .
+.It Li W
+The process is swapped out.
+.It Li X
+The process is being traced or debugged.
+.El
+.It Cm tt
+An abbreviation for the pathname of the controlling terminal, if any.
+The abbreviation consists of the three letters following
+.Pa /dev/tty ,
+or, for the console,
+.Dq Li con .
+This is followed by a
+.Ql -
+if the process can no longer reach that
+controlling terminal (i.e., it has been revoked).
+.It Cm wchan
+The event (an address in the system) on which a process waits.
+When printed numerically, the initial part of the address is
+trimmed off and the result is printed in hex, for example, 0x80324000 prints
+as 324000.
+.El
+.Pp
+When printing using the command keyword, a process that has exited and
+has a parent that has not yet waited for the process (in other words, a zombie)
+is listed as
+.Dq Li <defunct> ,
+and a process which is blocked while trying
+to exit is listed as
+.Dq Li <exiting> .
+If the arguments cannot be located (usually because it has not been set, as is
+the case of system processes and/or kernel threads) the command name is printed
+within square brackets.
+The process can change the arguments shown with
+.Xr setproctitle 3 .
+Otherwise,
+.Nm
+makes an educated guess as to the file name and arguments given when the
+process was created by examining memory or the swap area.
+The method is inherently somewhat unreliable and in any event a process
+is entitled to destroy this information.
+The ucomm (accounting) keyword can, however, be depended on.
+If the arguments are unavailable or do not agree with the ucomm keyword,
+the value for the ucomm keyword is appended to the arguments in parentheses.
+.Sh KEYWORDS
+The following is a complete list of the available keywords and their
+meanings.
+Several of them have aliases (keywords which are synonyms).
+.Pp
+.Bl -tag -width ".Cm sigignore" -compact
+.It Cm %cpu
+percentage CPU usage (alias
+.Cm pcpu )
+.It Cm %mem
+percentage memory usage (alias
+.Cm pmem )
+.It Cm acflag
+accounting flag (alias
+.Cm acflg )
+.It Cm args
+command and arguments
+.It Cm comm
+command
+.It Cm command
+command and arguments
+.It Cm cpu
+short-term CPU usage factor (for scheduling)
+.It Cm etime
+elapsed running time
+.It Cm flags
+the process flags, in hexadecimal (alias
+.Cm f )
+.It Cm gid
+processes group id (alias
+.Cm group )
+.It Cm inblk
+total blocks read (alias
+.Cm inblock )
+.It Cm jobc
+job control count
+.It Cm ktrace
+tracing flags
+.It Cm ktracep
+tracing vnode
+.It Cm lim
+memoryuse limit
+.It Cm logname
+login name of user who started the session
+.It Cm lstart
+time started
+.It Cm majflt
+total page faults
+.It Cm minflt
+total page reclaims
+.It Cm msgrcv
+total messages received (reads from pipes/sockets)
+.It Cm msgsnd
+total messages sent (writes on pipes/sockets)
+.It Cm nice
+nice value (alias
+.Cm ni )
+.It Cm nivcsw
+total involuntary context switches
+.It Cm nsigs
+total signals taken (alias
+.Cm nsignals )
+.It Cm nswap
+total swaps in/out
+.It Cm nvcsw
+total voluntary context switches
+.It Cm nwchan
+wait channel (as an address)
+.It Cm oublk
+total blocks written (alias
+.Cm oublock )
+.It Cm p_ru
+resource usage (valid only for zombie)
+.It Cm paddr
+swap address
+.It Cm pagein
+pageins (same as majflt)
+.It Cm pgid
+process group number
+.It Cm pid
+process ID
+.It Cm ppid
+parent process ID
+.It Cm pri
+scheduling priority
+.It Cm re
+core residency time (in seconds; 127 = infinity)
+.It Cm rgid
+real group ID
+.It Cm rss
+resident set size
+.It Cm ruid
+real user ID
+.It Cm ruser
+user name (from ruid)
+.It Cm sess
+session ID
+.It Cm sig
+pending signals (alias
+.Cm pending )
+.It Cm sigmask
+blocked signals (alias
+.Cm blocked )
+.It Cm sl
+sleep time (in seconds; 127 = infinity)
+.It Cm start
+time started
+.It Cm state
+symbolic process state (alias
+.Cm stat )
+.It Cm svgid
+saved gid from a setgid executable
+.It Cm svuid
+saved UID from a setuid executable
+.It Cm tdev
+control terminal device number
+.It Cm time
+accumulated CPU time, user + system (alias
+.Cm cputime )
+.It Cm tpgid
+control terminal process group ID
+.\".It Cm trss
+.\"text resident set size (in Kbytes)
+.It Cm tsess
+control terminal session ID
+.It Cm tsiz
+text size (in Kbytes)
+.It Cm tt
+control terminal name (two letter abbreviation)
+.It Cm tty
+full name of control terminal
+.It Cm ucomm
+name to be used for accounting
+.It Cm uid
+effective user ID
+.It Cm upr
+scheduling priority on return from system call (alias
+.Cm usrpri )
+.It Cm user
+user name (from UID)
+.It Cm utime
+user CPU time (alias
+.Cm putime )
+.It Cm vsz
+virtual size in Kbytes (alias
+.Cm vsize )
+.It Cm wchan
+wait channel (as a symbolic name)
+.It Cm wq
+total number of workqueue threads
+.It Cm wqb
+number of blocked workqueue threads
+.It Cm wqr
+number of running workqueue threads
+.It Cm wql
+workqueue limit status (C = constrained thread limit, T = total thread limit)
+.It Cm xstat
+exit or stop status (valid only for stopped or zombie process)
+.El
+.Sh ENVIRONMENT
+The following environment variables affect the execution of
+.Nm :
+.Bl -tag -width ".Ev COLUMNS"
+.It Ev COLUMNS
+If set, specifies the user's preferred output width in column positions.
+By default,
+.Nm
+attempts to automatically determine the terminal width.
+.El
+.Sh FILES
+.Bl -tag -width ".Pa /boot/kernel/kernel" -compact
+.It Pa /dev
+special files and device names
+.It Pa /var/run/dev.db
+/dev name database
+.It Pa /var/db/kvm_kernel.db
+system namelist database
+.El
+.Sh LEGACY DESCRIPTION
+In legacy mode,
+.Nm
+functions as described above, with the following differences:
+.Bl -tag -width indent
+.It Fl e
+Display the environment as well. Same as
+.Fl E .
+.It Fl g
+Ignored for compatibility. Takes no argument.
+.It Fl l
+Display information associated with the following keywords:
+.Cm uid , pid , ppid , cpu , pri , nice , vsz , rss , wchan , state ,
+.Cm tt, time ,
+and
+.Cm command .
+.It Fl u
+Display information associated with the following keywords:
+.Cm user , pid , %cpu , %mem , vsz , rss , tt , state , start , time ,
+and
+.Cm command .
+The
+.Fl u
+option implies the
+.Fl r
+option.
+.El
+.Pp
+The biggest change is in the interpretation of the
+.Fl u
+option,
+which now displays processes belonging to the specified username(s).
+Thus, "ps -aux" will fail (unless you want to know about user "x").
+As a convenience, however, "ps aux" still works as it did in Tiger.
+.Pp
+For more information about legacy mode, see
+.Xr compat 5 .
+.Sh SEE ALSO
+.Xr kill 1 ,
+.Xr w 1 ,
+.Xr kvm 3 ,
+.Xr strftime 3 ,
+.Xr sysctl 8
+.Sh STANDARDS
+The
+.Nm
+utility supports the
+.St -susv3
+standard.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.At v4 .
+.Sh BUGS
+Since
+.Nm
+cannot run faster than the system and is run as any other scheduled
+process, the information it displays can never be exact.
+.Pp
+The
+.Nm
+utility does not correctly display argument lists containing multibyte
+characters.
diff --git a/adv_cmds/ps/ps.c b/adv_cmds/ps/ps.c
new file mode 100644
index 0000000..72c0242
--- /dev/null
+++ b/adv_cmds/ps/ps.c
@@ -0,0 +1,1373 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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.
+ * 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.
+ * ------+---------+---------+-------- + --------+---------+---------+---------*
+ * Copyright (c) 2004 - Garance Alistair Drosehn <gad@FreeBSD.org>.
+ * All rights reserved.
+ *
+ * Significant modifications made to bring `ps' options somewhat closer
+ * to the standard for `ps' as described in SingleUnixSpec-v3.
+ * ------+---------+---------+-------- + --------+---------+---------+---------*
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1990, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)ps.c 8.4 (Berkeley) 4/2/94";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/ps/ps.c,v 1.110 2005/02/09 17:37:38 ru Exp $");
+
+#include <sys/param.h>
+#ifdef __APPLE__
+#include <sys/time.h>
+#endif /* __APPLE__ */
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/sysctl.h>
+#include <sys/mount.h>
+#include <sys/resourcevar.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#ifndef __APPLE__
+#include <kvm.h>
+#endif /* !__APPLE__ */
+#include <limits.h>
+#include <locale.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ps.h"
+
+#ifdef __APPLE__
+#include <get_compat.h>
+#else /* !__APPLE__ */
+#define COMPAT_MODE(func, mode) (1)
+#endif /* __APPLE__ */
+
+#define W_SEP " \t" /* "Whitespace" list separators */
+#define T_SEP "," /* "Terminate-element" list separators */
+
+#ifdef LAZY_PS
+#define DEF_UREAD 0
+#define OPT_LAZY_f "f"
+#else
+#define DEF_UREAD 1 /* Always do the more-expensive read. */
+#define OPT_LAZY_f /* I.e., the `-f' option is not added. */
+#endif
+
+/*
+ * isdigit takes an `int', but expects values in the range of unsigned char.
+ * This wrapper ensures that values from a 'char' end up in the correct range.
+ */
+#define isdigitch(Anychar) isdigit((u_char)(Anychar))
+
+int cflag; /* -c */
+int eval; /* Exit value */
+time_t now; /* Current time(3) value */
+int rawcpu; /* -C */
+int sumrusage; /* -S */
+int termwidth; /* Width of the screen (0 == infinity). */
+int totwidth; /* Calculated-width of requested variables. */
+
+struct velisthead varlist = STAILQ_HEAD_INITIALIZER(varlist);
+
+#ifndef __APPLE__
+static int forceuread = DEF_UREAD; /* Do extra work to get u-area. */
+static kvm_t *kd;
+#endif /* !__APPLE__ */
+static KINFO *kinfo;
+static int needcomm; /* -o "command" */
+static int needenv; /* -e */
+static int needuser; /* -o "user" */
+static int optfatal; /* Fatal error parsing some list-option. */
+
+static enum sort { DEFAULT, SORTMEM, SORTCPU } sortby = DEFAULT;
+
+struct listinfo;
+typedef int addelem_rtn(struct listinfo *_inf, const char *_elem);
+
+struct listinfo {
+ int count;
+ int maxcount;
+ int elemsize;
+ addelem_rtn *addelem;
+ const char *lname;
+ union {
+ gid_t *gids;
+ pid_t *pids;
+ dev_t *ttys;
+ uid_t *uids;
+ void *ptr;
+ } l;
+};
+
+#ifndef __APPLE__
+static int check_procfs(void);
+#endif /* !__APPLE__ */
+static int addelem_gid(struct listinfo *, const char *);
+static int addelem_pid(struct listinfo *, const char *);
+static int addelem_tty(struct listinfo *, const char *);
+static int addelem_uid(struct listinfo *, const char *);
+static void add_list(struct listinfo *, const char *);
+static void dynsizevars(KINFO *);
+static void *expand_list(struct listinfo *);
+#ifndef __APPLE__
+static const char *
+ fmt(char **(*)(kvm_t *, const struct kinfo_proc *, int),
+ KINFO *, char *, int);
+#endif /* !__APPLE__ */
+static void free_list(struct listinfo *);
+static void init_list(struct listinfo *, addelem_rtn, int, const char *);
+static char *kludge_oldps_options(const char *, char *, const char *, int *);
+static int pscomp(const void *, const void *);
+static void saveuser(KINFO *);
+static void scanvars(void);
+static void sizevars(void);
+static void usage(int);
+
+/* 5842004: Fix -f option. */
+VAR *findvar(char *, int, char **);
+
+/* p_ == POSIX/SUSv3/UNIX2003 format */
+static char dfmt[] = "pid,tt,state,time,command";
+static char jfmt[] = "user,pid,ppid,pgid,sess,jobc,state,tt,time,command";
+static char lfmt[] = "uid,pid,ppid,cpu,pri,nice,vsz,rss,wchan,state,"
+ "tt,time,command";
+static char o1[] = "pid";
+static char o2[] = "tt,state,time,command";
+static char ufmt[] = "user,pid,%cpu,%mem,vsz,rss,tt,state,start,time,command";
+static char vfmt[] = "pid,state,time,sl,re,pagein,vsz,rss,lim,tsiz,"
+ "%cpu,%mem,command";
+#ifndef __APPLE__
+static char Zfmt[] = "label";
+#endif /* !__APPLE__ */
+char p_dfmt[] = "pid tty time command=CMD";
+char p_ffmt[] = "uid pid ppid cpu=C start=STIME tty time command=CMD";
+char p_uffmt[] = "user pid ppid cpu=C start=STIME tty time command=CMD";
+char p_lfmt[] = "uid pid ppid flags cpu pri nice vsz=SZ rss wchan state=S paddr=ADDR tty time command=CMD";
+char mfmt[] = "user pid tt %cpu state pri stime utime command";
+
+int eflg = 0;
+int mflg = 0; /* if -M option to display all mach threads */
+int print_thread_num = 0;
+int print_all_thread = 0;
+
+#define PS_ARGS (u03 ? "aACcdeEfg:G:hjLlMmO:o:p:rSTt:U:u:vwx" : \
+ "aACcdeEgG:hjLlMmO:o:p:rSTt:U:uvwx")
+
+int
+main(int argc, char *argv[])
+{
+ struct listinfo gidlist, pgrplist, pidlist;
+ struct listinfo ruidlist, sesslist, ttylist, uidlist;
+ struct kinfo_proc *kp;
+ KINFO *next_KINFO;
+ struct varent *vent;
+ struct winsize ws;
+#ifndef __APPLE__
+ const char *nlistf, *memf;
+#endif /* !__APPLE__ */
+ char *cols;
+ int all, ch, elem, flag, _fmt, i, lineno;
+ int nentries, nkept, nselectors;
+ int prtheader, showthreads, wflag, what, xkeep, xkeep_implied;
+#ifndef __APPLE__
+ char errbuf[_POSIX2_LINE_MAX];
+#endif /* !__APPLE__ */
+ struct kinfo_proc *kprocbuf;
+ int j;
+ int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
+ size_t bufSize = 0;
+ size_t orig_bufSize = 0;
+ int local_error=0;
+ int retry_count = 0;
+ int u03 = COMPAT_MODE("bin/ps", "unix2003");
+#ifdef __APPLE__
+ int dflag = 0;
+#endif /* __APPLE__ */
+
+ (void) setlocale(LC_ALL, "");
+ time(&now); /* Used by routines in print.c. */
+
+ if ((cols = getenv("COLUMNS")) != NULL && *cols != '\0')
+ termwidth = atoi(cols);
+ else if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&ws) == -1 &&
+ ioctl(STDERR_FILENO, TIOCGWINSZ, (char *)&ws) == -1 &&
+ ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&ws) == -1) ||
+ ws.ws_col == 0)
+ termwidth = 79;
+ else
+ termwidth = ws.ws_col - 1;
+
+ /*
+ * Hide a number of option-processing kludges in a separate routine,
+ * to support some historical BSD behaviors, such as `ps axu'.
+ */
+ if (argc > 1)
+ argv[1] = kludge_oldps_options(PS_ARGS, argv[1], argv[2], &u03);
+
+ all = _fmt = nselectors = optfatal = 0;
+ prtheader = showthreads = wflag = xkeep_implied = 0;
+ xkeep = -1; /* Neither -x nor -X. */
+ init_list(&gidlist, addelem_gid, sizeof(gid_t), "group");
+ init_list(&pgrplist, addelem_pid, sizeof(pid_t), "process group");
+ init_list(&pidlist, addelem_pid, sizeof(pid_t), "process id");
+ init_list(&ruidlist, addelem_uid, sizeof(uid_t), "ruser");
+ init_list(&sesslist, addelem_pid, sizeof(pid_t), "session id");
+ init_list(&ttylist, addelem_tty, sizeof(dev_t), "tty");
+ init_list(&uidlist, addelem_uid, sizeof(uid_t), "user");
+#ifndef __APPLE__
+ memf = nlistf = _PATH_DEVNULL;
+#endif /* !__APPLE__ */
+ while ((ch = getopt(argc, argv, PS_ARGS)) != -1)
+ switch ((char)ch) {
+#ifdef __APPLE__
+ case 'd':
+ dflag = 1;
+#endif /* __APPLE__ */
+ case 'A':
+ /*
+ * Exactly the same as `-ax'. This has been
+ * added for compatability with SUSv3, but for
+ * now it will not be described in the man page.
+ */
+ nselectors++;
+ all = xkeep = 1;
+ break;
+ case 'a':
+ nselectors++;
+ all = 1;
+ break;
+ case 'C':
+ rawcpu = 1;
+ break;
+ case 'c':
+ cflag = 1;
+ break;
+ case 'e': /* XXX set ufmt */
+ if (u03) {
+ nselectors++;
+ all = xkeep = 1;
+ break;
+ }
+ case 'E':
+ needenv = 1;
+ eflg = 1;
+ break;
+#ifdef LAZY_PS
+ case 'f':
+ if (getuid() == 0 || getgid() == 0)
+ forceuread = 1;
+ break;
+#endif
+ case 'f':
+ termwidth = UNLIMITED; /* 4990408 */
+ if (u03 && uidlist.count == 0) {
+ parsefmt(p_ffmt, 0);
+ /* This is a unplesent little trick that makes
+ ./ps -f -p PID -o pid,comm,args
+ print out the whole command even if they slap
+ more fields on after it and gobble up too much
+ space */
+ VAR *v = findvar("command", 0, NULL);
+ if (v) {
+ v->width = 64;
+ }
+ } else {
+ parsefmt(p_uffmt, 0);
+ }
+ _fmt = 1;
+ break;
+ case 'G':
+ add_list(&gidlist, optarg);
+ xkeep_implied = 1;
+ nselectors++;
+ break;
+ case 'g':
+ /* The historical BSD-ish (from SunOS) behavior. */
+ if (!u03) break;
+
+ add_list(&pgrplist, optarg);
+ xkeep_implied = 1;
+ nselectors++;
+ break;
+#ifndef __APPLE__
+ case 'H':
+ showthreads = KERN_PROC_INC_THREAD;
+ break;
+#endif /* !__APPLE__ */
+ case 'h':
+ prtheader = ws.ws_row > 5 ? ws.ws_row : 22;
+ break;
+ case 'j':
+ parsefmt(jfmt, 0);
+ _fmt = 1;
+ jfmt[0] = '\0';
+ break;
+ case 'L':
+ showkey();
+ exit(0);
+ case 'l':
+ parsefmt(u03 ? p_lfmt : lfmt, 0);
+ _fmt = 1;
+ lfmt[0] = '\0';
+ break;
+ case 'M':
+#ifndef __APPLE__
+ memf = optarg;
+#else
+ parsefmt(mfmt, 0);
+ _fmt = 1;
+ mfmt[0] = '\0';
+ mflg = 1;
+#endif /* 0 */
+ break;
+ case 'm':
+ sortby = SORTMEM;
+ break;
+#ifndef __APPLE__
+ case 'N':
+ nlistf = optarg;
+ break;
+#endif /* !__APPLE__ */
+ case 'O':
+ parsefmt(o1, 1);
+ parsefmt(optarg, 1);
+ parsefmt(o2, 1);
+ o1[0] = o2[0] = '\0';
+ _fmt = 1;
+ break;
+ case 'o':
+ parsefmt(optarg, 1);
+ _fmt = 1;
+ break;
+ case 'p':
+ add_list(&pidlist, optarg);
+ /*
+ * Note: `-p' does not *set* xkeep, but any values
+ * from pidlist are checked before xkeep is. That
+ * way they are always matched, even if the user
+ * specifies `-X'.
+ */
+ nselectors++;
+ break;
+ case 'r':
+ sortby = SORTCPU;
+ break;
+ case 'S':
+ sumrusage = 1;
+ break;
+ case 'T':
+ if ((optarg = ttyname(STDIN_FILENO)) == NULL)
+ errx(1, "stdin: not a terminal");
+ /* FALLTHROUGH */
+ case 't':
+ add_list(&ttylist, optarg);
+ xkeep_implied = 1;
+ nselectors++;
+ break;
+ case 'U':
+ add_list(&ruidlist, optarg);
+ xkeep_implied = 1;
+ nselectors++;
+ break;
+ case 'u':
+ if (u03) {
+ /* This is what SUSv3 defines as the `-u' option. */
+ add_list(&uidlist, optarg);
+ xkeep_implied = 1;
+ nselectors++;
+ break;
+ }
+ parsefmt(ufmt, 0);
+ sortby = SORTCPU;
+ _fmt = 1;
+ ufmt[0] = '\0';
+ break;
+ case 'v':
+ parsefmt(vfmt, 0);
+ sortby = SORTMEM;
+ _fmt = 1;
+ vfmt[0] = '\0';
+ break;
+ case 'w':
+ if (wflag)
+ termwidth = UNLIMITED;
+ else if (termwidth < 131)
+ termwidth = 131;
+ wflag++;
+ break;
+ case 'X':
+ /*
+ * Note that `-X' and `-x' are not standard "selector"
+ * options. For most selector-options, we check *all*
+ * processes to see if any are matched by the given
+ * value(s). After we have a set of all the matched
+ * processes, then `-X' and `-x' govern whether we
+ * modify that *matched* set for processes which do
+ * not have a controlling terminal. `-X' causes
+ * those processes to be deleted from the matched
+ * set, while `-x' causes them to be kept.
+ */
+ xkeep = 0;
+ break;
+ case 'x':
+ xkeep = 1;
+ break;
+ case '?':
+ default:
+ usage(u03);
+ }
+ argc -= optind;
+ argv += optind;
+
+#ifdef __APPLE__
+ /* 3862041 */
+ if (!isatty(STDOUT_FILENO))
+ termwidth = UNLIMITED;
+#endif /* __APPLE__ */
+
+ /*
+ * If the user specified ps -e then they want a copy of the process
+ * environment kvm_getenvv(3) attempts to open /proc/<pid>/mem.
+ * Check to make sure that procfs is mounted on /proc, otherwise
+ * print a warning informing the user that output will be incomplete.
+ */
+#ifndef __APPLE__
+ if (needenv == 1 && check_procfs() == 0)
+ warnx("Process environment requires procfs(5)");
+#endif /* !__APPLE__ */
+ /*
+ * If there arguments after processing all the options, attempt
+ * to treat them as a list of process ids.
+ */
+ while (*argv) {
+ if (!isdigitch(**argv))
+ break;
+ add_list(&pidlist, *argv);
+ argv++;
+ }
+ if (*argv) {
+ fprintf(stderr, "%s: illegal argument: %s\n",
+ getprogname(), *argv);
+ usage(u03);
+ }
+ if (optfatal)
+ exit(1); /* Error messages already printed. */
+ if (xkeep < 0) /* Neither -X nor -x was specified. */
+ xkeep = xkeep_implied;
+
+#if FIXME
+ kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
+ if (kd == 0)
+ errx(1, "%s", errbuf);
+#endif /* FIXME */
+
+ if (!_fmt) {
+ if (u03 && uidlist.count != 0) {
+ parsefmt("uid", 0);
+ }
+ parsefmt(u03 ? p_dfmt : dfmt, 0);
+ }
+
+ if (nselectors == 0) {
+ uidlist.l.ptr = malloc(sizeof(uid_t));
+ if (uidlist.l.ptr == NULL)
+ errx(1, "malloc failed");
+ nselectors = 1;
+ uidlist.count = uidlist.maxcount = 1;
+ *uidlist.l.uids = getuid();
+ }
+
+ /*
+ * scan requested variables, noting what structures are needed,
+ * and adjusting header widths as appropriate.
+ */
+ scanvars();
+
+ /*
+ * Get process list. If the user requested just one selector-
+ * option, then kvm_getprocs can be asked to return just those
+ * processes. Otherwise, have it return all processes, and
+ * then this routine will search that full list and select the
+ * processes which match any of the user's selector-options.
+ */
+ what = KERN_PROC_ALL;
+ flag = 0;
+ if (nselectors == 1) {
+ if (gidlist.count == 1) {
+#if 0
+ what = KERN_PROC_RGID | showthreads;
+ flag = *gidlist.l.gids;
+ nselectors = 0;
+#endif /* 0 */
+ } else if (pgrplist.count == 1) {
+ what = KERN_PROC_PGRP | showthreads;
+ flag = *pgrplist.l.pids;
+ nselectors = 0;
+ } else if (pidlist.count == 1) {
+ what = KERN_PROC_PID | showthreads;
+ flag = *pidlist.l.pids;
+ nselectors = 0;
+ } else if (ruidlist.count == 1) {
+ what = KERN_PROC_RUID | showthreads;
+ flag = *ruidlist.l.uids;
+ nselectors = 0;
+ } else if (sesslist.count == 1) {
+ what = KERN_PROC_SESSION | showthreads;
+ flag = *sesslist.l.pids;
+ nselectors = 0;
+ } else if (ttylist.count == 1) {
+ what = KERN_PROC_TTY | showthreads;
+ flag = *ttylist.l.ttys;
+ nselectors = 0;
+ } else if (uidlist.count == 1) {
+ what = (xkeep ? KERN_PROC_RUID : KERN_PROC_UID) | showthreads;
+ flag = *uidlist.l.uids;
+ nselectors = 0;
+ }
+ }
+
+ /*
+ * select procs
+ */
+ nentries = -1;
+#if FIXME
+ kp = kvm_getprocs(kd, what, flag, &nentries);
+ if ((kp == NULL && nentries > 0) || (kp != NULL && nentries < 0))
+ errx(1, "%s", kvm_geterr(kd));
+#else /* FIXME */
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = what;
+ mib[3] = flag;
+
+ if (sysctl(mib, 4, NULL, &bufSize, NULL, 0) < 0) {
+ perror("Failure calling sysctl");
+ return 0;
+ }
+
+ kprocbuf= kp = (struct kinfo_proc *)malloc(bufSize);
+
+ retry_count = 0;
+ orig_bufSize = bufSize;
+ for(retry_count=0; ; retry_count++) {
+ /* retry for transient errors due to load in the system */
+ local_error = 0;
+ bufSize = orig_bufSize;
+ if ((local_error = sysctl(mib, 4, kp, &bufSize, NULL, 0)) < 0) {
+ if (retry_count < 1000) {
+ /* 1 sec back off */
+ sleep(1);
+ continue;
+ }
+ perror("Failure calling sysctl");
+ return 0;
+ } else if (local_error == 0) {
+ break;
+ }
+ /* 1 sec back off */
+ sleep(1);
+ }
+
+ /* This has to be after the second sysctl since the bufSize
+ may have changed. */
+ nentries = bufSize / sizeof(struct kinfo_proc);
+#endif /* FIXME */
+ nkept = 0;
+ if (nentries > 0) {
+ if ((kinfo = calloc(nentries, sizeof(*kinfo))) == NULL)
+ errx(1, "malloc failed");
+ for (i = nentries; --i >= 0; ++kp) {
+#ifdef __APPLE__
+ if (kp->kp_proc.p_pid == 0) {
+ continue;
+ }
+#endif /* __APPLE__ */
+
+#ifdef __APPLE__
+ if (dflag && (kp->kp_proc.p_pid == kp->kp_eproc.e_pgid))
+ continue;
+#endif /* __APPLE__ */
+
+ /*
+ * If the user specified multiple selection-criteria,
+ * then keep any process matched by the inclusive OR
+ * of all the selection-criteria given.
+ */
+ if (pidlist.count > 0) {
+ for (elem = 0; elem < pidlist.count; elem++)
+ if (kp->kp_proc.p_pid == pidlist.l.pids[elem])
+ goto keepit;
+ }
+ /*
+ * Note that we had to process pidlist before
+ * filtering out processes which do not have
+ * a controlling terminal.
+ */
+ if (xkeep == 0) {
+ if ((kp->kp_eproc.e_tdev == NODEV ||
+ (kp->kp_proc.p_flag & P_CONTROLT) == 0))
+ continue;
+ }
+ if (all || nselectors == 0)
+ goto keepit;
+ if (gidlist.count > 0) {
+ for (elem = 0; elem < gidlist.count; elem++)
+ if (kp->kp_eproc.e_pcred.p_rgid == gidlist.l.gids[elem])
+ goto keepit;
+ }
+ if (pgrplist.count > 0) {
+ for (elem = 0; elem < pgrplist.count; elem++)
+ if (kp->kp_eproc.e_pgid ==
+ pgrplist.l.pids[elem])
+ goto keepit;
+ }
+ if (ruidlist.count > 0) {
+ for (elem = 0; elem < ruidlist.count; elem++)
+ if (kp->kp_eproc.e_pcred.p_ruid ==
+ ruidlist.l.uids[elem])
+ goto keepit;
+ }
+#if 0
+ if (sesslist.count > 0) {
+ for (elem = 0; elem < sesslist.count; elem++)
+ if (kp->ki_sid == sesslist.l.pids[elem])
+ goto keepit;
+ }
+#endif
+ if (ttylist.count > 0) {
+ for (elem = 0; elem < ttylist.count; elem++)
+ if (kp->kp_eproc.e_tdev == ttylist.l.ttys[elem])
+ goto keepit;
+ }
+ if (uidlist.count > 0) {
+ for (elem = 0; elem < uidlist.count; elem++)
+ if (kp->kp_eproc.e_ucred.cr_uid == uidlist.l.uids[elem])
+ goto keepit;
+ }
+ /*
+ * This process did not match any of the user's
+ * selector-options, so skip the process.
+ */
+ continue;
+
+ keepit:
+ next_KINFO = &kinfo[nkept];
+ next_KINFO->ki_p = kp;
+ get_task_info(next_KINFO);
+#ifndef __APPLE__
+ next_KINFO->ki_pcpu = getpcpu(next_KINFO);
+ if (sortby == SORTMEM)
+ next_KINFO->ki_memsize = kp->ki_tsize +
+ kp->ki_dsize + kp->ki_ssize;
+#endif /* !__APPLE__ */
+ if (needuser)
+ saveuser(next_KINFO);
+ dynsizevars(next_KINFO);
+ nkept++;
+ }
+ }
+
+ sizevars();
+
+ /*
+ * print header
+ */
+ printheader();
+ if (nkept == 0)
+ exit(1);
+
+ /*
+ * sort proc list
+ */
+ qsort(kinfo, nkept, sizeof(KINFO), pscomp);
+ /*
+ * For each process, call each variable output function.
+ */
+ for (i = lineno = 0; i < nkept; i++) {
+ if(mflg) {
+ print_all_thread = 1;
+ for(j=0; j < kinfo[i].thread_count; j++) {
+ print_thread_num = j;
+ STAILQ_FOREACH(vent, &varlist, next_ve) {
+ (vent->var->oproc)(&kinfo[i], vent);
+ if (STAILQ_NEXT(vent, next_ve) != NULL)
+ (void)putchar(' ');
+ }
+
+ (void)putchar('\n');
+ if (prtheader && lineno++ == prtheader - 4) {
+ (void)putchar('\n');
+ printheader();
+ lineno = 0;
+ }
+ }
+ print_all_thread = 0;
+ } else {
+ STAILQ_FOREACH(vent, &varlist, next_ve) {
+ (vent->var->oproc)(&kinfo[i], vent);
+ if (STAILQ_NEXT(vent, next_ve) != NULL)
+ (void)putchar(' ');
+ }
+
+ (void)putchar('\n');
+ if (prtheader && lineno++ == prtheader - 4) {
+ (void)putchar('\n');
+ printheader();
+ lineno = 0;
+ }
+ }
+ }
+ for (i = 0; i < nkept; i++) {
+ if (kinfo[i].invalid_tinfo == 0 && kinfo[i].thread_count)
+ free(kinfo[i].thval);
+ }
+ free(kprocbuf);
+ free(kinfo);
+ free_list(&gidlist);
+ free_list(&pidlist);
+ free_list(&pgrplist);
+ free_list(&ruidlist);
+ free_list(&sesslist);
+ free_list(&ttylist);
+ free_list(&uidlist);
+
+ exit(eval);
+}
+
+static int
+addelem_gid(struct listinfo *inf, const char *elem)
+{
+ struct group *grp;
+ const char *nameorID;
+ char *endp;
+ u_long bigtemp;
+
+ if (*elem == '\0' || strlen(elem) >= MAXLOGNAME) {
+ if (*elem == '\0')
+ warnx("Invalid (zero-length) %s name", inf->lname);
+ else
+ warnx("%s name too long: %s", inf->lname, elem);
+ optfatal = 1;
+ return (0); /* Do not add this value. */
+ }
+
+ /*
+ * SUSv3 states that `ps -G grouplist' should match "real-group
+ * ID numbers", and does not mention group-names. I do want to
+ * also support group-names, so this tries for a group-id first,
+ * and only tries for a name if that doesn't work. This is the
+ * opposite order of what is done in addelem_uid(), but in
+ * practice the order would only matter for group-names which
+ * are all-numeric.
+ */
+ grp = NULL;
+ nameorID = "named";
+ errno = 0;
+ bigtemp = strtoul(elem, &endp, 10);
+ if (errno == 0 && *endp == '\0' && bigtemp <= GID_MAX) {
+ nameorID = "name or ID matches";
+ grp = getgrgid((gid_t)bigtemp);
+ }
+ if (grp == NULL)
+ grp = getgrnam(elem);
+ if (grp == NULL) {
+ warnx("No %s %s '%s'", inf->lname, nameorID, elem);
+ optfatal = 1;
+ return (0);
+ }
+ if (inf->count >= inf->maxcount)
+ expand_list(inf);
+ inf->l.gids[(inf->count)++] = grp->gr_gid;
+ return (1);
+}
+
+#define BSD_PID_MAX 99999 /* Copy of PID_MAX from sys/proc.h. */
+static int
+addelem_pid(struct listinfo *inf, const char *elem)
+{
+ char *endp;
+ long tempid;
+
+ if (*elem == '\0') {
+ warnx("Invalid (zero-length) process id");
+ optfatal = 1;
+ return (0); /* Do not add this value. */
+ }
+
+ errno = 0;
+ tempid = strtol(elem, &endp, 10);
+ if (*endp != '\0' || tempid < 0 || elem == endp) {
+ warnx("Invalid %s: %s", inf->lname, elem);
+ errno = ERANGE;
+ } else if (errno != 0 || tempid > BSD_PID_MAX) {
+ warnx("%s too large: %s", inf->lname, elem);
+ errno = ERANGE;
+ }
+ if (errno == ERANGE) {
+ optfatal = 1;
+ return (0);
+ }
+ if (inf->count >= inf->maxcount)
+ expand_list(inf);
+ inf->l.pids[(inf->count)++] = tempid;
+ return (1);
+}
+#undef BSD_PID_MAX
+
+/*-
+ * The user can specify a device via one of three formats:
+ * 1) fully qualified, e.g.: /dev/ttyp0 /dev/console
+ * 2) missing "/dev", e.g.: ttyp0 console
+ * 3) two-letters, e.g.: p0 co
+ * (matching letters that would be seen in the "TT" column)
+ */
+static int
+addelem_tty(struct listinfo *inf, const char *elem)
+{
+ const char *ttypath;
+ struct stat sb;
+ char pathbuf[PATH_MAX], pathbuf2[PATH_MAX];
+
+ ttypath = NULL;
+ pathbuf2[0] = '\0';
+ switch (*elem) {
+ case '/':
+ ttypath = elem;
+ break;
+ case 'c':
+ if (strcmp(elem, "co") == 0) {
+ ttypath = _PATH_CONSOLE;
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ strlcpy(pathbuf, _PATH_DEV, sizeof(pathbuf));
+ strlcat(pathbuf, elem, sizeof(pathbuf));
+ ttypath = pathbuf;
+ if (strncmp(pathbuf, _PATH_TTY, strlen(_PATH_TTY)) == 0)
+ break;
+ if (strcmp(pathbuf, _PATH_CONSOLE) == 0)
+ break;
+ /* Check to see if /dev/tty${elem} exists */
+ strlcpy(pathbuf2, _PATH_TTY, sizeof(pathbuf2));
+ strlcat(pathbuf2, elem, sizeof(pathbuf2));
+ if (stat(pathbuf2, &sb) == 0 && S_ISCHR(sb.st_mode)) {
+ /* No need to repeat stat() && S_ISCHR() checks */
+ ttypath = NULL;
+ break;
+ }
+ break;
+ }
+ if (ttypath) {
+#ifdef __APPLE__
+ if (access(ttypath, F_OK) == -1 || stat(ttypath, &sb) == -1) {
+#else
+ if (stat(ttypath, &sb) == -1) {
+#endif
+ if (pathbuf2[0] != '\0')
+ warn("%s and %s", pathbuf2, ttypath);
+ else
+ warn("%s", ttypath);
+ optfatal = 1;
+ return (0);
+ }
+ if (!S_ISCHR(sb.st_mode)) {
+ if (pathbuf2[0] != '\0')
+ warnx("%s and %s: Not a terminal", pathbuf2,
+ ttypath);
+ else
+ warnx("%s: Not a terminal", ttypath);
+ optfatal = 1;
+ return (0);
+ }
+ }
+ if (inf->count >= inf->maxcount)
+ expand_list(inf);
+ inf->l.ttys[(inf->count)++] = sb.st_rdev;
+ return (1);
+}
+
+static int
+addelem_uid(struct listinfo *inf, const char *elem)
+{
+ struct passwd *pwd;
+ char *endp;
+ u_long bigtemp;
+
+ if (*elem == '\0' || strlen(elem) >= MAXLOGNAME) {
+ if (*elem == '\0')
+ warnx("Invalid (zero-length) %s name", inf->lname);
+ else
+ warnx("%s name too long: %s", inf->lname, elem);
+ optfatal = 1;
+ return (0); /* Do not add this value. */
+ }
+
+ pwd = getpwnam(elem);
+ if (pwd == NULL) {
+ errno = 0;
+ bigtemp = strtoul(elem, &endp, 10);
+ if (errno != 0 || *endp != '\0' || bigtemp > UID_MAX)
+ warnx("No %s named '%s'", inf->lname, elem);
+ else {
+ /* The string is all digits, so it might be a userID. */
+ pwd = getpwuid((uid_t)bigtemp);
+ if (pwd == NULL)
+ warnx("No %s name or ID matches '%s'",
+ inf->lname, elem);
+ }
+ }
+ if (pwd == NULL) {
+ /*
+ * These used to be treated as minor warnings (and the
+ * option was simply ignored), but now they are fatal
+ * errors (and the command will be aborted).
+ */
+ optfatal = 1;
+ return (0);
+ }
+ if (inf->count >= inf->maxcount)
+ expand_list(inf);
+ inf->l.uids[(inf->count)++] = pwd->pw_uid;
+ return (1);
+}
+
+static void
+add_list(struct listinfo *inf, const char *argp)
+{
+ const char *savep;
+ char *cp, *endp;
+ int toolong;
+ char elemcopy[PATH_MAX];
+
+ if (*argp == 0)
+ inf->addelem(inf, elemcopy);
+ while (*argp != '\0') {
+ while (*argp != '\0' && strchr(W_SEP, *argp) != NULL)
+ argp++;
+ savep = argp;
+ toolong = 0;
+ cp = elemcopy;
+ if (strchr(T_SEP, *argp) == NULL) {
+ endp = elemcopy + sizeof(elemcopy) - 1;
+ while (*argp != '\0' && cp <= endp &&
+ strchr(W_SEP T_SEP, *argp) == NULL)
+ *cp++ = *argp++;
+ if (cp > endp)
+ toolong = 1;
+ }
+ if (!toolong) {
+ *cp = '\0';
+ /*
+ * Add this single element to the given list.
+ */
+ inf->addelem(inf, elemcopy);
+ } else {
+ /*
+ * The string is too long to copy. Find the end
+ * of the string to print out the warning message.
+ */
+ while (*argp != '\0' && strchr(W_SEP T_SEP,
+ *argp) == NULL)
+ argp++;
+ warnx("Value too long: %.*s", (int)(argp - savep),
+ savep);
+ optfatal = 1;
+ }
+ /*
+ * Skip over any number of trailing whitespace characters,
+ * but only one (at most) trailing element-terminating
+ * character.
+ */
+ while (*argp != '\0' && strchr(W_SEP, *argp) != NULL)
+ argp++;
+ if (*argp != '\0' && strchr(T_SEP, *argp) != NULL) {
+ argp++;
+#if 0
+ /* Catch case where string ended with a comma. */
+ if (*argp == '\0')
+ inf->addelem(inf, argp);
+#endif /* 0 */
+ }
+ }
+}
+
+static void *
+expand_list(struct listinfo *inf)
+{
+ void *newlist;
+ int newmax;
+
+ newmax = (inf->maxcount + 1) << 1;
+ newlist = realloc(inf->l.ptr, newmax * inf->elemsize);
+ if (newlist == NULL) {
+ free(inf->l.ptr);
+ errx(1, "realloc to %d %ss failed", newmax, inf->lname);
+ }
+ inf->maxcount = newmax;
+ inf->l.ptr = newlist;
+
+ return (newlist);
+}
+
+static void
+free_list(struct listinfo *inf)
+{
+
+ inf->count = inf->elemsize = inf->maxcount = 0;
+ if (inf->l.ptr != NULL)
+ free(inf->l.ptr);
+ inf->addelem = NULL;
+ inf->lname = NULL;
+ inf->l.ptr = NULL;
+}
+
+static void
+init_list(struct listinfo *inf, addelem_rtn artn, int elemsize,
+ const char *lname)
+{
+
+ inf->count = inf->maxcount = 0;
+ inf->elemsize = elemsize;
+ inf->addelem = artn;
+ inf->lname = lname;
+ inf->l.ptr = NULL;
+}
+
+VARENT *
+find_varentry(VAR *v)
+{
+ struct varent *vent;
+
+ STAILQ_FOREACH(vent, &varlist, next_ve) {
+ if (strcmp(vent->var->name, v->name) == 0)
+ return vent;
+ }
+ return NULL;
+}
+
+static void
+scanvars(void)
+{
+ struct varent *vent;
+ VAR *v;
+
+ STAILQ_FOREACH(vent, &varlist, next_ve) {
+ v = vent->var;
+ if (v->flag & DSIZ) {
+ v->dwidth = v->width;
+ v->width = 0;
+ }
+ if (v->flag & USER)
+ needuser = 1;
+ if (v->flag & COMM)
+ needcomm = 1;
+ }
+}
+
+static void
+dynsizevars(KINFO *ki)
+{
+ struct varent *vent;
+ VAR *v;
+ int i;
+
+ STAILQ_FOREACH(vent, &varlist, next_ve) {
+ v = vent->var;
+ if (!(v->flag & DSIZ))
+ continue;
+ i = (v->sproc)( ki);
+ if (v->width < i)
+ v->width = i;
+ if (v->width > v->dwidth)
+ v->width = v->dwidth;
+ }
+}
+
+static void
+sizevars(void)
+{
+ struct varent *vent;
+ VAR *v;
+ int i;
+
+ STAILQ_FOREACH(vent, &varlist, next_ve) {
+ v = vent->var;
+ i = strlen(vent->header);
+ if (v->width < i)
+ v->width = i;
+ totwidth += v->width + 1; /* +1 for space */
+ }
+ totwidth--;
+}
+
+#ifndef __APPLE__
+static const char *
+fmt(char **(*fn)(kvm_t *, const struct kinfo_proc *, int), KINFO *ki,
+ char *comm, int maxlen)
+{
+ const char *s;
+
+ s = fmt_argv((*fn)(kd, ki->ki_p, termwidth), comm, maxlen);
+ return (s);
+}
+#endif /* !__APPLE__ */
+
+#define UREADOK(ki) (forceuread || (KI_PROC(ki)->p_flag & P_INMEM))
+
+static void
+saveuser(KINFO *ki)
+{
+ struct usave *usp;
+#if FIXME
+ struct user *u_addr = (struct user *)USRSTACK;
+#endif /* FIXME */
+
+ usp = &ki->ki_u;
+#if FIXME
+ if (UREADOK(ki) && kvm_uread(kd, KI_PROC(ki), (unsigned long)&u_addr->u_stats,
+ (char *)&pstats, sizeof(pstats)) == sizeof(pstats))
+ {
+ /*
+ * The u-area might be swapped out, and we can't get
+ * at it because we have a crashdump and no swap.
+ * If it's here fill in these fields, otherwise, just
+ * leave them 0.
+ */
+ usp->u_start = pstats.p_start;
+ usp->u_ru = pstats.p_ru;
+ usp->u_cru = pstats.p_cru;
+ usp->u_valid = 1;
+ } else
+ usp->u_valid = 0;
+#else /* FIXME */
+ usp->u_valid = 0;
+#endif /* FIXME */
+ /*
+ * save arguments if needed
+ */
+#if FIXME
+ if (needcomm && UREADOK(ki)) {
+ ki->ki_args = fmt(kvm_getargv, ki, KI_PROC(ki)->p_comm,
+ MAXCOMLEN);
+ } else if (needcomm) {
+ ki->ki_args = malloc(strlen(KI_PROC(ki)->p_comm) + 3);
+ sprintf(ki->ki_args, "(%s)", KI_PROC(ki)->p_comm);
+ } else {
+ ki->ki_args = NULL;
+ }
+#else /* FIXME */
+ ki->ki_args = malloc(strlen(KI_PROC(ki)->p_comm) + 3);
+ sprintf(ki->ki_args, "%s", KI_PROC(ki)->p_comm);
+ //ki->ki_args = malloc(10);
+ //strcpy(ki->ki_args, "()");
+#endif /* FIXME */
+#if FIXME
+ if (needenv && UREADOK(ki)) {
+ ki->ki_env = fmt(kvm_getenvv, ki, (char *)NULL, 0);
+ } else if (needenv) {
+ ki->ki_env = malloc(3);
+ strcpy(ki->ki_env, "()");
+ } else {
+ ki->ki_env = NULL;
+ }
+#else /* FIXME */
+ ki->ki_env = malloc(10);
+ strcpy(ki->ki_env, "");
+#endif /* FIXME */
+}
+
+static int
+pscomp(const void *a, const void *b)
+{
+ int i;
+#if FIXME
+#define VSIZE(k) (KI_EPROC(k)->e_vm.vm_dsize + KI_EPROC(k)->e_vm.vm_ssize + \
+ KI_EPROC(k)->e_vm.vm_tsize)
+#else /* FIXME */
+#define VSIZE(k) ((k)->tasks_info.resident_size)
+
+#endif /* FIXME */
+
+ if (sortby == SORTCPU)
+ return (getpcpu((KINFO *)b) - getpcpu((KINFO *)a));
+ if (sortby == SORTMEM)
+ return (VSIZE((KINFO *)b) - VSIZE((KINFO *)a));
+ i = KI_EPROC((KINFO *)a)->e_tdev - KI_EPROC((KINFO *)b)->e_tdev;
+ if (i == 0)
+ i = KI_PROC((KINFO *)a)->p_pid - KI_PROC((KINFO *)b)->p_pid;
+ return (i);
+}
+
+/*
+ * ICK (all for getopt), would rather hide the ugliness
+ * here than taint the main code.
+ *
+ * ps foo -> ps -foo
+ * ps 34 -> ps -p34
+ *
+ * The old convention that 't' with no trailing tty arg means the users
+ * tty, is only supported if argv[1] doesn't begin with a '-'. This same
+ * feature is available with the option 'T', which takes no argument.
+ */
+static char *
+kludge_oldps_options(const char *optlist, char *origval, const char *nextarg, int *u03)
+{
+ size_t len;
+ char *argp, *cp, *newopts, *ns, *optp, *pidp;
+
+ /*
+ * See if the original value includes any option which takes an
+ * argument (and will thus use up the remainder of the string).
+ */
+ argp = NULL;
+ if (optlist != NULL) {
+ for (cp = origval; *cp != '\0'; cp++) {
+ optp = strchr(optlist, *cp);
+ if ((optp != NULL) && *(optp + 1) == ':') {
+ argp = cp;
+ break;
+ }
+ }
+ }
+ if (argp != NULL && *origval == '-')
+ return (origval);
+
+ /*
+ * if last letter is a 't' flag with no argument (in the context
+ * of the oldps options -- option string NOT starting with a '-' --
+ * then convert to 'T' (meaning *this* terminal, i.e. ttyname(0)).
+ *
+ * However, if a flag accepting a string argument is found earlier
+ * in the option string (including a possible `t' flag), then the
+ * remainder of the string must be the argument to that flag; so
+ * do not modify that argument. Note that a trailing `t' would
+ * cause argp to be set, if argp was not already set by some
+ * earlier option.
+ */
+ len = strlen(origval);
+ cp = origval + len - 1;
+ pidp = NULL;
+ if (*cp == 't' && *origval != '-' && cp == argp) {
+ if (nextarg == NULL || *nextarg == '-' || isdigitch(*nextarg))
+ *cp = 'T';
+ } else if (argp == NULL) {
+ /*
+ * The original value did not include any option which takes
+ * an argument (and that would include `p' and `t'), so check
+ * the value for trailing number, or comma-separated list of
+ * numbers, which we will treat as a pid request.
+ */
+ if (isdigitch(*cp)) {
+ while (cp >= origval && (*cp == ',' || isdigitch(*cp)))
+ --cp;
+ pidp = cp + 1;
+ }
+ }
+
+ /*
+ * If nothing needs to be added to the string, then return
+ * the "original" (although possibly modified) value.
+ */
+ if (*origval == '-' && pidp == NULL)
+ return (origval);
+
+ /*
+ * Create a copy of the string to add '-' and/or 'p' to the
+ * original value.
+ */
+ if ((newopts = ns = malloc(len + 3)) == NULL)
+ errx(1, "malloc failed");
+
+ if (*origval != '-') {
+ *ns++ = '-'; /* add option flag */
+ *u03 = 0;
+ }
+
+ if (pidp == NULL)
+ strcpy(ns, origval);
+ else {
+ /*
+ * Copy everything before the pid string, add the `p',
+ * and then copy the pid string.
+ */
+ len = pidp - origval;
+ memcpy(ns, origval, len);
+ ns += len;
+ *ns++ = 'p';
+ strcpy(ns, pidp);
+ }
+
+ return (newopts);
+}
+
+#ifndef __APPLE__
+static int
+check_procfs(void)
+{
+ struct statfs mnt;
+
+ if (statfs("/proc", &mnt) < 0)
+ return (0);
+ if (strcmp(mnt.f_fstypename, "procfs") != 0)
+ return (0);
+ return (1);
+}
+#endif /* !__APPLE__ */
+
+static void
+usage(int u03)
+{
+#define SINGLE_OPTS "[-AaCcEefhjlMmrSTvwXx]"
+
+ (void)fprintf(stderr, "%s\n%s\n%s\n%s\n",
+ "usage: ps " SINGLE_OPTS " [-O fmt | -o fmt] [-G gid[,gid...]]",
+ (u03 ? " [-g grp[,grp...]] [-u [uid,uid...]]" : " [-u]"),
+ " [-p pid[,pid...]] [-t tty[,tty...]] [-U user[,user...]]",
+ " ps [-L]");
+ exit(1);
+}
diff --git a/adv_cmds/ps/ps.h b/adv_cmds/ps/ps.h
new file mode 100644
index 0000000..a077eff
--- /dev/null
+++ b/adv_cmds/ps/ps.h
@@ -0,0 +1,131 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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.
+ *
+ * @(#)ps.h 8.1 (Berkeley) 5/31/93
+ * $FreeBSD: ps.h,v 1.6 1998/09/14 08:32:20 dfr Exp $
+ */
+
+#include <sys/queue.h>
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <mach/policy.h>
+#include <mach/task_info.h>
+#include <mach/thread_info.h>
+
+#define UNLIMITED 0 /* unlimited terminal width */
+enum type { CHAR, UCHAR, SHORT, USHORT, INT, UINT, LONG, ULONG, KPTR, PGTOK };
+
+struct usave {
+ struct timeval u_start;
+ struct rusage u_ru;
+ struct rusage u_cru;
+ char u_acflag;
+ char u_valid;
+};
+
+#define KI_PROC(ki) (&(ki)->ki_p->kp_proc)
+#define KI_EPROC(ki) (&(ki)->ki_p->kp_eproc)
+
+typedef struct thread_values {
+ struct thread_basic_info tb;
+ /* struct policy_infos schedinfo; */
+ union {
+ struct policy_timeshare_info tshare;
+ struct policy_rr_info rr;
+ struct policy_fifo_info fifo;
+ } schedinfo;
+} thread_values_t;
+
+typedef struct kinfo {
+ struct kinfo_proc *ki_p; /* kinfo_proc structure */
+ struct usave ki_u; /* interesting parts of user */
+ char *ki_args; /* exec args */
+ char *ki_env; /* environment */
+ task_port_t task;
+ int state;
+ int cpu_usage;
+ int curpri;
+ int basepri;
+ int swapped;
+ struct task_basic_info tasks_info;
+ struct task_thread_times_info times;
+ /* struct policy_infos schedinfo; */
+ union {
+ struct policy_timeshare_info tshare;
+ struct policy_rr_info rr;
+ struct policy_fifo_info fifo;
+ } schedinfo;
+ int invalid_tinfo;
+ unsigned int thread_count;
+ thread_port_array_t thread_list;
+ thread_values_t *thval;
+ int invalid_thinfo;
+} KINFO;
+
+/* Variables. */
+typedef struct varent {
+ STAILQ_ENTRY(varent) next_ve;
+ const char *header;
+ struct var *var;
+} VARENT;
+
+typedef struct var {
+ const char *name; /* name(s) of variable */
+ const char *header; /* default header */
+ const char *alias; /* aliases */
+#define COMM 0x01 /* needs exec arguments and environment (XXX) */
+#define LJUST 0x02 /* left adjust on output (trailing blanks) */
+#define USER 0x04 /* needs user structure */
+#define DSIZ 0x08 /* field size is dynamic*/
+#define INF127 0x10 /* values >127 displayed as 127 */
+ u_int flag;
+ /* output routine */
+ void (*oproc)(struct kinfo *, struct varent *);
+ /* sizing routine*/
+ int (*sproc)(struct kinfo *);
+ short width; /* printing width */
+ /*
+ * The following (optional) elements are hooks for passing information
+ * to the generic output routine pvar (which prints simple elements
+ * from the well known kinfo_proc structure).
+ */
+ size_t off; /* offset in structure */
+ enum type type; /* type of element */
+ const char *fmt; /* printf format */
+ short dwidth; /* dynamic printing width */
+ /*
+ * glue to link selected fields together
+ */
+} VAR;
+
+#include "extern.h"
diff --git a/adv_cmds/ps/tasks.c b/adv_cmds/ps/tasks.c
new file mode 100644
index 0000000..4548b56
--- /dev/null
+++ b/adv_cmds/ps/tasks.c
@@ -0,0 +1,246 @@
+#include <sys/param.h>
+#include <sys/user.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/sysctl.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <nlist.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <locale.h>
+#include <pwd.h>
+
+#include "ps.h"
+#include <mach/shared_memory_server.h>
+
+extern kern_return_t task_for_pid(task_port_t task, pid_t pid, task_port_t *target);
+
+#define STATE_MAX 7
+
+int
+mach_state_order(s, sleep_time)
+int s;
+long sleep_time;
+{
+switch (s) {
+case TH_STATE_RUNNING: return(1);
+case TH_STATE_UNINTERRUPTIBLE:
+ return(2);
+ case TH_STATE_WAITING: return((sleep_time > 20) ? 4 : 3);
+ case TH_STATE_STOPPED: return(5);
+ case TH_STATE_HALTED: return(6);
+ default: return(7);
+ }
+}
+ /*01234567 */
+char mach_state_table[] = " RUSITH?";
+
+
+int
+thread_schedinfo(
+ KINFO *ki,
+ thread_port_t thread,
+ policy_t pol,
+ void * buf)
+{
+ unsigned int count;
+ int ret = KERN_FAILURE;
+
+ switch (pol) {
+
+ case POLICY_TIMESHARE:
+ count = POLICY_TIMESHARE_INFO_COUNT;
+ ret = thread_info(thread, THREAD_SCHED_TIMESHARE_INFO,
+ (thread_info_t)buf, &count);
+ if((ret == KERN_SUCCESS) && (ki->curpri < (((struct policy_timeshare_info *)buf)->cur_priority)))
+ ki->curpri = ((struct policy_timeshare_info *)buf)->cur_priority;
+ break;
+
+ case POLICY_FIFO:
+ count = POLICY_FIFO_INFO_COUNT;
+ ret = thread_info(thread, THREAD_SCHED_FIFO_INFO,
+ buf, &count);
+ if((ret == KERN_SUCCESS) && (ki->curpri < (((struct policy_fifo_info *)buf)->base_priority)))
+ ki->curpri = ((struct policy_fifo_info *)buf)->base_priority;
+ break;
+
+ case POLICY_RR:
+ count = POLICY_RR_INFO_COUNT;
+ ret = thread_info(thread, THREAD_SCHED_RR_INFO,
+ buf, &count);
+ if((ret == KERN_SUCCESS) && (ki->curpri < (((struct policy_rr_info *)buf)->base_priority)))
+ ki->curpri = ((struct policy_rr_info *)buf)->base_priority;
+ break;
+ }
+ return(ret);
+}
+
+int get_task_info (KINFO *ki)
+{
+ kern_return_t error;
+ unsigned int info_count = TASK_BASIC_INFO_COUNT;
+ unsigned int thread_info_count = THREAD_BASIC_INFO_COUNT;
+ pid_t pid;
+ int j, err = 0;
+
+ ki->state = STATE_MAX;
+
+ pid = KI_PROC(ki)->p_pid;
+ if (task_for_pid(mach_task_self(), pid, &ki->task) != KERN_SUCCESS) {
+ return(1);
+ }
+ info_count = TASK_BASIC_INFO_COUNT;
+ error = task_info(ki->task, TASK_BASIC_INFO, (task_info_t)&ki->tasks_info, &info_count);
+ if (error != KERN_SUCCESS) {
+ ki->invalid_tinfo=1;
+#ifdef DEBUG
+ mach_error("Error calling task_info()", error);
+#endif
+ return(1);
+ }
+ {
+ vm_region_basic_info_data_64_t b_info;
+ vm_address_t address = GLOBAL_SHARED_TEXT_SEGMENT;
+ vm_size_t size;
+ mach_port_t object_name;
+
+ /*
+ * try to determine if this task has the split libraries
+ * mapped in... if so, adjust its virtual size down by
+ * the 2 segments that are used for split libraries
+ */
+ info_count = VM_REGION_BASIC_INFO_COUNT_64;
+ error = vm_region_64(ki->task, &address, &size, VM_REGION_BASIC_INFO,
+ (vm_region_info_t)&b_info, &info_count, &object_name);
+ if (error == KERN_SUCCESS) {
+ if (b_info.reserved && size == (SHARED_TEXT_REGION_SIZE) &&
+ ki->tasks_info.virtual_size > (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE))
+ ki->tasks_info.virtual_size -= (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE);
+ }
+ }
+ info_count = TASK_THREAD_TIMES_INFO_COUNT;
+ error = task_info(ki->task, TASK_THREAD_TIMES_INFO, (task_info_t)&ki->times, &info_count);
+ if (error != KERN_SUCCESS) {
+ ki->invalid_tinfo=1;
+#ifdef DEBUG
+ mach_error("Error calling task_info()", error);
+#endif
+ return(1);
+ }
+ switch(ki->tasks_info.policy) {
+ case POLICY_TIMESHARE :
+ info_count = POLICY_TIMESHARE_INFO_COUNT;
+ error = task_info(ki->task, TASK_SCHED_TIMESHARE_INFO, (task_info_t)&ki->schedinfo.tshare, &info_count);
+ if (error != KERN_SUCCESS) {
+ ki->invalid_tinfo=1;
+#ifdef DEBUG
+ mach_error("Error calling task_info()", error);
+#endif
+ return(1);
+ }
+
+ ki->curpri = ki->schedinfo.tshare.cur_priority;
+ ki->basepri = ki->schedinfo.tshare.base_priority;
+ break;
+ case POLICY_RR :
+ info_count = POLICY_RR_INFO_COUNT;
+ error = task_info(ki->task, TASK_SCHED_RR_INFO, (task_info_t)&ki->schedinfo.rr, &info_count);
+ if (error != KERN_SUCCESS) {
+ ki->invalid_tinfo=1;
+#ifdef DEBUG
+ mach_error("Error calling task_info()", error);
+#endif
+ return(1);
+ }
+
+ ki->curpri = ki->schedinfo.rr.base_priority;
+ ki->basepri = ki->schedinfo.rr.base_priority;
+ break;
+
+ case POLICY_FIFO :
+ info_count = POLICY_FIFO_INFO_COUNT;
+ error = task_info(ki->task, TASK_SCHED_FIFO_INFO, (task_info_t)&ki->schedinfo.fifo, &info_count);
+ if (error != KERN_SUCCESS) {
+ ki->invalid_tinfo=1;
+#ifdef DEBUG
+ mach_error("Error calling task_info()", error);
+#endif
+ return(1);
+ }
+
+ ki->curpri = ki->schedinfo.fifo.base_priority;
+ ki->basepri = ki->schedinfo.fifo.base_priority;
+ break;
+ }
+
+ ki->invalid_tinfo=0;
+
+ ki->cpu_usage=0;
+ error = task_threads(ki->task, &ki->thread_list, &ki->thread_count);
+ if (error != KERN_SUCCESS) {
+ mach_port_deallocate(mach_task_self(),ki->task);
+#ifdef DEBUG
+ mach_error("Call to task_threads() failed", error);
+#endif
+ return(1);
+ }
+ err=0;
+ //ki->curpri = 255;
+ //ki->basepri = 255;
+ ki->swapped = 1;
+ ki->thval = calloc(ki->thread_count, sizeof(struct thread_values));
+ for (j = 0; j < ki->thread_count; j++) {
+ int tstate;
+ thread_info_count = THREAD_BASIC_INFO_COUNT;
+ error = thread_info(ki->thread_list[j], THREAD_BASIC_INFO,
+ (thread_info_t)&ki->thval[j].tb,
+ &thread_info_count);
+ if (error != KERN_SUCCESS) {
+#ifdef DEBUG
+ mach_error("Call to thread_info() failed", error);
+#endif
+ err=1;
+ } else {
+ ki->cpu_usage += ki->thval[j].tb.cpu_usage;
+ }
+ error = thread_schedinfo(ki, ki->thread_list[j],
+ ki->thval[j].tb.policy, &ki->thval[j].schedinfo);
+ if (error != KERN_SUCCESS) {
+#ifdef DEBUG
+ mach_error("Call to thread_schedinfo() failed", error);
+#endif
+ err=1;
+ }
+ tstate = mach_state_order(ki->thval[j].tb.run_state,
+ ki->thval[j].tb.sleep_time);
+ if (tstate < ki->state)
+ ki->state = tstate;
+ if ((ki->thval[j].tb.flags & TH_FLAGS_SWAPPED ) == 0)
+ ki->swapped = 0;
+ mach_port_deallocate(mach_task_self(),
+ ki->thread_list[j]);
+ }
+ ki->invalid_thinfo = err;
+ /* Deallocate the list of threads. */
+ error = vm_deallocate(mach_task_self(),
+ (vm_address_t)(ki->thread_list),
+ sizeof(*ki->thread_list) * ki->thread_count);
+ if (error != KERN_SUCCESS) {
+#ifdef DEBUG
+ mach_error("Trouble freeing thread_list", error);
+#endif
+ }
+
+ mach_port_deallocate(mach_task_self(),ki->task);
+ return(0);
+}
diff --git a/adv_cmds/stty/cchar.c b/adv_cmds/stty/cchar.c
new file mode 100644
index 0000000..da9d523
--- /dev/null
+++ b/adv_cmds/stty/cchar.c
@@ -0,0 +1,153 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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
+#if 0
+static char sccsid[] = "@(#)cchar.c 8.5 (Berkeley) 4/2/94";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/bin/stty/cchar.c,v 1.13 2002/06/30 05:15:04 obrien Exp $");
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "stty.h"
+#include "extern.h"
+
+static int c_cchar(const void *, const void *);
+
+/*
+ * Special control characters.
+ *
+ * Cchars1 are the standard names, cchars2 are the old aliases.
+ * The first are displayed, but both are recognized on the
+ * command line.
+ */
+struct cchar cchars1[] = {
+ { "discard", VDISCARD, CDISCARD },
+ { "dsusp", VDSUSP, CDSUSP },
+ { "eof", VEOF, CEOF },
+ { "eol", VEOL, CEOL },
+ { "eol2", VEOL2, CEOL },
+ { "erase", VERASE, CERASE },
+#ifndef __APPLE__
+ { "erase2", VERASE2, CERASE2 },
+#endif
+ { "intr", VINTR, CINTR },
+ { "kill", VKILL, CKILL },
+ { "lnext", VLNEXT, CLNEXT },
+ { "min", VMIN, CMIN },
+ { "quit", VQUIT, CQUIT },
+ { "reprint", VREPRINT, CREPRINT },
+ { "start", VSTART, CSTART },
+ { "status", VSTATUS, CSTATUS },
+ { "stop", VSTOP, CSTOP },
+ { "susp", VSUSP, CSUSP },
+ { "time", VTIME, CTIME },
+ { "werase", VWERASE, CWERASE },
+ { NULL, 0, 0},
+};
+
+struct cchar cchars2[] = {
+ { "brk", VEOL, CEOL },
+ { "flush", VDISCARD, CDISCARD },
+ { "rprnt", VREPRINT, CREPRINT },
+ { NULL, 0, 0 },
+};
+
+static int
+c_cchar(const void *a, const void *b)
+{
+
+ return (strcmp(((const struct cchar *)a)->name, ((const struct cchar *)b)->name));
+}
+
+int
+csearch(char ***argvp, struct info *ip)
+{
+ struct cchar *cp, tmp;
+ long val;
+ char *arg, *ep, *name;
+
+ name = **argvp;
+
+ tmp.name = name;
+ if (!(cp = (struct cchar *)bsearch(&tmp, cchars1,
+ sizeof(cchars1)/sizeof(struct cchar) - 1, sizeof(struct cchar),
+ c_cchar)) && !(cp = (struct cchar *)bsearch(&tmp, cchars2,
+ sizeof(cchars2)/sizeof(struct cchar) - 1, sizeof(struct cchar),
+ c_cchar)))
+ return (0);
+
+ arg = *++*argvp;
+ if (!arg) {
+ warnx("option requires an argument -- %s", name);
+ usage();
+ }
+
+#define CHK(s) (*arg == s[0] && !strcmp(arg, s))
+ if (CHK("undef") || CHK("<undef>"))
+ ip->t.c_cc[cp->sub] = _POSIX_VDISABLE;
+ else if (cp->sub == VMIN || cp->sub == VTIME) {
+ val = strtol(arg, &ep, 10);
+#ifdef __APPLE__
+ if (val == _POSIX_VDISABLE) {
+ warnx("value of %ld would disable the option -- %s",
+ val, name);
+ usage();
+ }
+#endif
+ if (val > UCHAR_MAX) {
+ warnx("maximum option value is %d -- %s",
+ UCHAR_MAX, name);
+ usage();
+ }
+ if (*ep != '\0') {
+ warnx("option requires a numeric argument -- %s", name);
+ usage();
+ }
+ ip->t.c_cc[cp->sub] = val;
+ } else if (arg[0] == '^')
+ ip->t.c_cc[cp->sub] = (arg[1] == '?') ? 0177 :
+ (arg[1] == '-') ? _POSIX_VDISABLE : arg[1] & 037;
+ else
+ ip->t.c_cc[cp->sub] = arg[0];
+ ip->set = 1;
+ return (1);
+}
diff --git a/adv_cmds/stty/extern.h b/adv_cmds/stty/extern.h
new file mode 100644
index 0000000..193142a
--- /dev/null
+++ b/adv_cmds/stty/extern.h
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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.
+ *
+ * @(#)extern.h 8.1 (Berkeley) 5/31/93
+ * $FreeBSD: src/bin/stty/extern.h,v 1.9 2002/02/02 06:50:56 imp Exp $
+ */
+
+int c_cchars(const void *, const void *);
+int c_modes(const void *, const void *);
+int csearch(char ***, struct info *);
+void checkredirect(void);
+void gprint(struct termios *, struct winsize *, int);
+void gread(struct termios *, char *);
+int ksearch(char ***, struct info *);
+int msearch(char ***, struct info *);
+void optlist(void);
+void print(struct termios *, struct winsize *, int, enum FMT);
+void usage(void);
+
+extern struct cchar cchars1[], cchars2[];
diff --git a/adv_cmds/stty/gfmt.c b/adv_cmds/stty/gfmt.c
new file mode 100644
index 0000000..4e5203f
--- /dev/null
+++ b/adv_cmds/stty/gfmt.c
@@ -0,0 +1,135 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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
+#if 0
+static char sccsid[] = "@(#)gfmt.c 8.6 (Berkeley) 4/2/94";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/bin/stty/gfmt.c,v 1.18 2002/06/30 05:15:04 obrien Exp $");
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "stty.h"
+#include "extern.h"
+
+static void gerr(const char *s);
+
+static void
+gerr(const char *s)
+{
+ if (s)
+ errx(1, "illegal gfmt1 option -- %s", s);
+ else
+ errx(1, "illegal gfmt1 option");
+}
+
+void
+#ifndef __APPLE__
+gprint(struct termios *tp, struct winsize *wp __unused, int ldisc __unused)
+#else
+gprint(struct termios *tp, struct winsize *wp, int ldisc)
+#endif
+{
+ struct cchar *cp;
+
+ (void)printf("gfmt1:cflag=%lx:iflag=%lx:lflag=%lx:oflag=%lx:",
+ (u_long)tp->c_cflag, (u_long)tp->c_iflag, (u_long)tp->c_lflag,
+ (u_long)tp->c_oflag);
+ for (cp = cchars1; cp->name; ++cp)
+ (void)printf("%s=%x:", cp->name, tp->c_cc[cp->sub]);
+ (void)printf("ispeed=%lu:ospeed=%lu\n",
+ (u_long)cfgetispeed(tp), (u_long)cfgetospeed(tp));
+}
+
+void
+gread(struct termios *tp, char *s)
+{
+ struct cchar *cp;
+ char *ep, *p;
+ long tmp;
+
+ if ((s = strchr(s, ':')) == NULL)
+ gerr(NULL);
+ for (++s; s != NULL;) {
+ p = strsep(&s, ":\0");
+ if (!p || !*p)
+ break;
+ if (!(ep = strchr(p, '=')))
+ gerr(p);
+ *ep++ = '\0';
+ (void)sscanf(ep, "%lx", &tmp);
+
+#define CHK(s) (*p == s[0] && !strcmp(p, s))
+ if (CHK("cflag")) {
+ tp->c_cflag = tmp;
+ continue;
+ }
+ if (CHK("iflag")) {
+ tp->c_iflag = tmp;
+ continue;
+ }
+ if (CHK("ispeed")) {
+ (void)sscanf(ep, "%ld", &tmp);
+ tp->c_ispeed = tmp;
+ continue;
+ }
+ if (CHK("lflag")) {
+ tp->c_lflag = tmp;
+ continue;
+ }
+ if (CHK("oflag")) {
+ tp->c_oflag = tmp;
+ continue;
+ }
+ if (CHK("ospeed")) {
+ (void)sscanf(ep, "%ld", &tmp);
+ tp->c_ospeed = tmp;
+ continue;
+ }
+ for (cp = cchars1; cp->name != NULL; ++cp)
+ if (CHK(cp->name)) {
+ if (cp->sub == VMIN || cp->sub == VTIME)
+ (void)sscanf(ep, "%ld", &tmp);
+ tp->c_cc[cp->sub] = tmp;
+ break;
+ }
+ if (cp->name == NULL)
+ gerr(p);
+ }
+}
diff --git a/adv_cmds/stty/key.c b/adv_cmds/stty/key.c
new file mode 100644
index 0000000..b38cab8
--- /dev/null
+++ b/adv_cmds/stty/key.c
@@ -0,0 +1,297 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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
+#if 0
+static char sccsid[] = "@(#)key.c 8.3 (Berkeley) 4/2/94";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/bin/stty/key.c,v 1.17 2002/06/30 05:15:04 obrien Exp $");
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "stty.h"
+#include "extern.h"
+
+__BEGIN_DECLS
+static int c_key(const void *, const void *);
+void f_all(struct info *);
+void f_cbreak(struct info *);
+void f_columns(struct info *);
+void f_dec(struct info *);
+void f_ek(struct info *);
+void f_everything(struct info *);
+void f_extproc(struct info *);
+void f_ispeed(struct info *);
+void f_nl(struct info *);
+void f_ospeed(struct info *);
+void f_raw(struct info *);
+void f_rows(struct info *);
+void f_sane(struct info *);
+void f_size(struct info *);
+void f_speed(struct info *);
+void f_tty(struct info *);
+__END_DECLS
+
+static struct key {
+ const char *name; /* name */
+ void (*f)(struct info *); /* function */
+#define F_NEEDARG 0x01 /* needs an argument */
+#define F_OFFOK 0x02 /* can turn off */
+ int flags;
+} keys[] = {
+ { "all", f_all, 0 },
+ { "cbreak", f_cbreak, F_OFFOK },
+ { "cols", f_columns, F_NEEDARG },
+ { "columns", f_columns, F_NEEDARG },
+ { "cooked", f_sane, 0 },
+ { "dec", f_dec, 0 },
+ { "ek", f_ek, 0 },
+ { "everything", f_everything, 0 },
+ { "extproc", f_extproc, F_OFFOK },
+ { "ispeed", f_ispeed, F_NEEDARG },
+ { "new", f_tty, 0 },
+ { "nl", f_nl, F_OFFOK },
+ { "old", f_tty, 0 },
+ { "ospeed", f_ospeed, F_NEEDARG },
+ { "raw", f_raw, F_OFFOK },
+ { "rows", f_rows, F_NEEDARG },
+ { "sane", f_sane, 0 },
+ { "size", f_size, 0 },
+ { "speed", f_speed, 0 },
+ { "tty", f_tty, 0 },
+};
+
+static int
+c_key(const void *a, const void *b)
+{
+
+ return (strcmp(((const struct key *)a)->name, ((const struct key *)b)->name));
+}
+
+int
+ksearch(char ***argvp, struct info *ip)
+{
+ char *name;
+ struct key *kp, tmp;
+
+ name = **argvp;
+ if (*name == '-') {
+ ip->off = 1;
+ ++name;
+ } else
+ ip->off = 0;
+
+ tmp.name = name;
+ if (!(kp = (struct key *)bsearch(&tmp, keys,
+ sizeof(keys)/sizeof(struct key), sizeof(struct key), c_key)))
+ return (0);
+ if (!(kp->flags & F_OFFOK) && ip->off) {
+ warnx("illegal option -- -%s", name);
+ usage();
+ }
+ if (kp->flags & F_NEEDARG && !(ip->arg = *++*argvp)) {
+ warnx("option requires an argument -- %s", name);
+ usage();
+ }
+ kp->f(ip);
+ return (1);
+}
+
+void
+f_all(struct info *ip)
+{
+ print(&ip->t, &ip->win, ip->ldisc, BSD);
+}
+
+void
+f_cbreak(struct info *ip)
+{
+
+ if (ip->off)
+ f_sane(ip);
+ else {
+ ip->t.c_iflag |= BRKINT|IXON|IMAXBEL;
+ ip->t.c_oflag |= OPOST;
+ ip->t.c_lflag |= ISIG|IEXTEN;
+ ip->t.c_lflag &= ~ICANON;
+ ip->set = 1;
+ }
+}
+
+void
+f_columns(struct info *ip)
+{
+
+ ip->win.ws_col = atoi(ip->arg);
+ ip->wset = 1;
+}
+
+void
+f_dec(struct info *ip)
+{
+
+ ip->t.c_cc[VERASE] = (u_char)0177;
+ ip->t.c_cc[VKILL] = CTRL('u');
+ ip->t.c_cc[VINTR] = CTRL('c');
+ ip->t.c_lflag &= ~ECHOPRT;
+ ip->t.c_lflag |= ECHOE|ECHOKE|ECHOCTL;
+ ip->t.c_iflag &= ~IXANY;
+ ip->set = 1;
+}
+
+void
+f_ek(struct info *ip)
+{
+
+ ip->t.c_cc[VERASE] = CERASE;
+ ip->t.c_cc[VKILL] = CKILL;
+ ip->set = 1;
+}
+
+void
+f_everything(struct info *ip)
+{
+
+ print(&ip->t, &ip->win, ip->ldisc, BSD);
+}
+
+void
+f_extproc(struct info *ip)
+{
+
+ if (ip->off) {
+ int tmp = 0;
+ (void)ioctl(ip->fd, TIOCEXT, &tmp);
+ } else {
+ int tmp = 1;
+ (void)ioctl(ip->fd, TIOCEXT, &tmp);
+ }
+}
+
+void
+f_ispeed(struct info *ip)
+{
+
+ cfsetispeed(&ip->t, (speed_t)atoi(ip->arg));
+ ip->set = 1;
+}
+
+void
+f_nl(struct info *ip)
+{
+
+ if (ip->off) {
+ ip->t.c_iflag |= ICRNL;
+ ip->t.c_oflag |= ONLCR;
+ } else {
+ ip->t.c_iflag &= ~ICRNL;
+ ip->t.c_oflag &= ~ONLCR;
+ }
+ ip->set = 1;
+}
+
+void
+f_ospeed(struct info *ip)
+{
+
+ cfsetospeed(&ip->t, (speed_t)atoi(ip->arg));
+ ip->set = 1;
+}
+
+void
+f_raw(struct info *ip)
+{
+
+ if (ip->off)
+ f_sane(ip);
+ else {
+ cfmakeraw(&ip->t);
+ ip->t.c_cflag &= ~(CSIZE|PARENB);
+ ip->t.c_cflag |= CS8;
+ ip->set = 1;
+ }
+}
+
+void
+f_rows(struct info *ip)
+{
+
+ ip->win.ws_row = atoi(ip->arg);
+ ip->wset = 1;
+}
+
+void
+f_sane(struct info *ip)
+{
+
+ ip->t.c_cflag = TTYDEF_CFLAG | (ip->t.c_cflag & CLOCAL);
+ ip->t.c_iflag = TTYDEF_IFLAG;
+ ip->t.c_iflag |= ICRNL;
+ /* preserve user-preference flags in lflag */
+#define LKEEP (ECHOKE|ECHOE|ECHOK|ECHOPRT|ECHOCTL|ALTWERASE|TOSTOP|NOFLSH)
+ ip->t.c_lflag = TTYDEF_LFLAG | (ip->t.c_lflag & LKEEP);
+ ip->t.c_oflag = TTYDEF_OFLAG;
+ ip->set = 1;
+}
+
+void
+f_size(struct info *ip)
+{
+
+ (void)printf("%d %d\n", ip->win.ws_row, ip->win.ws_col);
+}
+
+void
+f_speed(struct info *ip)
+{
+
+ (void)printf("%lu\n", (u_long)cfgetospeed(&ip->t));
+}
+
+void
+f_tty(struct info *ip)
+{
+ int tmp;
+
+ tmp = TTYDISC;
+ if (ioctl(ip->fd, TIOCSETD, &tmp) < 0)
+ err(1, "TIOCSETD");
+}
diff --git a/adv_cmds/stty/modes.c b/adv_cmds/stty/modes.c
new file mode 100644
index 0000000..0313c87
--- /dev/null
+++ b/adv_cmds/stty/modes.c
@@ -0,0 +1,308 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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
+#if 0
+static char sccsid[] = "@(#)modes.c 8.3 (Berkeley) 4/2/94";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/bin/stty/modes.c,v 1.12 2002/06/30 05:15:04 obrien Exp $");
+
+#include <sys/types.h>
+#include <stddef.h>
+#include <string.h>
+#include "stty.h"
+
+#ifdef __APPLE__
+#include <get_compat.h>
+#else
+#define COMPAT_MODE(a,b) (1)
+#endif /* __APPLE__ */
+
+int msearch(char ***, struct info *);
+
+struct modes {
+ const char *name;
+ long set;
+ long unset;
+};
+
+/*
+ * The code in optlist() depends on minus options following regular
+ * options, i.e. "foo" must immediately precede "-foo".
+ */
+struct modes cmodes[] = {
+ { "cs5", CS5, CSIZE },
+ { "cs6", CS6, CSIZE },
+ { "cs7", CS7, CSIZE },
+ { "cs8", CS8, CSIZE },
+ { "cstopb", CSTOPB, 0 },
+ { "-cstopb", 0, CSTOPB },
+ { "cread", CREAD, 0 },
+ { "-cread", 0, CREAD },
+ { "parenb", PARENB, 0 },
+ { "-parenb", 0, PARENB },
+ { "parodd", PARODD, 0 },
+ { "-parodd", 0, PARODD },
+ { "parity", PARENB | CS7, PARODD | CSIZE },
+ { "-parity", CS8, PARODD | PARENB | CSIZE },
+ { "evenp", PARENB | CS7, PARODD | CSIZE },
+ { "-evenp", CS8, PARODD | PARENB | CSIZE },
+ { "oddp", PARENB | CS7 | PARODD, CSIZE },
+ { "-oddp", CS8, PARODD | PARENB | CSIZE },
+ { "pass8", CS8, PARODD | PARENB | CSIZE },
+ { "-pass8", PARENB | CS7, PARODD | CSIZE },
+ { "hupcl", HUPCL, 0 },
+ { "-hupcl", 0, HUPCL },
+ { "hup", HUPCL, 0 },
+ { "-hup", 0, HUPCL },
+ { "clocal", CLOCAL, 0 },
+ { "-clocal", 0, CLOCAL },
+ { "crtscts", CRTSCTS, 0 },
+ { "-crtscts", 0, CRTSCTS },
+ { "ctsflow", CCTS_OFLOW, 0 },
+ { "-ctsflow", 0, CCTS_OFLOW },
+ { "dsrflow", CDSR_OFLOW, 0 },
+ { "-dsrflow", 0, CDSR_OFLOW },
+ { "dtrflow", CDTR_IFLOW, 0 },
+ { "-dtrflow", 0, CDTR_IFLOW },
+ { "rtsflow", CRTS_IFLOW, 0 },
+ { "-rtsflow", 0, CRTS_IFLOW },
+ { "mdmbuf", MDMBUF, 0 },
+ { "-mdmbuf", 0, MDMBUF },
+ { NULL, 0, 0 },
+};
+
+struct modes imodes[] = {
+ { "ignbrk", IGNBRK, 0 },
+ { "-ignbrk", 0, IGNBRK },
+ { "brkint", BRKINT, 0 },
+ { "-brkint", 0, BRKINT },
+ { "ignpar", IGNPAR, 0 },
+ { "-ignpar", 0, IGNPAR },
+ { "parmrk", PARMRK, 0 },
+ { "-parmrk", 0, PARMRK },
+ { "inpck", INPCK, 0 },
+ { "-inpck", 0, INPCK },
+ { "istrip", ISTRIP, 0 },
+ { "-istrip", 0, ISTRIP },
+ { "inlcr", INLCR, 0 },
+ { "-inlcr", 0, INLCR },
+ { "igncr", IGNCR, 0 },
+ { "-igncr", 0, IGNCR },
+ { "icrnl", ICRNL, 0 },
+ { "-icrnl", 0, ICRNL },
+ { "ixon", IXON, 0 },
+ { "-ixon", 0, IXON },
+ { "flow", IXON, 0 },
+ { "-flow", 0, IXON },
+ { "ixoff", IXOFF, 0 },
+ { "-ixoff", 0, IXOFF },
+ { "tandem", IXOFF, 0 },
+ { "-tandem", 0, IXOFF },
+ { "ixany", IXANY, 0 },
+ { "-ixany", 0, IXANY },
+ { "decctlq", 0, IXANY },
+ { "-decctlq", IXANY, 0 },
+ { "imaxbel", IMAXBEL, 0 },
+ { "-imaxbel", 0, IMAXBEL },
+ { "iutf8", IUTF8, 0 },
+ { "-iutf8", 0, IUTF8 },
+ { NULL, 0, 0 },
+};
+
+struct modes lmodes[] = {
+ { "echo", ECHO, 0 },
+ { "-echo", 0, ECHO },
+ { "echoe", ECHOE, 0 },
+ { "-echoe", 0, ECHOE },
+ { "crterase", ECHOE, 0 },
+ { "-crterase", 0, ECHOE },
+ { "crtbs", ECHOE, 0 }, /* crtbs not supported, close enough */
+ { "-crtbs", 0, ECHOE },
+ { "echok", ECHOK, 0 },
+ { "-echok", 0, ECHOK },
+ { "echoke", ECHOKE, 0 },
+ { "-echoke", 0, ECHOKE },
+ { "crtkill", ECHOKE, 0 },
+ { "-crtkill", 0, ECHOKE },
+ { "altwerase", ALTWERASE, 0 },
+ { "-altwerase", 0, ALTWERASE },
+ { "iexten", IEXTEN, 0 },
+ { "-iexten", 0, IEXTEN },
+ { "echonl", ECHONL, 0 },
+ { "-echonl", 0, ECHONL },
+ { "echoctl", ECHOCTL, 0 },
+ { "-echoctl", 0, ECHOCTL },
+ { "ctlecho", ECHOCTL, 0 },
+ { "-ctlecho", 0, ECHOCTL },
+ { "echoprt", ECHOPRT, 0 },
+ { "-echoprt", 0, ECHOPRT },
+ { "prterase", ECHOPRT, 0 },
+ { "-prterase", 0, ECHOPRT },
+ { "isig", ISIG, 0 },
+ { "-isig", 0, ISIG },
+ { "icanon", ICANON, 0 },
+ { "-icanon", 0, ICANON },
+ { "noflsh", NOFLSH, 0 },
+ { "-noflsh", 0, NOFLSH },
+ { "tostop", TOSTOP, 0 },
+ { "-tostop", 0, TOSTOP },
+ { "flusho", FLUSHO, 0 },
+ { "-flusho", 0, FLUSHO },
+ { "pendin", PENDIN, 0 },
+ { "-pendin", 0, PENDIN },
+ { "crt", ECHOE|ECHOKE|ECHOCTL, ECHOK|ECHOPRT },
+ { "-crt", ECHOK, ECHOE|ECHOKE|ECHOCTL },
+ { "newcrt", ECHOE|ECHOKE|ECHOCTL, ECHOK|ECHOPRT },
+ { "-newcrt", ECHOK, ECHOE|ECHOKE|ECHOCTL },
+ { "nokerninfo", NOKERNINFO, 0 },
+ { "-nokerninfo",0, NOKERNINFO },
+ { "kerninfo", 0, NOKERNINFO },
+ { "-kerninfo", NOKERNINFO, 0 },
+ { NULL, 0, 0 },
+};
+
+struct modes omodes[] = {
+ { "opost", OPOST, 0 },
+ { "-opost", 0, OPOST },
+ { "litout", 0, OPOST },
+ { "-litout", OPOST, 0 },
+ { "onlcr", ONLCR, 0 },
+ { "-onlcr", 0, ONLCR },
+#ifndef __APPLE__
+ { "ocrnl", OCRNL, 0 },
+ { "-ocrnl", 0, OCRNL },
+#endif
+ { "tabs", 0, OXTABS }, /* "preserve" tabs */
+ { "-tabs", OXTABS, 0 },
+ { "oxtabs", OXTABS, 0 },
+ { "-oxtabs", 0, OXTABS },
+#ifndef __APPLE__
+ { "onocr", ONOCR, 0 },
+ { "-onocr", 0, ONOCR },
+ { "onlret", ONLRET, 0 },
+ { "-onlret", 0, ONLRET },
+#endif
+ { NULL, 0, 0 },
+};
+
+struct modes umodes[] = { /* For Unix conformance only */
+ { "ocrnl", OCRNL, 0 },
+ { "-ocrnl", 0, OCRNL },
+ { "onocr", ONOCR, 0 },
+ { "-onocr", 0, ONOCR },
+ { "onlret", ONLRET, 0 },
+ { "-onlret", 0, ONLRET },
+
+ { "ofill", OFILL, 0 },
+ { "-ofill", 0, OFILL },
+
+ { "ofdel", OFDEL, 0 },
+ { "-ofdel", 0, OFDEL },
+
+ { "bs0", BS0, 0 },
+ { "bs1", BS1, 0 },
+
+ { "cr0", CR0, 0 },
+ { "cr1", CR1, 0 },
+ { "cr2", CR2, 0 },
+ { "cr3", CR3, 0 },
+
+ { "ff0", FF0, 0 },
+ { "ff1", FF1, 0 },
+
+ { "nl0", NL0, 0 },
+ { "nl1", NL1, 0 },
+
+ { "tab0", TAB0, 0 },
+ { "tab1", TAB1, 0 },
+ { "tab2", TAB2, 0 },
+ { "tab3", TAB3, 0 },
+
+ { "vt0", VT0, 0 },
+ { "vt1", VT1, 0 },
+
+ { NULL, 0, 0 },
+};
+
+#define CHK(s) (*name == s[0] && !strcmp(name, s))
+
+int
+msearch(char ***argvp, struct info *ip)
+{
+ struct modes *mp;
+ char *name;
+
+ name = **argvp;
+
+ for (mp = cmodes; mp->name; ++mp)
+ if (CHK(mp->name)) {
+ ip->t.c_cflag &= ~mp->unset;
+ ip->t.c_cflag |= mp->set;
+ ip->set = 1;
+ return (1);
+ }
+ for (mp = imodes; mp->name; ++mp)
+ if (CHK(mp->name)) {
+ ip->t.c_iflag &= ~mp->unset;
+ ip->t.c_iflag |= mp->set;
+ ip->set = 1;
+ return (1);
+ }
+ for (mp = lmodes; mp->name; ++mp)
+ if (CHK(mp->name)) {
+ ip->t.c_lflag &= ~mp->unset;
+ ip->t.c_lflag |= mp->set;
+ ip->set = 1;
+ return (1);
+ }
+ for (mp = omodes; mp->name; ++mp)
+ if (CHK(mp->name)) {
+ ip->t.c_oflag &= ~mp->unset;
+ ip->t.c_oflag |= mp->set;
+ ip->set = 1;
+ return (1);
+ }
+ if (COMPAT_MODE("bin/stty", "Unix2003")) {
+ for (mp = umodes; mp->name; ++mp)
+ if (CHK(mp->name)) {
+ ip->t.c_oflag &= ~mp->unset;
+ ip->t.c_oflag |= mp->set;
+ ip->set = 1;
+ return (1);
+ }
+ }
+ return (0);
+}
diff --git a/adv_cmds/stty/print.c b/adv_cmds/stty/print.c
new file mode 100644
index 0000000..ef59bf1
--- /dev/null
+++ b/adv_cmds/stty/print.c
@@ -0,0 +1,291 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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
+#if 0
+static char sccsid[] = "@(#)print.c 8.6 (Berkeley) 4/16/94";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/bin/stty/print.c,v 1.18 2002/06/30 05:15:04 obrien Exp $");
+
+#include <sys/types.h>
+
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "stty.h"
+#include "extern.h"
+
+#include <sys/ioctl_compat.h> /* XXX NTTYDISC is too well hidden */
+
+static void binit(const char *);
+static void bput(const char *);
+static const char *ccval(struct cchar *, int);
+
+void
+print(struct termios *tp, struct winsize *wp, int ldisc, enum FMT fmt)
+{
+ struct cchar *p;
+ long tmp;
+ u_char *cc;
+ int cnt, ispeed, ospeed;
+ char buf1[100], buf2[100];
+
+ cnt = 0;
+
+ /* Line discipline. */
+ if (ldisc != TTYDISC) {
+ switch(ldisc) {
+ case NTTYDISC:
+ cnt += printf("new tty disc; ");
+ break;
+#ifdef __APPLE__
+ case TABLDISC:
+ cnt += printf("tablet disc; ");
+ break;
+#endif
+ case SLIPDISC:
+ cnt += printf("slip disc; ");
+ break;
+ case PPPDISC:
+ cnt += printf("ppp disc; ");
+ break;
+ default:
+ cnt += printf("#%d disc; ", ldisc);
+ break;
+ }
+ }
+
+ /* Line speed. */
+ ispeed = cfgetispeed(tp);
+ ospeed = cfgetospeed(tp);
+ if (ispeed != ospeed)
+ cnt +=
+ printf("ispeed %d baud; ospeed %d baud;", ispeed, ospeed);
+ else
+ cnt += printf("speed %d baud;", ispeed);
+ if (fmt >= BSD)
+ cnt += printf(" %d rows; %d columns;", wp->ws_row, wp->ws_col);
+ if (cnt)
+ (void)printf("\n");
+
+#define on(f) ((tmp & (f)) != 0)
+#define put(n, f, d) \
+ if (fmt >= BSD || on(f) != (d)) \
+ bput((n) + on(f));
+
+ /* "local" flags */
+ tmp = tp->c_lflag;
+ binit("lflags");
+ put("-icanon", ICANON, 1);
+ put("-isig", ISIG, 1);
+ put("-iexten", IEXTEN, 1);
+ put("-echo", ECHO, 1);
+ put("-echoe", ECHOE, 0);
+ put("-echok", ECHOK, 0);
+ put("-echoke", ECHOKE, 0);
+ put("-echonl", ECHONL, 0);
+ put("-echoctl", ECHOCTL, 0);
+ put("-echoprt", ECHOPRT, 0);
+ put("-altwerase", ALTWERASE, 0);
+ put("-noflsh", NOFLSH, 0);
+ put("-tostop", TOSTOP, 0);
+ put("-flusho", FLUSHO, 0);
+ put("-pendin", PENDIN, 0);
+ put("-nokerninfo", NOKERNINFO, 0);
+ put("-extproc", EXTPROC, 0);
+
+ /* input flags */
+ tmp = tp->c_iflag;
+ binit("iflags");
+ put("-istrip", ISTRIP, 0);
+ put("-icrnl", ICRNL, 1);
+ put("-inlcr", INLCR, 0);
+ put("-igncr", IGNCR, 0);
+ put("-ixon", IXON, 1);
+ put("-ixoff", IXOFF, 0);
+ put("-ixany", IXANY, 1);
+ put("-imaxbel", IMAXBEL, 1);
+ put("-iutf8", IUTF8, 0);
+ put("-ignbrk", IGNBRK, 0);
+ put("-brkint", BRKINT, 1);
+ put("-inpck", INPCK, 0);
+ put("-ignpar", IGNPAR, 0);
+ put("-parmrk", PARMRK, 0);
+
+ /* output flags */
+ tmp = tp->c_oflag;
+ binit("oflags");
+ put("-opost", OPOST, 1);
+ put("-onlcr", ONLCR, 1);
+#ifndef __APPLE__
+ put("-ocrnl", OCRNL, 0);
+#endif
+ put("-oxtabs", OXTABS, 1);
+ put("-onocr", OXTABS, 0);
+ put("-onlret", OXTABS, 0);
+
+ /* control flags (hardware state) */
+ tmp = tp->c_cflag;
+ binit("cflags");
+ put("-cread", CREAD, 1);
+ switch(tmp&CSIZE) {
+ case CS5:
+ bput("cs5");
+ break;
+ case CS6:
+ bput("cs6");
+ break;
+ case CS7:
+ bput("cs7");
+ break;
+ case CS8:
+ bput("cs8");
+ break;
+ }
+ bput("-parenb" + on(PARENB));
+ put("-parodd", PARODD, 0);
+ put("-hupcl", HUPCL, 1);
+ put("-clocal", CLOCAL, 0);
+ put("-cstopb", CSTOPB, 0);
+ switch(tmp & (CCTS_OFLOW | CRTS_IFLOW)) {
+ case CCTS_OFLOW:
+ bput("ctsflow");
+ break;
+ case CRTS_IFLOW:
+ bput("rtsflow");
+ break;
+ default:
+ put("-crtscts", CCTS_OFLOW | CRTS_IFLOW, 0);
+ break;
+ }
+ put("-dsrflow", CDSR_OFLOW, 0);
+ put("-dtrflow", CDTR_IFLOW, 0);
+ put("-mdmbuf", MDMBUF, 0); /* XXX mdmbuf == dtrflow */
+
+ /* special control characters */
+ cc = tp->c_cc;
+ if (fmt == POSIX) {
+ binit("cchars");
+ for (p = cchars1; p->name; ++p) {
+ (void)snprintf(buf1, sizeof(buf1), "%s = %s;",
+ p->name, ccval(p, cc[p->sub]));
+ bput(buf1);
+ }
+ binit(NULL);
+ } else {
+ binit(NULL);
+ for (p = cchars1, cnt = 0; p->name; ++p) {
+ if (fmt != BSD && cc[p->sub] == p->def)
+ continue;
+#define WD "%-8s"
+ (void)snprintf(buf1 + cnt * 8, sizeof(buf1) - cnt * 8,
+ WD, p->name);
+ (void)snprintf(buf2 + cnt * 8, sizeof(buf2) - cnt * 8,
+ WD, ccval(p, cc[p->sub]));
+ if (++cnt == LINELENGTH / 8) {
+ cnt = 0;
+ (void)printf("%s\n", buf1);
+ (void)printf("%s\n", buf2);
+ }
+ }
+ if (cnt) {
+ (void)printf("%s\n", buf1);
+ (void)printf("%s\n", buf2);
+ }
+ }
+}
+
+static int col;
+static const char *label;
+
+static void
+binit(const char *lb)
+{
+
+ if (col) {
+ (void)printf("\n");
+ col = 0;
+ }
+ label = lb;
+}
+
+static void
+bput(const char *s)
+{
+
+ if (col == 0) {
+ col = printf("%s: %s", label, s);
+ return;
+ }
+ if ((col + strlen(s)) > LINELENGTH) {
+ (void)printf("\n\t");
+ col = printf("%s", s) + 8;
+ return;
+ }
+ col += printf(" %s", s);
+}
+
+static const char *
+ccval(struct cchar *p, int c)
+{
+ static char buf[5];
+ char *bp;
+
+ if (p->sub == VMIN || p->sub == VTIME) {
+ (void)snprintf(buf, sizeof(buf), "%d", c);
+ return (buf);
+ }
+ if (c == _POSIX_VDISABLE)
+ return ("<undef>");
+ bp = buf;
+ if (c & 0200) {
+ *bp++ = 'M';
+ *bp++ = '-';
+ c &= 0177;
+ }
+ if (c == 0177) {
+ *bp++ = '^';
+ *bp++ = '?';
+ }
+ else if (c < 040) {
+ *bp++ = '^';
+ *bp++ = c + '@';
+ }
+ else
+ *bp++ = c;
+ *bp = '\0';
+ return (buf);
+}
diff --git a/adv_cmds/stty/stty.1 b/adv_cmds/stty/stty.1
new file mode 100644
index 0000000..9a864b4
--- /dev/null
+++ b/adv_cmds/stty/stty.1
@@ -0,0 +1,633 @@
+.\" Copyright (c) 1990, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" 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.
+.\"
+.\" @(#)stty.1 8.4 (Berkeley) 4/18/94
+.\" $FreeBSD: src/bin/stty/stty.1,v 1.27 2001/11/29 15:46:54 green Exp $
+.\"
+.Dd April 18, 1994
+.Dt STTY 1
+.Os
+.Sh NAME
+.Nm stty
+.Nd set the options for a terminal device interface
+.Sh SYNOPSIS
+.Nm
+.Op Fl a | Fl e | Fl g
+.Op Fl f Ar file
+.Op operands
+.Sh DESCRIPTION
+The
+.Nm
+utility sets or reports on terminal
+characteristics for the device that is its standard input.
+If no options or operands are specified, it reports the settings of a subset
+of characteristics as well as additional ones if they differ from their
+default values.
+Otherwise it modifies
+the terminal state according to the specified arguments.
+Some combinations of arguments are mutually
+exclusive on some terminal types.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl a
+Display all the current settings for the terminal to standard output
+as per
+.St -p1003.2 .
+.It Fl e
+Display all the current settings for the terminal to standard output
+in the traditional
+.Bx
+``all'' and ``everything'' formats.
+.It Fl f
+Open and use the terminal named by
+.Ar file
+rather than using standard input. The file is opened
+using the
+.Dv O_NONBLOCK
+flag of
+.Fn open ,
+making it possible to
+set or display settings on a terminal that might otherwise
+block on the open.
+.It Fl g
+Display all the current settings for the terminal to standard output
+in a form that may be used as an argument to a subsequent invocation of
+.Nm
+to restore the current terminal state as per
+.St -p1003.2 .
+.El
+.Pp
+The following arguments are available to set the terminal
+characteristics:
+.Ss Control Modes:
+.Pp
+Control mode flags affect hardware characteristics associated with the
+terminal. This corresponds to the c_cflag in the termios structure.
+.Bl -tag -width Fl
+.It Ar number
+Set terminal baud rate to the number given, if possible.
+If the baud rate is set to zero,
+modem control is no longer asserted.
+.It Cm clocal Pq Fl clocal
+Assume a line without (with) modem control.
+.It Cm cread Pq Fl cread
+Enable (disable) the receiver.
+.It Cm crtscts Pq Fl crtscts
+Enable (disable) RTS/CTS flow control.
+.It Cm cs5 cs6 cs7 cs8
+Select character size, if possible.
+.It Cm cstopb Pq Fl cstopb
+Use two (one) stop bits per character.
+.It Cm hup Pq Fl hup
+Same as
+.Cm hupcl
+.Pq Fl hupcl .
+.It Cm hupcl Pq Fl hupcl
+Stop asserting modem control
+(do not stop asserting modem control) on last close.
+.It Cm ispeed Ar number
+Set terminal input baud rate to the number given, if possible.
+If the input baud rate is set to zero,
+the input baud rate is set to the value of the output baud rate.
+.It Cm ospeed Ar number
+Set terminal output baud rate to the number given, if possible.
+If the output baud rate is set to zero,
+modem control is no longer asserted.
+.It Cm parenb Pq Fl parenb
+Enable (disable) parity generation and detection.
+.It Cm parodd Pq Fl parodd
+Select odd (even) parity.
+.It Cm speed Ar number
+This sets both
+.Cm ispeed
+and
+.Cm ospeed
+to
+.Ar number .
+.El
+.Ss Input Modes:
+This corresponds to the c_iflag in the termios structure.
+.Bl -tag -width Fl
+.It Cm brkint Pq Fl brkint
+Signal (do not signal)
+.Dv INTR
+on
+break.
+.It Cm icrnl Pq Fl icrnl
+Map (do not map)
+.Dv CR
+to
+.Dv NL
+on input.
+.It Cm ignbrk Pq Fl ignbrk
+Ignore (do not ignore) break on input.
+.It Cm igncr Pq Fl igncr
+Ignore (do not ignore)
+.Dv CR
+on input.
+.It Cm ignpar Pq Fl ignpar
+Ignore (do not ignore) characters with parity errors.
+.It Cm imaxbel Pq Fl imaxbel
+The system imposes a limit of
+.Dv MAX_INPUT
+(currently 255) characters in the input queue. If
+.Cm imaxbel
+is set and the input queue limit has been reached,
+subsequent input causes the system to send an ASCII BEL
+character to the output queue (the terminal beeps at you). Otherwise,
+if
+.Cm imaxbel
+is unset and the input queue is full, the next input character causes
+the entire input and output queues to be discarded.
+.It Cm inlcr Pq Fl inlcr
+Map (do not map)
+.Dv NL
+to
+.Dv CR
+on input.
+.It Cm inpck Pq Fl inpck
+Enable (disable) input parity checking.
+.It Cm istrip Pq Fl istrip
+Strip (do not strip) input characters to seven bits.
+.It Cm iutf8 Pq Fl iutf8
+Assume input characters are UTF-8 encoded.
+.It Cm ixany Pq Fl ixany
+Allow any character (allow only
+.Dv START )
+to restart output.
+.It Cm ixoff Pq Fl ixoff
+Request that the system send (not send)
+.Dv START/STOP
+characters when the input queue is nearly empty/full.
+.It Cm ixon Pq Fl ixon
+Enable (disable)
+.Dv START/STOP
+output control.
+Output from the system is stopped when the system receives
+.Dv STOP
+and started when the system receives
+.Dv START ,
+or if
+.Cm ixany
+is set, any character restarts output.
+.It Cm parmrk Pq Fl parmrk
+Mark (do not mark) characters with parity errors.
+.El
+.Ss Output Modes:
+This corresponds to the c_oflag of the termios structure.
+.Bl -tag -width Fl
+.It Cm bs0 bs1
+Select the style of delay for backspaces (e.g., set BSDLY to BS0).
+.It Cm cr0 cr1 cr2 cr3
+Select the style of delay for carriage returns (e.g., set CRDLY to CR0).
+.It Cm ff0 ff1
+Select the style of delay for form feeds (e.g., set FFDLY to FF0).
+.It Cm nl0 nl1
+Select the style of delay for newlines (e.g., set NLDLY to NL0).
+.It Cm ocrnl Pq Fl ocrnl
+Map (do not map) carriage return to newline on output.
+.It Cm ofdel Pq Fl odell
+Use DELs (NULs) as fill characters.
+.It Cm ofill Pq Fl ofill
+Use fill characters (use timing) for delays.
+.It Cm onlcr Pq Fl onlcr
+Map (do not map)
+.Dv NL
+to
+.Dv CR-NL
+on output.
+.It Cm onlret Pq Fl onlret
+On the terminal, NL performs (does not perform) the CR function.
+.It Cm onocr Pq Fl onocr
+Do not (do) output CRs at column zero.
+.It Cm opost Pq Fl opost
+Post-process output (do not post-process output;
+ignore all other output modes).
+.It Cm oxtabs Pq Fl oxtabs
+Expand (do not expand) tabs to spaces on output.
+.It Cm tab0 tab1 tab2 tab3
+Select the style of delay for horizontal tabs (e.g., set TABDLY to TAB0).
+.It Cm tabs Pq Fl tabs
+Same as
+.Cm tab0
+.Cm ( tab3 ) .
+.It Cm vt0 vt1
+Select the style of delay for vertical tabs (e.g., set VTDLY to VT0).
+.El
+.Ss Local Modes:
+.Pp
+Local mode flags (lflags) affect various and sundry characteristics
+of terminal processing.
+Historically the term "local" pertained to new job control features
+implemented by Jim Kulp on a
+.Tn Pdp 11/70
+at
+.Tn IIASA .
+Later, the driver ran on the first
+.Tn VAX
+at Evans Hall, UC Berkeley, where the job control details
+were greatly modified,
+but the structure definitions and names remained essentially unchanged.
+The second interpretation of the 'l' in lflag
+is ``line discipline flag'', which corresponds to the
+.Ar c_lflag
+of the
+.Ar termios
+structure.
+.Bl -tag -width Fl
+.It Cm altwerase Pq Fl altwerase
+Use (do not use) an alternate word erase algorithm when processing
+.Dv WERASE
+characters.
+This alternate algorithm considers sequences of
+alphanumeric/underscores as words.
+It also skips the first preceding character in its classification
+(as a convenience, since the one preceding character could have been
+erased with simply an
+.Dv ERASE
+character.)
+.It Cm echo Pq Fl echo
+Echo back (do not echo back) every character typed.
+.It Cm echoctl Pq Fl echoctl
+If
+.Cm echoctl
+is set, echo control characters as ^X.
+Otherwise, control characters echo as themselves.
+.It Cm echoe Pq Fl echoe
+The
+.Dv ERASE
+character shall (shall not) visually erase the last character
+in the current line from the display, if possible.
+.It Cm echok Pq Fl echok
+Echo (do not echo)
+.Dv NL
+after
+.Dv KILL
+character.
+.It Cm echoke Pq Fl echoke
+The
+.Dv KILL
+character shall (shall
+not) visually erase the
+current line from the
+display, if possible.
+.It Cm echonl Pq Fl echonl
+Echo (do not echo)
+.Dv NL ,
+even if echo is disabled.
+.It Cm echoprt Pq Fl echoprt
+For printing terminals.
+If set, echo erased characters backwards within ``\\'' and ``/''.
+Otherwise, disable this feature.
+.It Cm flusho Pq Fl flusho
+Indicates output is (is not) being discarded.
+.It Cm icanon Pq Fl icanon
+Enable (disable) canonical input
+.Pf ( Dv ERASE
+and
+.Dv KILL
+processing).
+.It Cm iexten Pq Fl iexten
+Enable (disable) any implementation-defined special control characters
+that are not currently controlled by
+.Cm icanon ,
+.Cm isig ,
+.Cm ixoff ,
+or
+.Cm ixon .
+.It Cm isig Pq Fl isig
+Enable (disable) the checking of characters
+against the special control characters
+.Dv INTR , QUIT ,
+and
+.Dv SUSP .
+.It Cm mdmbuf Pq Fl mdmbuf
+If set, flow control output based on condition of Carrier Detect.
+Otherwise, writes return an error if Carrier Detect is low
+(and Carrier is not being ignored with the
+.Dv CLOCAL
+flag.)
+.It Cm noflsh Pq Fl noflsh
+Disable (enable) flush after
+.Dv INTR , QUIT ,
+or
+.Dv SUSP .
+.It Cm pendin Pq Fl pendin
+Indicates input is (is not) pending
+after a switch from non-canonical to canonical mode
+and will be re-input when a read becomes pending or more input arrives.
+.It Cm tostop Pq Fl tostop
+Send (do not send)
+.Dv SIGTTOU
+for background output.
+This causes background jobs to stop if they attempt terminal output.
+.El
+.Ss Control Characters:
+.Bl -tag -width Fl
+.It Ar control-character Ar string
+Set
+.Ar control-character
+to
+.Ar string .
+If string is a single character,
+the control character is set to
+that character.
+If string is the
+two character sequence "^-" or the
+string "undef" the control character
+is disabled (i.e. set to
+.Pf { Dv _POSIX_VDISABLE Ns } . )
+.Pp
+Recognized control-characters:
+.Bd -ragged -offset indent
+.Bl -column character Subscript
+.It control-
+.It character Ta Subscript Ta Description
+.It _________ Ta _________ Ta _______________
+.It eof Ta Tn VEOF Ta EOF No character
+.It eol Ta Tn VEOL Ta EOL No character
+.It eol2 Ta Tn VEOL2 Ta EOL2 No character
+.It erase Ta Tn VERASE Ta ERASE No character
+.It erase2 Ta Tn VERASE2 Ta ERASE2 No character
+.It werase Ta Tn VWERASE Ta WERASE No character
+.It intr Ta Tn VINTR Ta INTR No character
+.It kill Ta Tn VKILL Ta KILL No character
+.It quit Ta Tn VQUIT Ta QUIT No character
+.It susp Ta Tn VSUSP Ta SUSP No character
+.It start Ta Tn VSTART Ta START No character
+.It stop Ta Tn VSTOP Ta STOP No character
+.It dsusp Ta Tn VDSUSP Ta DSUSP No character
+.It lnext Ta Tn VLNEXT Ta LNEXT No character
+.It reprint Ta Tn VREPRINT Ta REPRINT No character
+.It status Ta Tn VSTATUS Ta STATUS No character
+.El
+.Ed
+.It Cm min Ar number
+.It Cm time Ar number
+Set the value of min or time to number.
+.Dv MIN
+and
+.Dv TIME
+are used in Non-Canonical mode input processing (-icanon).
+.El
+.Ss Combination Modes:
+.Pp
+.Bl -tag -width Fl
+.It Ar saved settings
+Set the current terminal characteristics
+to the saved settings produced by the
+.Fl g
+option.
+.It Cm cols Ar number
+Same as
+.Cm columns .
+.It Cm columns Ar number
+The terminal size is recorded as having
+.Ar number
+columns.
+.It Cm crt Pq Fl crt
+Set (disable) all modes suitable for a CRT display device.
+.It Cm dec
+Set modes suitable for users of Digital Equipment Corporation systems
+.Dv ( ERASE ,
+.Dv KILL ,
+and
+.Dv INTR
+characters are set to ^?, ^U, and ^C;
+.Dv ixany
+is disabled, and
+.Dv crt
+is enabled.)
+.It Cm ek
+Reset
+.Dv ERASE ,
+.Dv ERASE2 ,
+and
+.Dv KILL
+characters
+back to system defaults.
+.It Fl evenp
+Same as
+.Fl oddp
+and
+.Fl parity .
+.It Cm evenp
+Enable
+.Cm parenb
+and
+.Cm cs7 ;
+disable
+.Cm parodd .
+.It Cm extproc Pq Fl extproc
+If set, this flag indicates that some amount of terminal processing
+is being performed by either the terminal hardware
+or by the remote side connected to a pty.
+.It Cm kerninfo Pq Fl kerninfo
+Enable (disable) the system generated status line associated with
+processing a
+.Dv STATUS
+character (usually set to ^T). The status line consists of the
+system load average, the current command name, its process ID, the
+event the process is waiting on (or the status of the process), the user
+and system times, percent cpu, and current memory usage.
+.It Cm \&nl Pq Fl \&nl
+Enable (disable)
+.Cm icrnl .
+In addition,
+.Fl nl
+unsets
+.Cm inlcr
+and
+.Cm igncr .
+.It Fl oddp
+Same as
+.Fl evenp
+and
+.Fl parity .
+.It Cm oddp
+Enable
+.Cm parenb ,
+.Cm cs7 ,
+and
+.Cm parodd .
+.It Fl parity
+Disable
+.Cm parenb ;
+set
+.Cm cs8 .
+.It Cm parity
+Same as
+.Cm evenp .
+.It Cm raw Pq Fl raw
+If set, change the modes of the terminal
+so that no input or output processing is performed.
+If unset, change the modes of the terminal to some reasonable state
+that performs input and output processing.
+Note that since the terminal driver no longer has a single
+.Dv RAW
+bit, it is not possible to intuit what flags were set prior to setting
+.Cm raw .
+This means that unsetting
+.Cm raw
+may not put back all the setting that were previously in effect.
+To set the terminal into a raw state and then accurately restore it,
+the following shell code is recommended:
+.Bd -literal
+save_state=$(stty -g)
+stty raw
+\&...
+stty "$save_state"
+.Ed
+.It Cm rows Ar number
+The terminal size is recorded as having
+.Ar number
+rows.
+.It Cm sane
+Resets all modes to reasonable values for interactive terminal use.
+.It Cm size
+The size of the terminal is printed as two numbers on a single line,
+first rows, then columns.
+.It Cm tty
+Set the line discipline to the standard terminal line discipline
+.Dv TTYDISC .
+.El
+.Ss Compatibility Modes:
+.Pp
+These modes remain for compatibility with the previous version of
+the
+.Nm
+command.
+.Bl -tag -width Fl
+.It Cm all
+Reports all the terminal modes as with
+.Cm stty Fl a ,
+except that the control characters are printed in a columnar format.
+.It Cm brk Ar value
+Same as the control character
+.Cm eol .
+.It Cm cbreak
+If set, enables
+.Cm brkint , ixon , imaxbel , opost , isig , iexten ,
+and
+.Fl icanon .
+If unset, same as
+.Cm sane .
+.It Cm cooked
+Same as
+.Cm sane .
+.It Cm crtbs Pq Fl crtbs
+Same as
+.Cm echoe .
+.It Cm crterase Pq Fl crterase
+Same as
+.Cm echoe .
+.It Cm crtkill Pq Fl crtkill
+Same as
+.Cm echoke .
+.It Cm ctlecho Pq Fl ctlecho
+Same as
+.Cm echoctl .
+.It Cm decctlq Pq Fl decctlq
+The converse of
+.Cm ixany .
+.It Cm everything
+Same as
+.Cm all .
+.It Cm flush Ar value
+Same as the control character
+.Cm discard .
+.It Cm litout Pq Fl litout
+The converse of
+.Cm opost .
+.It Cm new
+Same as
+.Cm tty .
+.It Cm newcrt Pq Fl newcrt
+Same as
+.Cm crt .
+.It Cm old
+Same as
+.Cm tty .
+.It Cm pass8
+The converse of
+.Cm parity .
+.It Cm prterase Pq Fl prterase
+Same as
+.Cm echoprt .
+.It Cm rprnt Ar value
+Same as the control character
+.Cm reprint .
+.It Cm tabs Pq Fl tabs
+The converse of
+.Cm oxtabs .
+.It Cm tandem Pq Fl tandem
+Same as
+.Cm ixoff .
+.El
+.Sh DIAGNOSTICS
+.Ex -std
+.Sh LEGACY DESCRIPTION
+In legacy operation, the
+.Cm bs[01] ,
+.Cm cr[0-3] ,
+.Cm ff[01] ,
+.Cm nl[01] ,
+.Cm tab[0-3] ,
+and
+.Cm vt[01]
+control modes are not accepted, nor are
+.Cm ocrnl Pq Fl ocrnl ,
+.Cm ofdel Pq Fl ofdel ,
+.Cm ofill Pq Fl ofill ,
+.Cm onlret Pq Fl onlret ,
+and
+.Cm onocr Pq Fl onocr .
+.Pp
+For more information about legacy mode, see
+.Xr compat 5 .
+.Sh SEE ALSO
+.Xr termios 4 ,
+.Xr compat 5
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be
+.St -p1003.2
+compatible. The flags
+.Fl e
+and
+.Fl f
+are
+extensions to the standard.
diff --git a/adv_cmds/stty/stty.c b/adv_cmds/stty/stty.c
new file mode 100644
index 0000000..a7feaf0
--- /dev/null
+++ b/adv_cmds/stty/stty.c
@@ -0,0 +1,164 @@
+/*-
+ * Copyright (c) 1989, 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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 const copyright[] =
+"@(#) Copyright (c) 1989, 1991, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)stty.c 8.3 (Berkeley) 4/2/94";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/bin/stty/stty.c,v 1.20 2002/06/30 05:15:04 obrien Exp $");
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "stty.h"
+#include "extern.h"
+
+int
+main(int argc, char *argv[])
+{
+ struct info i;
+ enum FMT fmt;
+ int ch;
+
+ fmt = NOTSET;
+ i.fd = STDIN_FILENO;
+
+ opterr = 0;
+ while (optind < argc &&
+ strspn(argv[optind], "-aefg") == strlen(argv[optind]) &&
+ (ch = getopt(argc, argv, "aef:g")) != -1)
+ switch(ch) {
+ case 'a': /* undocumented: POSIX compatibility */
+ fmt = POSIX;
+ break;
+ case 'e':
+ fmt = BSD;
+ break;
+ case 'f':
+ if ((i.fd = open(optarg, O_RDONLY | O_NONBLOCK)) < 0)
+ err(1, "%s", optarg);
+ break;
+ case 'g':
+ fmt = GFLAG;
+ break;
+ case '?':
+ default:
+ goto args;
+ }
+
+args: argc -= optind;
+ argv += optind;
+
+ if (tcgetattr(i.fd, &i.t) < 0)
+ errx(1, "stdin isn't a terminal");
+ if (ioctl(i.fd, TIOCGETD, &i.ldisc) < 0)
+ err(1, "TIOCGETD");
+ if (ioctl(i.fd, TIOCGWINSZ, &i.win) < 0)
+ warn("TIOCGWINSZ");
+
+ checkredirect(); /* conversion aid */
+
+ switch(fmt) {
+ case NOTSET:
+ if (*argv)
+ break;
+ /* FALLTHROUGH */
+ case BSD:
+ case POSIX:
+ print(&i.t, &i.win, i.ldisc, fmt);
+ break;
+ case GFLAG:
+ gprint(&i.t, &i.win, i.ldisc);
+ break;
+ }
+
+ for (i.set = i.wset = 0; *argv; ++argv) {
+ if (ksearch(&argv, &i))
+ continue;
+
+ if (csearch(&argv, &i))
+ continue;
+
+ if (msearch(&argv, &i))
+ continue;
+
+ if (isdigit(**argv)) {
+ speed_t speed;
+
+ speed = atoi(*argv);
+ cfsetospeed(&i.t, speed);
+ cfsetispeed(&i.t, speed);
+ i.set = 1;
+ continue;
+ }
+
+ if (!strncmp(*argv, "gfmt1", sizeof("gfmt1") - 1)) {
+ gread(&i.t, *argv + sizeof("gfmt1") - 1);
+ i.set = 1;
+ continue;
+ }
+
+ warnx("illegal option -- %s", *argv);
+ usage();
+ }
+
+ if (i.set && tcsetattr(i.fd, 0, &i.t) < 0)
+ err(1, "tcsetattr");
+ if (i.wset && ioctl(i.fd, TIOCSWINSZ, &i.win) < 0)
+ warn("TIOCSWINSZ");
+ exit(0);
+}
+
+void
+usage(void)
+{
+
+ (void)fprintf(stderr, "usage: stty [-a|-e|-g] [-f file] [options]\n");
+ exit (1);
+}
diff --git a/adv_cmds/stty/stty.h b/adv_cmds/stty/stty.h
new file mode 100644
index 0000000..91c710f
--- /dev/null
+++ b/adv_cmds/stty/stty.h
@@ -0,0 +1,59 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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.
+ *
+ * @(#)stty.h 8.1 (Berkeley) 5/31/93
+ * $FreeBSD: src/bin/stty/stty.h,v 1.8 2001/05/18 11:04:19 kris Exp $
+ */
+
+#include <sys/ioctl.h>
+#include <termios.h>
+
+struct info {
+ int fd; /* file descriptor */
+ int ldisc; /* line discipline */
+ int off; /* turn off */
+ int set; /* need set */
+ int wset; /* need window set */
+ const char *arg; /* argument */
+ struct termios t; /* terminal info */
+ struct winsize win; /* window info */
+};
+
+struct cchar {
+ const char *name;
+ int sub;
+ u_char def;
+};
+
+enum FMT { NOTSET, GFLAG, BSD, POSIX };
+
+#define LINELENGTH 72
diff --git a/adv_cmds/stty/util.c b/adv_cmds/stty/util.c
new file mode 100644
index 0000000..9695365
--- /dev/null
+++ b/adv_cmds/stty/util.c
@@ -0,0 +1,68 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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
+#if 0
+static char sccsid[] = "@(#)util.c 8.3 (Berkeley) 4/2/94";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/bin/stty/util.c,v 1.10 2002/06/30 05:15:04 obrien Exp $");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "stty.h"
+#include "extern.h"
+
+/*
+ * Gross, but since we're changing the control descriptor from 1 to 0, most
+ * users will be probably be doing "stty > /dev/sometty" by accident. If 1
+ * and 2 are both ttys, but not the same, assume that 1 was incorrectly
+ * redirected.
+ */
+void
+checkredirect(void)
+{
+ struct stat sb1, sb2;
+
+ if (isatty(STDOUT_FILENO) && isatty(STDERR_FILENO) &&
+ !fstat(STDOUT_FILENO, &sb1) && !fstat(STDERR_FILENO, &sb2) &&
+ (sb1.st_rdev != sb2.st_rdev))
+warnx("stdout appears redirected, but stdin is the control descriptor");
+}
diff --git a/adv_cmds/tabs/tabs.1 b/adv_cmds/tabs/tabs.1
new file mode 100644
index 0000000..b2f8523
--- /dev/null
+++ b/adv_cmds/tabs/tabs.1
@@ -0,0 +1,160 @@
+.\" Copyright (c) 2002 Tim J. Robbins.
+.\" All rights reserved.
+.\"
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+.\"
+.\" $FreeBSD: src/usr.bin/tabs/tabs.1,v 1.7 2005/01/17 07:44:29 ru Exp $
+.\"
+.Dd May 20, 2002
+.Dt TABS 1
+.Os
+.Sh NAME
+.Nm tabs
+.Nd set terminal tabs
+.Sh SYNOPSIS
+.Nm
+.Op Fl Ar n | Fl a | a2 | c | c2 | c3 | f | p | s | u
+.Op Cm +m Ns Op Ar n
+.Op Fl T Ar type
+.Nm
+.Op Fl T Ar type
+.Op Cm + Ns Op Ar n
+.Ar n1 Ns Op Ns , Ns Ar n2 , Ns ...
+.Sh DESCRIPTION
+The
+.Nm
+utility displays a series of characters that clear the hardware terminal
+tab settings then initialises tab stops at specified positions, and
+optionally adjusts the margin.
+.Pp
+In the first synopsis form, the tab stops set depend on the command line
+options used, and may be one of the predefined formats or at regular
+intervals.
+.Pp
+In the second synopsis form, tab stops are set at positions
+.Ar n1 , n2 ,
+etc.
+If a position is preceded by a
+.Ql + ,
+it is relative to the previous position set.
+No more than 20 positions may be specified.
+.Pp
+If no tab stops are specified, the
+.Dq standard
+.Ux
+tab width of 8 is used.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl Ar n
+Set a tab stop every
+.Ar n
+columns.
+If
+.Ar n
+is 0, the tab stops are cleared but no new ones are set.
+.It Fl a
+Assembler format (columns 1, 10, 16, 36, 72).
+.It Fl a2
+Assembler format (columns 1, 10, 16, 40, 72).
+.It Fl c
+.Tn COBOL
+normal format (columns 1, 8, 12, 16, 20, 55)
+.It Fl c2
+.Tn COBOL
+compact format (columns 1, 6, 10, 14, 49)
+.It Fl c3
+.Tn COBOL
+compact format (columns 1, 6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46,
+50, 54, 58, 62, 67).
+.It Fl f
+.Tn FORTRAN
+format (columns 1, 7, 11, 15, 19, 23).
+.It Fl p
+.Tn PL/1
+format (columns 1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53,
+57, 61).
+.It Fl s
+.Tn SNOBOL
+format (columns 1, 10, 55).
+.It Fl u
+Assembler format (columns 1, 12, 20, 44).
+.It Xo
+.Cm +m Ns Op Ar n ,
+.Cm + Ns Op Ar n
+.Xc
+Set an
+.Ar n
+character left margin, or 10 if
+.Ar n
+is omitted.
+.It Fl T Ar type
+Output escape sequence for the terminal type
+.Ar type .
+.El
+.Sh ENVIRONMENT
+The
+.Ev LANG , LC_ALL , LC_CTYPE
+and
+.Ev TERM
+environment variables affect the execution of
+.Nm
+as described in
+.Xr environ 7 .
+.Pp
+The
+.Fl T
+option overrides the setting of the
+.Ev TERM
+environment variable.
+If neither
+.Ev TERM
+nor the
+.Fl T
+option are present,
+.Nm
+will fail.
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr expand 1 ,
+.Xr stty 1 ,
+.Xr tput 1 ,
+.Xr unexpand 1 ,
+.Xr termcap 5
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.1-2001 .
+.Sh HISTORY
+A
+.Nm
+utility appeared in PWB UNIX.
+This implementation was introduced in
+.Fx 5.0 .
+.Sh BUGS
+The current
+.Xr termcap 5
+database does not define the
+.Ql ML
+(set left soft margin) capability for any terminals.
diff --git a/adv_cmds/tabs/tabs.c b/adv_cmds/tabs/tabs.c
new file mode 100644
index 0000000..8130b8b
--- /dev/null
+++ b/adv_cmds/tabs/tabs.c
@@ -0,0 +1,240 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+/*
+ * tabs -- set terminal tabs
+ *
+ * This utility displays a series of characters that clears the terminal
+ * hardware tab settings, then initialises them to specified values,
+ * and optionally sets a soft margin.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/tabs/tabs.c,v 1.3 2002/06/08 11:33:22 tjr Exp $");
+
+#ifdef __APPLE__
+#include <sys/ioctl.h>
+#endif
+#include <sys/types.h>
+#include <sys/tty.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <term.h>
+#include <unistd.h>
+
+/* Maximum number of tab stops allowed in table. */
+#define NSTOPS 20
+
+#define NELEMS(a) (sizeof(a) / sizeof(a[0]))
+
+/* Predefined formats, taken from IEEE Std 1003.1-2001. */
+static const struct {
+ const char *name; /* Format name used on cmd. line */
+ long stops[NSTOPS]; /* Column positions */
+} formats[] = {
+ { "a", { 1, 10, 16, 36, 72 } },
+ { "a2", { 1, 10, 16, 40, 72 } },
+ { "c", { 1, 8, 12, 16, 20, 55 } },
+ { "c2", { 1, 6, 10, 14, 49 } },
+ { "c3", { 1, 6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 50, 54, 58,
+ 62, 67 } },
+ { "f", { 1, 7, 11, 15, 19, 23 } },
+ { "p", { 1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57,
+ 61 } },
+ { "s", { 1, 10, 55 } },
+ { "u", { 1, 12, 20, 44 } }
+};
+
+static void gettabs(char *, long *, long *);
+static int ttywidth(void);
+static void usage(void);
+
+int
+main(int argc __unused, char *argv[])
+{
+ long cols, i, inc, j, margin, nstops, stops[NSTOPS];
+ const char *cr, *ct, *st, *ML;
+ char area[1024], *ap, *arg, *end;
+
+ setlocale(LC_ALL, "");
+
+ inc = 8;
+ margin = 0;
+ nstops = -1;
+ while ((arg = *++argv) != NULL && (*arg == '-' || *arg == '+')) {
+ if (*arg == '+') {
+ /* +m[n] or +[n] */
+ if (*++arg == 'm')
+ arg++;
+ if (*arg != '\0') {
+ errno = 0;
+ margin = strtol(arg, &end, 10);
+ if (errno != 0 || *end != '\0' || margin < 0)
+ errx(1, "%s: invalid margin width",
+ arg);
+ } else
+ margin = 10;
+ } else if (isdigit(arg[1])) {
+ /* -n */
+ errno = 0;
+ inc = strtol(arg + 1, &end, 10);
+ if (errno != 0 || *end != '\0' || inc < 0)
+ errx(1, "%s: invalid increment", arg + 1);
+ } else if (arg[1] == 'T') {
+ /* -Ttype or -T type */
+ if (arg[2] != '\0')
+ setenv("TERM", arg + 2, 1);
+ else {
+ if ((arg = *++argv) == NULL)
+ usage();
+ setenv("TERM", arg, 1);
+ }
+ } else if (arg[1] == '-') {
+ arg = *++argv;
+ break;
+ } else {
+ /* Predefined format */
+ for (i = 0; i < (int)NELEMS(formats); i++)
+ if (strcmp(formats[i].name, arg + 1) == 0)
+ break;
+ if (i == NELEMS(formats))
+ usage();
+ for (j = nstops = 0; j < NSTOPS &&
+ formats[i].stops[j] != 0; j++)
+ stops[nstops++] = formats[i].stops[j];
+ }
+ }
+
+ if (arg != NULL) {
+ if (nstops != -1)
+ usage();
+ gettabs(arg, stops, &nstops);
+ }
+
+ /* Initialise terminal, get the strings we need */
+ setupterm(NULL, 1, NULL);
+ ap = area;
+ if ((ct = tgetstr("ct", &ap)) == NULL)
+ errx(1, "terminal cannot clear tabs");
+ if ((st = tgetstr("st", &ap)) == NULL)
+ errx(1, "terminal cannot set tabs");
+ if ((cr = tgetstr("cr", &ap)) == NULL)
+ cr = "\r";
+ ML = tgetstr("ML", &ap);
+ cols = ttywidth();
+
+ /* Clear all tabs. */
+ putp(cr);
+ putp(ct);
+
+ /*
+ * Set soft margin.
+ * XXX Does this actually work?
+ */
+ if (ML != NULL) {
+ printf("%*s", (int)margin, "");
+ putp(ML);
+ } else if (margin != 0)
+ warnx("terminal cannot set left margin");
+
+ /* Optionally output new tab stops. */
+ if (nstops >= 0) {
+ printf("%*s", (int)stops[0] - 1, "");
+ putp(st);
+ for (i = 1; i < nstops; i++) {
+ printf("%*s", (int)(stops[i] - stops[i - 1]), "");
+ putp(st);
+ }
+ } else if (inc > 0) {
+ for (i = 0; i < cols / inc; i++) {
+ putp(st);
+ printf("%*s", (int)inc, "");
+ }
+ putp(st);
+ }
+ putp(cr);
+
+ exit(0);
+}
+
+static void
+usage(void)
+{
+
+ fprintf(stderr,
+"usage: tabs [-n|-a|-a2|-c|-c2|-c3|-f|-p|-s|-u] [+m[n]] [-T type]\n");
+ fprintf(stderr,
+" tabs [-T type] [+[n]] n1,[n2,...]\n");
+ exit(1);
+}
+
+static void
+gettabs(char *arg, long stops[], long *nstops)
+{
+ char *tok, *end;
+ long last, stop;
+
+ for (last = *nstops = 0, tok = strtok(arg, ","); tok != NULL;
+ tok = strtok(NULL, ",")) {
+ if (*nstops >= NSTOPS)
+ errx(1, "too many tab stops (limit %d)", NSTOPS);
+ errno = 0;
+ stop = strtol(tok, &end, 10);
+ if (errno != 0 || *end != '\0' || stop <= 0)
+ errx(1, "%s: invalid tab stop", tok);
+ if (*tok == '+') {
+ if (tok == arg)
+ errx(1, "%s: first tab may not be relative",
+ tok);
+ stop += last;
+ }
+ if (last > stop)
+ errx(1, "cannot go backwards");
+ last = stops[(*nstops)++] = stop;
+ }
+}
+
+static int
+ttywidth(void)
+{
+ struct winsize ws;
+ int width;
+
+ if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1)
+ width = ws.ws_col;
+ else if ((width = tgetnum("co")) == 0) {
+ width = 80;
+ warnx("cannot find terminal width; defaulted to %d", width);
+ }
+
+ return (width);
+}
diff --git a/adv_cmds/tty/tty.1 b/adv_cmds/tty/tty.1
new file mode 100644
index 0000000..1fd66b8
--- /dev/null
+++ b/adv_cmds/tty/tty.1
@@ -0,0 +1,87 @@
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" 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.
+.\"
+.\" @(#)tty.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/tty/tty.1,v 1.9 2006/12/13 20:15:49 ru Exp $
+.\"
+.Dd June 6, 1993
+.Dt TTY 1
+.Os
+.Sh NAME
+.Nm tty
+.Nd return user's terminal name
+.Sh SYNOPSIS
+.Nm
+.Op Fl s
+.Sh DESCRIPTION
+The
+.Nm
+utility writes the name of the terminal attached to standard input
+to standard output.
+The name that is written is the string returned by
+.Xr ttyname 3 .
+If the standard input is not a terminal, the message
+.Dq Li "not a tty"
+is written.
+The options are as follows:
+.Bl -tag -width indent
+.It Fl s
+Do not write the terminal name; only the exit status is affected
+when this option is specified.
+The
+.Fl s
+option is deprecated in favor of the
+.Dq Li "test -t 0"
+command.
+.El
+.Sh EXIT STATUS
+The
+.Nm
+utility
+exits 0 if the standard input is a terminal, 1 if the standard input is
+not a terminal, and >1 if an error occurs.
+.Sh SEE ALSO
+.Xr test 1 ,
+.Xr ttyname 3
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be
+.St -p1003.2
+compatible.
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v1 .
diff --git a/adv_cmds/tty/tty.c b/adv_cmds/tty/tty.c
new file mode 100644
index 0000000..806fe4b
--- /dev/null
+++ b/adv_cmds/tty/tty.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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 const char copyright[] =
+"@(#) Copyright (c) 1988, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)tty.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/tty/tty.c,v 1.9 2002/05/29 17:12:30 jmallett Exp $");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ int ch, sflag;
+ char *t;
+
+ sflag = 0;
+ while ((ch = getopt(argc, argv, "s")) != -1)
+ switch (ch) {
+ case 's':
+ sflag = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+
+ t = ttyname(0);
+ if (!sflag)
+ puts(t ? t : "not a tty");
+ exit(t ? 0 : 1);
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: tty [-s]\n");
+ exit(2);
+}
diff --git a/adv_cmds/whois/whois.1 b/adv_cmds/whois/whois.1
new file mode 100644
index 0000000..0177b48
--- /dev/null
+++ b/adv_cmds/whois/whois.1
@@ -0,0 +1,287 @@
+.\" Copyright (c) 1985, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" 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.
+.\"
+.\" From: @(#)whois.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD$
+.\"
+.Dd April 25, 2016
+.Dt WHOIS 1
+.Os
+.Sh NAME
+.Nm whois
+.Nd "Internet domain name and network number directory service"
+.Sh SYNOPSIS
+.Nm
+.Op Fl aAbfgiIklmPQrRS
+.Op Fl c Ar TLD | Fl h Ar host
+.Op Fl p Ar port
+.Op Fl -
+.Ar name ...
+.Sh DESCRIPTION
+The
+.Nm
+utility looks up records in the databases maintained by several
+Network Information Centers
+.Pq Tn NICs .
+.Pp
+By default
+.Nm
+starts by querying the Internet Assigned Numbers Authority (IANA) whois server,
+and follows referrals to whois servers
+that have more specific details about the query
+.Ar name .
+The IANA whois server knows about
+IP address and AS numbers
+as well as domain names.
+.Pp
+There are a few special cases where referrals do not work, so
+.Nm
+goes directly to the appropriate server.
+These include point-of-contact handles for ARIN,
+.Pa nic.at ,
+NORID, and RIPE,
+and domain names under
+.Pa ac.uk .
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl a
+Use the American Registry for Internet Numbers
+.Pq Tn ARIN
+database.
+It contains network numbers used in those parts of the world covered neither by
+.Tn APNIC , AfriNIC , LACNIC ,
+nor by
+.Tn RIPE .
+The query syntax is documented at
+.Pa https://www.arin.net/resources/whoisrws/whois_api.html#nicname
+.It Fl A
+Use the Asia/Pacific Network Information Center
+.Pq Tn APNIC
+database.
+It contains network numbers used in East Asia, Australia,
+New Zealand, and the Pacific islands.
+Get query syntax documentation using
+.Ic whois -A help
+.It Fl b
+Use the Network Abuse Clearinghouse database.
+It contains addresses to which network abuse should be reported,
+indexed by domain name.
+.It Fl c Ar TLD
+This is the equivalent of using the
+.Fl h
+option with an argument of
+.Qq Ar TLD Ns Li .whois-servers.net .
+This can be helpful for locating country-class TLD whois servers.
+.It Fl f
+Use the African Network Information Centre
+.Pq Tn AfriNIC
+database.
+It contains network numbers used in Africa and the islands of the
+western Indian Ocean.
+Get query syntax documentation using
+.Ic whois -f help
+.It Fl g
+Use the US non-military federal government database, which contains points of
+contact for subdomains of
+.Pa .GOV .
+.It Fl h Ar host
+Use the specified host instead of the default.
+Either a host name or an IP address may be specified.
+.It Fl i
+Use the traditional Network Information Center (InterNIC)
+.Pq Pa whois.internic.net
+database.
+This now contains only registrations for domain names under
+.Pa .COM ,
+.Pa .NET ,
+.Pa .EDU .
+You can specify the type of object to search for like
+.Ic whois -i ' Ns Ar type Ar name Ns Ic '
+where
+.Ar type
+can be
+.Nm domain , nameserver , registrar .
+The
+.Ar name
+can contain
+.Li *
+wildcards.
+.It Fl I
+Use the Internet Assigned Numbers Authority
+.Pq Tn IANA
+database.
+.It Fl k
+Use the National Internet Development Agency of Korea's
+.Pq Tn KRNIC
+database.
+It contains network numbers and domain contact information
+for Korea.
+.It Fl l
+Use the Latin American and Caribbean IP address Regional Registry
+.Pq Tn LACNIC
+database.
+It contains network numbers used in much of Latin America and the
+Caribbean.
+.It Fl m
+Use the Route Arbiter Database
+.Pq Tn RADB
+database.
+It contains route policy specifications for a large
+number of operators' networks.
+.It Fl p Ar port
+Connect to the whois server on
+.Ar port .
+If this option is not specified,
+.Nm
+defaults to port 43.
+.It Fl P
+Use the PeeringDB database of AS numbers.
+It contains details about presence at internet peering points
+for many network operators.
+.It Fl Q
+Do a quick lookup;
+.Nm
+will not attempt to follow referrals to other whois servers.
+This is the default if a server is explicitly specified
+using one of the other options or in an environment variable.
+See also the
+.Fl R
+option.
+.It Fl r
+Use the R\(aaeseaux IP Europ\(aaeens
+.Pq Tn RIPE
+database.
+It contains network numbers and domain contact information
+for Europe.
+Get query syntax documentation using
+.Ic whois -r help
+.It Fl R
+Do a recursive lookup;
+.Nm
+will attempt to follow referrals to other whois servers.
+This is the default if no server is explicitly specified.
+See also the
+.Fl Q
+option.
+.It Fl S
+By default
+.Nm
+adjusts simple queries (without spaces) to produce more useful output
+from certain whois servers,
+and it suppresses some uninformative output.
+With the
+.Fl S
+option,
+.Nm
+sends the query and prints the output verbatim.
+.El
+.Pp
+The operands specified to
+.Nm
+are treated independently and may be used
+as queries on different whois servers.
+.Sh ENVIRONMENT
+.Bl -tag -width WHOIS_SERVER
+.It Ev WHOIS_SERVER
+The primary default whois server.
+If this is unset,
+.Nm
+uses the
+.Ev RA_SERVER
+environment variable.
+.It Ev RA_SERVER
+The secondary default whois server.
+If this is unset,
+.Nm
+will use
+.Pa whois.iana.org .
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+To obtain contact information about an
+administrator located in the Russian
+.Tn TLD
+domain
+.Qq Li RU ,
+use the
+.Fl c
+option as shown in the following example, where
+.Ar CONTACT-ID
+is substituted with the actual contact identifier.
+.Pp
+.Dl Ic whois -c RU CONTACT-ID
+.Pp
+(Note: This example is specific to the
+.Tn TLD
+.Qq Li RU ,
+but other
+.Tn TLDs
+can be queried by using a similar syntax.)
+.Pp
+The following example demonstrates how to query
+a whois server using a non-standard port, where
+.Dq Li query-data
+is the query to be sent to
+.Dq Li whois.example.com
+on port
+.Dq Li rwhois
+(written numerically as 4321).
+.Pp
+.Dl Ic whois -h whois.example.com -p rwhois query-data
+.Pp
+Some whois servers support complex queries
+with dash-letter options.
+You can use the
+.Fl -
+option to separate
+.Nm
+command options from whois server query options.
+A query containing spaces must be quoted as one
+argument to the
+.Nm
+command.
+The following example asks the RIPE whois server
+to return a brief description of its
+.Dq Li domain
+object type:
+.Pp
+.Dl Ic whois -r -- '-t domain'
+.Sh SEE ALSO
+.Rs
+.%A Ken Harrenstien
+.%A Vic White
+.%T NICNAME/WHOIS
+.%D 1 March 1982
+.%O RFC 812
+.Re
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.3 .
diff --git a/adv_cmds/whois/whois.c b/adv_cmds/whois/whois.c
new file mode 100644
index 0000000..a6c4f6c
--- /dev/null
+++ b/adv_cmds/whois/whois.c
@@ -0,0 +1,629 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1980, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)whois.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <err.h>
+#include <netdb.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#ifdef __APPLE__
+#ifndef SOCK_NONBLOCK
+#define SOCK_NONBLOCK 0
+#endif
+#ifndef INFTIM
+#define INFTIM -1
+#endif
+#endif
+
+#define ABUSEHOST "whois.abuse.net"
+#define ANICHOST "whois.arin.net"
+#define DENICHOST "whois.denic.de"
+#define DKNICHOST "whois.dk-hostmaster.dk"
+#define FNICHOST "whois.afrinic.net"
+#define GNICHOST "whois.nic.gov"
+#define IANAHOST "whois.iana.org"
+#define INICHOST "whois.internic.net"
+#define KNICHOST "whois.krnic.net"
+#define LNICHOST "whois.lacnic.net"
+#define MNICHOST "whois.ra.net"
+#define PDBHOST "whois.peeringdb.com"
+#define PNICHOST "whois.apnic.net"
+#define QNICHOST_TAIL ".whois-servers.net"
+#define RNICHOST "whois.ripe.net"
+#define VNICHOST "whois.verisign-grs.com"
+
+#ifdef __APPLE__
+#define DEFAULT_PORT "nicname"
+#else
+#define DEFAULT_PORT "whois"
+#endif
+
+#define WHOIS_RECURSE 0x01
+#define WHOIS_QUICK 0x02
+#define WHOIS_SPAM_ME 0x04
+
+#define CHOPSPAM ">>> Last update of WHOIS database:"
+
+#define ishost(h) (isalnum((unsigned char)h) || h == '.' || h == '-')
+
+#define SCAN(p, end, check) \
+ while ((p) < (end)) \
+ if (check) ++(p); \
+ else break
+
+static struct {
+ const char *suffix, *server;
+} whoiswhere[] = {
+ /* Various handles */
+ { "-ARIN", ANICHOST },
+ { "-NICAT", "at" QNICHOST_TAIL },
+ { "-NORID", "no" QNICHOST_TAIL },
+ { "-RIPE", RNICHOST },
+ /* Nominet's whois server doesn't return referrals to JANET */
+ { ".ac.uk", "ac.uk" QNICHOST_TAIL },
+ { ".gov.uk", "ac.uk" QNICHOST_TAIL },
+ { "", IANAHOST }, /* default */
+ { NULL, NULL } /* safety belt */
+};
+
+#define WHOIS_REFERRAL(s) { s, sizeof(s) - 1 }
+static struct {
+ const char *prefix;
+ size_t len;
+} whois_referral[] = {
+ WHOIS_REFERRAL("whois:"), /* IANA */
+ WHOIS_REFERRAL("Whois Server:"),
+ WHOIS_REFERRAL("Registrar WHOIS Server:"), /* corporatedomains.com */
+ WHOIS_REFERRAL("ReferralServer: whois://"), /* ARIN */
+ WHOIS_REFERRAL("descr: region. Please query"), /* AfriNIC */
+ { NULL, 0 }
+};
+
+/*
+ * We have a list of patterns for RIRs that assert ignorance rather than
+ * providing referrals. If that happens, we guess that ARIN will be more
+ * helpful. But, before following a referral to an RIR, we check if we have
+ * asked that RIR already, and if so we make another guess.
+ */
+static const char *actually_arin[] = {
+ "netname: ERX-NETBLOCK\n", /* APNIC */
+ "netname: NON-RIPE-NCC-MANAGED-ADDRESS-BLOCK\n",
+ NULL
+};
+
+static struct {
+ int loop;
+ const char *host;
+} try_rir[] = {
+ { 0, ANICHOST },
+ { 0, RNICHOST },
+ { 0, PNICHOST },
+ { 0, FNICHOST },
+ { 0, LNICHOST },
+ { 0, NULL }
+};
+
+static void
+reset_rir(void) {
+ int i;
+
+ for (i = 0; try_rir[i].host != NULL; i++)
+ try_rir[i].loop = 0;
+}
+
+static const char *port = DEFAULT_PORT;
+
+static const char *choose_server(char *);
+static struct addrinfo *gethostinfo(char const *host, int exitnoname);
+#ifdef __APPLE__
+static void s_asprintf(char **ret, const char *format, ...) __attribute__((__format__(printf, 2, 3)));
+#else
+static void s_asprintf(char **ret, const char *format, ...) __printflike(2, 3);
+#endif
+static void usage(void);
+static void whois(const char *, const char *, int);
+
+int
+main(int argc, char *argv[])
+{
+ const char *country, *host;
+ int ch, flags;
+
+#ifdef SOCKS
+ SOCKSinit(argv[0]);
+#endif
+
+ country = host = NULL;
+ flags = 0;
+ while ((ch = getopt(argc, argv, "aAbc:fgh:iIklmp:PQrRS")) != -1) {
+ switch (ch) {
+ case 'a':
+ host = ANICHOST;
+ break;
+ case 'A':
+ host = PNICHOST;
+ break;
+ case 'b':
+ host = ABUSEHOST;
+ break;
+ case 'c':
+ country = optarg;
+ break;
+ case 'f':
+ host = FNICHOST;
+ break;
+ case 'g':
+ host = GNICHOST;
+ break;
+ case 'h':
+ host = optarg;
+ break;
+ case 'i':
+ host = INICHOST;
+ break;
+ case 'I':
+ host = IANAHOST;
+ break;
+ case 'k':
+ host = KNICHOST;
+ break;
+ case 'l':
+ host = LNICHOST;
+ break;
+ case 'm':
+ host = MNICHOST;
+ break;
+ case 'p':
+ port = optarg;
+ break;
+ case 'P':
+ host = PDBHOST;
+ break;
+ case 'Q':
+ flags |= WHOIS_QUICK;
+ break;
+ case 'r':
+ host = RNICHOST;
+ break;
+ case 'R':
+ flags |= WHOIS_RECURSE;
+ break;
+ case 'S':
+ flags |= WHOIS_SPAM_ME;
+ break;
+ case '?':
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (!argc || (country != NULL && host != NULL))
+ usage();
+
+ /*
+ * If no host or country is specified, rely on referrals from IANA.
+ */
+ if (host == NULL && country == NULL) {
+ if ((host = getenv("WHOIS_SERVER")) == NULL &&
+ (host = getenv("RA_SERVER")) == NULL) {
+ if (!(flags & WHOIS_QUICK))
+ flags |= WHOIS_RECURSE;
+ }
+ }
+ while (argc-- > 0) {
+ if (country != NULL) {
+ char *qnichost;
+ s_asprintf(&qnichost, "%s%s", country, QNICHOST_TAIL);
+ whois(*argv, qnichost, flags);
+ free(qnichost);
+ } else
+ whois(*argv, host != NULL ? host :
+ choose_server(*argv), flags);
+ reset_rir();
+ argv++;
+ }
+ exit(0);
+}
+
+static const char *
+choose_server(char *domain)
+{
+ size_t len = strlen(domain);
+ int i;
+
+ for (i = 0; whoiswhere[i].suffix != NULL; i++) {
+ size_t suffix_len = strlen(whoiswhere[i].suffix);
+ if (len > suffix_len &&
+ strcasecmp(domain + len - suffix_len,
+ whoiswhere[i].suffix) == 0)
+ return (whoiswhere[i].server);
+ }
+ errx(EX_SOFTWARE, "no default whois server");
+}
+
+static struct addrinfo *
+gethostinfo(char const *host, int exit_on_noname)
+{
+ struct addrinfo hints, *res;
+ int error;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ res = NULL;
+ error = getaddrinfo(host, port, &hints, &res);
+ if (error && (exit_on_noname || error != EAI_NONAME))
+ err(EX_NOHOST, "%s: %s", host, gai_strerror(error));
+ return (res);
+}
+
+/*
+ * Wrapper for asprintf(3) that exits on error.
+ */
+static void
+s_asprintf(char **ret, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ if (vasprintf(ret, format, ap) == -1) {
+ va_end(ap);
+ err(EX_OSERR, "vasprintf()");
+ }
+ va_end(ap);
+}
+
+static int
+connect_to_any_host(struct addrinfo *hostres)
+{
+ struct addrinfo *res;
+ nfds_t i, j;
+ size_t count;
+ struct pollfd *fds;
+ int timeout = 180, s = -1;
+
+ for (res = hostres, count = 0; res; res = res->ai_next)
+ count++;
+ fds = calloc(count, sizeof(*fds));
+ if (fds == NULL)
+ err(EX_OSERR, "calloc()");
+
+ /*
+ * Traverse the result list elements and make non-block
+ * connection attempts.
+ */
+ count = i = 0;
+ for (res = hostres; res != NULL; res = res->ai_next) {
+ s = socket(res->ai_family, res->ai_socktype | SOCK_NONBLOCK,
+ res->ai_protocol);
+ if (s < 0)
+ continue;
+#ifdef __APPLE__
+ int flags = fcntl(s, F_GETFL, 0);
+ if (flags < 0) {
+ close(s);
+ continue;
+ }
+ flags |= O_NONBLOCK;
+ if (fcntl(s, F_SETFL, flags) != 0) {
+ close(s);
+ continue;
+ }
+#endif
+ if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
+ if (errno == EINPROGRESS) {
+ /* Add the socket to poll list */
+ fds[i].fd = s;
+ fds[i].events = POLLERR | POLLHUP |
+ POLLIN | POLLOUT;
+ /*
+ * From here until a socket connects, the
+ * socket fd is owned by the fds[] poll array.
+ */
+ s = -1;
+ count++;
+ i++;
+ } else {
+ close(s);
+ s = -1;
+
+ /*
+ * Poll only if we have something to poll,
+ * otherwise just go ahead and try next
+ * address
+ */
+ if (count == 0)
+ continue;
+ }
+ } else
+ goto done;
+
+ /*
+ * If we are at the last address, poll until a connection is
+ * established or we failed all connection attempts.
+ */
+ if (res->ai_next == NULL)
+ timeout = INFTIM;
+
+ /*
+ * Poll the watched descriptors for successful connections:
+ * if we still have more untried resolved addresses, poll only
+ * once; otherwise, poll until all descriptors have errors,
+ * which will be considered as ETIMEDOUT later.
+ */
+ do {
+ int n;
+
+ n = poll(fds, i, timeout);
+ if (n == 0) {
+ /*
+ * No event reported in time. Try with a
+ * smaller timeout (but cap at 2-3ms)
+ * after a new host have been added.
+ */
+ if (timeout >= 3)
+ timeout >>= 1;
+
+ break;
+ } else if (n < 0) {
+ /*
+ * errno here can only be EINTR which we would
+ * want to clean up and bail out.
+ */
+ s = -1;
+ goto done;
+ }
+
+ /*
+ * Check for the event(s) we have seen.
+ */
+ for (j = 0; j < i; j++) {
+ if (fds[j].fd == -1 || fds[j].events == 0 ||
+ fds[j].revents == 0)
+ continue;
+ if (fds[j].revents & ~(POLLIN | POLLOUT)) {
+ close(fds[j].fd);
+ fds[j].fd = -1;
+ fds[j].events = 0;
+ count--;
+ continue;
+ } else if (fds[j].revents & (POLLIN | POLLOUT)) {
+ /* Connect succeeded. */
+ s = fds[j].fd;
+ fds[j].fd = -1;
+
+ goto done;
+ }
+
+ }
+ } while (timeout == INFTIM && count != 0);
+ }
+
+ /* All attempts were failed */
+ s = -1;
+ if (count == 0)
+ errno = ETIMEDOUT;
+
+done:
+ /* Close all watched fds except the succeeded one */
+ for (j = 0; j < i; j++)
+ if (fds[j].fd != -1)
+ close(fds[j].fd);
+ free(fds);
+ return (s);
+}
+
+static void
+whois(const char *query, const char *hostname, int flags)
+{
+ FILE *fp;
+ struct addrinfo *hostres;
+ char *buf, *host, *nhost, *p;
+ int comment, s, f;
+ size_t len, i;
+
+ hostres = gethostinfo(hostname, 1);
+ s = connect_to_any_host(hostres);
+ if (s == -1)
+ err(EX_OSERR, "connect()");
+
+ /* Restore default blocking behavior. */
+ if ((f = fcntl(s, F_GETFL)) == -1)
+ err(EX_OSERR, "fcntl()");
+ f &= ~O_NONBLOCK;
+ if (fcntl(s, F_SETFL, f) == -1)
+ err(EX_OSERR, "fcntl()");
+
+ fp = fdopen(s, "r+");
+ if (fp == NULL)
+ err(EX_OSERR, "fdopen()");
+
+ if (!(flags & WHOIS_SPAM_ME) &&
+ (strcasecmp(hostname, DENICHOST) == 0 ||
+ strcasecmp(hostname, "de" QNICHOST_TAIL) == 0)) {
+ const char *q;
+ int idn = 0;
+ for (q = query; *q != '\0'; q++)
+ if (!isascii(*q))
+ idn = 1;
+ fprintf(fp, "-T dn%s %s\r\n", idn ? "" : ",ace", query);
+ } else if (!(flags & WHOIS_SPAM_ME) &&
+ (strcasecmp(hostname, DKNICHOST) == 0 ||
+ strcasecmp(hostname, "dk" QNICHOST_TAIL) == 0))
+ fprintf(fp, "--show-handles %s\r\n", query);
+ else if ((flags & WHOIS_SPAM_ME) ||
+ strchr(query, ' ') != NULL)
+ fprintf(fp, "%s\r\n", query);
+ else if (strcasecmp(hostname, ANICHOST) == 0) {
+ if (strncasecmp(query, "AS", 2) == 0 &&
+ strspn(query+2, "0123456789") == strlen(query+2))
+ fprintf(fp, "+ a %s\r\n", query+2);
+ else
+ fprintf(fp, "+ %s\r\n", query);
+ } else if (strcasecmp(hostres->ai_canonname, VNICHOST) == 0)
+ fprintf(fp, "domain %s\r\n", query);
+ else
+ fprintf(fp, "%s\r\n", query);
+ fflush(fp);
+
+ comment = 0;
+ if (!(flags & WHOIS_SPAM_ME) &&
+ (strcasecmp(hostname, ANICHOST) == 0 ||
+ strcasecmp(hostname, RNICHOST) == 0)) {
+ comment = 2;
+ }
+
+ nhost = NULL;
+ while ((buf = fgetln(fp, &len)) != NULL) {
+ /* Nominet */
+ if (!(flags & WHOIS_SPAM_ME) &&
+ len == 5 && strncmp(buf, "-- \r\n", 5) == 0)
+ break;
+ /* RIRs */
+ if (comment == 1 && buf[0] == '#')
+ break;
+ else if (comment == 2) {
+ if (strchr("#%\r\n", buf[0]) != NULL)
+ continue;
+ else
+ comment = 1;
+ }
+
+ printf("%.*s", (int)len, buf);
+
+ if ((flags & WHOIS_RECURSE) && nhost == NULL) {
+ for (i = 0; whois_referral[i].prefix != NULL; i++) {
+ p = buf;
+ SCAN(p, buf+len, *p == ' ');
+ if (strncasecmp(p, whois_referral[i].prefix,
+ whois_referral[i].len) != 0)
+ continue;
+ p += whois_referral[i].len;
+ SCAN(p, buf+len, *p == ' ');
+ host = p;
+ SCAN(p, buf+len, ishost(*p));
+ if (p > host)
+ s_asprintf(&nhost, "%.*s",
+ (int)(p - host), host);
+ break;
+ }
+ for (i = 0; actually_arin[i] != NULL; i++) {
+ if (strncmp(buf, actually_arin[i], len) == 0) {
+ s_asprintf(&nhost, "%s", ANICHOST);
+ break;
+ }
+ }
+ }
+ /* Verisign etc. */
+ if (!(flags & WHOIS_SPAM_ME) &&
+ len >= sizeof(CHOPSPAM)-1 &&
+ (strncasecmp(buf, CHOPSPAM, sizeof(CHOPSPAM)-1) == 0 ||
+ strncasecmp(buf, CHOPSPAM+4, sizeof(CHOPSPAM)-5) == 0)) {
+ printf("\n");
+ break;
+ }
+ }
+ fclose(fp);
+ freeaddrinfo(hostres);
+
+ f = 0;
+ for (i = 0; try_rir[i].host != NULL; i++) {
+ /* Remember visits to RIRs */
+ if (try_rir[i].loop == 0 &&
+ strcasecmp(try_rir[i].host, hostname) == 0)
+ try_rir[i].loop = 1;
+ /* Do we need to find an alternative RIR? */
+ if (try_rir[i].loop != 0 && nhost != NULL &&
+ strcasecmp(try_rir[i].host, nhost) == 0) {
+ free(nhost);
+ nhost = NULL;
+ f = 1;
+ }
+ }
+ if (f) {
+ /* Find a replacement RIR */
+ for (i = 0; try_rir[i].host != NULL; i++) {
+ if (try_rir[i].loop == 0) {
+ s_asprintf(&nhost, "%s",
+ try_rir[i].host);
+ break;
+ }
+ }
+ }
+ if (nhost != NULL) {
+ /* Ignore self-referrals */
+ if (strcasecmp(hostname, nhost) != 0) {
+ printf("# %s\n\n", nhost);
+ whois(query, nhost, flags);
+ }
+ free(nhost);
+ }
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr,
+ "usage: whois [-aAbfgiIklmPQrRS] [-c country-code | -h hostname] "
+ "[-p port] name ...\n");
+ exit(EX_USAGE);
+}
diff --git a/adv_cmds/xcodescripts/variant_links.sh b/adv_cmds/xcodescripts/variant_links.sh
new file mode 100644
index 0000000..523c755
--- /dev/null
+++ b/adv_cmds/xcodescripts/variant_links.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+#
+# Variant links cannot be created in the actual target, because Strip/CodeSign/etc are
+# after all other phases. Running it in the aggregate target guarantees that the variants
+# are really linked to the actual stripped/signed binary.
+#
+
+set -ex
+
+ln ${DSTROOT}/usr/bin/pkill ${DSTROOT}/usr/bin/pgrep
+ln ${DSTROOT}/usr/share/man/man1/pkill.1 ${DSTROOT}/usr/share/man/man1/pgrep.1