/* ** File: dyn_page.c ** Desc: A dynamic buffer, and functions to manipulate it ... ** Auth: Cian Synnott ** Date: Tue Nov 10 21:58:17 GMT 1998 ** ** $Id: dyn_page.c,v 1.2 2001/12/30 23:26:06 c-hey Exp $ */ #include #include #include #include "dyn_page.h" /* Allocate a page structure, giving it the width at which to wrap lines ** appended to it. */ dyn_page *dyn_pageAlloc(int width) { dyn_page *p; /* Allocate memory */ if (!(p = (dyn_page *) malloc(sizeof(dyn_page)))) { perror("Error allocating page"); exit(1); } /* Setup values */ p->buff = NULL; p->rows = 0; p->cols = width; return p; } /* Free an entire page structure. */ void dyn_pageFree(dyn_page *p) { int i; /* Free all the separate lines */ for (i = 0; i < p->rows; i++) { free(p->buff[i]); p->buff[i] = NULL; /* Ok, so I'm paranoid ... */ } /* Free the 'page pointer' */ free(p->buff); p->buff = NULL; /* Free the structure memory */ free(p); return; } /* How many lines, or what width, is the page ... ** Should be macros, but I like to keep my functions together :o) */ int dyn_pageLines(dyn_page *page) { return page->rows; } int dyn_pageWidth(dyn_page *page) { return page->cols; } /* Append a line to the page, wrapping as necessary */ int dyn_pageAppend(dyn_page *p, char *line) { char *line_ptr; int last_space = 0; int len = strlen(line); /* Firstly, if now is the time to allocate more pointers to lines, ** do it (remember to set all these pointers to NULL ... */ if (!(p->rows % 10)) { if (!(p->buff = (char **) realloc(p->buff, (p->rows + 10) * sizeof(char *)))) return 0; } /* We're adding a line, so increment p->rows. Would be nicer to do ** this later, but control leaves this function suddenly quite a lot */ p->rows++; /* If there's no word-wrapping specified (p->cols == 0), or if the line ** is less than p->cols anyhows, just add the line */ if (!p->cols || len < p->cols) { /* Allocate the space for the line ... */ if (!(p->buff[p->rows - 1] = (char *) calloc(len + 1, sizeof(char)))) return 0; /* Copy in the line ... */ strncpy(p->buff[p->rows - 1], line, len); /* Success ... */ return 1; } /* Otherwise, search for the last space before the end of the wrapping ** line (p->cols) and add the line up to that, then call ourselves for ** the rest of the line. Huzzah for recursion. */ for (line_ptr = line; *line_ptr; line_ptr++) { /* If we're at a column boundry (setting len == difference between ** line & line_ptr ... */ if ((len = line_ptr - line) + 1 == p->cols) { /* If there was a last space recorded, set len equal to it */ if (last_space) len = last_space; /* Allocate the space for the line ... */ if (!(p->buff[p->rows - 1] = (char *) calloc(len + 1, sizeof(char)))) return 0; /* Copy the stated length into it ... */ strncpy(p->buff[p->rows - 1], line, len); /* Set line equal to it's new value & skip any whitespace ** at the start of it ... */ line += len; while (*line && *line == ' ') line++; /* Now call dyn_pageAppend() to add the rest of it, ** propogating results back up the recursive calls ... */ return dyn_pageAppend(p, line); } /* Otherwise control reaches here ... */ if (*line_ptr == ' ') last_space = (line_ptr - line); } /* End while (*line_ptr) */ /* Control never reaches here ... */ return 0; } /* Extract a line by index */ char *dyn_pageLineAt(dyn_page *p, int line) { /* Invalid reference ... */ if (line >= p->rows || line < 0) return NULL; /* Otherwise return the line asked for */ return p->buff[line]; } /* Modify a line by index */ int dyn_pageLineMod(dyn_page *p, char *line, int lineno) { /* Invalid reference ... */ if (lineno >= p->rows || lineno < 0) return 0; /* free the existing line */ if((p->buff[lineno]=(char *)realloc(p->buff[lineno],strlen(line) + 1)) == NULL) return 0; /* modify the line */ strcpy(p->buff[lineno], line); return 1; } /* Step along the page, returning the next line on subsequent calls that are ** passed NULL. Standard iterator ... */ char *dyn_pageRead(dyn_page *p) { static dyn_page *on_page = NULL; static int line = 0; if (p) { on_page = p; line = 0; if (!on_page->rows) return NULL; return on_page->buff[line++]; } /* If we get this far, if there's no current page, error */ if (!on_page) return NULL; /* Otherwise return line asked for */ else { if (line >= on_page->rows) return NULL; return on_page->buff[line++]; } /* Control never reaches here */ return NULL; }