/*ident "@(#)G2++:g2++lib/putrec.c 3.1" */ /****************************************************************************** * * C++ Standard Components, Release 3.0. * * Copyright (c) 1991, 1992 AT&T and Unix System Laboratories, Inc. * Copyright (c) 1988, 1989, 1990 AT&T. All Rights Reserved. * * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T and Unix System * Laboratories, Inc. The copyright notice above does not evidence * any actual or intended publication of such source code. * ******************************************************************************/ #include #include #include #include #include #include #ifdef __GNUG__ #define IOSTREAMH #endif static char sccs_id[] = "@(#)G2++ library, version 093096"; #ifdef IOSTREAMH #define OSWRITE os.write #else #define OSWRITE os.put #endif static void emit_node(int, void*, G2DESC*, ostream& os); static void emit_builtin(ostream& os, int, void*, int); // Current name hierarchy: static struct { char* name; // NULL name implies index int index; int maxarray; // if maxarray != 0, it is an array size } namestk[G2MAXDEPTH_ATTLC]; // TBD_fixed_limit static int outlevel=0; // depth of name hierarchy static int isnull_leaf(void *vp, G2DESC *rd) { int retval; if (rd->size == 0) { // user-defined type retval = rd->isn(vp); // run the "is_null" function // for the user-defined type } else { // builtin type switch (rd->size) { case LONG_INT_ATTLC+1: retval = *(long*)vp == 0L; break; case SHORT_INT_ATTLC+1: retval = *(short*)vp == 0; break; case CHAR_INT_ATTLC+1: retval = *(char*)vp == 0; break; case STRING_INT_ATTLC+1: { String& temp = *(String*)vp; retval = temp.is_empty(); } } /* end switch */ } return (retval); } static int isnull_general(void *base, G2DESC *rd) { int retval = 1; switch (rd->type) { case 'L': retval = isnull_leaf(base, rd); break; case 'S': { G2DESC *child = rd->child; int nel = rd->nel; for (; --nel >= 0; child++) { if (child->type != 'L') { void *vp; vp = (char*)base + child->offset; if (isnull_general(vp, child) == 0) { retval = 0; break; } } else { void *vp = ((char*)base + child->offset); if (!isnull_leaf(vp, child)) { retval = 0; break; } } } break; } case 'A': { void* vp = ((Vb_ATTLC*)base)->beginning(); int nel = ((Vb_ATTLC*)base)->size(); G2DESC* element = rd->child; if (element->type != 'L') { int i = 0; for (; --nel >= 0; vp = (char*)vp + element->size) { if (i >= rd->nel && rd->nel > 0) { break; } if (!isnull_general(vp, element)) { retval = 0; break; } } } else { int i = 0; for (; --nel >= 0; vp = ((char*)vp + REALSIZE(element->size)),i++) { if (i >= rd->nel && rd->nel > 0) { break; } if (!isnull_leaf(vp, element)) { retval = 0; break; } if (element->size == 0) { vp = (char*)vp + element->nel; } } } } } /* end switch */ return (retval); } static int getmaxarray(void *base, G2DESC *rd) { void* vp = ((Vb_ATTLC*)base)->beginning(); int nel = ((Vb_ATTLC*)base)->size(); G2DESC* element = rd->child; int incr_size; if (element->type != 'L') { incr_size = element->size; } else { if (element->size == 0) { incr_size = element->nel; } else { incr_size = REALSIZE(element->size); } } int i = 0; int max_defined = -1; for (; --nel >= 0; vp = (char*)vp + incr_size) { if (!isnull_general(vp, element)) { // os << i << " "; if (i > max_defined) { max_defined = i; } } i++; } return (max_defined + 1); } // Map a C structure to an output stream int putrec_ATTLC(void* rec, G2DESC* rd, ostream& os) { g2err_ATTLC = 0; DEBUG(cerr << "\nenter putrec_ATTLC with rd=\n";) DEBUG(showdesc_ATTLC(rd);) DEBUG(cerr << "rec=" << rec << "\n";) // Emit name os << rd->name; // print the name of the record type DEBUG(cerr << "Emit name: " << rd->name << "\n";) DEBUG(cerr << "rd->type=" << char(rd->type) << '\n';) if (rd->type == 'L') { // Record is a Leaf DEBUG(cerr << "Record is a leaf\n";) int size = rd->size; DEBUG(cerr << "size=" << size << "\n";) if (isnull_leaf(rec, rd)) { DEBUG(cerr << "null: filter out\n";) } else { if (size == 0) { DEBUG(cerr << "emit it by calling pfn\n";) rd->pfn(os,rec); DEBUG(cerr << "back from call to pfn\n";) } else { DEBUG(cerr << "emit tab\n";) os << '\t'; // Call emit_builtin to emit value DEBUG(cerr << "emit value by calling emit_builtin\n";) emit_builtin(os, size, rec, rd->nel); } } DEBUG(cerr << "emit newline\n";) os << '\n'; } else { // Record is a Structure or Array DEBUG(cerr << "Record is a Structure or Array\n";) if (rd->type == 'A') { os << '\t' << getmaxarray(rec, rd); } DEBUG(cerr << "emit newline\n";) os << '\n'; namestk[0].name = rd->name; DEBUG(cerr << "namestk[0].name gets " << rd->name << "\n";) // Call emit_node with this record DEBUG(cerr << "Call emit_node with this record\n";) outlevel = 1; // call emit_node with level, base, record descriptor, output emit_node(1, rec, rd, os); } // Calculate checksum and return error flag DEBUG(cerr << "Calculate checksum and return error flag\n";) if (Cchksum(os)) { _g2putdot_ATTLC(os); } else { os << '\n'; } /*Eor(os);*/ return (Check_error(os)? -1 : 0); } // Map a Structure or Array to the output stream static void emit_node(int level, void* base, G2DESC* rd, ostream& os) { DEBUG(cerr << "\nenter emit_node with" << "\n" << " level=" << level << "\n" << " base=" << base << "\n";) DEBUG(cerr << "rd=\n";) DEBUG(showdesc_ATTLC(rd);) switch (rd->type) { case 'S': { // This node is a Structure DEBUG(cerr << "This node is a Structure\n";) G2DESC* child = rd->child; int nel = rd->nel; // loop through each child of this node for (; --nel >= 0; child++) { int i; DEBUG(cerr << "in loop, consider child:\n";) DEBUG(showdesc_ATTLC(child);) if (child->type != 'L') { // This child is an Array or Structure DEBUG(cerr << "This child is an Array " << "or Structure\n";) namestk[level].name = child->name; DEBUG(cerr << "namestk[" << level << "].name gets " << child->name << "\n";) if (child->type == 'A') { namestk[level].maxarray = getmaxarray((char*)base + child->offset, child); } // Calculate vp void* vp; DEBUG(cerr << "Calculate vp\n";) vp = (char*)base + child->offset; DEBUG(cerr << "base=" << base << "\n" << "child->offset=" << child->offset << "\n" << "vp=" << vp << "\n";) // Call emit_node recursively for this child DEBUG(cerr << "Call emit_node recursively\n";) emit_node(level+1, vp, child, os); // Fiddle with outlevel (?) DEBUG(cerr << "Fiddle with outlevel\n";) DEBUG(cerr << "return from from emit_node with " << "outlevel=" << outlevel << "\n";) if (outlevel > level) { outlevel = level; DEBUG(cerr << "adjust outlevel to " << outlevel << "\n";) } } else { // This child is a Leaf // // Note: the calculation of vp is common to the then_case // and the else_case of this if; factor it out! DEBUG(cerr << "The child is a leaf\n";) void* vp = ((char*)base + child->offset); DEBUG(cerr << "vp=" << vp << "\n";) // Filter out nulls if (isnull_leaf(vp, child)) { DEBUG(cerr << "null: filter out\n";) continue; } // Emit name hierarchy DEBUG(cerr << "Emit name hierarchy\n";) // do for each level in outlevel..level-1 for(; outlevel < level; outlevel++) { DEBUG(cerr << "in for loop, outlevel=" << outlevel << "\n";) i = outlevel; DEBUG(cerr << "emit " << i << " tabs\n";) while (--i >= 0) { os << '\t'; } char* cp = namestk[outlevel].name; if (cp) { // Name is alphabetic DEBUG(cerr << "Name is alphabetic: \n";) os << cp; DEBUG( cerr << cp << "\n"; ) } else { // Name is an index DEBUG(cerr << "Name is an index: ";) os << namestk[outlevel].index; DEBUG(cerr << namestk[outlevel].index << "\n";) } /* new code to put the size of the array in an array record */ if (namestk[outlevel].maxarray != 0) { os << "\t" << namestk[outlevel].maxarray; namestk[outlevel].maxarray = 0; } DEBUG(cerr << "emit newline\n";) os << '\n'; } // Emit a name-value pair DEBUG(cerr << "ready to emit leaf\n";) i = level; DEBUG(cerr << "emit " << i << " tabs\n";) while (--i >= 0) { os << '\t'; } DEBUG(cerr << "emit name: " << child->name << '\n';) os << child->name; DEBUG(cerr << "emit tab\n";) os << '\t'; if (child->size == 0) { // User-defined type (case 3) DEBUG(cerr << "User-defined type (case 3)\n";) child->pfn(os,vp); DEBUG(cerr << "back from call to pfn\n";) } else { // Builtin type DEBUG(cerr << "builtin type\n";) DEBUG(cerr << "vp=" << vp << "\n";) // Call emit_builtin emit_builtin(os, child->size, vp, child->nel); } DEBUG(cerr << "emit newline\n";) os << '\n'; } } break; } case 'A': { // This node is an Array DEBUG(cerr << "This node is an Array\n";) void* vp = ((Vb_ATTLC*)base)->beginning(); DEBUG(cerr << "base=" << base << "\n" << "vp=" << vp << "\n";) int nel = ((Vb_ATTLC*)base)->size(); DEBUG(cerr << "rd->nel=" << rd->nel << "\n" << "nel=" << nel << "\n";) G2DESC* element = rd->child; DEBUG(cerr << "element=\n";) DEBUG(showdesc_ATTLC(element);) int incr_size; if (element->type != 'L') { incr_size = element->size; } else { if (element->size == 0) { incr_size = element->nel; } else { incr_size = REALSIZE(element->size); } } int i = 0; int max_defined = 0; for (; --nel >= 0; vp = (char*)vp + incr_size) { if (!isnull_general(vp, element)) { // os << i << " "; if (i > max_defined) { max_defined = i; } } i++; } // namestk[level].maxarray = max_defined + 1; vp = ((Vb_ATTLC*)base)->beginning(); nel = ((Vb_ATTLC*)base)->size(); if (element->type != 'L') { // Element type is 'A' or 'S DEBUG(cerr << "Element type is 'A or 'S'\n";) namestk[level].name = NULL; DEBUG(cerr << "namestk[" << level << "].name gets NULL\n";) int i=0; // for each element in the array or structure for (; --nel >= 0; vp = (char*)vp + element->size) { DEBUG(cerr << "in forloop, " << "vp=" << vp << "\n";) // Truncate fixed arrays if necessary if (i>=rd->nel && rd->nel>0) { break; } // Set up namestk[level] for this element namestk[level].name = NULL; DEBUG(cerr << "namestk[" << level << "].name = NULL\n";) DEBUG(cerr << "namestk[" << level << "].index = " << i << "\n";) namestk[level].index = i++; DEBUG(cerr << "Call emit_node recursively:\n";) // Call emit_node recursively for this element emit_node(level+1, vp, element, os); // Fiddle with outlevel (?) DEBUG(cerr << "return from from emit_node with " << "outlevel=" << outlevel << "\n";) DEBUG(cerr << "Fiddle with outlevel\n";) if (outlevel > level) { outlevel = level; DEBUG(cerr << "adjust outlevel to " << outlevel << "\n";) } } } else { // Its element type is a leaf DEBUG(cerr << "Its element type is a leaf\n";) int i = 0; // for each element for (; --nel >= 0; vp = ((char*)vp + REALSIZE(element->size)),i++) { DEBUG(cerr << "in for loop:\n" << " nel=" << nel << "\n" << " vp=" << vp << "\n";) // Filter out nulls if (isnull_leaf(vp, element)) { if (element->size == 0 && element->isn(vp)) { vp = (char*)vp + element->nel; /* size of user defined type is in nel */ } continue; } // Emit name hierarchy DEBUG(cerr << "Emit name hierarchy\n";) // for each level in outlevel..level-1 for (; outlevel < level; outlevel++) { DEBUG(cerr << "in for loop, outlevel=" << outlevel << "\n";) int j = outlevel; DEBUG(cerr << "emit " << j << " tabs\n";) while (--j >= 0) { os << '\t'; } char* cp = namestk[outlevel].name; if (cp) { // Name is alphabetic DEBUG(cerr << "Name is alphabetic: ";) os << cp; DEBUG(cerr << cp << "\n";) } else { // Name is an index DEBUG(cerr << "Name is an index: ";) os << namestk[outlevel].index; DEBUG(cerr << namestk[outlevel].index << "\n";) } /* new code to put the size of the array in an array record */ if (namestk[outlevel].maxarray != 0) { os << "\t" << namestk[outlevel].maxarray; namestk[outlevel].maxarray = 0; } DEBUG(cerr << "emit newline\n";) os << '\n'; } int j = level; DEBUG(cerr << "emit " << j << " tabs\n";) while (--j >= 0) { os << '\t'; } // Emit builtin DEBUG( cerr << "emit builtin: " << i << '\n'; ) os << i; DEBUG(cerr << "emit tab\n";) os << '\t'; if (element->size < 0) { emit_builtin(os, element->size, vp, element->nel); } else if (element->size == 0) { element->pfn(os,vp); DEBUG(cerr << "back from call to pfn\n";) vp = (char*)vp + element->nel; /* size of user defined type is in nel */ } os << '\n'; } } break; } /* end switch */ } } // Emit a value of builtin type static void emit_builtin(ostream& os, int size, void* vp, int max) { DEBUG(cerr << "\nenter emit_builtin with vp, size=" << vp << ", " << size << "\n";) switch (size) { char buf[MAXINTSTR_ATTLC]; // TBD_fixed_limit case LONG_INT_ATTLC+1: { DEBUG(cerr << "emit LONG value: " << *((long*)vp) << '\n'; ) os << *((long*)vp); break; } case SHORT_INT_ATTLC+1: { DEBUG(cerr << "emit SHORT value: " << *((short*)vp) << '\n'; ) os << *((short*)vp); break; } case CHAR_INT_ATTLC+1: { DEBUG(cerr << "CHAR" << '\n';) if (isprint_ATTLC(*(unsigned char *)vp)) { DEBUG(cerr << "emit printable character: " << char(*(char*)vp) << "\n";) os << (*(char*)vp); } else { DEBUG(cerr << "string begins with unprintable character: \\";) os << '\\'; char* p = _g2ctostr_ATTLC(buf, sizeof(buf), *(unsigned char *)vp); while (*p) { DEBUG(cerr << *p;) os << *p++; } DEBUG(cerr << "\n";) } break; } case STRING_INT_ATTLC+1: { DEBUG(cerr << "STRING\n";) const char* cp = (const char*)(*(String*)vp); const char* guard = cp+max; const char* p = cp; while (*p && (max==0 || p