User Tools

Site Tools


os_cp:prog_filebasics_signals:solutions

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

os_cp:prog_filebasics_signals:solutions [2024/05/08 14:36] (current)
jkonczak utworzono
Line 1: Line 1:
 +~~Exercise.#​~~
 +<code c>
 +#include <​unistd.h>​
 +#include <​stdio.h>​
 +int main(int argc, char *argv[]){
 +    char buffer[256];​
 +    while(1){
 +        int length = read(STDIN_FILENO,​ buffer, 256);
 +        if(length == -1){
 +            perror(NULL);​
 +            return 1;
 +        }
 +        if(length == 0)
 +            break;
 +        write(STDOUT_FILENO,​ buffer, length);
 +    }
 +    return 0;
 +}
 +</​code>​
 +
 +~~Exercise.#​~~
 +<code c>
 +#include <​unistd.h>​
 +#include <​stdio.h>​
 +int readFile(){
 +    char buffer[256];​
 +    while(1){
 +        int length = read(STDIN_FILENO,​ buffer, 256);
 +        if(length == -1){
 +            perror(NULL);​
 +            return 1;
 +        }
 +        if(length == 0)
 +            return 0;
 +        write(STDOUT_FILENO,​ buffer, length);
 +    }
 +}
 +int main(int argc, char *argv[]){
 +    if(readFile())
 +        return -1;
 +    lseek(STDIN_FILENO,​ 0, SEEK_SET);
 +    if(readFile())
 +        return -1;
 +    return 0;
 +}
 +</​code>​
 +
 +~~Exercise.#​~~
 +<code c>
 +#include <​unistd.h>​
 +#include <​stdio.h>​
 +int main(int argc, char *argv[]){
 +    char buffer[256];​
 +    while(1){
 +        int length = read(4, buffer, 256);
 +        if(length == -1){
 +            perror(NULL);​
 +            return 1;
 +        }
 +        if(length == 0)
 +            break;
 +        write(STDOUT_FILENO,​ buffer, length);
 +    }
 +    return 0;
 +}
 +</​code>​
 +
 +
 +~~Exercise.#​~~
 +<code c>
 +#include <​unistd.h>​
 +#include <​fcntl.h>​
 +#include <​stdio.h>​
 +int main(int argc, char *argv[]){
 +    int fd = open("/​tmp/​z",​ O_RDONLY);
 +    if(fd == -1){
 +        perror(NULL);​
 +        return 1;
 +    }
 +    char buffer[256];​
 +    while(1){
 +        int length = read(fd, buffer, 256);
 +        if(length == -1){
 +            perror(NULL);​
 +            return 1;
 +        }
 +        if(length == 0)
 +            break;
 +        write(STDOUT_FILENO,​ buffer, length);
 +    }
 +    close(fd);
 +    return 0;
 +}
 +</​code>​
 +
 +~~Exercise.#​~~
 +<code c>
 +#include <​unistd.h>​
 +#include <​fcntl.h>​
 +#include <​stdio.h>​
 +int main(int argc, char *argv[]){
 +    int fd = open(argv[1],​ O_RDONLY);
 +    if(fd == -1){
 +        perror(NULL);​
 +        return 1;
 +    }
 +    char buffer[256];​
 +    while(1){
 +        int length = read(fd, buffer, 256);
 +        if(length == -1){
 +            perror(NULL);​
 +            return 1;
 +        }
 +        if(length == 0)
 +            break;
 +        write(STDOUT_FILENO,​ buffer, length);
 +    }
 +    close(fd);
 +    return 0;
 +}
 +</​code>​
 +
 +~~Exercise.#​~~
 +<code c>
 +#include <​unistd.h>​
 +#include <​fcntl.h>​
 +#include <​stdio.h>​
 +#include <​stdlib.h>​
 +#include <​string.h>​
 +
 +int main(int argc, char *argv[]){
 +    int fd = open(argv[1],​ O_RDONLY);
 +    if(fd == -1){
 +        perror(NULL);​
 +        return 1;
 +    }
 +    int num = 1;
 +    int printNumber = 1;
 +    while(1){
 +        char c;
 +        int count = read(fd, &c, 1);
 +        if(count == -1){
 +            perror(NULL);​
 +            return 1;
 +        }
 +        if(count == 0)
 +            break;
 +        if(printNumber){
 +            char numBuf[16];
 +            sprintf(numBuf,​ "%5d ", num++);
 +            write(STDOUT_FILENO,​ numBuf, strlen(numBuf));​
 +            printNumber=0;​
 +        }
 +        write(STDOUT_FILENO,​ &c, 1);
 +        if(c == '​\n'​)
 +            printNumber=1;​
 +    }
 +    close(fd);
 +    return 0;
 +}</​code>​
 +++++ The program above is intentionally made simple rather than efficient; the program below is more efficient, but has a few more lines. |
 +<code c>
 +#include <​unistd.h>​
 +#include <​fcntl.h>​
 +#include <​stdio.h>​
 +#include <​string.h>​
 +
 +void checkPrintNl(int *shallPrint,​ unsigned *number){
 +    if(!*shallPrint)
 +        return;
 +    char buf[12];
 +    sprintf(buf,​ "%5u ", (*number)++);​
 +    write(STDOUT_FILENO,​ buf, strlen(buf));​
 +    *shallPrint=0;​
 +}
 +
 +int main(int argc, char *argv[]){
 +    int fd = open(argv[1],​ O_RDONLY);
 +    if(fd == -1){
 +        perror(NULL);​
 +        return 1;
 +    }
 +    int printLineNum = 1;
 +    unsigned lineNum = 1;
 +    while(1){
 +        char buf[256];
 +        int length = read(fd, buf, 256);
 +        if(length == -1){
 +            perror(NULL);​
 +            return 1;
 +        }
 +        if(length == 0)
 +            break;
 +        char *it = buf, *nlPos;
 +        while( (nlPos = memchr(it, '​\n',​ length)) ){
 +            checkPrintNl(&​printLineNum,​ &​lineNum);​
 +            int partLen = nlPos+1-it;
 +            write(STDOUT_FILENO,​ it, partLen);
 +            length -= partLen;
 +            it = nlPos+1;
 +            printLineNum = 1;
 +        }
 +        if(length){
 +            checkPrintNl(&​printLineNum,​ &​lineNum);​
 +            write(STDOUT_FILENO,​ it, length);
 +        }
 +    }
 +    return 0;
 +}
 +</​code>​
 +++++
 +
 +~~Exercise.#​~~
 +<code c>
 +#include <​unistd.h>​
 +#include <​fcntl.h>​
 +#include <​stdio.h>​
 +#include <​string.h>​
 +
 +#define CHECK(result,​ textOnFail) \
 +if(result == -1){                 \
 +    perror(textOnFail); ​          \
 +    return 1;                     \
 +}
 +int main(int argc, char *argv[]){
 +    if(argc < 3){
 +        write(STDERR_FILENO,​ "Not enough arguments\n",​ 21);
 +        return 1;
 +    }
 +    int file1 = open(argv[1],​ O_RDONLY);
 +    CHECK(file1,​ argv[1]);
 +    int file2 = open(argv[2],​ O_RDONLY);
 +    CHECK(file2,​ argv[2]);
 +    while(1){
 +        char buf1[256], buf2[256];
 +        int len1 = read(file1, buf1, 256);
 +        CHECK(len1, argv[1]);
 +        int len2 = read(file2, buf2, 256);
 +        CHECK(len2, argv[2]);
 +        if(len1 != len2)
 +            break;
 +        if(len1 == 0){
 +            write(STDOUT_FILENO,​ "Files have the same contents\n",​ 29);
 +            return 0;
 +        }
 +        if(memcmp(buf1,​ buf2, len1))
 +            break;
 +    }
 +    write(STDOUT_FILENO,​ "Files differ\n",​ 13);
 +    return 0;
 +}
 +</​code>​
 +
 +~~Exercise.#​~~
 +<code c>
 +#include <​unistd.h>​
 +#include <​fcntl.h>​
 +#include <​stdio.h>​
 +#include <​stdlib.h>​
 +
 +int main(int argc, char *argv[]){
 +    ++argv; --argc; // get rid of program name; simplifies array indexes
 +    int *file = malloc(sizeof(int) * argc);
 +    int running = 0;
 +    for(int i = 0; i < argc; ++i){
 +        file[i] = open(argv[i],​ O_RDONLY);
 +        if(file[i] == -1)
 +            perror(argv[i]);​
 +        else
 +            running = 1;
 +    }
 +    while(running){
 +        running = 0;
 +        for(int i = 0; i < argc; ++i){
 +            while(file[i] != -1){
 +                char c;
 +                int l = read(file[i],​ &c, 1);
 +                if(l <= 0){
 +                    if(l == -1)
 +                        perror(argv[i]);​
 +                    close(file[i]);​
 +                    file[i] = -1;
 +                    break;
 +                }
 +                if(c == '​\n'​){
 +                    running = 1;
 +                    break;
 +                }
 +                write(STDOUT_FILENO,​ &c, 1);
 +            }
 +            write(STDOUT_FILENO,​ (i == argc-1) ? "​\n"​ : "​\t",​ 1);
 +        }
 +    }
 +    free(file);
 +    return 0;
 +}
 +</​code>​
 +++++ The program above is intentionally made simple rather than efficient; the program below is more efficient, but has more lines. |
 +NB: speedup of this program vs the one above is way beyond 100x 
 +<code c>
 +#include <​unistd.h>​
 +#include <​fcntl.h>​
 +#include <​stdio.h>​
 +#include <​string.h>​
 +#include <​stdlib.h>​
 +#include <​assert.h>​
 +
 +/** A few words of explanation:​ each '​read'​ and '​write'​ call involves
 + * the operating system. Calling the OS is expensive. Thus, I/O is
 + * usually buffered. This program buffers both input and output, but
 + * to buffer output and still use OS API, one has to buffer I/O oneself.
 + */
 +#define BUFSIZE 4096
 +
 +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ OUTPUT BUFFERING ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 +
 +struct { //< custom standard output buffer
 +    char b[2*BUFSIZE];​
 +    size_t c;
 +} outBuf;
 +
 +void flushOutput(){ //< writes out the standard output buffer
 +    if(outBuf.c != write(STDOUT_FILENO,​ outBuf.b, outBuf.c)){
 +        perror("​writing to output failed"​);​
 +        exit(1);
 +    }
 +    outBuf.c = 0;
 +}
 +
 +/** adds data to output buffer and outputs if buffer is sufficiently filled
 +  * @warning: this relies on an assumption that count never exceeds BUFSIZE */
 +void bufferOutput(char *data, size_t count){ ​
 +    assert(count <= BUFSIZE);
 +    memcpy(outBuf.b + outBuf.c, data, count);
 +    if((outBuf.c += count) >= BUFSIZE)
 +        flushOutput();​
 +}
 +
 +// ~ ~ ~ ~ ~ READING LINES FROM INPUT & BUFFERING INPUT ~ ~ ~ ~ ~
 +
 +struct myFile {  //< stores state & buffer of a file
 +    char *name; ​ //< used for diagnostics when read returns -1
 +    int fd;      //< once the file ends (or read fails), -1 is put here
 +    char buf[BUFSIZE];​
 +    int pos;     //<​ position where data in buf starts
 +    int count; ​  //<​ number of bytes in but from pos to end of data
 +};
 +
 +/// reads from file to buffer, ​
 +/// @returns 0 if any data was read, else returns 1
 +int readChunk(struct myFile *f){
 +    f->pos = 0;
 +    f->count = read(f->​fd,​ f->buf, BUFSIZE);
 +    if(f->​count<​=0){
 +        if(f->​count == -1)
 +            perror(f->​name);​
 +        close(f->​fd);​
 +        f->fd = -1;
 +        return 1;
 +    }
 +    return 0;
 +}
 +
 +/** reads and outputs a line from file,
 + * @returns 0 if there is any outstanding data in file, else returns 1 */
 +int readAndOutputLine(struct myFile *f){
 +    while(1){
 +        if(f->fd == -1)
 +            return 1;
 +        if(f->​count == 0)
 +            if(readChunk(f))
 +                return 1;
 +        char *nlPos, *startPos = f->​buf+f->​pos;​
 +        if( (nlPos = memchr(startPos,​ '​\n',​ f->​count)) ){
 +            int partLen = nlPos-startPos;​
 +            bufferOutput(startPos,​ partLen);
 +            f->​pos ​  += partLen+1;
 +            f->count -= partLen+1;
 +            if(f->​count)
 +                return 0;
 +            return readChunk(f);​
 +        }
 +        bufferOutput(startPos,​ f->​count);​
 +        f->count = 0;
 +    }
 +}
 +
 +// ~ ~ ~ ~ ~ OPENING FILES, LOOPING THROUGH LINES ~ ~ ~ ~ ~
 +
 +int main(int argc, char *argv[]){
 +    ++argv; --argc; // get rid of program name; simplifies array indexes
 +    struct myFile *myFiles = malloc(sizeof(myFiles) * argc);
 +    int allFilesEof = 1;
 +    for(int i = 0 ; i < argc; ++i){
 +        myFiles[i].fd = open(argv[i],​ O_RDONLY);
 +        if(myFiles[i].fd == -1)
 +            perror(argv[i]);​
 +        else {
 +            myFiles[i].name = argv[i];
 +            allFilesEof &= readChunk(myFiles+i);​
 +        }
 +    }
 +    while(!allFilesEof){
 +        allFilesEof = readAndOutputLine(myFiles);​
 +        for(int i = 1 ; i < argc; ++i){
 +            bufferOutput("​\t",​ 1);
 +            allFilesEof &= readAndOutputLine(myFiles+i);​
 +        }
 +        bufferOutput("​\n",​ 1);
 +    }
 +    free(myFiles);​
 +    flushOutput();​
 +    return 0;
 +}
 +</​code>​
 +++++
 +
 +~~Exercise.#​~~
 +<code c>
 +#include <​signal.h>​
 +#include <​stdio.h>​
 +#include <​stdlib.h>​
 +#include <​unistd.h>​
 +
 +void handleSignal(int num) {
 +  write(2, "​Shutting down...\n",​ 17);
 +  exit(1);
 +}
 +
 +int main() {
 +  signal(SIGINT,​ handleSignal);​
 +  while (1)
 +    getchar();
 +}
 +</​code>​
 +
 +~~Exercise.#​~~
 +<code c>
 +#include <​fcntl.h>​
 +#include <​signal.h>​
 +#include <​stdio.h>​
 +#include <​stdlib.h>​
 +#include <​time.h>​
 +#include <​unistd.h>​
 +
 +void writeDateTo(int fd) {
 +  struct timespec now;
 +  char buf[21];
 +  clock_gettime(CLOCK_REALTIME,​ &now);
 +  buf[20] = '​\n';​
 +  for (int i = 0; i < 10; ++i, now.tv_nsec /= 10)
 +    buf[19 - i] = '​0'​ + now.tv_nsec % 10;
 +  buf[10] = '​.';​
 +  for (int i = 0; i < 10; ++i, now.tv_sec /= 10)
 +    buf[9 - i] = '​0'​ + now.tv_sec % 10;
 +  write(fd, buf, 21);
 +}
 +
 +void handleSignal(int num) {
 +  int fd = open("​signal_log",​ O_WRONLY | O_APPEND | O_CREAT, 0666);
 +  writeDateTo(fd);​
 +  close(fd);
 +}
 +
 +int main() {
 +  signal(SIGUSR1,​ handleSignal);​
 +  while (1)
 +    getchar();
 +}
 +</​code>​
 +
 +
 +~~META:
 +language = en
 +~~
  
os_cp/prog_filebasics_signals/solutions.txt · Last modified: 2024/05/08 14:36 by jkonczak