modules/up/src/rpsl/rpsl/object.cc

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. Object
  2. read
  3. read
  4. parse
  5. scan
  6. scan
  7. reportErrors
  8. PRINT1
  9. PRINT2
  10. printPTree
  11. setClass
  12. addAttr
  13. setAttr
  14. setAttr

//  $Id: object.cc,v 1.1.1.1 2000/03/10 16:32:24 engin Exp $
//
//  Copyright (c) 1994 by the University of Southern California
//  All rights reserved.
//
//  Permission to use, copy, modify, and distribute this software and its
//  documentation in source and binary forms for lawful non-commercial
//  purposes and without fee is hereby granted, provided that the above
//  copyright notice appear in all copies and that both the copyright
//  notice and this permission notice appear in supporting documentation,
//  and that any documentation, advertising materials, and other materials
//  related to such distribution and use acknowledge that the software was
//  developed by the University of Southern California, Information
//  Sciences Institute. The name of the USC may not be used to endorse or
//  promote products derived from this software without specific prior
//  written permission.
//
//  THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY
//  REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY
//  PURPOSE.  THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
//  IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
//  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
//  TITLE, AND NON-INFRINGEMENT.
//
//  IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
//  SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT, TORT,
//  OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH, THE USE
//  OR PERFORMANCE OF THIS SOFTWARE.
//
//  Questions concerning this software should be directed to 
//  ratoolset@isi.edu.
//
//  Author(s): Cengiz Alaettinoglu <cengiz@ISI.EDU>

#include "config.h"
#include <istream.h>
#include <cstdio>
#include <strstream.h>
#include <fstream.h>
#include <iomanip.h>

#include "object.hh"
#include "schema.hh"

extern int rpslparse(void *);
extern void rpsl_scan_object(Object *);

Object::~Object() {
/* [<][>][^][v][top][bottom][index][help] */
   attrs.clear();
}

const int MAX_KEY_LENGTH       = 1024;
const int INITIAL_CHUNK_SIZE   = 1024;
const int TOO_SMALL_CHUNK_SIZE = 64;


bool Object::read(istream &in) {
/* [<][>][^][v][top][bottom][index][help] */
   return read(*this, in);
}

bool Object::read(Buffer &buf, istream &in) {
/* [<][>][^][v][top][bottom][index][help] */
   if (in.eof())
      return false;

   int size = INITIAL_CHUNK_SIZE;
   int remaining = size;

   char *text = (char *) malloc(size);
   char *start = text;
   char *p;

   int linelen;
   int len = 0;

   while (1) {
      in.getline(start, remaining);

      linelen = strlen(start);
      remaining -= linelen;
      len       += linelen;
      start     += linelen;

      if (!linelen || in.eof()) // empty line or eof => end of object
         break;
      // blank line => end of object?
      for (p = start - linelen; 
           *p && (*p == ' ' || *p == '\t' || *p == '\r'); ++p)
         ;
      if (! *p)
         break;

      if (remaining < TOO_SMALL_CHUNK_SIZE) {
         remaining += size;
         size *= 2;
         text = (char *) realloc(text, size);
         start = text + len;
      }
      
      if (in) { // append \n if we successfully read a line
         *start = '\n';
         start++;
         len++;
         remaining--;
      } else
         in.clear();
   }

   buf.size=len;
   buf.contents = (char *) realloc(text, len+2);

   return len;
}

void Object::parse() {
/* [<][>][^][v][top][bottom][index][help] */
   rpsl_scan_object(this);
   rpslparse(this);

   if (type) {
      bool forgiving = schema.isForgiving();
      if (isDeleted || schema.isVeryForgiving()) {
         if (has_error) {
            has_error = false;
            Attr *n_attr;

            for (Attr *attr = attrs.head(); attr; attr = attrs.next(attr))
               if (! attr->errors.empty() 
                   && attr->type && attr->type->isKey()) {
                  has_error = true;
                  break;
               }
         }
         schema.beForgiving();
      }
      has_error |= ! type->validate(errors);
      schema.beForgiving(forgiving);
   } else {
      errors = "***Error: Unknown class encountered.";
      has_error = true;
   }
}

bool Object::scan(ostream &err) {
/* [<][>][^][v][top][bottom][index][help] */
   parse();

   if (has_error)
      reportErrors(err);

   return ! has_error;
}

bool Object::scan(const char *_text, const int sz, ostream &err) {
/* [<][>][^][v][top][bottom][index][help] */
   contents = (char *) _text;
   size     = sz;

   scan(err);

   contents = NULL;
   size     = 0;
   return ! has_error;
}

void Object::reportErrors(ostream &ostrm) {
/* [<][>][^][v][top][bottom][index][help] */
   Attr *n_attr;

   for (Attr *attr = attrs.head(); attr; attr = n_attr) {
      n_attr = attrs.next(attr);
      if (attr->errors.empty() || attr->errorLeng == 0) {
         ostrm.write(&contents[attr->offset], attr->len);
         ostrm << attr->errors;
      } else {
         char *begin = &contents[attr->offset];
         char *end = begin;
         for (int i = 0; i <= attr->errorLine; ++i)
            end = strchr(end, '\n') + 1;
         ostrm.write(begin, end - begin);
         for (int i = 0; i < attr->errorColon; ++i)
            ostrm << " ";
         for (int i = 0; i < attr->errorLeng; ++i)
            ostrm << "^";
         ostrm << "\n";
         ostrm << attr->errors;
         ostrm.write(end, attr->len - (end - begin));
      }
   }
   if (! attrs.head() && contents)
      ostrm << contents;

   ostrm << errors;
   ostrm << "\n";
}

// Added by wlee@isi.edu
#ifdef DEBUG

#define PRINT1(x) os << "  " #x " = " << x << endl
/* [<][>][^][v][top][bottom][index][help] */
#define PRINT2(x, y) os << "  " #x " = " << y << endl
/* [<][>][^][v][top][bottom][index][help] */

void Object::printPTree(ostream &os) const
/* [<][>][^][v][top][bottom][index][help] */
{
  os << "Object" << endl; 
  PRINT2(contents, "\"...\"");
  PRINT1(size);
  os << "  type" << endl;
  os << "  "; PRINT2(name, type->name);
  os << "  attrs (List <Attr>)" << endl;
  os << "  "; PRINT2(length, attrs.size());
  for (Attr *attr = attrs.head(); attr; attr = attrs.next(attr)) {
    os << "    ListNode" << endl;
    //    os << "      forw" << endl;
    //    os << "      back" << endl;
    os << "      data (Attr *)" << endl;
    os << "      "; PRINT2(offset, attr->offset);
    os << "      "; PRINT2(len, attr->len);
    os << "      " << attr->className() << endl; 
    attr->printClass(os, 10);
  }
}

#endif // #ifdef DEBUG

ostream& operator<<(ostream &os, const Object &o) {
   Attr *attr;
      
   for (attr = o.attrs.head(); attr; attr = o.attrs.next(attr))
      if (attr->type && !attr->type->isObsolete())
         os << *attr << "\n";

   os << "\n";
   return os;
}

bool Object::setClass(char *cls) {
/* [<][>][^][v][top][bottom][index][help] */
   type = schema.searchClass(cls);
   // make sure there is an extra \n at the end
   append("\n", 1);
   return type;
}

bool Object::addAttr(char *attr, Item *item) {
/* [<][>][^][v][top][bottom][index][help] */
   if (!type)
      return false;

   const AttrAttr *attrType = type->searchAttr(attr);
   if (!attrType)
      return false;

   ItemList *items = new ItemList;
   items->append(item);
   Attr *attrib = new AttrGeneric(attrType, items);

   ostrstream s;
   s << *attrib << ends;
   attrib->offset = size;
   attrib->len    = strlen(s.str());

   // delete the extra \n at the end, and reinsert after this attribute
   size--;
   append(s.str(), attrib->len);
   append("\n", 1);
   s.freeze(0);

   (*this) += attrib;
   return true;
}

bool Object::setAttr(char *attrName, Item *item) {
/* [<][>][^][v][top][bottom][index][help] */
   if (!type)
      return false;

   const AttrAttr *attrType = type->searchAttr(attrName);
   if (!attrType)
      return false;

   ItemList *items = new ItemList;
   items->append(item);
   AttrGeneric *attr = new AttrGeneric(attrType, items);
  
   return setAttr(attrName, attr);
}

bool Object::setAttr(char *attrName, Attr *attr) {
/* [<][>][^][v][top][bottom][index][help] */
   if (!type)
      return false;

   const AttrAttr *attrType = type->searchAttr(attrName);
   if (!attrType)
      return false;

   Attr *atr2;
   for (Attr *atr = attrs.head(); atr; atr = atr2) {
      atr2 = attrs.next(atr);
      if (atr->type == attrType) {
         attrs.remove(atr);
         flush(atr->len, atr->offset);
         delete atr;
      }
   }

   (*this) += attr;

   ostrstream s;
   s << *attr << "\n" << ends;
   attr->offset = size;
   attr->len    = strlen(s.str());
   
   // delete the extra \n at the end, and reinsert after this attribute
   size--;
   append(s.str(), attr->len);
   append("\n", 1);
   s.freeze(0);

   return true;
}


/* [<][>][^][v][top][bottom][index][help] */