view oldclasslib/include/charsink.h @ 16:f9e4689b837d

Some minor updates for 15 years later.
author David A. Holland
date Tue, 31 May 2022 01:45:26 -0400
parents 607e3be6bad8
children
line wrap: on
line source

/*
 * AnaGram, a System for Syntax Directed Programming
 *
 * Character Sink Class Definitions
 *
 * Copyright 1993 Parsifal Software. All Rights Reserved.
 *
 * This software is provided 'as-is', without any express or implied
 * warranty.  In no event will the authors be held liable for any damages
 * arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must not
 *    claim that you wrote the original software. If you use this software
 *    in a product, an acknowledgment in the product documentation would be
 *    appreciated but is not required.
 * 2. Altered source versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.
 * 3. This notice may not be removed or altered from any source distribution.
 */

#ifndef CHARSINK_H
#define CHARSINK_H

#include <stdio.h>
#include <assert.h>


// Class Definition for character_sink

class character_sink {
public:
  virtual ~character_sink() {}
  virtual character_sink& operator << (int c) = 0;
  virtual character_sink& operator << (const char *str) = 0;
  virtual character_sink& operator << (const unsigned char *str) = 0;
  virtual character_sink& printf(const char *, ...) = 0;
};


// Class Definition for output_file

class output_file : public character_sink {
private:
  FILE *file;
  char *name;
  int error_flag;
  int copy_flag;                            // is it live or memorex?

public:

// Constructors

  output_file() {
    file = stdout;
    error_flag = copy_flag = 0;
  }

  output_file(char *path) : character_sink() {
    name = path;
    if (name == NULL) file = stdout;
    else file = fopen(name = path, "wt");
    if (file == NULL) file = stdout;
    error_flag = copy_flag = 0;
  }

  void operator = (const output_file &f) {
     file = f.file;
     name = f.name;
     error_flag = f.error_flag;
     copy_flag = f.copy_flag;
  }

  output_file(const output_file &f) : character_sink() {
    *this = f;
    copy_flag++;
  }


// Destructor

  ~output_file() {if (copy_flag == 0) fclose(file);}


// Xmit data to sink

  character_sink& operator << (int c) {
    error_flag = putc((char) c,file);
    return *this;
  }

  character_sink& operator << (const char *str) {
    fputs(str,file);
    return *this;
  }

  character_sink& operator << (const unsigned char *str) {
    fputs((const char *)str, file);
    return *this;
  }

  character_sink& printf(const char *, ...);


// Check for error

  friend int error(output_file &f);
};

inline int error(output_file &f) {
  return f.error_flag < 0;
}

class string_accumulator : public character_sink {
private:
  char *cs;                // character storage
  unsigned *xs;            // index storage
  unsigned csx;            // next available character
  unsigned xsx;            // next available index
  unsigned csmax;          // max number of characters
  unsigned xsmax;          // max number of indices
  int copy_flag;           // is it live or is it memorex?

public:

// Constructor

  string_accumulator(int nc, int nx = 1);
  string_accumulator(const string_accumulator &);
  void operator = (const string_accumulator &);


// Destructor

  ~string_accumulator();


// Reset string_accumulator

  friend string_accumulator &reset(string_accumulator &);


// Change stack level

  string_accumulator& operator ++(){        // preincrement stack level
    assert(copy_flag == 0);
    assert(xsx);
    xs[--xsx] = csx;
    return *this;
  }

  string_accumulator operator ++ (int);     // postincrement stack level

  string_accumulator &operator -- () {      // predecrement stack level
    assert(copy_flag == 0);
    csx = xs[xsx++];                        // discard top string
    assert(xsx < xsmax);
    return *this;
  }

  string_accumulator operator -- (int);     // post decrement stack level

// Append data to stack

  character_sink& operator << (int c) {     // append char to top string
    assert(copy_flag == 0);
    assert(csx < csmax);
    cs[csx++] = (char) c;
    return *this;
  }

  character_sink &operator << (const char *str); // append string to top string

  character_sink &operator << (const unsigned char *str);

  character_sink &operator << (string_accumulator &s) {
    assert(this != &s);                     // prevent disaster
    return *this << s.top();
  }

  character_sink &printf(const char *, ...);


// Pop character from stack

  string_accumulator &operator >> (int &c); // pop last character


// Access character on stack

  char &operator [] (unsigned);                  // inspect character


// Retrieve pointer to top string

// See README.txt
#if 0
  operator char *() const {                 // pointer to top string
    cs[csx] = 0;
    return &cs[xs[xsx]];
  }

  operator unsigned char *() const {        // pointer to top string
    cs[csx] = 0;
    return (unsigned char *) &cs[xs[xsx]];
  }
#else
  char *top() const {
    cs[csx] = 0;
    return &cs[xs[xsx]];
  }
#endif


// Concatenate strings

  friend string_accumulator& concat(string_accumulator &);


// Make permanent copy of string

  friend char *copy(const string_accumulator &);


// Get length of string

  friend unsigned size(const string_accumulator &);

};

inline unsigned size(const string_accumulator &s) {
  assert(s.xsx < s.xsmax);
  return s.csx - s.xs[s.xsx];
}

#endif