aboutsummaryrefslogtreecommitdiff
path: root/lib/fs.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/fs.c')
-rw-r--r--lib/fs.c98
1 files changed, 98 insertions, 0 deletions
diff --git a/lib/fs.c b/lib/fs.c
index 20a5999..e75c6a0 100644
--- a/lib/fs.c
+++ b/lib/fs.c
@@ -641,3 +641,101 @@ char *spm_mkdtemp(const char *base, const char *name, const char *extended_path)
return 0;
}
+
+char **file_readlines(const char *filename, size_t start, size_t limit, ReaderFn *readerFn) {
+ FILE *fp = NULL;
+ char **result = NULL;
+ char *buffer = NULL;
+ size_t lines = 0;
+ int use_stdin = 0;
+
+ if (strcmp(filename, "-") == 0) {
+ use_stdin = 1;
+ }
+
+ if (use_stdin) {
+ fp = stdin;
+ } else {
+ fp = fopen(filename, "r");
+ }
+
+ if (fp == NULL) {
+ perror(filename);
+ fprintf(SYSERROR);
+ return NULL;
+ }
+
+ // Allocate buffer
+ if ((buffer = calloc(BUFSIZ, sizeof(char))) == NULL) {
+ perror("line buffer");
+ fprintf(SYSERROR);
+ if (!use_stdin) {
+ fclose(fp);
+ }
+ return NULL;
+ }
+
+ // count number the of lines in the file
+ while ((fgets(buffer, BUFSIZ - 1, fp)) != NULL) {
+ lines++;
+ }
+
+ if (!lines) {
+ free(buffer);
+ if (!use_stdin) {
+ fclose(fp);
+ }
+ return NULL;
+ }
+
+ rewind(fp);
+
+ // Handle invalid start offset
+ if (start > lines) {
+ start = 0;
+ }
+
+ // Adjust line count when start offset is non-zero
+ if (start != 0 && start < lines) {
+ lines -= start;
+ }
+
+
+ // Handle minimum and maximum limits
+ if (limit == 0 || limit > lines) {
+ limit = lines;
+ }
+
+ // Populate results array
+ result = calloc(limit + 1, sizeof(char *));
+ for (size_t i = start; i < limit; i++) {
+ if (i < start) {
+ continue;
+ }
+
+ if (fgets(buffer, BUFSIZ - 1, fp) == NULL) {
+ break;
+ }
+
+ if (readerFn != NULL) {
+ int status = readerFn(i - start, &buffer);
+ // A status greater than zero indicates we should ignore this line entirely and "continue"
+ // A status less than zero indicates we should "break"
+ // A zero status proceeds normally
+ if (status > 0) {
+ i--;
+ continue;
+ } else if (status < 0) {
+ break;
+ }
+ }
+ result[i] = strdup(buffer);
+ memset(buffer, '\0', BUFSIZ);
+ }
+
+ free(buffer);
+ if (!use_stdin) {
+ fclose(fp);
+ }
+ return result;
+} \ No newline at end of file