Question

In: Computer Science

Systems Programming - File Operations Create your version of the tail command in Linux using C...

Systems Programming - File Operations

Create your version of the tail command in Linux using C

The lseek system call allows you to move the current position anywhere in a file. The call lseek(fd, 0, SEEK_END) moves the current position to the end of the file.

The tail command displays the last ten liens of a file. Try it. tail has to move, not to the end of the file, but to a spot ten lines before the end of a file. The distance argument to lseek, though, is in units of characters (bytes).

How can tail work? Design your own version. Think about buffering to make your program efficient. Read the manual page to see all the options tail supports. How would those work? Designing this program seems, like who and cp, to be a straightforward project.

Solutions

Expert Solution

#include <stdio.h>
#include <stdlib.h>

#define DEFLINES 10
#define MAXBUFF  20000

int findTail(char *lines[][2], int nlines, char buff[], int maxbuff);

/* main() processes optional cli argument '-n', where n is a number of lines.
 * The default is 10.  findTail finds the last n lines from the input so that
 * they can be printed. */

main(int argc, char *argv[])
{
  int nlines; char *endptr;

  endptr = NULL;
  nlines = DEFLINES;
  if (argc > 2) {
    printf("error: too many arguments.\n");
    return EXIT_FAILURE;
  }
  else if (argc == 2) {
    if (*argv[1] == '-') {
      nlines = strtol(argv[1] + 1, &endptr, 10);
      if (*endptr != '\0') {
        printf("error: not a number of lines: %s\n", argv[1] + 1);
        return EXIT_FAILURE;
      }
    }
    else {
      printf("error: malformed argument: %s\n", argv[1]);
      return EXIT_FAILURE;
    }
  }

  int i;
  char *lines[nlines][2], buff[MAXBUFF];

  findTail(lines, nlines, buff, MAXBUFF);
  for (i=0; i < nlines; ++i) {
    if (lines[i][0] != NULL)
      printf(lines[i][0]);
    if (lines[i][1] != NULL)
      printf(lines[i][1]);
  }
}

#define TRUE     1
#define FALSE    0

void shift(char *lines[][2], int nlines);
void testForRoom(char *lines[][2], int index, char *buffp);

/* findTail stores characters from stdin in the buffer 'buff'. When it finds
 * the end of a line, it stores the pointer for the beginning of that line in
 * 'lines'. once nlines have been found, pointers to previous lines are shifted
 * off of the end of 'lines'. If there is space at the start of 'buff' not
 * pointed to by 'lines', then the end of a line that hits the end of the
 * buffer can continue its storage at the beginning of the buffer. This makes
 * the best use of a fixed-sized buffer for long input. */

int findTail(char *lines[][2], int nlines, char buff[], int maxbuff)
{
  char *buffp, *linestart;
  int i, c, wrap, nfound;

  for (i=0; i < nlines; ++i) {
    lines[i][0] = NULL; // [0] for storing line, or beginning of wrapped line
    lines[i][1] = NULL; // [1] for storing second half of a wrapped line
  }

  nfound = 0;
  wrap = FALSE;
  linestart = buffp = buff;
  while ((c=getchar()) != EOF) {
    if (buffp == linestart && wrap == FALSE) {
      if (nfound < nlines)
        ++nfound;
      shift(lines, nlines);
    }

    if (buffp - buff == maxbuff - 1) {
      *buffp = '\0';
      lines[nlines - 1][0] = linestart;
      wrap = TRUE;
      linestart = buffp = buff;
    }

    testForRoom(lines, nlines - nfound, buffp);

    *buffp++ = c;
    if (c == '\n') {
      *buffp++ = '\0';
      lines[nlines - 1][wrap] = linestart;
      wrap = FALSE;
      if (buffp - buff >= maxbuff - 1)
        buffp = buff;
      linestart = buffp;
    }

  }
  // this is in case the input ended without a newline.
  if (c == EOF && buffp != buff && buffp[-1] != '\0') {
    testForRoom(lines, nlines - nfound, buffp);
    *buffp = '\0';
    lines[nlines - 1][wrap] = linestart;
  }

}

/* shift is used upon finding a character that starts a new line. It shifts
 * line pointers in the pointer array to the left, making room for new line
 * pointer(s) and forgetting the pointer(s) for the oldest line in memory. */

void shift(char *lines[][2], int nlines)
{
  int i;
  for (i=0; i < nlines - 1; ++i) {
    lines[i][0] = lines[i + 1][0];
    lines[i][1] = lines[i + 1][1];
  }
  lines[nlines - 1][0] = NULL;
  lines[nlines - 1][1] = NULL;
}

/* testForRoom tests to see if the location for (or the location following the)
 * next character that would be placed in the buffer is pointed to by a line in
 * the lines pointer array. */

void testForRoom(char *lines[][2], int index, char *buffp) {
  if (buffp == lines[index][0]
      || buffp + 1 == lines[index][0]) {
    printf("error: not enough room in buffer.\n");
    exit(EXIT_FAILURE);
  }
}

Related Solutions

Systems Programming in Linux using C Remake the version of the ls -ialR command in C.....
Systems Programming in Linux using C Remake the version of the ls -ialR command in C.. In this version of ls, you must also consider symbolic file types. Make sure you have file header comments and function header comments. Also, write inline comments whenever necessary.
Linux Directories, File Properties, and the File System in C Understanding Unix/Linux Programming Your version of...
Linux Directories, File Properties, and the File System in C Understanding Unix/Linux Programming Your version of mv command The mv command is more than just a wrapper around the rename system call. Write a version of mv that accepts two argument. The first argument must be the name of a file, and the second argument may be the name of a file or the name of a directory. If the destination is the name of a directory, then mv moves...
Systems Programming - File Operations in Linux using C Preventing copying the same file What does...
Systems Programming - File Operations in Linux using C Preventing copying the same file What does the standard cp do if you try to copy a file onto itself? $ cp file1 file1 cp: 'file1' and 'file1' are the same file Modify cp1.c to handle the situation and include comments. /** * @file cp1.c * @brief Uses read and write with tunable buffer size * usage: cp1 src dest */ #include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <stdlib.h> #define BUFFERSIZE...
Linux Directories, File Properties, and the File System in C Code your version of mv command...
Linux Directories, File Properties, and the File System in C Code your version of mv command in C The mv command is more than just a wrapper around the rename system call. Write a version of mv that accepts two argument. The first argument must be the name of a file, and the second argument may be the name of a file or the name of a directory. If the destination is the name of a directory, then mv moves...
Linux Directories, File Properties, and the File System in C Your version of find command Try...
Linux Directories, File Properties, and the File System in C Your version of find command Try running the find command in the shell and observe the output. Try it in different folders to make sure you understand what it prints out. $ find Write your version of the find command and add comments.
unix/Linux Create a tar command using the man command and the link referred to in To...
unix/Linux Create a tar command using the man command and the link referred to in To Practice and Explore: Text File Utilities #9. Preliminaries Use the man pages to learn more about tar Review the links referred to in To Practice and Explore: Text File Utilities #9 to see examples of using tar command Perform Use tar "to stuff" three files and then "unstuff" them into a new directory. Include the -v option. Task ll to show the original 3...
a) b) c) Compare and contrast systems programming in Windows as against systems programming in Unix/Linux....
a) b) c) Compare and contrast systems programming in Windows as against systems programming in Unix/Linux. CR, 8 Explain the term structured exception handling (SEH) as used in systems programming and give a practical example of how it can be used to handle errors in a block of code. AP, 7 Write a C/C++ system program to delete an unwanted file in the Windows file system. Compile and run the program and copy the source code into your answer booklet....
This program is a simple version of the linux shell using execvp by forking using C...
This program is a simple version of the linux shell using execvp by forking using C Currently this program of the shell assumes user enters no spaces before and no extra spaces between strings. Using exec, an executable binary file (eg: a.out) can be converted into a process. An example of using exec is implementing a shell program or a command interpreter. A shell program takes user commands and executes them. int execvp(const char *file, char *const argv[]); Same as...
IN C PROGRAMMING LINUX how to use makefile to include .a static library and .h file...
IN C PROGRAMMING LINUX how to use makefile to include .a static library and .h file from another directory in C? I have a header file myheader.h and a static library libmylib.a file in directory1. In directory2, I'm writing a program which uses them. Suppose I have main.c in directory2 which uses myheader.h and libmylib.a. How do I create a Makefile to compile and link them? LIBB = -L/../directory1/libmylib.a HEADER = -L/../directory1/myheader.h main: main.o gcc $(HEADER) $(LIBB) main.o: main.c gcc...
Create by using Linux server • Create a file name it foo.txt • Remove all permissions...
Create by using Linux server • Create a file name it foo.txt • Remove all permissions from foo.txt • What happen if you try to read the file? • Change foo.txt permission to read and write only for owner • Change foo.txt permission to read for group • Change foo.txt permission to read and write everyone
ADVERTISEMENT
ADVERTISEMENT
ADVERTISEMENT