System V (by AT&T) is the ancestral Unix, and I have used it. But I have never read or heard anything about systems I-IV, other than they existed once upon a time in the dim past. How effective were they, and were they widespread? Is it possible to get one's hand on the code and/or install it? Does anyone here have any experience with these earlier systems?
Behold System V; what about systems I-IV
historical-unixhistorysystem-installationsystem-v
Related Solutions
This is mostly a historic matter, for a number of reasons:
Over the years, the System V based Unices have gotten a lot of BSD in them, and the BSDs have — to a lesser extent — adopted some System V features.
A lot of the differences simply don't matter any more, like XTI/TLI, having been beaten out in the market of ideas by BSD sockets.
The Unix market is consolidating. There are fewer weird nonstandard differences to deal with these days, and better tools for dealing with the ones that remain. One big area of difference is in how dynamic linkage works, for instance, but we have GNU libtool to deal with it now.
The best single resource I know of for learning about these sorts of differences is Advanced Programming in the Unix Environment by Stevens and Rago. If you have a special interest in networking and IPC, add in Stevens' Unix Network Programming, volume 1 and volume 2.
If you already have an earlier edition of APUE, it's still useful. The main thing the second edition added was explicit coverage of Linux and OS X, but since these are based on Unix, you could still puzzle out how to apply the information. The third edition updates this classic again for recent OS versions and adds some new material.
The difference is only in the wording of the padding behavior in the V4-V5 manual - but the behavior is the same throughout. As it stands the results of the V5 implementation is
identical to that of the System V one, which is itself identical to the GNU tr
behavior with the --truncate-set1
option. Furthermore, "truncating set1 to the lenght of set2" gives the same result as "padding string2 with corresponding characters from string1". It means the same thing in practice. Let's demonstrate this.
First, you need not be a developer to try to compile this. Compare the source code with the almost identical PWB/Unix version. You will see the only difference being reliance on the "modern" stdio.h assets basically, so I've stripped the source of its references to inbuf
, fout
, dup
and flush
and replaced it with what PWB/Unix does - but this in no way should alter the behavior as the algorithms remain untouched. I've annotated the trivial changes I've made from the original:
#include <stdio.h> <------ added
int dflag = 0; <------ added "=" sign to those
int sflag = 0;
int cflag = 0;
int save = 0;
char code[256];
char squeez[256];
char vect[256];
struct string { int last, max, rep; char *p; } string1, string2;
FILE *input; <------ part of the stdio framework I guess;
main(argc,argv)
char **argv;
{
int i, j;
int c, d;
char *compl;
string1.last = string2.last = 0;
string1.max = string2.max = 0;
string1.rep = string2.rep = 0;
string1.p = string2.p = "";
if(--argc>0) {
argv++;
if(*argv[0]=='-'&&argv[0][1]!=0) {
while(*++argv[0])
switch(*argv[0]) {
case 'c':
cflag++;
continue;
case 'd':
dflag++;
continue;
case 's':
sflag++;
continue;
}
argc--;
argv++;
}
}
if(argc>0) string1.p = argv[0];
if(argc>1) string2.p = argv[1];
for(i=0; i<256; i++)
code[i] = vect[i] = 0;
if(cflag) {
while(c = next(&string1))
vect[c&0377] = 1;
j = 0;
for(i=1; i<256; i++)
if(vect[i]==0) vect[j++] = i;
vect[j] = 0;
compl = vect;
}
for(i=0; i<256; i++)
squeez[i] = 0;
for(;;){
if(cflag) c = *compl++;
else c = next(&string1);
if(c==0) break;
d = next(&string2);
if(d==0) d = c;
code[c&0377] = d;
squeez[d&0377] = 1;
}
while(d = next(&string2))
squeez[d&0377] = 1;
squeez[0] = 1;
for(i=0;i<256;i++) {
if(code[i]==0) code[i] = i;
else if(dflag) code[i] = 0;
}
input = stdin; <------ again stdio
while((c=getc(input)) != EOF ) { <------
if(c == 0) continue;
if(c = code[c&0377]&0377)
if(!sflag || c!=save || !squeez[c&0377])
putchar(save = c);
}
}
next(s)
struct string *s;
{
int a, b, c, n;
int base;
if(--s->rep > 0) return(s->last);
if(s->last < s->max) return(++s->last);
if(*s->p=='[') {
nextc(s);
s->last = a = nextc(s);
s->max = 0;
switch(nextc(s)) {
case '-':
b = nextc(s);
if(b<a || *s->p++!=']')
goto error;
s->max = b;
return(a);
case '*':
base = (*s->p=='0')?8:10;
n = 0;
while((c = *s->p)>='0' && c<'0'+base) {
n = base*n + c - '0';
s->p++;
}
if(*s->p++!=']') goto error;
if(n==0) n = 1000;
s->rep = n;
return(a);
default:
error:
write(1,"Bad string\n",11);
exit(0); <------original was exit();
}
}
return(nextc(s));
}
nextc(s)
struct string *s;
{
int c, i, n;
c = *s->p++;
if(c=='\\') {
i = n = 0;
while(i<3 && (c = *s->p)>='0' && c<='7') {
n = n*8 + c - '0';
i++;
s->p++;
}
if(i>0) c = n;
else c = *s->p++;
}
if(c==0) *--s->p = 0;
return(c&0377);
}
So cc tr.c
compiles:
tr.c: In function ‘next’:
tr.c:118:4: warning: incompatible implicit declaration of built-in function ‘exit’
[enabled by default]
exit(0);
^
But a.out is there and works, so let's now compare the padding behavior of the two programs we have:
GNU tr
#tr 0123456789 d
0123456789 input
dddddddddd output <----- BSD classic behavior
#tr 0123456789 d123456789 <----- padding set2 with set1 explicitly
0123456789 i
d123456789 o
01234567890123456789 i
d123456789d123456789 o
#tr -t 0123456789 d <----- --truncate-set1 i.e. System V behavior
0123456789 i
d123456789 o <----- concretely, this is what is meant by a result
0012 i where set2 was padded with set1
dd12 o
#tr -t 0123456789 d123456789 <----- padding set2 with set1 explicitly
0123456789 i
d123456789 o <----- note this is identical to the last results
Unix V5 tr + stdio mod
#./a.out 0123456789 d <----- our compiled version with the classic example
0123456789 i
d123456789 o
./a.out 0123456789 d123456789 <----- padding set2 with set1 explicitly
0123456789 i
d123456789 o
So our V5 version behaves exactly like the System V version in that respect. Furthermore explicitly padding set2 with set1 yields the same result for all implementations because it insures that set1 and set2 have the same number of elements (and it's when you don't have this that results vary historically).
Finally, explicitly padding or having tr
pad set2 with set1
as described in the original V4-V5 manuals means the same thing as truncating set1 to the length of set2
insofar as results are concerned - it IS the classic System V implementation for padding and yields the same results. V5 tr
is not a different implementation, despite the difference in the man pages.
Related Question
- POSIX Compliance – Is Linux ARG_MAX Different from Other System Variables?
- What’s this I hear about First Edition Unix being restored
- What’s special about “!xxx%s%s%s%s%s%s%s%s”
- How Do Pipelines Limit Memory Usage? – Detailed Explanation
- What ever became of the “prep” program? And what can I use instead on modern Linux systems
Best Answer
According to wikipedia System V was preceded by System III, a release of UNIX/TS 3. Since there were no official release of UNIX/TS 4, System III was superseded directly by System V.