Историческая команда Unix V5 tr дополняет поведение set2, отличающихся от того, что мы рассматриваем сегодня “классической” System V (1983-1988) поведение?

wget проблема перенаправления может быть решена при помощи

wget --trust-server-names http://www.example.com/X?1234
5
04.01.2014, 06:59
1 ответ

Различие находится только в формулировке дополнительного поведения в руководстве V4-V5 - но поведение является тем же повсюду.как есть Результаты реализации V5 идентичны результату System V один, который самостоятельно идентичен GNU tr поведение с --truncate-set1 опция. Кроме того, "усечение set1 к длине set2" дает тот же результат как "дополняющий string2 с соответствующими символами от string1". Это означает то же самое на практике. Давайте продемонстрируем это.

Во-первых, Вы не должны быть разработчиком, чтобы попытаться скомпилировать это. Сравните исходный код с почти идентичной версией PWB/Unix. Вы будете видеть, что единственная разница зависимостью от "современных" stdio.h активов в основном, таким образом, я лишил источник ее ссылок на inbuf, fout, dup и flush и замененный оно тем, что PWB/Unix делает - но это никоим образом не должно изменять поведение, поскольку алгоритмы остаются нетронутыми. Я аннотировал тривиальные изменения, которые я внес из оригинала:

#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);
}

Так cc tr.c компиляции:

tr.c: In function ‘next’:
tr.c:118:4: warning: incompatible implicit declaration of built-in function ‘exit’ 
[enabled by default]
exit(0);
^

Но a.out там и работы, поэтому давайте теперь сравним дополнительное поведение этих двух программ, которые мы имеем:

TR GNU

#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 модификация

#./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

Таким образом, наша версия V5 ведет себя точно как версия System V в этом отношении. Кроме того, явно дополнение set2 с set1 приводит к тому же результату для всех реализаций, потому что это обеспечивает, чтобы set1 и set2 имели то же число элементов (и это - когда у Вас нет этого, которое результаты варьируются исторически).

Наконец, явно дополнение или наличие tr pad set2 with set1 как описано в оригинале V4-V5 руководства означает то же самое как truncating set1 to the length of set2 поскольку результаты затронуты - это - классическая реализация System V для дополнения и приводит к тем же результатам. V5 tr не другая реализация, несмотря на различие в страницах справочника.

4
27.01.2020, 20:40

Теги

Похожие вопросы