Logo Search packages:      
Sourcecode: af version File versions  Download package

textline.c

/* Textline.c - Text line list handling for af.
   Copyright (C) 2002 Malc Arnold.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */


#include <stdio.h>
#include <ctype.h>
#include "af.h"
#include STRING_HDR

/****************************************************************************/
/* RCS info */

#ifndef lint
static char *RcsId = "$Id: textline.c,v 1.1 2002/08/21 23:54:48 malc Exp $";
#endif /* ! lint */

/****************************************************************************/
/* External function declarations */

extern char *xmalloc(), *xstrdup();
extern void free();

/* Local function declarations */

void free_text();
TEXTLINE *add_bintext(), *append_bintext();

/****************************************************************************/
TEXTLINE *add_text(list, line)
TEXTLINE *list;
char *line;
{
      /* Add a line to a list of strings */

      return(add_bintext(list, line, strlen(line)));
}
/****************************************************************************/
TEXTLINE *add_bintext(list, line, len)
TEXTLINE *list;
char *line;
size_t len;
{
      /*
       * Add a binary line to a list of strings - basic list
       * handling, except that we enhance performance by keeping
       * a static pointer to the last entry.  This means that this
       * only works when used to build a text list from scratch.
       */

      static TEXTLINE *last;
      TEXTLINE *node;

      /* Create the new node for the list */

      node = (TEXTLINE *) xmalloc(sizeof(TEXTLINE));
      node->len = len;
      node->line = line;
      node->next = NULL;

      /* Add the node to the list */

      if (list == NULL) {
            /* Just make the node the new list */

            list = node;
      } else {
            /* Append the node to the list */

            last->next = node;
      }

      /* Set the copy of the last entry before we exit */

      last = node;
      return(list);
}
/****************************************************************************/
TEXTLINE *append_text(list, line)
TEXTLINE *list;
char *line;
{
      /* Append a line to a list of strings */

      return(append_bintext(list, line, strlen(line)));
}
/****************************************************************************/
TEXTLINE *append_bintext(list, line, len)
TEXTLINE *list;
char *line;
size_t len; 
{
      /* Append a line to a list of strings */

      TEXTLINE *node, *t;

      /* Create the new node */

      node = (TEXTLINE *) xmalloc(sizeof(TEXTLINE));
      node->len = len;
      node->line = line;
      node->next = NULL;

      /* Add the node to the list */

      if (list == NULL) {
            /* Just return the node as the new list */

            return(node);
      }

      /* We have to do this the long way */

      for (t = list; t != NULL && t->next != NULL; t = t->next) {
            /* NULL LOOP */
      }

      /* Append the node to the list */

      t->next = node;
      return(list);
}
/****************************************************************************/
TEXTLINE *insert_text(list, point, line)
TEXTLINE *list, *point;
char *line;
{
      /* Insert line into the list before point */

      TEXTLINE *node, *t;

      /* Allocate and fill the new node */

      node = (TEXTLINE *) xmalloc(sizeof(TEXTLINE));
      node->len = strlen(line);
      node->line = line;
      node->next = point;

      /* That's it if we're prepending to the list */

      if (point == list) {
            return(node);
      }

      /* Find the node's insert position */

      for (t = list; t != NULL && t->next != point; t = t->next) {
            /* NULL LOOP */
      }

      /* Insert the node into the list */

      if (t != NULL) {
            t->next = node;
      }

      /* And return the updated list */

      return(list);
}
/****************************************************************************/
TEXTLINE *delete_text(list, node)
TEXTLINE *list, *node;
{
      /* Delete the node from the text list */

      TEXTLINE *t;

      /* Handle deletions at the start of the list */

      if (node == list) {
            list = list->next;
            free(node->line);
            free(node);
            return(list);
      }

      /* Or find the line in the list and delete it */

      for (t = list; t != NULL; t = t->next) {
            /* Is this the node before the deletion? */

            if (t->next == node) {
                  /* Delete this node and return the list */

                  t->next = node->next;
                  free(node->line);
                  free(node);
                  return(list);
            }
      }

      /* We didn't find the node to delete */

      return(list);
}
/****************************************************************************/
TEXTLINE *copy_text(list)
TEXTLINE *list;
{
      /* Copy a text list, returning the copy */

      char *new_line;
      TEXTLINE *t, *new_list = NULL;

      /* Just loop over the list adding each line */

      for (t = list; t != NULL; t = t->next) {
            /* Copy the text of the line */

            new_line = xmalloc(t->len + 1);
            (void) memcpy(new_line, t->line, t->len);
            *(new_line + t->len) = '\0';

            /* Add add the new line to the list */

            new_list = add_bintext(new_list, new_line, t->len);
      }

      /* And return the list */

      return(new_list);
}
/****************************************************************************/
TEXTLINE *replace_text(list, point, new_list)
TEXTLINE *list, *point, *new_list;
{
      /* Replace the entries in the list from point with new_list */

      TEXTLINE *t;

      /* Handle replacing at the start of the list */

      if (point == list) {
            free_text(list);
            return(new_list);
      }

      /* Or find the line in the list and replace it */

      for (t = list; t != NULL; t = t->next) {
            /* Is this the node before the replacement? */

            if (t->next == point) {
                  /* Replace this section of the list */

                  free_text(t->next);
                  t->next = new_list;
                  return(list);
            }
      }

      /* We didn't find the replacement point */

      return(list);
}
/****************************************************************************/
void change_text(node, line)
TEXTLINE *node;
char *line;
{
      /* Change the text node to contain line */

      free(node->line);
      node->line = line;
      node->len = strlen(line);
      return;
}
/****************************************************************************/
size_t trim_text(list)
TEXTLINE *list;
{
      /*
       * Trim any trailing blank lines from a list, returning the
       * number of characters deleted.
       */

      char *p;
      int blank;
      size_t nchars = 0;
      TEXTLINE *line, *last_line = NULL;

      /* Check the list has lines to trim */

      if (list == NULL) {
            /* No lines; return unchanged */

            return(0);
      }

      /* Find the last non-blank line */

      for (line = list; line->next != NULL; line = line->next) {
            /* Is the next (binary?) line blank */

            blank = TRUE;
            for (p = line->next->line;
                 p < line->next->line + line->next->len; p++) {
                  if (*p == '\0' || !isascii(*p) || !isspace(*p)) {
                        /* This line isn't blank */

                        blank = FALSE;
                        break;
                  }
            }
            last_line = (blank) ? (last_line != NULL)
                  ? last_line : line : NULL;
      }

      /* Delete any blank lines from the message */

      while (last_line != NULL && last_line->next != NULL) {
            /* Update the number of chars and delete the line */

            nchars += last_line->next->len;
            (void) delete_text(last_line, last_line->next);
      }

      /* All done, return the characters deleted */

      return(nchars);
}
/****************************************************************************/
unsigned text_lines(list)
TEXTLINE *list;
{
      /* Return the number of lines in the list */

      size_t nlines = 0;
      TEXTLINE *t;

      /* Count the number of lines */

      for (t = list; t != NULL; t = t->next) {
            nlines++;
      }

      /* And return the number of lines */

      return(nlines);
}
/****************************************************************************/
unsigned text_chars(list)
TEXTLINE *list;
{
      /* Return the size in characters of the text in a list */

      size_t nchars = 0;
      TEXTLINE *t;

      /* Count the length of each line */

      for (t = list; t != NULL; t = t->next) {
            nchars += t->len;
      }

      /* And return the number of characters */

      return(nchars);
}
/****************************************************************************/
void free_text(list)
TEXTLINE *list;
{
      /* Free a text list */

      TEXTLINE *next;

      /* Don't use recursion here for speed */

      while (list != NULL) {
            /* Save the next line */

            next = list->next;
      
            /* Free this line */

            free(list->line);
            free(list);

            /* And move on */

            list = next;
      }

      /* That's all folks */

      return;
}
/****************************************************************************/

Generated by  Doxygen 1.6.0   Back to index