Home > Net >  I want to create my own tail command with using getline and wihout use of lseek and fseek
I want to create my own tail command with using getline and wihout use of lseek and fseek

Time:07-22

I implemented below code but i want tailbuf[] should be in order. I want tailbuf[9] should be last line, tailbuf[8] second and so on. Please help me how i cant implement that in this code.

#include<stdio.h>
#include<stdlib.h>
char ** lastnumlines(FILE *fp, unsigned int num)   
{
  int count = num;
  int n, i, iNo1 = 0, iNo2= 0,z = 0;
  size_t MAXSIZE = 1024;
  char **tailbuf=calloc(count, sizeof(char *));

  for (i = 0; i < count; i  ) 
  {
    tailbuf[i] = calloc(MAXSIZE, sizeof(char));
  }

  while (getline(&tailbuf[iNo2], &MAXSIZE, fp) != EOF)
  {
     iNo2 = (iNo2   1) % count;
     if (iNo2 == iNo1) 
     {
        iNo1 = (iNo1   1) % count; 
     }
  }

 i = iNo2;
 int k = 0;
 do{ 
     printf("%s\n",tailbuf[i]);
     i = (i 1) % count;            
   }while (i != iNo2);


   free(tailbuf);    
 }

int main()
{
  char *filename = "demo1.txt";
  FILE *fp = fopen(filename,"r");

  if(fp == NULL)
  {
     printf("Unable to open file!\n");
     exit(1);
  }

  lastnumlines(fp,10);    
  fclose(fp);   
  return 0;
}

How i can tailbuf in order?

CodePudding user response:

A simple solution should be to have two arrays of lines pointers (note that the memory won't be duplicated)

  • a circular buffer to read the file without other difficulty than using a mod op %
  • a linear buffer reordering the read line to be used elsewhere:
void lastnumlines(FILE *fp, unsigned int num)   
{
    /* variable names have been made more expressive */

    int i; 
    size_t size = 1024;
    char **tailbuf=calloc(num, sizeof(char *));
    char **circbuf=calloc(num, sizeof(char *));
    
    int index_in_buff = 0;
    int line_no = 0;
    
    for (i = 0; i < num;   i) {
        circbuf[i] = malloc(size);
    }

    /* get lines in circular buffer */
    while (getline(&circbuf[index_in_buff % num], &size, fp) != EOF)
    {
          index_in_buff;
          line_no;
    }

    /* reorder lines from circular to linear buffer */
    for (i = 0; i < num;   i) {
        printf("%d --> %d\n", (line_no i)%num, i);
        tailbuf[i] = circbuf[(line_no i)%num];
    } 

    /* display lines, warning, some may be null if num > line_no */
    for (i = 0; i < num;   i) {
        if (tailbuf[i])
            printf("%s", tailbuf[i]);
    }

    /* cleanup memory */
    for (i = 0; i < num;   i) {
        free(tailbuf[i]);
    }

    free(tailbuf);    
    free(circbuf);    
}

Note that the circbuf can be deleted at the end of function, and tailbuf can be returned to be used in other functions. Both tailbuf and circbuf point to line memory, but there is no deep bind.

CodePudding user response:

Here's a sketch of how you could do this with a single array of pointers.

Up to 10 lines populate pArr pointers, then memmove will "scroll-up" the array so that the 'next' read is always to the final pointer.

const int n = 10; // Want last 10 lines. (fewer if short input).
char *pArr[ n ];

for( int i = 0; i < n; i   )
    pArr[ i ] = calloc( 128, sizeof(char) );

int lcnt = 0, retCode = 0;
while( retCode != EOF ) {
    if( lcnt == n - 1 ) {
        char *hold = pArr[0];
        memmove( pArr, pArr   1, (n - 1) * sizeof(pArr[0]) );
        pArr[ lcnt ] = hold;
    }
    retCode = getline( pArr[ lcnt ], size, fp );
    if(   lcnt == n )
        lcnt--;
}

for( i = 0; i <= lcnt; i   )
    printf( ... );

for( i = 0; i < n; i   )
    free( pArr[ i ] );
  • Related