2017-02-06 14 views
0

Hi stackoverflow (ers)!Unix (in C) пытается написать хвост для XV6

Я учусь Unix с помощью xv6 ОС (документация нашли here) и пытался написать хвостовую функцию в С. Ожидаемый выход:

  1. хвост, чтобы дать последние 10 строк файл
  2. хвост - это дать последний из строк файла
  3. хвост ... чтобы дать последние 10 строк файлов ...
  4. хвост - ... чтобы дать последний линии ...
  5. gre p | tail должен дать последние 10 предложений, в которых содержатся

Я написал две версии хвоста, один из которых реализован с использованием char * [], а другой - путем записи в файл, а затем чтения из него (оба размещены ниже) Моя версия, которая реализует хвост с использованием char * [], кажется более точным для фактической команды. Однако в версии, где я пишу во временный файл, а затем читаю из него, я получаю больше строк в качестве вывода, и я не уверен, почему это происходит. Моя догадка заключается в том, что при чтении из одного файла и записи в другое место «\ n» перепуталось. Я был бы очень признателен за помощь в выяснении этого!

Пожалуйста, не сердитесь на меня, если я делаю что-то глупое. Я новичок в C в Unix и только пытаюсь учиться.

tail.c, используя символ * []

#include "types.h" 
#include "stat.h" 
#include "user.h" 
#include "fcntl.h" 

char buf [512]; 

void tail (int fd, int toSub) { 
    int n; 
    int numLines = 0; 
    int linesToPrint = 0; 
    char *buffer; 
    buffer = (char*) malloc (500000); 
    int buffSize = 0; 
    while ((n = read(fd, buf, sizeof(buf))) > 0) { 
    for (int i = 0; i<n; i++) { 
     buffer[buffSize] = (char)buf[i]; 
     buffSize++; 
     if(buf[i] == '\n') 
     numLines++; 
    } 
    } 
    if (n < 0) { 
    printf (1, "tail: read error \n"); 
    exit(); 
    } 
    if (numLines < toSub) 
    linesToPrint = 0; 
    linesToPrint = numLines - toSub; 

    int counter = 0; 
    for (int i = 0; i < buffSize; i++) { 
    if (counter >= linesToPrint) 
     printf(1,"%c",buffer[i]); 
    if (buffer[i] == '\n') 
     counter++; 
    } 
    free (buffer); 
} 

int main (int argc, char *argv[]) { 
    int toSub = 10; 
    int fd = -1; 

    if (argc <= 1) { 
    tail (0, toSub); 
    exit(); 
    } 
    else if (argc > 1 && argv[1][0] == '-') { 
    char getToSub [10]; 
    for (int k=1; k<strlen(argv[1]); k++) { 
     getToSub[k-1] = argv[1][k]; 
    } 
    toSub = (atoi)(getToSub); 
    } 
    else { 
    if((fd = open (argv[1], toSub)) < 0) { 
     printf (1, "tail: cannot open %s\n", argv[1]); 
     exit(); 
    } 
    tail (fd, toSub); 
    close (fd); 
    } 
    if (argc > 2) { 
    for (int i=2; i<argc; i++) { 
     if((fd = open (argv[i], 0)) < 0) { 
     printf (1, "tail: cannot open %s\n", argv[i]); 
     exit(); 
     } 
     else { 
     tail (fd, toSub); 
     close (fd); 
     } 
    } 
    } 
    exit(); 
} 

tail.c с помощью записи

#include "types.h" 
#include "stat.h" 
#include "user.h" 
#include "fcntl.h" 

char buf [512]; 

void tail (int fd, int toSub) { 
    int n; 
    int numLines; 
    int linesToPrint; 
    int ptrDump; 
    ptrDump = open ("tailDump", O_CREATE | O_RDWR); 
    while ((n = read(fd, buf, sizeof(buf))) > 0) { 
    write (ptrDump, buf, sizeof(buf)); 
    for (int i = 0; i<n; i++) { 
     if(buf[i] == '\n') 
     numLines++; 
    } 
    } 
    if (n < 0) { 
    printf (1, "tail: read error \n"); 
    exit(); 
    } 
    if (numLines < toSub) 
    linesToPrint = 0; 
    linesToPrint = numLines - toSub; 

    close (ptrDump); 
    ptrDump = open ("tailDump", 0); 

    int counter = 0; 
    while ((n = read(ptrDump, buf, sizeof(buf))) > 0) { 
    for (int i = 0; i<n; i++) { 
     if (counter > linesToPrint) 
     printf(1,"%c",buf[i]); 
     if (buf[i] == '\n') 
     counter++; 
     } 
    } 
    close (ptrDump); 
    unlink("tailDump"); 
} 

int main (int argc, char *argv[]) { 
    int toSub = 10; 
    int fd = -1; 

    if (argc <= 1) { 
    tail (0, toSub); 
    exit(); 
    } 
    else if (argc > 1 && argv[1][0] == '-') { 
    char getToSub [10]; 
    for (int k=1; k<strlen(argv[1]); k++) { 
     getToSub[k-1] = argv[1][k]; 
    } 
    toSub = (atoi)(getToSub); 
    } 
    else { 
    if((fd = open (argv[1], toSub)) < 0) { 
     printf (1, "tail: cannot open %s\n", argv[1]); 
     exit(); 
    } 
    tail (fd, toSub); 
    close (fd); 
    } 
    if (argc > 2) { 
    for (int i=2; i<argc; i++) { 
     if((fd = open (argv[i], 0)) < 0) { 
     printf (1, "tail: cannot open %s\n", argv[i]); 
     exit(); 
     } 
     else { 
     tail (fd, toSub); 
     close (fd); 
     } 
    } 
    } 
    exit(); 
} 

У меня есть код поставить на моем Github (нашел here), а также в tail_using_str.c и tail_using_file.c

ответ

2

Я думаю, ваша проблема здесь:

while ((n = read(fd, buf, sizeof(buf))) > 0) { 
    write (ptrDump, buf, sizeof(buf)); 

Вы читаете в n байт, но когда вы пишете, вы пишете sizeof(buf) байт. Другими словами, вы можете написать слишком много байтов.

Может быть, вы хотите вместо этого:

while ((n = read(fd, buf, sizeof(buf))) > 0) { 
    write (ptrDump, buf, n); 
         ^
         note 
+0

Это исправлено! большое спасибо! Теперь, когда я думаю об этом, он имеет такой смысл! Я обновил код и дал вам заслуженный кредит! (Https://github.com/AdityaSingh/XV6/tree/Tail) –

0

Пожалуйста, не сердитесь на меня, если я делаю что-то глупое. Я новичок в C в Unix и только пытаюсь учиться.

Таким образом, этот ответ не является абсолютно необходимым, поскольку основной вопрос, который вы задали, имеет already been answered. Ваш опубликованный вопрос фактически поднимает кучу вопросов, которые явным образом не задал, и я намереваюсь ответить здесь.

Ожидаемый выход: ... tail -, чтобы дать последний из строк файла

Согласно кто? Not according to POSIX и not according to UNIX V7, где впервые появился tail(1).

(ну, на самом деле tail(1) первый появился в PWB/UNIX, но это не был широко использован.)

grep | tail, чтобы дать последние 10 предложений, в которых содержатся

Вы имеете в виду в прошлом 10 строки, а не предложения. grep не производит предложений.

(За исключением советской Unix, где grep предложения вы!)

char *buffer;

buffer = (char*) malloc (500000);

Этот и следующий вызов exit создать утечку памяти. Вы можете сказать, что это безобидно, так как ОС вернет память на выход программы, но она неаккуратная, и такие инструменты, как Valgrind, вызовут вас на этом.

Либо free() ваши буферы, прежде чем все возможные точки выхода из функции, или объявить этот буфер в стеке вместо:

char buffer[500000] 

Вы не могли бы быть в состоянии объявить буфер, который большой в стеке, в зависимости от xv6. Общим современным пределом для размера стека является 2 MiB, и это для всего пакета, используемого всеми функциями в вашей самой глубокой цепочке вызовов. Это настраиваемые современные системы, но они не могут быть конфигурированы в xv6.

Если вы вынуждены идти с опцией malloc(), вы можете сделать это на одной строке:

char *buffer = (char*) malloc (500000); 

Дополнительно:

  • это плохой стиль, чтобы иметь buf и buffer , Ленивый. Дайте каждому буферу целевое имя, например lineBuf и accumBuf

  • buffSize смутно названо. Непонятно , на который ссылается буфер, и в любом случае это не размер буфера. Назовите это что-то вроде accumBytes, чтобы решить обе проблемы.

  • Вам не хватает пучки #includes, необходимых для современных POSIX-систем, и у вас есть некоторые, которые не работают на них. Я бы посмотрел, имеет ли xv6 stdio.h.h, stdlib.h, string.h и unistd.h и #include их для портативности POSIX. Я бы также посмотрел, можете ли вы #includetypes.h через sys/types.h, поскольку это необходимо хотя бы на macOS и, возможно, в других Unix. user.h не требуется для современных систем, поэтому, если вам это действительно не нужно на xv6, удалите его.

  • Входящий в память вариант считывает весь файл в ОЗУ и затем пропускает обратно в байтах в ОЗУ, который он не хочет печатать.Немного мысли покажет, как вы можете сократить размер буфера вниз и не сделать два прохода над входными данными. (Подсказка:.. accumBuf[toSub][sizeof(lineBuf)] Смело умножим второе слагаемое некоторой суммы, если вы хотите, чтобы линии больше, чем sizeof(lineBuf) байт)

if(buf[i] == '\n') numLines++;

Вы, вероятно, следует проверить для не - '\ n' байт в конце буфера накопления и добавьте еще одну строку для него. Строки без LF-терминаторов не совсем кошерны, но ожидания пользователя обычно таковы, что вы рассматриваете этот конечный фрагмент как строку.

printf (1, "tail: read error \n");

Что это 1, шум? Вы пытаетесь указать stdout? Это верно только для write, а не printf. printf() уже отправляет stdout. (Действительно, вы должны использовать fprintf() для отправки в любом месте.)

Поскольку это только в ваших случаях ошибок, это означает, что вы не должны тестировать ошибки.

Это еще одна причина для написания кода для переносимости POSIX, хотя вы в конечном счете нацелены на xv6: современные компиляторы системы Unix System намного более строгие относительно кода, который они готовы принять. Современные компиляторы C делают многое из того, что мы должны были использовать в таких инструментах, как lint.

exit()

exit(2) принимает параметр, код состояния выхода, традиционно 0 для чистого выхода и отлична от нуля для ошибки. Единственная причина, по которой ваш компилятор позволяет вам уйти, заключается в том, что ранние компиляторы C не строго проверяли список аргументов, заданный против объявленных параметров функции. На самом деле, xv6, вероятно, отправляет компилятор K & R, который даже не имеет функции прототипов для объявления списков параметров. Программист должен был поступать правильно, не будучи предупрежденным.

linesToPrint = numLines - toSub;

Это не "линии для печати", это "линия на пропустить печати". Мне потребовалось 5 минут, чтобы посмотреть на код, чтобы преодолеть это семантическое несоответствие. Компилятору все равно, но имена переменных не для компилятора. Если бы они были только для компилятора, мы просто называем их все a, b и т.д.

printf("%c",buffer[i]);

Используйте putchar() здесь.

int counter = 0;

Опять же, ленивый. Количество Что такое?

Я только на полпути через первую программу, но этого достаточно комментариев. Надеюсь, вы узнали кое-что из этого.

 Смежные вопросы

  • Нет связанных вопросов^_^