# include # include # include # include # include # include # include # include # define MAX_LINE_LENGTH 100 # define FILE_BUFFER_SIZE 512 # define INIT_BUFF_SIZE 50 # define INC_BUFF_SIZE 10 /*************************************************************************** * Program: myhead v.0.2 * * Author: Chad Milburn * * Created: Mar. 17, 2008 * * Completed: Feb. 21, 2008 * * Abstract: (C) Outputs the first N lines of input. * * Detail: Written for CS306, reads input from standard input or a file. * * Accepts a single option, -nN, which specifies the number of * * lines to be written to the screen, 1-N. No option defaults to * * the first 10 lines. Uses system call I/O and unlimited line length. * * Compile using gcc -Wall -o myhead lab2.c * ***************************************************************************/ //Prototypes: char *get_next_line(int fd); int get_next_char(int fd); int main(int argc, char *argv[]) { int fd = 0; char *pathname; char *line; int count = 10; //Default lines to be read. if(argc > 3) //Wrong usage. fprintf(stdout, "Usage: myhead [-nN] [FILE]\n"); else { if(argc == 2) if(argv[1][0]=='-') //myhead -* if(argv[1][1]=='n') //myhead -nN count = atoi(argv[1]+2); //Convert string to int, no error checking. else //Whoops! Not my bad. { fprintf(stderr, "Argument not recognized. Should be in the form:\nmyhead [-nN] [FILE]\n"); return EXIT_SUCCESS; } else //myhead file.ext { pathname = argv[1]; if((fd = open(pathname, O_RDONLY)) == -1) //Test for existence & permission. { fprintf(stderr, "Error opening file %s: %s\n", pathname, strerror(errno)); return EXIT_FAILURE; } } else if(argc == 3) //myhead -nN file.ext { if((argv[1][0]=='-') && (argv[1][1]=='n')) //Tests proper usage. { count = atoi(argv[1]+2); //Parse int. pathname = argv[2]; // if((fd = open(pathname, O_RDONLY)) == -1) //Test for existence & permission. { fprintf(stderr, "Error opening file %s: %s\n", pathname, strerror(errno)); return EXIT_FAILURE; } } else //Wrong usage. { fprintf(stderr, "Arguments are not correct. Should be in the form:\nmyhead [-nN] [FILE]\n"); return EXIT_SUCCESS; } } while(count > 0) //Print line (count) times. { if((line = get_next_line(fd)) == NULL) //NULL means EOF here. { if(!(errno)) //Reached EOF on good terms WILL IT WORK?? { close(fd); free(line); return EXIT_SUCCESS; } else //EOF with something wrong. { fprintf(stderr, "Error reading line.\nBut there's nothing I can do.\n"); close(fd); free(line); return EXIT_FAILURE; } } else //Nothing doing, print line. { fprintf(stdout, "%s\n", line); free(line); count--; } } free(line); close(fd); } return EXIT_SUCCESS; } //Retrieves a single line as an array of char (string) from input fpntr. char *get_next_line(int fd) { static int size = INIT_BUFF_SIZE; static char *line; char *ret = NULL; line = malloc(size); int i = 0; while(!(((line[i] = get_next_char(fd)) == '\n') || ((line[i]) == EOF))) //NEED TO Check for EOF { i++; if(i > size) { size = size + INC_BUFF_SIZE; if((ret = realloc(line, size)) == NULL) return NULL; else line = ret; } } line[i] = '\0'; if((line[i] == EOF) && (i == 0)) //EOF on blank line. return NULL; else //Normal new line or EOF on non-blank line. line[i] = '\0'; return line; } //Gets a single char from input fd, uses a buffer to minimize HD-reads. int get_next_char(int fd) { static char file[FILE_BUFFER_SIZE]; static int pos = 0; if(read(fd, file, FILE_BUFFER_SIZE) == -1) return 0; //Read error. if(pos >= FILE_BUFFER_SIZE) read(fd, file, FILE_BUFFER_SIZE); // if(file[pos] == EOF) return 0; else return file[pos++]; }