Initial checkin. This version of the sources matches that used to

build the GNO v2.0.4 distribution.
This commit is contained in:
gdr-ftp 1998-03-09 15:30:26 +00:00
parent 784e3de7cd
commit 31e9970070
16 changed files with 2467 additions and 0 deletions

37
usr.bin/alarm/alarm.1 Normal file
View File

@ -0,0 +1,37 @@
alarm (1)
NAME
alarm - alarm clock reminder
SYNOPSIS
alarm [+]#### [<delay> ["<message>"]]
DESCRIPTION
alarm is a reminder program. Typically it is executed in the
background. The program sleeps until the alarm time, and so
uses very little CPU.
The first argument defines the time, or time delay, for the
alarm to ring. It must consist of an optional leading plus
sign followed by four decimal digits. If the plus sign is
present the alarm will ring in 'hhmm' hours. If the plus sign
is absent, the alarm will ring at time 'hhmm' in 24-hour
format. The alarm rings five times, each time delivering a
beep, with beeps two seconds apart. The second argument, if
present, changes the time between beeps. The third argument,
if present, is echoed to stdout after each beep as a reminder
message.
EXAMPLES
alarm +0080 5 "Your TV show is on in five minutes" &
rings the bell every five seconds and delivers the
message eighty minutes after the current time.
alarm 1955
rings the bell every two seconds at 7:55 PM
FILES
none
AUTHOR
Christopher Neufeld (neufeld@physics.utoronto.ca)

83
usr.bin/alarm/alarm.c Normal file
View File

@ -0,0 +1,83 @@
/* Alarm v1.0. Copyright 1994 by Christopher Neufeld */
#include <stdio.h>
#include <gno/gno.h>
#include <stdlib.h>
#include <stddef.h>
#include <time.h>
#include <ctype.h>
#pragma stacksize 512
#define BEEP putchar((char)0x07)
#define TBEEPS 2 /* Time between beeps in seconds */
#define MAXBEEPS 5
#define SECSPERDAY (60 * 60 * 24)
#define DIGTOI(x) ((int) ((x) - '0'))
void usage(char *exename)
{
fprintf(stderr, "Alarm program. Copyright 1994 by Christopher Neufeld\n");
fprintf(stderr, "Usage: %s [+]#### [<delay> [\"<message>\"]]\n", exename);
fprintf(stderr, "Where #### is a time in hhmm format, ie. 0010 is ten past midnight\n");
fprintf(stderr, " +#### indicates that number of hhmm after the current time.\n");
fprintf(stderr, " delay is the time delay between beeps or messages, if any.\n");
fprintf(stderr, " message is delivered to stdout at alarm condition\n\n");
fprintf(stderr, "This executable contains linked runtime libraries copyrighted\n");
fprintf(stderr, "by The Byte Works. Used with Permission.\n\n");
exit(1);
}
int main(int argc, char **argv)
{
char *ptr1, *tptr, *msg;
static struct tm timenow, timethen;
static time_t curtime, alarmtime;
static int i, mins, hrs, offset, message, deltat;
unsigned long initwait;
message = 0;
deltat = TBEEPS;
if (argc < 2 || argc > 4) usage(argv[0]);
if (argc > 2) {
deltat = (int) strtoul(argv[2], &ptr1, 0);
if (*ptr1 != 0) usage(argv[0]); /* Unable to parse delay time */
if (argc == 4) {
msg = argv[3];
message = 1;
}
}
tptr = argv[1] + (offset = (argv[1][0] == '+'));
if (strlen(tptr) != 4) usage(argv[0]);
for (i=0;i<4;i++)
if (!isdigit(tptr[i])) usage(argv[0]);
hrs = 10 * DIGTOI(tptr[0]) + DIGTOI(tptr[1]);
mins = atoi(tptr + 2);
if (mins > 59) {
if (offset) hrs++;
else usage(argv[0]);
}
if (hrs > 23 && !offset) usage(argv[0]);
if (!offset) {
curtime = time(NULL);
timethen = *localtime(&curtime);
timethen.tm_sec = 0;
timethen.tm_min = mins;
timethen.tm_hour = hrs;
alarmtime = mktime(&timethen);
initwait = difftime(alarmtime, curtime);
if (initwait <= 0) initwait += SECSPERDAY;
} else initwait = 60 * (mins + 60 * hrs);
sleep(initwait);
for (i=0;i<MAXBEEPS;i++) {
BEEP;
fflush(stdout);
if (message) printf("%s\n", msg);
sleep(deltat);
}
exit(0);
}

253
usr.bin/aw30/aw30.c Normal file
View File

@ -0,0 +1,253 @@
#pragma keep "AppleWorks"
#pragma stacksize 2048
#pragma optimize -1
#include <stdio.h>
#include <stdlib.h>
#pragma lint -1
#define PROG_VERSION "0.70"
#define DATE "11/21/92"
FILE *f;
char SFMinVers; /* Minimum AppleWorks Version required */
int MultRulers; /* Boolean - Multiple Rulers */
char Ruler[80]; /* Ruler for Tab Stops */
int *input;
int lcv;
int *ID1, *ID2;
char Center; /* Boolean - Centering on */
char Codes; /* Boolean - Special Codes switch */
char NewPage; /* Boolean - Use New Page */
char LeftMargin; /* Size of left margin (tenths of an inch) */
char RightMargin; /* Size of right margin (tenths of an inch) */
char PlatenWidth; /* Width of platen (tenths of an inch) */
char argument;
char ShowNames; /* Boolean - Show names of file being processed */
void usage (void)
{
fprintf (stderr, " Version %s (%s)\n", PROG_VERSION, DATE);
fprintf (stderr, " Robert Hill\n");
fprintf (stderr, " INTERNET: rhill@oread.cc.ukans.edu\n AOL: RobertHill\n\n");
fprintf (stderr, "Usage: appleworks [-cn] filename\n");
}
int initialize (void)
{
fseek (f, 4L, SEEK_SET);
*input = (char) fgetc (f);
if (*input != 79) {
fprintf (stderr, "appleworks: File is not an AppleWorks file.\n");
return -1;
}
for (lcv = 0; lcv < 80; ++lcv) {
Ruler [lcv] = (char) fgetc (f);
if (Ruler[lcv] == EOF) {
fprintf (stderr, "appleworks: File is corrupted.\n");
return -1;
}
}
fseek (f, 177L, SEEK_SET);
MultRulers = (char) fgetc (f);
fseek (f, 184L, SEEK_SET);
SFMinVers = (char) fgetc (f);
fseek (f, 300L, SEEK_SET);
return 0;
}
int TextLine (void)
{
char indent;
int length;
float location;
*input = (char) fgetc (f);
if (*input == EOF)
return -1;
indent = (*input & 127);
for (lcv = 0; lcv < indent; ++ lcv)
printf (" ");
*input = (char) fgetc (f);
if (*input == EOF)
return -1;
length = (*input) & 127;
if (Center) {
location = (((PlatenWidth - RightMargin - LeftMargin) / 10.0) -
length) / 2.0;
for (lcv = 0; lcv < (int) location; ++ lcv)
printf (" ");
}
for (lcv = 0; lcv < length; ++ lcv) {
*input = (char) fgetc (f);
if (*input == EOF)
return -1;
else if (((*input) > 0x18) && ((*input) <= 0x7F))
printf ("%c", *input);
else switch (*input) {
case 0x01 : printf ("%c", 15); /* Boldface on */
break;
case 0x02 : printf ("%c", 14); /* Boldface off */
break;
case 0x07 : printf ("%c", 15); /* Underline on */
break;
case 0x08 : printf ("%c", 14); /* Underline off */
break;
case 0x16 : printf (" ");
++indent;
while ((Ruler[indent]=='=') && (indent < 81)) {
printf (" "); /* Tab */
++indent;
}
break;
}
}
printf("\n");
}
void HandleCommand (int *ID1, int *ID2)
{
switch (*ID2) {
case 0xD8 : PlatenWidth = *ID1;
if (Codes)
printf ("---Platen Width=%.1f inches\n",
(float) (PlatenWidth / 10));
break;
case 0xD9 : LeftMargin = *ID1;
if (Codes)
printf ("---Left Margin=%.1f inches\n",
(float) (LeftMargin / 10));
break;
case 0xDA : RightMargin = *ID1;
if (Codes)
printf ("---Right Margin=%.1f inches\n",
(float) (RightMargin / 10));
break;
case 0xE0 : Center = 0;
if (Codes)
printf ("---Unjustified\n");
break;
case 0xE1 : Center = 1;
if (Codes)
printf ("---Center\n");
break;
case 0xE9 : if (NewPage)
printf ("%c", 12);
break;
}
}
int main (int argc, char **argv)
{
argument = 1;
Codes = NewPage = ShowNames = 0;
input = (int *) malloc (sizeof(int));
ID1 = (int *) malloc (sizeof(int));
ID2 = (int *) malloc (sizeof(int));
if (argc == 1)
usage ();
else {
while (argc > argument) {
Center = 0;
LeftMargin = RightMargin = 10;
PlatenWidth = 80;
if ((argument == 1) && (argv[1][0] == '-')) {
lcv = 1;
while (argv[1][lcv] != 0x00) {
switch (argv[1][lcv]) {
case 'c' : Codes = 1;
break;
case 'n' : NewPage = 1;
break;
case 's' : ShowNames = 1;
break;
}
++lcv;
}
if (argc > 2) {
++argument;
f = fopen (argv[2], "rb");
if (f == NULL) {
fprintf (stderr,
"appleworks: Could not open %s.\n",
argv[2]);
return -1;
}
else if (ShowNames)
printf ("appleworks: %s\n\n", argv[2]);
}
else {
usage ();
return 0;
}
}
else {
f = fopen (argv[argument], "rb");
if (f == NULL) {
fprintf (stderr, "appleworks: Could not open %s.\n",
argv[argument]);
return -1;
}
else if (ShowNames)
printf ("appleworks: %s\n\n", argv[argument]);
}
if (initialize () == -1)
return -1;
while ((!((*ID1==0xFF) && (*ID2==0xFF))) &&
(!((*ID1==EOF) || (*ID2==EOF)))) {
*ID1 = fgetc (f);
*ID2 = fgetc (f);
if ((*ID1 != EOF) && (*ID2 != EOF)) {
if (*ID2==0x00)
if (TextLine () == -1) {
fprintf (stderr,
"appleworks: %s is corrupted.\n",
argv[argument]);
return -1;
}
if (*ID2==0xD0)
printf ("\n");
if ((*ID2) > 0xD0)
HandleCommand (ID1, ID2);
}
}
*ID1 = *ID2 = 0;
++argument;
printf ("\n");
fclose (f);
}
}
return 0;
}

3
usr.bin/banner/Makefile Normal file
View File

@ -0,0 +1,3 @@
banner: banner.c
compile banner.c keep=banner
link banner 2/direct256 keep=banner

1169
usr.bin/banner/banner.c Normal file

File diff suppressed because it is too large Load Diff

40
usr.bin/banner/banner.man Normal file
View File

@ -0,0 +1,40 @@
BANNER(6) MISCELLANEOUS BANNER(6)
NAME
banner - print large banner on printer
SYNOPSIS
/usr/games/banner [ -w n ] message ...
DESCRIPTION
Banner prints a large, high quality banner on the standard
output. If the message is omitted, it prompts for and reads
one line of its standard input. If -w is given, the output
is scrunched down from a width of 132 to n , suitable for a
narrow terminal. If n is omitted, it defaults to 80.
The output should be printed on a hard-copy device, up to
132 columns wide, with no breaks between the pages. The
volume is great enough that you may want a printer or a fast
hardcopy terminal, but if you are patient, a decwriter or
other 300 baud terminal will do.
BUGS
Several ASCII characters are not defined, notably <, >, [,
], \,^, _, {, }, |, and ~. Also, the characters ", ', and &
are funny looking (but in a useful way.)
The -w option is implemented by skipping some rows and
columns. The smaller it gets, the grainier the output.
Sometimes it runs letters together.
AUTHOR
Mark Horton
ACKNOWLEDGEMENTS
Copyright (c) 1980 The Regents of the University of
California. All rights reserved. This product includes
software developed by the University of California, Berkeley
and its contributors

5
usr.bin/cal/Makefile Normal file
View File

@ -0,0 +1,5 @@
cal.a: cal.cc
compile cal.cc keep=cal
cal: cal.a
link cal 2/direct256 keep=cal

223
usr.bin/cal/cal.c Normal file
View File

@ -0,0 +1,223 @@
/* static char rcsid[] = "$Header: /nobackup/gdr/copy-of-cvs-from-tekarra/gno/usr.bin/cal/cal.c,v 1.1 1998/03/09 15:29:53 gdr-ftp Exp $";
#ifdef __ORCAC__
#pragma stacksize 1024
#pragma optimize 8
#endif
#ifndef lint
static char sccsid[] = "@(#)cal.c 4.3 (Berkeley) 83/08/11";
#endif */
#include <stdio.h>
char dayw[] = {
" S M Tu W Th F S"
};
char *smon[]= {
"January", "February", "March", "April",
"May", "June", "July", "August",
"September", "October", "November", "December",
};
char string[432];
char *progname;
main(argc, argv)
char *argv[];
{
register y, i, j;
int m;
extern int _INITGNOSTDIO(void);
_INITGNOSTDIO();
/* setvbuf(stdout, NULL,_IOFBF, 1024l); */
progname = argv[0];
if(argc < 2) {
fprintf(stderr, "usage: %s [month] year\n",progname);
exit(0);
}
if(argc == 2)
goto xlong;
/*
* print out just month
*/
m = number(argv[1]);
if(m<1 || m>12)
goto badarg;
y = number(argv[2]);
if(y<1 || y>9999)
goto badarg;
printf(" %s %u\n", smon[m-1], y);
printf("%s\n", dayw);
cal(m, y, string, 24);
for(i=0; i<6*24; i+=24)
pstr(string+i, 24);
exit(0);
/*
* print out complete year
*/
xlong:
y = number(argv[1]);
if(y<1 || y>9999)
goto badarg;
printf("\n\n\n");
printf(" %u\n", y);
printf("\n");
for(i=0; i<12; i+=3) {
for(j=0; j<6*72; j++)
string[j] = '\0';
printf(" %.3s", smon[i]);
printf(" %.3s", smon[i+1]);
printf(" %.3s\n", smon[i+2]);
printf("%s %s %s\n", dayw, dayw, dayw);
cal(i+1, y, string, 72);
cal(i+2, y, string+23, 72);
cal(i+3, y, string+46, 72);
for(j=0; j<6*72; j+=72)
pstr(string+j, 72);
}
printf("\n\n\n");
exit(0);
badarg:
printf("Bad argument\n");
}
number(str)
char *str;
{
register n, c;
register char *s;
n = 0;
s = str;
while(c = *s++) {
if(c<'0' || c>'9')
return(0);
n = n*10 + c-'0';
}
return(n);
}
pstr(str, n)
char *str;
{
register i;
register char *s;
s = str;
i = n;
while(i--)
if(*s++ == '\0')
s[-1] = ' ';
i = n+1;
while(i--)
if(*--s != ' ')
break;
s[1] = '\0';
printf("%s\n", str);
}
char mon[] = {
0,
31, 29, 31, 30,
31, 30, 31, 31,
30, 31, 30, 31,
};
cal(m, y, p, w)
char *p;
{
register d, i;
register char *s;
s = p;
d = jan1(y);
mon[2] = 29;
mon[9] = 30;
switch((jan1(y+1)+7-d)%7) {
/*
* non-leap year
*/
case 1:
mon[2] = 28;
break;
/*
* 1752
*/
default:
mon[9] = 19;
break;
/*
* leap year
*/
case 2:
;
}
for(i=1; i<m; i++)
d += mon[i];
d %= 7;
s += 3*d;
for(i=1; i<=mon[m]; i++) {
if(i==3 && mon[m]==19) {
i += 11;
mon[m] += 11;
}
if(i > 9)
*s = i/10+'0';
s++;
*s++ = i%10+'0';
s++;
if(++d == 7) {
d = 0;
s = p+w;
p = s;
}
}
}
/*
* return day of the week
* of jan 1 of given year
*/
jan1(yr)
{
register y, d;
/*
* normal gregorian calendar
* one extra day per four years
*/
y = yr;
d = 4+y+(y+3)/4;
/*
* julian calendar
* regular gregorian
* less three days per 400
*/
if(y > 1800) {
d -= (y-1701)/100;
d += (y-1601)/400;
}
/*
* great calendar changeover instant
*/
if(y > 1752)
d += 3;
return(d%7);
}

4
usr.bin/calendar/README Normal file
View File

@ -0,0 +1,4 @@
To install the calendar program, create a file called "Calendar" in your
home directory, and put a line:
:bin:calendar
in your "gshrc" file.

View File

@ -0,0 +1,21 @@
CALENDAR(1) CALENDAR(1)
NAME
calendar - reminder service
SYNOPSIS
calendar
DESCRIPTION
calendar consults the file calendar in the current directory and prints
out lines that contain today's or tomorrow's date anywhere in the line.
Most reasonable month-day dates such as ``Aug. 24,'' ``august 24,''
``8/24,'' etc., are recognized, but not ``24 August'' or ``24/8''. On
weekends ``tomorrow'' extends through Monday.
BUGS
calendar's extended idea of ``tomorrow'' does not account for holidays.
Page 1 Release 4.0.5 May 1992

View File

@ -0,0 +1,82 @@
/* Calendar file v1.0. Copyright 1994 by Christopher Neufeld */
/* The executable for this file contains linked runtime libraries
copyrighted by The Byte Works. Used with permission. */
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <time.h>
#include <ctype.h>
#pragma stacksize 512
#define NMONTHS 12
#define NDAYS 31
#define MAXLINELEN 255
#define CALFILE "calendar"
#define SECSPERDAY (24 * 60 * 60)
const char months[NMONTHS][] = {"jan", "feb", "mar", "apr", "may", "jun",
"jul", "aug", "sep", "oct", "nov", "dec"};
int main(void)
{
FILE *ifile;
time_t t1, t2;
struct tm st1, st2;
int monthnum, daynum, dayschk, i, j;
char *ptr1, *ptr2, holdmnth[4];
static char thislin[MAXLINELEN+1];
long deltat;
if ((ifile = fopen(CALFILE, "r")) == NULL) exit(0);
t1 = time(NULL);
st1 = *localtime(&t1);
st1.tm_sec = st1.tm_min = st1.tm_hour = 0;
t1 = mktime(&st1);
dayschk = (st1.tm_wday >= 5) ? 8 - st1.tm_wday : 1;
thislin[MAXLINELEN] = 0;
while (!feof(ifile)) {
fgets(thislin, MAXLINELEN, ifile);
ptr1 = thislin;
while (isspace(*ptr1) && *ptr1 != 0) ptr1++;
if (*ptr1 == 0) continue; /* Blank line */
monthnum = -1;
if (isdigit(*ptr1)) { /* month/day format */
monthnum = strtoul(ptr1, &ptr2, 10) - 1;
daynum = strtoul(ptr2+1, NULL, 10);
if (monthnum < 0 || monthnum >= NMONTHS || daynum < 0 || daynum > NDAYS)
continue;
} else {
for (i=0; i<3; i++) holdmnth[i] = tolower(ptr1[i]);
holdmnth[3] = 0;
for (i = 0; i < NMONTHS; i++)
if (!(strcmp(holdmnth, months[i]))) {
monthnum = i;
break;
}
if (monthnum == -1) continue;
while (!isspace(*ptr1) && *ptr1 != 0) ptr1++;
if (*ptr1 == 0) continue;
while (isspace(*ptr1) && *ptr1 != 0) ptr1++;
if (*ptr1 == 0) continue;
daynum = atoi(ptr1);
if (daynum < 1 || daynum > NDAYS) continue;
}
st2.tm_sec = st2.tm_min = st2.tm_hour = st2.tm_isdst = 0;
st2.tm_mday = daynum;
st2.tm_mon = monthnum;
st2.tm_year = st1.tm_year;
t2 = mktime(&st2);
if ((deltat = difftime(t2, t1)) < 0) { /* Next year */
st2.tm_year++;
t2 = mktime(&st2);
deltat = difftime(t2, t1);
}
if (deltat <= dayschk * SECSPERDAY) printf(thislin);
}
fclose(ifile);
exit(0);
}

View File

@ -0,0 +1,2 @@
Dec 25 No more shopping days until Christmas.
Jul 1 A Canadian holiday

152
usr.bin/fold/fold.c Normal file
View File

@ -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;
}
}
}

5
usr.bin/tsort/Makefile Normal file
View File

@ -0,0 +1,5 @@
tsort.a: tsort.c
compile tsort.c keep=tsort
tsort: tsort.a
link tsort 2/direct256 keep=tsort

8
usr.bin/tsort/testtsort Normal file
View File

@ -0,0 +1,8 @@
a b
b c
c f
c o
o m
m d
f b

380
usr.bin/tsort/tsort.c Normal file
View File

@ -0,0 +1,380 @@
/*
* Copyright (c) 1989 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Michael Rendell of Memorial University of Newfoundland.
*
* 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.
*/
#ifdef __ORCAC__
#pragma stacksize 3072
#pragma optimize -1
#endif
#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[] = "@(#)tsort.c 5.3 (Berkeley) 6/1/90";
#endif /* not lint */
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
/*
* Topological sort. Input is a list of pairs of strings seperated by
* white space (spaces, tabs, and/or newlines); strings are written to
* standard output in sorted order, one per line.
*
* usage:
* tsort [inputfile]
* If no input file is specified, standard input is read.
*
* Should be compatable with AT&T tsort HOWEVER the output is not identical
* (i.e. for most graphs there is more than one sorted order, and this tsort
* usually generates a different one then the AT&T tsort). Also, cycle
* reporting seems to be more accurate in this version (the AT&T tsort
* sometimes says a node is in a cycle when it isn't).
*
* Michael Rendell, michael@stretch.cs.mun.ca - Feb 26, '90
*/
#define HASHSIZE 53 /* doesn't need to be big */
#define NF_MARK 0x1 /* marker for cycle detection */
#define NF_ACYCLIC 0x2 /* this node is cycle free */
typedef struct node_str NODE;
struct node_str {
char *n_name; /* name of this node */
NODE **n_prevp; /* pointer to previous node's n_next */
NODE *n_next; /* next node in graph */
NODE *n_hash; /* next node in hash table */
int n_narcs; /* number of arcs in n_arcs[] */
int n_arcsize; /* size of n_arcs[] array */
NODE **n_arcs; /* array of arcs to other nodes */
int n_refcnt; /* # of arcs pointing to this node */
int n_flags; /* NF_* */
};
typedef struct _buf {
char *b_buf;
int b_bsize;
} BUF;
NODE *add_node(char *), *find_node(char *);
void add_arc(char *,char *), no_memory(void), remove_node(NODE *), tsort(void);
char *grow_buf(char *, int);
char *strdup(char*);
extern int errno;
NODE *graph;
NODE *hashtable[HASHSIZE];
NODE **cycle_buf;
NODE **longest_cycle;
int main(int argc, char **argv)
{
register BUF *b;
register int c, n;
FILE *fp;
int bsize, nused;
BUF bufs[2];
if (argc < 2)
fp = stdin;
else if (argc > 2) {
(void)fprintf(stderr, "usage: tsort [ inputfile ]\n");
exit(1);
} else if (!(fp = fopen(argv[1], "r"))) {
(void)fprintf(stderr, "tsort: %s.\n", strerror(errno));
exit(1);
}
for (b = bufs, n = 2; --n >= 0; b++)
b->b_buf = grow_buf((char *)NULL, b->b_bsize = 1024);
/* parse input and build the graph */
for (n = 0, c = getc(fp);;) {
while (c != EOF && isspace(c))
c = getc(fp);
if (c == EOF)
break;
nused = 0;
b = &bufs[n];
bsize = b->b_bsize;
do {
b->b_buf[nused++] = c;
if (nused == bsize) {
bsize *= 2;
b->b_buf = grow_buf(b->b_buf, bsize);
}
c = getc(fp);
} while (c != EOF && !isspace(c));
b->b_buf[nused] = '\0';
b->b_bsize = bsize;
if (n)
add_arc(bufs[0].b_buf, bufs[1].b_buf);
n = !n;
}
(void)fclose(fp);
if (n) {
(void)fprintf(stderr, "tsort: odd data count.\n");
exit(1);
}
/* do the sort */
tsort();
exit(0);
}
/* double the size of oldbuf and return a pointer to the new buffer. */
char *grow_buf(char *bp, int size)
{
if (!(bp = realloc(bp, (u_int)size)))
no_memory();
return(bp);
}
/*
* add an arc from node s1 to node s2 in the graph. If s1 or s2 are not in
* the graph, then add them.
*/
void add_arc(char *s1, char *s2)
{
register NODE *n1;
NODE *n2;
int bsize;
n1 = find_node(s1);
if (!n1)
n1 = add_node(s1);
if (!strcmp(s1, s2))
return;
n2 = find_node(s2);
if (!n2)
n2 = add_node(s2);
/*
* could check to see if this arc is here already, but it isn't
* worth the bother -- there usually isn't and it doesn't hurt if
* there is (I think :-).
*/
if (n1->n_narcs == n1->n_arcsize) {
if (!n1->n_arcsize)
n1->n_arcsize = 10;
bsize = n1->n_arcsize * sizeof(*n1->n_arcs) * 2;
n1->n_arcs = (NODE **)grow_buf((char *)n1->n_arcs, bsize);
n1->n_arcsize = bsize / sizeof(*n1->n_arcs);
}
n1->n_arcs[n1->n_narcs++] = n2;
++n2->n_refcnt;
}
int hash_string(char *s)
{
register int hash, i;
for (hash = 0, i = 1; *s; s++, i++)
hash += *s * i;
return(hash % HASHSIZE);
}
/*
* find a node in the graph and return a pointer to it - returns null if not
* found.
*/
NODE *find_node(char *name)
{
register NODE *n;
for (n = hashtable[hash_string(name)]; n; n = n->n_hash)
if (!strcmp(n->n_name, name))
return(n);
return((NODE *)NULL);
}
/* Add a node to the graph and return a pointer to it. */
NODE *add_node(char *name)
{
register NODE *n;
int hash;
if (!(n = (NODE *)malloc(sizeof(NODE))) || !(n->n_name = strdup(name)))
no_memory();
n->n_narcs = 0;
n->n_arcsize = 0;
n->n_arcs = (NODE **)NULL;
n->n_refcnt = 0;
n->n_flags = 0;
/* add to linked list */
if (n->n_next = graph)
graph->n_prevp = &n->n_next;
n->n_prevp = &graph;
graph = n;
/* add to hash table */
hash = hash_string(name);
n->n_hash = hashtable[hash];
hashtable[hash] = n;
return(n);
}
/* do topological sort on graph */
void tsort(void)
{
register NODE *n, *next;
register int cnt;
while (graph) {
/*
* keep getting rid of simple cases until there are none left,
* if there are any nodes still in the graph, then there is
* a cycle in it.
*/
do {
for (cnt = 0, n = graph; n; n = next) {
next = n->n_next;
if (n->n_refcnt == 0) {
remove_node(n);
++cnt;
}
}
} while (graph && cnt);
if (!graph)
break;
if (!cycle_buf) {
/*
* allocate space for two cycle logs - one to be used
* as scratch space, the other to save the longest
* cycle.
*/
for (cnt = 0, n = graph; n; n = n->n_next)
++cnt;
cycle_buf =
(NODE **)malloc((u_int)sizeof(NODE *) * cnt);
longest_cycle =
(NODE **)malloc((u_int)sizeof(NODE *) * cnt);
if (!cycle_buf || !longest_cycle)
no_memory();
}
for (n = graph; n; n = n->n_next)
if (!(n->n_flags & NF_ACYCLIC)) {
if (cnt = find_cycle(n, n, 0, 0)) {
register int i;
(void)fprintf(stderr,
"tsort: cycle in data.\n");
for (i = 0; i < cnt; i++)
(void)fprintf(stderr,
"tsort: %s.\n", longest_cycle[i]->n_name);
remove_node(n);
break;
} else
/* to avoid further checks */
n->n_flags = NF_ACYCLIC;
}
if (!n) {
(void)fprintf(stderr,
"tsort: internal error -- could not find cycle.\n");
exit(1);
}
}
}
/* print node and remove from graph (does not actually free node) */
void remove_node(NODE *n)
{
register NODE **np;
register int i;
(void)printf("%s\n", n->n_name);
for (np = n->n_arcs, i = n->n_narcs; --i >= 0; np++)
--(*np)->n_refcnt;
n->n_narcs = 0;
*n->n_prevp = n->n_next;
if (n->n_next)
n->n_next->n_prevp = n->n_prevp;
}
/* look for the longest cycle from node from to node to. */
int find_cycle(NODE *from, NODE *to, int longest_len, int depth)
{
register NODE **np;
register int i, len;
/*
* avoid infinite loops and ignore portions of the graph known
* to be acyclic
*/
if (from->n_flags & (NF_MARK|NF_ACYCLIC))
return(0);
from->n_flags = NF_MARK;
for (np = from->n_arcs, i = from->n_narcs; --i >= 0; np++) {
cycle_buf[depth] = *np;
if (*np == to) {
if (depth + 1 > longest_len) {
longest_len = depth + 1;
(void)memcpy((char *)longest_cycle,
(char *)cycle_buf,
longest_len * sizeof(NODE *));
}
} else {
len = find_cycle(*np, to, longest_len, depth + 1);
if (len > longest_len)
longest_len = len;
}
}
from->n_flags &= ~NF_MARK;
return(longest_len);
}
void no_memory(void)
{
(void)fprintf(stderr, "tsort: %s.\n", strerror(ENOMEM));
exit(1);
}