> 
> Write the program `tail`, which prints the last `n` lines of its input. By default, `n` is 10, let us say, but it can be changed by an optional argument, si that
>  `tail -n`
>  prints the last `n` lines. The program should behave rationally no matter how unresonable the input or the value `n`. Write the program so it makes the best use of available storage; lines should be stored as in the sorting program of section 5.6, not in a two-dimensional array of fixed size.
> 
> 
> 

The exercise can be found on page 133 in K&R.

I will explain the way my program works. 
First it parses the value of the symbolic argument(if any). Based on the value of the symbolic argument the program will initialize a queue which stores pointer to each line.

Then, the program will read lines and push every line in the queue until the end of files is reached. When the end of file is reached all elements of the queue are printed out.

There are multiple files in my project:

`main.c`:

```
#include <stdio.h>
#include <stdlib.h>
#include "tail.h"

#define MAXLINES 100
#define LINESIZE 100

int main(int argc, char *argv[]) {
    int linesNumber = 10;

    if(argc > 2) {
        return 1;
    }
    else if(argc == 2) {
        linesNumber = atoi(argv[1] + 1);

        if(linesNumber == 0) {
            return 0;
        }

        initQueue(linesNumber, LINESIZE);
    }
    else {
        initQueue(linesNumber, LINESIZE);
    }

    readLines(LINESIZE, MAXLINES);

    printQueueElements();

    return 0;
}

```

`linesNumber` represent the variable that will store the size of the queue. By default this variable is `10`. If the value of the symbolic argument is `0` there is no reasone to continue reading lines, so the program will terminate execution.

`queue.c`

```
#include <stdio.h>
#include <string.h>
#include "alloc.h"

static char **queue;
static int queueSize;

static int head = -1;
static int rear = -1;

static int isEmpty(void) {
    return (head == -1 && rear == -1);
}

static int isFull(void) {
    return (rear + 1) % queueSize == head ? 1 : 0; 
}

void initQueue(int lineNumbers, int sizeOfEachLine) {
    int i;

    queue = palloc(lineNumbers);
    queueSize = lineNumbers;

    for(i = 0; i < lineNumbers; i++) {
        queue[i] = alloc(sizeOfEachLine);
    }
}

char *dequeue(void) {
    char *returnValue;

    if(isEmpty()) {
        return NULL;
    }
    else if(head == rear) {
        returnValue = queue[head];
        head = -1;
        rear = -1;

        return returnValue;
    }

    returnValue = queue[head];
    head = (head + 1) % queueSize;

    return returnValue;    
}

void enqueue(char *source) {
    if(isFull()) {
        dequeue();
    }

    if(isEmpty()) {
        rear = 0;
        head = 0;
    }
    else {
        rear = (rear + 1) % queueSize;
    }

    strcpy(queue[rear], source);
}

void printQueueElements(void) {
    while(!isEmpty()) {
        printf("%s", dequeue());
    }
}

```

This is an array based implementation of a queue. 
I use the circular array data structure for my queue.

When the queue is full, `enqueue` will call `dequeue` to make space for the incoming element. 

`printQueueElements` will `dequeue` each element and print it, since I don't need anymore the lines. 

`readlines.c`:

```
#include <stdio.h>
#include "alloc.h"
#include "tail.h"

static int getLine(char *source, int lim) {
    int c;
    int i;

    c = getchar();
    lim--; /* 1 space for null charachter  */

    for(i = 0; c != EOF && c != '\n' && lim > 0; i++, c = getchar(), lim--) {
        source[i] = c;
    }

    if(c == '\n') {
        source[i] = '\n';
        i++;
    }

    source[i] = '\0';
    return i;
}

void readLines(int lineSize, int maxLines) {
    char *temp = alloc(lineSize);

    for(; maxLines && getLine(temp, lineSize); maxLines--) {
        enqueue(temp);
    }
}

```

This function will read each line and `enqueue` it.

`alloc.c`

```
#include <stdio.h>

#define ALLOCSIZE 10000

static char allocBuf[ALLOCSIZE];
static char *allocp = allocBuf; /* next free position  */

char *alloc(int allocSize) {
    if(allocBuf + ALLOCSIZE - allocp >= allocSize) {
        allocp += allocSize;
        return allocp - allocSize;
    }
    else {
        return NULL;        
    }
}

```

This function will return a pointer to a block of `allocSize` `chars`.

`palloc.c`

```
#include <stdio.h>

#define BLOCKSIZE 100000

static char *sharedBlock[BLOCKSIZE];
static char **pSharedBlock = sharedBlock;

char **palloc(int size) {
    if(sharedBlock + BLOCKSIZE - pSharedBlock >= size) {
        pSharedBlock += size;
        return pSharedBlock - size;
    }
    else {
        return NULL;
    }
}

```

This function wil return a pointer to a block of `size` `pointers to char`.

`palloc` and `alloc` are used to set the size of the queue dynamically. The `malloc` function was not introduced at this point, so I don't think it will be a valid solution if I use this function.

`alloc.h`

```
char *alloc(int);
char **palloc(int);

```

`tail.h`

```
/* input functions */

void readLines(int lineSize, int maxLines);

/* queue related functions  */

void initQueue(int lineNumbers, int sizeOfEachElement);
void enqueue(char *source);
void printQueueElements(void);

char *dequeue(void);
int getSimbolicArgValue(char* source);

```