Logo Search packages:      
Sourcecode: fhist version File versions

modlin.c

/*
 *    fhist - file history and comparison tools
 *    Copyright (C) 1991-1994, 1998-2002 Peter Miller;
 *    All rights reserved.
 *
 *    Derived from a work
 *    Copyright (C) 1990 David I. Bell.
 *
 *    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 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
 *
 * MANIFEST: functions to modify lines of files for special purposes.
 */

#include <ac/string.h>

#include <cmalloc.h>
#include <compare.h>
#include <error_intl.h>
#include <fcheck.h>
#include <fhist.h>
#include <fileio.h>
#include <input/file_text.h>
#include <input/file.h>
#include <input/quotprinenco.h>
#include <modlin.h>
#include <trace.h>

#define INPUT_LINE_SIZE 200   /* longest input line */
#define OUTPUT_LINE_SIZE 300  /* longest output line */
#define MAX_VALUES 4          /* most number of values per line */
#define MIN_WORD 4            /* shortest keyword */
#define MAX_WORD 6            /* longest keyword */
#define SEQ_EDGE 3            /* size of edge of sequence */
#define MIN_SEQUENCE ((SEQ_EDGE * 2) + MIN_WORD)      /* smallest sequence */

#define V_EDIT 1        /* edit keyword */
#define V_DATE 2        /* date keyword */
#define V_USER 3        /* user name keyword */
#define     V_MODULE 4        /* module keyword */

typedef struct VALUE VALUE;
struct VALUE
{
      short v_type;           /* type of value */
      char  *v_str;           /* new string value */
      char  *v_begval;  /* beginning of old value */
      char  *v_endval;  /* end of old value */
};

/*
 * Routine to find a special sequence inside of a line, and return
 * pointers to the beginning and end of the inner part of the sequence.
 * Returns 1 if found a potential sequence for examination.
 */

static int
scansequence(char *cp, long linelen, char **begseq, char **endseq)
{
      char  *cp2;       /* test characters */
      long  linelen2;   /* length of line left */

      if (linelen > INPUT_LINE_SIZE)
            return 0;
      while (linelen > MIN_SEQUENCE) {
            if ((cp[0] != '[') || (cp[1] != '#') || (cp[2] != ' ')) {
                  cp++;
                  linelen--;
                  continue;
            }
            cp += SEQ_EDGE;
            linelen -= SEQ_EDGE;
            linelen2 = linelen;
            cp2 = cp;
            while ((cp2[0] != ' ') || (cp2[1] != '#') || (cp2[2] != ']')) {
                  if (--linelen2 <= SEQ_EDGE)
                        return 0;
                  cp2++;
            }
            *begseq = cp;
            *endseq = cp2;
            return 1;
      }
      return 0;
}


/*
 * Routine to find keywords within special sequences on a line.
 * Returns a list of the new values for those keywords, and the locations
 * where the old values are within the line.  Return value is the number
 * of keywords found, or -1 if something invalid was found.
 */

static int
scanwords(char *line, long len, INFO *info, VALUE *vp)
{
      char  *cp;        /* current character */
      char  *op;        /* output character */
      char  *beg;       /* beginning of special sequence */
      char  *end;       /* end of special sequence */
      char  *endword;   /* end of word */
      char  *str;       /* string value */
      int   count;            /* number of values found */
      int   ch;         /* current character */
      int   type;       /* type of value found */
      char  word[MAX_WORD + 2]; /* lower cased word */

      count = 0;
      endword = &word[MAX_WORD];
      while (scansequence(line, len, &beg, &end)) {
            for (cp = beg; cp != end; ) {
                  if (++count > MAX_VALUES)
                        return -1;
                  for (op = word; ; cp++) {
                        ch = *cp;
                        if ((ch == ' ') || (ch == ','))
                              break;
                        if (op == endword)
                              return -1;
                        if ((ch >= 'A') && (ch <= 'Z'))
                              ch += ('a' - 'A');
                        *op++ = ch;
                  }
                  *op = '\0';
                  vp->v_begval = cp;
                  while ((cp != end) && (*cp != ','))
                        cp++;
                  vp->v_endval = cp;
                  if (cp != end) {
                        if ((++cp == end) || (*cp++ != ' ') || (cp == end))
                              return -1;
                  }
                  if (strcmp(word, "edit") == 0)
                        type = V_EDIT;
                  else if (strcmp(word, "date") == 0)
                        type = V_DATE;
                  else if (strcmp(word, "user") == 0)
                        type = V_USER;
                  else if (strcmp(word, "module") == 0)
                        type = V_MODULE;
                  else
                        return -1;
                  str = NULL;
                  if (info) switch (type) {
                        case V_EDIT: str = info->i_edit; break;
                        case V_DATE: str = info->i_date; break;
                        case V_USER: str = info->i_user; break;
                        case V_MODULE: str = sc.modulename; break;
                  }
                  vp->v_str = str;
                  vp->v_type = type;
                  vp++;
            }
            len -= (end - line);
            line = end;
      }
      return count;
}


/*
 * This routine detects lines which contain strings with the format:
 *    [# keyword value, keyword value, ..., keyword value #]
 * and changes the values to appropriate strings as specified by the keywords.
 * If the format is not correct, any keyword is unknown, or the line is too
 * long, then the line is unchanged.  Keywords can be in either lower or upper
 * case.  This routine is only called for the first 20 lines of the file in
 * order to increase the speed of processing the rest of the file data.
 * The info structure provides the values for insertion.  If the pointer is
 * NULL, then all the values will be cleared.
 */

char *
modifyline(char *cp, long *linelen, INFO *info)
{
      char  *op;        /* current output character */
      VALUE *vp;        /* current value on line */
      char  *endline;   /* ending position in line */
      char  *str;       /* string for replacement */
      long  len;        /* line length */
      int   count;            /* number of values on line */
      VALUE values[MAX_VALUES]; /* information about values */

      if (sc.modifylines == 0)
            return cp;
      len = *linelen;
      if ((len < MIN_SEQUENCE) || (len > INPUT_LINE_SIZE))
            return cp;
      count = scanwords(cp, len, info, values);
      if (count <= 0)
            return cp;
      if (!sc.modifybuffer)
            sc.modifybuffer = cm_alloc_and_check(OUTPUT_LINE_SIZE);

      /*
       * Copy the old line to the new one, except replace the old
       * values with the new ones.
       */
      endline = cp + len;
      op = sc.modifybuffer;
      for (vp = values; --count >= 0; vp++) {
            while (cp != vp->v_begval)
                  *op++ = *cp++;
            str = vp->v_str;
            if (str) {
                  *op++ = ' ';
                  while (*str)
                        *op++ = *str++;
            }
            cp = vp->v_endval;
      }
      while (cp != endline)
            *op++ = *cp++;
      *op = '\0';
      *linelen = (op - sc.modifybuffer);
      return sc.modifybuffer;
}


/*
 * Routine to search through the beginning of a file to find the edit
 * number, and return its value.  If the edit number is not found, or
 * if its value is null, then -1 is returned.
 *
 * The history (.e) file is binary, because we need to seek in it.
 * The source (.s) file is text, because we don't need to seek in it.
 * The input files are text, by definition.
 * The output files are text, by definition.
 */

long
findedit(char *inputname, int binary)
{
    char        *cp;    /* current line */
    input_ty        *fp;      /* file being read */
    VALUE       *vp;    /* current value */
    long        linelen;      /* line length */
    long        num;    /* scanned number */
    int             count;    /* number of values on line */
    long        i;            /* line counter */
    VALUE       values[MAX_VALUES]; /* returned values */
    int             bin;      /* IGNORED */

    trace(("findedit(inputname = \"%s\", binary = %d)\n{\n", inputname,
      binary));
    if (!binary)
      fp = input_file_text_open(inputname);
    else
    {
      fp = input_file_open(inputname);
      fp = input_quoted_printable_encode(fp, 1);
    }
    for (i = sc.modifylines; i > 0; i--)
    {
      cp = input_readline(fp, &linelen, 0, &bin);
      if (cp == NULL)
          break;
      count = scanwords(cp, linelen, (INFO *) NULL, values);
      for (vp = values; --count >= 0; vp++)
      {
          if (vp->v_type != V_EDIT)
            continue;
          cp = vp->v_begval + 1;
          num = 0;
          while ((*cp >= '0') && (*cp <= '9'))
            num = (num * 10) + (*cp++ - '0');
          if ((cp == vp->v_endval) && (num > 0))
          {
            input_delete(fp);
            trace(("return %ld;\n", num));
            trace(("}\n"));
            return num;
          }
      }
    }
    input_delete(fp);
    trace(("return -1;\n}\n"));
    return -1;
}

Generated by  Doxygen 1.6.0   Back to index