386BSD 0.1 development
authorWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Thu, 18 Apr 1991 00:48:07 +0000 (16:48 -0800)
committerWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Thu, 18 Apr 1991 00:48:07 +0000 (16:48 -0800)
Work on file usr/src/usr.bin/finger/finger.c
Work on file usr/src/usr.bin/finger/lprint.c
Work on file usr/src/usr.bin/finger/finger.h
Work on file usr/src/usr.bin/finger/sprint.c
Work on file usr/src/usr.bin/finger/net.c
Work on file usr/src/usr.bin/finger/util.c
Work on file usr/src/usr.bin/fmt/fmt.c
Work on file usr/src/usr.bin/fold/fold.c

Co-Authored-By: Lynne Greer Jolitz <ljolitz@cardio.ucsf.edu>
Synthesized-from: 386BSD-0.1

usr/src/usr.bin/finger/finger.c [new file with mode: 0644]
usr/src/usr.bin/finger/finger.h [new file with mode: 0644]
usr/src/usr.bin/finger/lprint.c [new file with mode: 0644]
usr/src/usr.bin/finger/net.c [new file with mode: 0644]
usr/src/usr.bin/finger/sprint.c [new file with mode: 0644]
usr/src/usr.bin/finger/util.c [new file with mode: 0644]
usr/src/usr.bin/fmt/fmt.c [new file with mode: 0644]
usr/src/usr.bin/fold/fold.c [new file with mode: 0644]

diff --git a/usr/src/usr.bin/finger/finger.c b/usr/src/usr.bin/finger/finger.c
new file mode 100644 (file)
index 0000000..3d6b7cd
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 1989 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.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1989 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)finger.c   5.22 (Berkeley) 6/29/90";
+#endif /* not lint */
+
+/*
+ * 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 office location/phone number.  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/param.h>
+#include <sys/file.h>
+#include <stdio.h>
+#include "finger.h"
+
+time_t now;
+int lflag, sflag, mflag, pplan;
+char tbuf[1024];
+
+main(argc, argv)
+       int argc;
+       char **argv;
+{
+       extern int optind;
+       int ch;
+       time_t time();
+
+       while ((ch = getopt(argc, argv, "lmps")) != EOF)
+               switch(ch) {
+               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 '?':
+               default:
+                       (void)fprintf(stderr,
+                           "usage: finger [-lmps] [login ...]\n");
+                       exit(1);
+               }
+       argc -= optind;
+       argv += optind;
+
+       (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 != 0) {
+               if (lflag)
+                       lflag_print();
+               else
+                       sflag_print();
+       }
+       exit(0);
+}
+
+loginlist()
+{
+       register PERSON *pn;
+       struct passwd *pw;
+       struct utmp user;
+       char name[UT_NAMESIZE + 1];
+
+       if (!freopen(_PATH_UTMP, "r", stdin)) {
+               (void)fprintf(stderr, "finger: can't read %s.\n", _PATH_UTMP);
+               exit(2);
+       }
+       name[UT_NAMESIZE] = NULL;
+       while (fread((char *)&user, sizeof(user), 1, stdin) == 1) {
+               if (!user.ut_name[0])
+                       continue;
+               if ((pn = find_person(user.ut_name)) == NULL) {
+                       bcopy(user.ut_name, name, UT_NAMESIZE);
+                       if ((pw = getpwnam(name)) == NULL)
+                               continue;
+                       pn = enter_person(pw);
+               }
+               enter_where(&user, pn);
+       }
+       for (pn = phead; lflag && pn != NULL; pn = pn->next)
+               enter_lastlog(pn);
+}
+
+userlist(argc, argv)
+       register argc;
+       register char **argv;
+{
+       register i;
+       register PERSON *pn;
+       PERSON *nethead, **nettail;
+       struct utmp user;
+       struct passwd *pw;
+       int dolocal, *used;
+       char *index();
+
+       if (!(used = (int *)calloc((u_int)argc, (u_int)sizeof(int)))) {
+               (void)fprintf(stderr, "finger: out of space.\n");
+               exit(1);
+       }
+
+       /* pull out all network requests */
+       for (i = 0, dolocal = 0, nettail = &nethead; i < argc; i++) {
+               if (!index(argv[i], '@')) {
+                       dolocal = 1;
+                       continue;
+               }
+               pn = palloc();
+               *nettail = pn;
+               nettail = &pn->next;
+               pn->name = argv[i];
+               used[i] = -1;
+       }
+       *nettail = NULL;
+
+       if (!dolocal)
+               goto net;
+
+       /*
+        * traverse the list of possible login names and check the login name
+        * and real name against the name specified by the user.
+        */
+       if (mflag) {
+               for (i = 0; i < argc; i++)
+                       if (used[i] >= 0 && (pw = getpwnam(argv[i]))) {
+                               enter_person(pw);
+                               used[i] = 1;
+                       }
+       } else while (pw = getpwent())
+               for (i = 0; i < argc; i++)
+                       if (used[i] >= 0 &&
+                           (!strcasecmp(pw->pw_name, argv[i]) ||
+                           match(pw, argv[i]))) {
+                               enter_person(pw);
+                               used[i] = 1;
+                       }
+
+       /* list errors */
+       for (i = 0; i < argc; i++)
+               if (!used[i])
+                       (void)fprintf(stderr,
+                           "finger: %s: no such user.\n", argv[i]);
+
+       /* handle network requests */
+net:   for (pn = nethead; pn; pn = pn->next) {
+               netfinger(pn->name);
+               if (pn->next || entries)
+                       putchar('\n');
+       }
+
+       if (entries == 0)
+               return;
+
+       /*
+        * Scan thru the list of users currently logged in, saving
+        * appropriate data whenever a match occurs.
+        */
+       if (!freopen(_PATH_UTMP, "r", stdin)) {
+               (void)fprintf( stderr, "finger: can't read %s.\n", _PATH_UTMP);
+               exit(1);
+       }
+       while (fread((char *)&user, sizeof(user), 1, stdin) == 1) {
+               if (!user.ut_name[0])
+                       continue;
+               if ((pn = find_person(user.ut_name)) == NULL)
+                       continue;
+               enter_where(&user, pn);
+       }
+       for (pn = phead; pn != NULL; pn = pn->next)
+               enter_lastlog(pn);
+}
diff --git a/usr/src/usr.bin/finger/finger.h b/usr/src/usr.bin/finger/finger.h
new file mode 100644 (file)
index 0000000..aef0d1b
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 1989 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    5.5 (Berkeley) 6/1/90
+ */
+
+#include <pwd.h>
+#include <utmp.h>
+
+/*
+ * All unique persons are linked in a list headed by "head" and linkd
+ * by the "next" field, as well as kept in a hash table.
+ */
+
+typedef struct person {
+       struct person *next;            /* link to next person */
+       struct person *hlink;           /* link to next person in hash bucket */
+       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 */
+       struct where *whead, *wtail;    /* list of where he is or has been */
+} PERSON;
+
+enum status { LASTLOG, LOGGEDIN };
+
+typedef struct where {
+       struct where *next;             /* next place he 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[UT_LINESIZE+1];        /* null terminated tty line */
+       char host[UT_HOSTSIZE+1];       /* null terminated remote host name */
+} WHERE;
+
+#define        HBITS   8                       /* number of bits in hash code */
+#define        HSIZE   (1 << 8)                /* hash table size */
+#define        HMASK   (HSIZE - 1)             /* hash code mask */
+
+PERSON *htab[HSIZE];                   /* the buckets */
+PERSON *phead, *ptail;                 /* the linked list of all people */
+
+int entries;                           /* number of people */
+
+PERSON *enter_person(), *find_person(), *palloc();
+WHERE *walloc();
+
+extern char tbuf[1024];                        /* temp buffer for anybody */
diff --git a/usr/src/usr.bin/finger/lprint.c b/usr/src/usr.bin/finger/lprint.c
new file mode 100644 (file)
index 0000000..25ea256
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 1989 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)lprint.c   5.13 (Berkeley) 10/31/90";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <tzfile.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <paths.h>
+#include "finger.h"
+
+#define        LINE_LEN        80
+#define        TAB_LEN         8               /* 8 spaces between tabs */
+#define        _PATH_PLAN      ".plan"
+#define        _PATH_PROJECT   ".project"
+
+lflag_print()
+{
+       extern int pplan;
+       register PERSON *pn;
+
+       for (pn = phead;;) {
+               lprint(pn);
+               if (!pplan) {
+                       (void)show_text(pn->dir, _PATH_PROJECT, "Project:");
+                       if (!show_text(pn->dir, _PATH_PLAN, "Plan:"))
+                               (void)printf("No Plan.\n");
+               }
+               if (!(pn = pn->next))
+                       break;
+               putchar('\n');
+       }
+}
+
+lprint(pn)
+       register PERSON *pn;
+{
+       extern time_t now;
+       register struct tm *delta;
+       register WHERE *w;
+       register int cpr, len, maxlen;
+       struct tm *tp;
+       int oddfield;
+       time_t time();
+       char *t, *tzn, *prphone();
+
+       /*
+        * long format --
+        *      login name
+        *      real name
+        *      home directory
+        *      shell
+        *      office, office phone, home phone if available
+        */
+       (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);
+
+       /*
+        * 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)sprintf(tbuf, "%s: %s, %s", OFFICE_TAG, pn->office,
+                   prphone(pn->officephone));
+               oddfield = demi_print(tbuf, oddfield);
+       } else {
+               if (pn->office) {
+                       (void)sprintf(tbuf, "%s: %s", OFFICE_TAG, pn->office);
+                       oddfield = demi_print(tbuf, oddfield);
+               }
+               if (pn->officephone) {
+                       (void)sprintf(tbuf, "%s: %s", OFFICE_PHONE_TAG,
+                           prphone(pn->officephone));
+                       oddfield = demi_print(tbuf, oddfield);
+               }
+       }
+       if (pn->homephone) {
+               (void)sprintf(tbuf, "%s: %s", "Home Phone",
+                   prphone(pn->homephone));
+               oddfield = demi_print(tbuf, oddfield);
+       }
+       if (oddfield)
+               putchar('\n');
+
+       /*
+        * 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) {
+               switch (w->info) {
+               case LOGGEDIN:
+                       tp = localtime(&w->loginat);
+                       t = asctime(tp);
+                       tzn = tp->tm_zone;
+                       cpr = printf("On since %.16s (%s) on %s",
+                           t, tzn, 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 (delta->tm_yday || delta->tm_hour || delta->tm_min) {
+                               cpr += printf("%-*s idle ",
+                                   maxlen - 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)");
+                       break;
+               case LASTLOG:
+                       if (w->loginat == 0) {
+                               (void)printf("Never logged in.");
+                               break;
+                       }
+                       tp = localtime(&w->loginat);
+                       t = asctime(tp);
+                       tzn = tp->tm_zone;
+                       if (now - w->loginat > SECSPERDAY * DAYSPERNYEAR / 2)
+                               cpr =
+                                   printf("Last login %.16s %.4s (%s) on %s",
+                                   t, t + 20, tzn, w->tty);
+                       else
+                               cpr = printf("Last login %.16s (%s) on %s",
+                                   t, tzn, w->tty);
+                       break;
+               }
+               if (*w->host) {
+                       if (LINE_LEN < (cpr + 6 + strlen(w->host)))
+                               (void)printf("\n   ");
+                       (void)printf(" from %s", w->host);
+               }
+               putchar('\n');
+       }
+}
+
+demi_print(str, oddfield)
+       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);
+}
+
+show_text(directory, file_name, header)
+       char *directory, *file_name, *header;
+{
+       register int ch, lastc;
+       register FILE *fp;
+
+       (void)sprintf(tbuf, "%s/%s", directory, file_name);
+       if ((fp = fopen(tbuf, "r")) == NULL)
+               return(0);
+       (void)printf("%s\n", header);
+       while ((ch = getc(fp)) != EOF)
+               vputc(lastc = ch);
+       if (lastc != '\n')
+               (void)putchar('\n');
+       (void)fclose(fp);
+       return(1);
+}
+
+vputc(ch)
+       register int ch;
+{
+       int meta;
+
+       if (!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/usr/src/usr.bin/finger/net.c b/usr/src/usr.bin/finger/net.c
new file mode 100644 (file)
index 0000000..e78734c
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 1989 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)net.c      5.5 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <ctype.h>
+
+netfinger(name)
+       char *name;
+{
+       extern int lflag;
+       register FILE *fp;
+       register int c, lastc;
+       struct in_addr defaddr;
+       struct hostent *hp, def;
+       struct servent *sp;
+       struct sockaddr_in sin;
+       int s;
+       char *alist[1], *host, *rindex();
+       u_long inet_addr();
+
+       if (!(host = rindex(name, '@')))
+               return;
+       *host++ = NULL;
+       if (!(hp = gethostbyname(host))) {
+               defaddr.s_addr = inet_addr(host);
+               if (defaddr.s_addr == -1) {
+                       (void)fprintf(stderr,
+                           "finger: unknown host: %s\n", host);
+                       return;
+               }
+               def.h_name = host;
+               def.h_addr_list = alist;
+               def.h_addr = (char *)&defaddr;
+               def.h_length = sizeof(struct in_addr);
+               def.h_addrtype = AF_INET;
+               def.h_aliases = 0;
+               hp = &def;
+       }
+       if (!(sp = getservbyname("finger", "tcp"))) {
+               (void)fprintf(stderr, "finger: tcp/finger: unknown service\n");
+               return;
+       }
+       sin.sin_family = hp->h_addrtype;
+       bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
+       sin.sin_port = sp->s_port;
+       if ((s = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) {
+               perror("finger: socket");
+               return;
+       }
+
+       /* have network connection; identify the host connected with */
+       (void)printf("[%s]\n", hp->h_name);
+       if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+               perror("finger: connect");
+               (void)close(s);
+               return;
+       }
+
+       /* -l flag for remote fingerd  */
+       if (lflag)
+               write(s, "/W ", 3);
+       /* send the name followed by <CR><LF> */
+       (void)write(s, name, strlen(name));
+       (void)write(s, "\r\n", 2);
+
+       /*
+        * 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.
+        */ 
+       if (fp = fdopen(s, "r"))
+               while ((c = getc(fp)) != EOF) {
+                       c &= 0x7f;
+                       if (c == 0x0d) {
+                               c = '\n';
+                               lastc = '\r';
+                       } else {
+                               if (!isprint(c) && !isspace(c))
+                                       c |= 0x40;
+                               if (lastc != '\r' || c != '\n')
+                                       lastc = c;
+                               else {
+                                       lastc = '\n';
+                                       continue;
+                               }
+                       }
+                       putchar(c);
+               }
+       if (lastc != '\n')
+               putchar('\n');
+       (void)fclose(fp);
+}
diff --git a/usr/src/usr.bin/finger/sprint.c b/usr/src/usr.bin/finger/sprint.c
new file mode 100644 (file)
index 0000000..7842370
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 1989 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)sprint.c   5.8 (Berkeley) 12/4/90";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <tzfile.h>
+#include <stdio.h>
+#include "finger.h"
+
+extern int entries;
+
+sflag_print()
+{
+       extern time_t now;
+       register PERSON *pn;
+       register WHERE *w;
+       register int cnt;
+       register char *p;
+       PERSON **list, **sort();
+       time_t time();
+       char *ctime(), *prphone();
+
+       list = sort();
+       /*
+        * 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 moths,
+        *              show year instead of time.
+        *      office location
+        *      office phone
+        */
+#define        MAXREALNAME     20
+       (void)printf("%-*s %-*s %s\n", UT_NAMESIZE, "Login", MAXREALNAME,
+           "Name", "Tty  Idle  Login Time   Office     Office Phone");
+       for (cnt = 0; cnt < entries; ++cnt) {
+               pn = list[cnt];
+               for (w = pn->whead; w != NULL; w = w->next) {
+                       (void)printf("%-*.*s %-*.*s ", UT_NAMESIZE, UT_NAMESIZE,
+                           pn->name, MAXREALNAME, MAXREALNAME,
+                           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("%-2.2s ",
+                                   w->tty[0] != 't' || w->tty[1] != 't' ||
+                                   w->tty[2] != 'y' ? w->tty : w->tty + 3);
+                       else
+                               (void)printf("   ");
+                       if (w->info == LOGGEDIN) {
+                               stimeprint(w);
+                               (void)printf("  ");
+                       } else
+                               (void)printf("    *  ");
+                       p = ctime(&w->loginat);
+                       (void)printf("%.6s", p + 4);
+                       if (now - w->loginat >= SECSPERDAY * DAYSPERNYEAR / 2)
+                               (void)printf("  %.4s", p + 20);
+                       else
+                               (void)printf(" %.5s", p + 11);
+office:                        if (pn->office)
+                               (void)printf(" %-10.10s", pn->office);
+                       else if (pn->officephone)
+                               (void)printf(" %-10.10s", " ");
+                       if (pn->officephone)
+                               (void)printf(" %-.15s",
+                                   prphone(pn->officephone));
+                       putchar('\n');
+               }
+       }
+}
+
+PERSON **
+sort()
+{
+       register PERSON *pn, **lp;
+       PERSON **list;
+       int psort();
+       char *malloc();
+
+       if (!(list = (PERSON **)malloc((u_int)(entries * sizeof(PERSON *))))) {
+               (void)fprintf(stderr, "finger: out of space.\n");
+               exit(1);
+       }
+       for (lp = list, pn = phead; pn != NULL; pn = pn->next)
+               *lp++ = pn;
+       (void)qsort(list, entries, sizeof(PERSON *), psort);
+       return(list);
+}
+
+psort(p, t)
+       PERSON **p, **t;
+{
+       return(strcmp((*p)->name, (*t)->name));
+}
+
+stimeprint(w)
+       WHERE *w;
+{
+       register struct tm *delta;
+
+       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/usr/src/usr.bin/finger/util.c b/usr/src/usr.bin/finger/util.c
new file mode 100644 (file)
index 0000000..a2b6dd3
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 1989 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)util.c     5.14 (Berkeley) 1/17/91";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <paths.h>
+#include "finger.h"
+
+find_idle_and_ttywrite(w)
+       register WHERE *w;
+{
+       extern time_t now;
+       extern int errno;
+       struct stat sb;
+       char *strerror();
+
+       (void)sprintf(tbuf, "%s/%s", _PATH_DEV, w->tty);
+       if (stat(tbuf, &sb) < 0) {
+               (void)fprintf(stderr,
+                   "finger: %s: %s\n", tbuf, strerror(errno));
+               return;
+       }
+       w->idletime = now < sb.st_atime ? 0 : now - sb.st_atime;
+
+#define        TALKABLE        0220            /* tty is writable if 220 mode */
+       w->writable = ((sb.st_mode & TALKABLE) == TALKABLE);
+}
+
+userinfo(pn, pw)
+       register PERSON *pn;
+       register struct passwd *pw;
+{
+       register char *p, *t;
+       char *bp, name[1024];
+
+       pn->realname = pn->office = pn->officephone = pn->homephone = NULL;
+
+       pn->uid = pw->pw_uid;
+       pn->name = strdup(pw->pw_name);
+       pn->dir = strdup(pw->pw_dir);
+       pn->shell = strdup(pw->pw_shell);
+
+       /* why do we skip asterisks!?!? */
+       (void)strcpy(bp = tbuf, pw->pw_gecos);
+       if (*bp == '*')
+               ++bp;
+
+       /* ampersands get replaced by the login name */
+       if (!(p = strsep(&bp, ",")))
+               return;
+       for (t = name; *t = *p; ++p)
+               if (*t == '&') {
+                       (void)strcpy(t, pw->pw_name);
+                       if (islower(*t))
+                               *t = toupper(*t);
+                       while (*++t);
+               }
+               else
+                       ++t;
+       pn->realname = strdup(name);
+       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;
+}
+
+match(pw, user)
+       struct passwd *pw;
+       char *user;
+{
+       register char *p, *t;
+       char name[1024];
+
+       /* why do we skip asterisks!?!? */
+       (void)strcpy(p = tbuf, pw->pw_gecos);
+       if (*p == '*')
+               ++p;
+
+       /* ampersands get replaced by the login name */
+       if (!(p = strtok(p, ",")))
+               return(0);
+       for (t = name; *t = *p; ++p)
+               if (*t == '&') {
+                       (void)strcpy(t, pw->pw_name);
+                       while (*++t);
+               }
+               else
+                       ++t;
+       for (t = name; p = strtok(t, "\t "); t = (char *)NULL)
+               if (!strcasecmp(p, user))
+                       return(1);
+       return(0);
+}
+
+enter_lastlog(pn)
+       register PERSON *pn;
+{
+       register WHERE *w;
+       static int opened, fd;
+       struct lastlog ll;
+       char doit = 0;
+       off_t lseek();
+
+       /* some systems may not maintain lastlog, don't report errors. */
+       if (!opened) {
+               fd = open(_PATH_LASTLOG, O_RDONLY, 0);
+               opened = 1;
+       }
+       if (fd == -1 ||
+           lseek(fd, (long)pn->uid * sizeof(ll), L_SET) !=
+           (long)pn->uid * sizeof(ll) ||
+           read(fd, (char *)&ll, sizeof(ll)) != sizeof(ll)) {
+                       /* as if never logged in */
+                       ll.ll_line[0] = ll.ll_host[0] = NULL;
+                       ll.ll_time = 0;
+               }
+       if ((w = pn->whead) == NULL)
+               doit = 1;
+       else if (ll.ll_time != 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_time)
+                               doit = 1;
+               /*
+                * and if it's not any of the current logins
+                * can't use time comparison because there may be a small
+                * discrepency 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, UT_LINESIZE) == 0)
+                               doit = 0;
+       }
+       if (doit) {
+               w = walloc(pn);
+               w->info = LASTLOG;
+               bcopy(ll.ll_line, w->tty, UT_LINESIZE);
+               w->tty[UT_LINESIZE] = 0;
+               bcopy(ll.ll_host, w->host, UT_HOSTSIZE);
+               w->host[UT_HOSTSIZE] = 0;
+               w->loginat = ll.ll_time;
+       }
+}
+
+enter_where(ut, pn)
+       struct utmp *ut;
+       PERSON *pn;
+{
+       register WHERE *w = walloc(pn);
+
+       w->info = LOGGEDIN;
+       bcopy(ut->ut_line, w->tty, UT_LINESIZE);
+       w->tty[UT_LINESIZE] = 0;
+       bcopy(ut->ut_host, w->host, UT_HOSTSIZE);
+       w->host[UT_HOSTSIZE] = 0;
+       w->loginat = (time_t)ut->ut_time;
+       find_idle_and_ttywrite(w);
+}
+
+PERSON *
+enter_person(pw)
+       register struct passwd *pw;
+{
+       register PERSON *pn, **pp;
+
+       for (pp = htab + hash(pw->pw_name);
+            *pp != NULL && strcmp((*pp)->name, pw->pw_name) != 0;
+            pp = &(*pp)->hlink)
+               ;
+       if ((pn = *pp) == NULL) {
+               pn = palloc();
+               entries++;
+               if (phead == NULL)
+                       phead = ptail = pn;
+               else {
+                       ptail->next = pn;
+                       ptail = pn;
+               }
+               pn->next = NULL;
+               pn->hlink = NULL;
+               *pp = pn;
+               userinfo(pn, pw);
+               pn->whead = NULL;
+       }
+       return(pn);
+}
+
+PERSON *
+find_person(name)
+       char *name;
+{
+       register PERSON *pn;
+
+       /* name may be only UT_NAMESIZE long and not terminated */
+       for (pn = htab[hash(name)];
+            pn != NULL && strncmp(pn->name, name, UT_NAMESIZE) != 0;
+            pn = pn->hlink)
+               ;
+       return(pn);
+}
+
+hash(name)
+       register char *name;
+{
+       register int h, i;
+
+       h = 0;
+       /* name may be only UT_NAMESIZE long and not terminated */
+       for (i = UT_NAMESIZE; --i >= 0 && *name;)
+               h = ((h << 2 | h >> HBITS - 2) ^ *name++) & HMASK;
+       return(h);
+}
+
+PERSON *
+palloc()
+{
+       PERSON *p;
+
+       if ((p = (PERSON *)malloc((u_int) sizeof(PERSON))) == NULL) {
+               (void)fprintf(stderr, "finger: out of space.\n");
+               exit(1);
+       }
+       return(p);
+}
+
+WHERE *
+walloc(pn)
+       register PERSON *pn;
+{
+       register WHERE *w;
+
+       if ((w = (WHERE *)malloc((u_int) sizeof(WHERE))) == NULL) {
+               (void)fprintf(stderr, "finger: out of space.\n");
+               exit(1);
+       }
+       if (pn->whead == NULL)
+               pn->whead = pn->wtail = w;
+       else {
+               pn->wtail->next = w;
+               pn->wtail = w;
+       }
+       w->next = NULL;
+       return(w);
+}
+
+char *
+prphone(num)
+       char *num;
+{
+       register char *p;
+       int len;
+       static char pbuf[15];
+
+       /* 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 */
+               *p++ = 'x';
+               *p++ = *num++;
+               break;
+       default:
+               return(num);
+       }
+       *p++ = '-';
+       *p++ = *num++;
+       *p++ = *num++;
+       *p++ = *num++;
+       *p++ = *num++;
+       *p = '\0';
+       return(pbuf);
+}
diff --git a/usr/src/usr.bin/fmt/fmt.c b/usr/src/usr.bin/fmt/fmt.c
new file mode 100644 (file)
index 0000000..7ddc34e
--- /dev/null
@@ -0,0 +1,467 @@
+/*
+ * Copyright (c) 1980 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
+char copyright[] =
+"@(#) Copyright (c) 1980 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)fmt.c      5.10 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+#include <stdio.h>
+#include <ctype.h>
+
+/*
+ * fmt -- format the concatenation of input files or standard input
+ * onto standard output.  Designed for use with Mail ~|
+ *
+ * Syntax : fmt [ goal [ max ] ] [ name ... ]
+ * Authors: Kurt Shoens (UCB) 12/7/78;
+ *          Liz Allen (UMCP) 2/24/83 [Addition of goal length concept].
+ */
+
+/* LIZ@UOM 6/18/85 -- Don't need LENGTH any more.
+ * #define     LENGTH  72              Max line length in output
+ */
+#define        NOSTR   ((char *) 0)    /* Null string pointer for lint */
+
+/* LIZ@UOM 6/18/85 --New variables goal_length and max_length */
+#define GOAL_LENGTH 65
+#define MAX_LENGTH 75
+int    goal_length;            /* Target or goal line length in output */
+int    max_length;             /* Max line length in output */
+int    pfx;                    /* Current leading blank count */
+int    lineno;                 /* Current input line */
+int    mark;                   /* Last place we saw a head line */
+
+char   *malloc();              /* for lint . . . */
+char   *headnames[] = {"To", "Subject", "Cc", 0};
+
+/*
+ * Drive the whole formatter by managing input files.  Also,
+ * cause initialization of the output stuff and flush it out
+ * at the end.
+ */
+
+main(argc, argv)
+       int argc;
+       char **argv;
+{
+       register FILE *fi;
+       register int errs = 0;
+       int number;             /* LIZ@UOM 6/18/85 */
+
+       goal_length = GOAL_LENGTH;
+       max_length = MAX_LENGTH;
+       setout();
+       lineno = 1;
+       mark = -10;
+       /*
+        * LIZ@UOM 6/18/85 -- Check for goal and max length arguments 
+        */
+       if (argc > 1 && (1 == (sscanf(argv[1], "%d", &number)))) {
+               argv++;
+               argc--;
+               goal_length = number;
+               if (argc > 1 && (1 == (sscanf(argv[1], "%d", &number)))) {
+                       argv++;
+                       argc--;
+                       max_length = number;
+               }
+       }
+       if (max_length <= goal_length) {
+               fprintf(stderr, "Max length must be greater than %s\n",
+                       "goal length");
+               exit(1);
+       }
+       if (argc < 2) {
+               fmt(stdin);
+               oflush();
+               exit(0);
+       }
+       while (--argc) {
+               if ((fi = fopen(*++argv, "r")) == NULL) {
+                       perror(*argv);
+                       errs++;
+                       continue;
+               }
+               fmt(fi);
+               fclose(fi);
+       }
+       oflush();
+       exit(errs);
+}
+
+/*
+ * Read up characters from the passed input file, forming lines,
+ * doing ^H processing, expanding tabs, stripping trailing blanks,
+ * and sending each line down for analysis.
+ */
+fmt(fi)
+       FILE *fi;
+{
+       char linebuf[BUFSIZ], canonb[BUFSIZ];
+       register char *cp, *cp2;
+       register int c, col;
+
+       c = getc(fi);
+       while (c != EOF) {
+               /*
+                * Collect a line, doing ^H processing.
+                * Leave tabs for now.
+                */
+               cp = linebuf;
+               while (c != '\n' && c != EOF && cp-linebuf < BUFSIZ-1) {
+                       if (c == '\b') {
+                               if (cp > linebuf)
+                                       cp--;
+                               c = getc(fi);
+                               continue;
+                       }
+                       if ((c < ' ' || c >= 0177) && c != '\t') {
+                               c = getc(fi);
+                               continue;
+                       }
+                       *cp++ = c;
+                       c = getc(fi);
+               }
+               *cp = '\0';
+
+               /*
+                * Toss anything remaining on the input line.
+                */
+               while (c != '\n' && c != EOF)
+                       c = getc(fi);
+               
+               /*
+                * Expand tabs on the way to canonb.
+                */
+               col = 0;
+               cp = linebuf;
+               cp2 = canonb;
+               while (c = *cp++) {
+                       if (c != '\t') {
+                               col++;
+                               if (cp2-canonb < BUFSIZ-1)
+                                       *cp2++ = c;
+                               continue;
+                       }
+                       do {
+                               if (cp2-canonb < BUFSIZ-1)
+                                       *cp2++ = ' ';
+                               col++;
+                       } while ((col & 07) != 0);
+               }
+
+               /*
+                * Swipe trailing blanks from the line.
+                */
+               for (cp2--; cp2 >= canonb && *cp2 == ' '; cp2--)
+                       ;
+               *++cp2 = '\0';
+               prefix(canonb);
+               if (c != EOF)
+                       c = getc(fi);
+       }
+}
+
+/*
+ * Take a line devoid of tabs and other garbage and determine its
+ * blank prefix.  If the indent changes, call for a linebreak.
+ * If the input line is blank, echo the blank line on the output.
+ * Finally, if the line minus the prefix is a mail header, try to keep
+ * it on a line by itself.
+ */
+prefix(line)
+       char line[];
+{
+       register char *cp, **hp;
+       register int np, h;
+
+       if (strlen(line) == 0) {
+               oflush();
+               putchar('\n');
+               return;
+       }
+       for (cp = line; *cp == ' '; cp++)
+               ;
+       np = cp - line;
+
+       /*
+        * The following horrible expression attempts to avoid linebreaks
+        * when the indent changes due to a paragraph.
+        */
+       if (np != pfx && (np > pfx || abs(pfx-np) > 8))
+               oflush();
+       if (h = ishead(cp))
+               oflush(), mark = lineno;
+       if (lineno - mark < 3 && lineno - mark > 0)
+               for (hp = &headnames[0]; *hp != (char *) 0; hp++)
+                       if (ispref(*hp, cp)) {
+                               h = 1;
+                               oflush();
+                               break;
+                       }
+       if (!h && (h = (*cp == '.')))
+               oflush();
+       pfx = np;
+       if (h)
+               pack(cp);
+       else    split(cp);
+       if (h)
+               oflush();
+       lineno++;
+}
+
+/*
+ * Split up the passed line into output "words" which are
+ * maximal strings of non-blanks with the blank separation
+ * attached at the end.  Pass these words along to the output
+ * line packer.
+ */
+split(line)
+       char line[];
+{
+       register char *cp, *cp2;
+       char word[BUFSIZ];
+       int wordl;              /* LIZ@UOM 6/18/85 */
+
+       cp = line;
+       while (*cp) {
+               cp2 = word;
+               wordl = 0;      /* LIZ@UOM 6/18/85 */
+
+               /*
+                * Collect a 'word,' allowing it to contain escaped white
+                * space. 
+                */
+               while (*cp && *cp != ' ') {
+                       if (*cp == '\\' && isspace(cp[1]))
+                               *cp2++ = *cp++;
+                       *cp2++ = *cp++;
+                       wordl++;/* LIZ@UOM 6/18/85 */
+               }
+
+               /*
+                * Guarantee a space at end of line. Two spaces after end of
+                * sentence punctuation. 
+                */
+               if (*cp == '\0') {
+                       *cp2++ = ' ';
+                       if (index(".:!", cp[-1]))
+                               *cp2++ = ' ';
+               }
+               while (*cp == ' ')
+                       *cp2++ = *cp++;
+               *cp2 = '\0';
+               /*
+                * LIZ@UOM 6/18/85 pack(word); 
+                */
+               pack(word, wordl);
+       }
+}
+
+/*
+ * Output section.
+ * Build up line images from the words passed in.  Prefix
+ * each line with correct number of blanks.  The buffer "outbuf"
+ * contains the current partial line image, including prefixed blanks.
+ * "outp" points to the next available space therein.  When outp is NOSTR,
+ * there ain't nothing in there yet.  At the bottom of this whole mess,
+ * leading tabs are reinserted.
+ */
+char   outbuf[BUFSIZ];                 /* Sandbagged output line image */
+char   *outp;                          /* Pointer in above */
+
+/*
+ * Initialize the output section.
+ */
+setout()
+{
+       outp = NOSTR;
+}
+
+/*
+ * Pack a word onto the output line.  If this is the beginning of
+ * the line, push on the appropriately-sized string of blanks first.
+ * If the word won't fit on the current line, flush and begin a new
+ * line.  If the word is too long to fit all by itself on a line,
+ * just give it its own and hope for the best.
+ *
+ * LIZ@UOM 6/18/85 -- If the new word will fit in at less than the
+ *     goal length, take it.  If not, then check to see if the line
+ *     will be over the max length; if so put the word on the next
+ *     line.  If not, check to see if the line will be closer to the
+ *     goal length with or without the word and take it or put it on
+ *     the next line accordingly.
+ */
+
+/*
+ * LIZ@UOM 6/18/85 -- pass in the length of the word as well
+ * pack(word)
+ *     char word[];
+ */
+pack(word,wl)
+       char word[];
+       int wl;
+{
+       register char *cp;
+       register int s, t;
+
+       if (outp == NOSTR)
+               leadin();
+       /*
+        * LIZ@UOM 6/18/85 -- change condition to check goal_length; s is the
+        * length of the line before the word is added; t is now the length
+        * of the line after the word is added
+        *      t = strlen(word);
+        *      if (t+s <= LENGTH) 
+        */
+       s = outp - outbuf;
+       t = wl + s;
+       if ((t <= goal_length) ||
+           ((t <= max_length) && (t - goal_length <= goal_length - s))) {
+               /*
+                * In like flint! 
+                */
+               for (cp = word; *cp; *outp++ = *cp++);
+               return;
+       }
+       if (s > pfx) {
+               oflush();
+               leadin();
+       }
+       for (cp = word; *cp; *outp++ = *cp++);
+}
+
+/*
+ * If there is anything on the current output line, send it on
+ * its way.  Set outp to NOSTR to indicate the absence of the current
+ * line prefix.
+ */
+oflush()
+{
+       if (outp == NOSTR)
+               return;
+       *outp = '\0';
+       tabulate(outbuf);
+       outp = NOSTR;
+}
+
+/*
+ * Take the passed line buffer, insert leading tabs where possible, and
+ * output on standard output (finally).
+ */
+tabulate(line)
+       char line[];
+{
+       register char *cp;
+       register int b, t;
+
+       /*
+        * Toss trailing blanks in the output line.
+        */
+       cp = line + strlen(line) - 1;
+       while (cp >= line && *cp == ' ')
+               cp--;
+       *++cp = '\0';
+       
+       /*
+        * Count the leading blank space and tabulate.
+        */
+       for (cp = line; *cp == ' '; cp++)
+               ;
+       b = cp-line;
+       t = b >> 3;
+       b &= 07;
+       if (t > 0)
+               do
+                       putc('\t', stdout);
+               while (--t);
+       if (b > 0)
+               do
+                       putc(' ', stdout);
+               while (--b);
+       while (*cp)
+               putc(*cp++, stdout);
+       putc('\n', stdout);
+}
+
+/*
+ * Initialize the output line with the appropriate number of
+ * leading blanks.
+ */
+leadin()
+{
+       register int b;
+       register char *cp;
+
+       for (b = 0, cp = outbuf; b < pfx; b++)
+               *cp++ = ' ';
+       outp = cp;
+}
+
+/*
+ * Save a string in dynamic space.
+ * This little goodie is needed for
+ * a headline detector in head.c
+ */
+char *
+savestr(str)
+       char str[];
+{
+       register char *top;
+
+       top = malloc(strlen(str) + 1);
+       if (top == NOSTR) {
+               fprintf(stderr, "fmt:  Ran out of memory\n");
+               exit(1);
+       }
+       strcpy(top, str);
+       return (top);
+}
+
+/*
+ * Is s1 a prefix of s2??
+ */
+ispref(s1, s2)
+       register char *s1, *s2;
+{
+
+       while (*s1++ == *s2)
+               ;
+       return (*s1 == '\0');
+}
diff --git a/usr/src/usr.bin/fold/fold.c b/usr/src/usr.bin/fold/fold.c
new file mode 100644 (file)
index 0000000..44c8561
--- /dev/null
@@ -0,0 +1,152 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kevin Ruddy.
+ *
+ * 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
+char copyright[] =
+"@(#) Copyright (c) 1990 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)fold.c     5.5 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+#include <stdio.h>
+#include <string.h>
+
+#define        DEFLINEWIDTH    80
+
+main(argc, argv)
+       int argc;
+       char **argv;
+{
+       extern int errno, optind;
+       extern char *optarg;
+       register int ch;
+       int width;
+       char *p;
+
+       width = -1;
+       while ((ch = getopt(argc, argv, "0123456789w:")) != EOF)
+               switch (ch) {
+               case 'w':
+                       if ((width = atoi(optarg)) <= 0) {
+                               (void)fprintf(stderr,
+                                   "fold: illegal width value.\n");
+                               exit(1);
+                       }
+                       break;
+               case '0': case '1': case '2': case '3': case '4':
+               case '5': case '6': case '7': case '8': case '9':
+                       if (width == -1) {
+                               p = argv[optind - 1];
+                               if (p[0] == '-' && p[1] == ch && !p[2])
+                                       width = atoi(++p);
+                               else
+                                       width = atoi(argv[optind] + 1);
+                       }
+                       break;
+               default:
+                       (void)fprintf(stderr,
+                           "usage: fold [-w width] [file ...]\n");
+                       exit(1);
+               }
+       argv += optind;
+       argc -= optind;
+
+       if (width == -1)
+               width = DEFLINEWIDTH;
+       if (!*argv)
+               fold(width);
+       else for (; *argv; ++argv)
+               if (!freopen(*argv, "r", stdin)) {
+                       (void)fprintf(stderr,
+                           "fold: %s: %s\n", *argv, strerror(errno));
+                       exit(1);
+               } else
+                       fold(width);
+       exit(0);
+}
+
+fold(width)
+       register int width;
+{
+       register int ch, col, new;
+
+       for (col = 0;;) {
+               switch (ch = getchar()) {
+               case EOF:
+                       return;
+               case '\b':
+                       new = col ? col - 1 : 0;
+                       break;
+               case '\n':
+               case '\r':
+                       new = 0;
+                       break;
+               case '\t':
+                       new = (col + 8) & ~7;
+                       break;
+               default:
+                       new = col + 1;
+                       break;
+               }
+
+               if (new > width) {
+                       putchar('\n');
+                       col = 0;
+               }
+               putchar(ch);
+
+               switch (ch) {
+               case '\b':
+                       if (col > 0)
+                               --col;
+                       break;
+               case '\n':
+               case '\r':
+                       col = 0;
+                       break;
+               case '\t':
+                       col += 8;
+                       col &= ~7;
+                       break;
+               default:
+                       ++col;
+                       break;
+               }
+       }
+}