1
0
Fork 0
src/Wip/tail.c

153 lines
3.3 KiB
C

#include <ctype.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "args.h"
#include "libcharin.h"
#include "libstris.h"
#define DEFAULT_LENGTH 10
#define OFLOW(STR) (STR[strlen(STR)-1] != '\n')
#ifndef PAGE_SIZE
# ifndef PAGESIZE
# define PAGE_SIZE 1024
# else
# define PAGE_SIZE PAGESIZE
# endif
#endif
/*
TODO
* fix limits.h stuff; if limits.h isn't on the system define
reasonable limits in its place
* don't use unsafe string functions
* fix bugs
*/
void
tail(FILE *input, FILE *output, int length){
bool loop = 1;
char *lines[length];
size_t ls[length];
int i;
int filelines = 0;
size_t offset = 0;
for(i = 0; i < length; i++){
ls[i] = PAGE_SIZE;
lines[i] = (char *)calloc(ls[i], sizeof(char));
}
i = 0;
while(fgets(lines[i] + offset, ls[i], input)){
if(OFLOW(lines[i])){
offset += ls[i] - 1;
ls[i] += PAGE_SIZE;
/* should be more resilient */
if(realloc(lines[i], ls[i]) == NULL){
fprintf(stderr, "tail: Couldn't re-allocate memory (%d bytes)\n", ls[i] * sizeof(char));
exit(1);
}
continue;
}
offset = 0;
++filelines;
i = (i + 1) % length;
}
for(i = filelines % length; loop || i != filelines % length; i = (i + 1) % length){
if(loop && i == filelines % length)
loop = 0;
printf("%s", lines[i]);
}
/* glitch here when `tail`ing normal files */
for(i = 0; i < length; i++){
free(lines[i]);
}
return;
}
void
usage(char *name){
fprintf(stderr, "Usage: %s [-ht] [-n integer] [file...]\n", name);
exit(1);
}
int
main(int argc, char *argv[]){
char **argsv = getargsv(argc, argv);
char *flags = getflags(argc, argv);
char mode[3] = "rb";
char filepath[NAME_MAX+PATH_MAX];
char *lengthstr;
size_t fplen = NAME_MAX+PATH_MAX;
FILE *input;
FILE *output = stdout;
int argsc = getargsc(argc, argv);
int i;
int length = DEFAULT_LENGTH;
size_t s;
if(charin(flags, 'h'))
usage(argv[0]);
if(charin(flags, 'n')){
lengthstr = getflag(argc, argv, 'n');
if(!strisint(lengthstr) || *lengthstr == '\0')
usage(argv[0]);
else
length = atoi(lengthstr);
}
if(charin(flags, 't'))
/* Explicitly open files as text rather than as binary.
* this changes "rb" to "r". Should have no effect on
* POSIX systems but may change CRLF to just LF with
* MS Windows. I don't know why anyone would need this
* but it's here for those that do. */
mode[1] = '\0';
if(argsc == 0)
tail(stdin, output, length);
else
for(i = 1; i < argsc; ++i){
if(i > 1)
fprintf(output, "\n");
if(!strcmp(argv[i], "-")){
realpath(argv[i], filepath);
input = fopen(argv[i], "r");
if(input == NULL){
fprintf(stderr, "%s: %s: Could not open file for reading\n", argv[0], filepath);
exit(1);
}
}else{
input = stdin;
/* probably safe but could be vulnerable */
/* just making filepath[] = "<stdin>" */
s = strlen("<stdin>") + 1; /* minimum size for filepath */
if(fplen >= s)
strcpy(filepath, "<stdin>");
else if(realloc(filepath, s) == NULL)
fprintf(stderr, "%s: Failed to reallocate path string, using <stdin>\n", argv[0]);
}
fprintf(output, "==> %s <==\n", filepath);
tail(input, output, length);
if(input != stdin && fclose(input) != 0){
fprintf(stderr, "%s: %s: Could not close file. Exiting...\n", argv[0], filepath);
exit(1);
}
}
return 0;
}