//# Template.cc: Canonicalise, format etc. Casacore template definitions //# Copyright (C) 2001-2005 //# Associated Universities, Inc. Washington DC, USA. //# //# This library is free software; you can redistribute it and/or modify it //# under the terms of the GNU Library General Public License as published by //# the Free Software Foundation; either version 2 of the License, or (at your //# option) any later version. //# //# This library 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 Library General Public //# License for more details. //# //# You should have received a copy of the GNU Library General Public License //# along with this library; if not, write to the Free Software Foundation, //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. //# //# Correspondence concerning AIPS++ should be addressed as follows: //# Internet email: aips2-request@nrao.edu. //# Postal address: AIPS++ Project Office //# National Radio Astronomy Observatory //# 520 Edgemont Road //# Charlottesville, VA 22903-2475 USA //# //# $Id$ #ifndef CASA_TEMPLATE_TCC #define CASA_TEMPLATE_TCC //# Includes #include #include #include #include #include #include #include #include #include namespace casacore { //# NAMESPACE CASACORE - BEGIN //# Static constants // Patterns to analyse an input line const Regex Template::spaces = String("^[[:space:]]*$"); const Regex Template::comment = String("^[[:space:]]*#"); const Regex Template::ifRE = String("^[[:space:]]*#if"); const Regex Template::endifRE = String("^[[:space:]]*#endif[[:space:]]*$"); const Regex Template::elseRE = String("^[[:space:]]*#else[[:space:]]*$"); const Regex Template::templateRE = String("^[[:space:]]*template[[:space:]<]"); const Regex Template::contRE = String("^[[:space:]]*="); const Regex Template::fileRE = String("^[[:space:]]*[[:digit:]]*" "[[:space:]]*" "[^.[:space:]]*[.](cc|h)"); const Regex Template::typedefRE = String("^[[:space:]]*typedef[[:space:]]"); const Regex Template::auxtemplRE = String("^[[:space:]]*" "AIPS_[A-Z0-9]*_AUX_TEMPLATES" "[[:space:](]"); const Regex Template::namespaceRE= String("^[[:space:]]*#namespace"); // Simple pattern and replacements to make canonical templates files const Regex Template::PATcanon[Ncanon] = { String("[[:space:]]"), // 00 String(" ="), String(" *"), String("^ "), String(" $"), String(" [(]"), String(" ,"), String(","), String("&"), String("[*][*]"), String(" [*] [*]"), // 10 String("[(] [*][)]"), String("[(] *"), String("[*]const"), String(" operator "), String(" operator[ ]*&[ ]*&[(]"), String(" <"), String("< "), String(" >"), String(">>"), String(">>"), // 20 String("operator> >[(]"), String(" template *< *>"), String(" template *<"), String("> *class "), String("short unsigned int"), String("unsigned short int"), String("short signed int"), String("signed short int"), String("long unsigned int"), String("unsigned long int"), // 30 String("long signed int"), String("signed long int"), String("unsigned char"), String("signed char"), String("unsigned short"), String("short unsigned"), String("signed short"), String("short signed"), String("short int"), String("unsigned long"), // 40 String("long unsigned"), String("signed long"), String("long signed"), String("long int"), String("long float"), String("long double"), String("unsigned int"), String("signed int"), String(" *;+$"), String(" *"), // 50 String(">const") }; const String Template::REPcanon[Ncanon] = { " ", // 00 " = ", " ", "", "", "(", ",", ", ", " &", "* *", " **", // 10 "(*)", "(", "* const", " operator", " operator&&(", "<", "<", ">", "> >", "> >", // 20 "operator>>(", " template <> ", " template <", "> class ", "uShort", "uShort", "Short", "Short", "uLong", "uLong", // 30 "Long", "Long", "uChar", "Char", "uShort", "uShort", "Short", "Short", "Short", "uLong", // 40 "uLong", "Long", "Long", "Long", "Double", "lDouble", "uInt", "Int", "", " ", // 50 "> const" }; const Regex Template::PATcanon20[Ncanon2] = { String("[^[:alnum:]_]char[^[:alnum:]_]"), // 00 String("[^[:alnum:]_]short[^[:alnum:]_]"), String("[^[:alnum:]_]unsigned[^[:alnum:]_]"), String("[^[:alnum:]_]signed[^[:alnum:]_]"), String("[^[:alnum:]_]int[^[:alnum:]_]"), String("[^[:alnum:]_]long[^[:alnum:]_]"), String("[^[:alnum:]_]float[^[:alnum:]_]"), String("[^[:alnum:]_]double[^[:alnum:]_]"), String("[^[:alnum:]_]complex"), String("[^[:alnum:]_]complex"), String(""), // 10 String(""), String("[^[:alnum:]_]bool[^[:alnum:]_]"), String("std::Complex"), String("std::DComplex") }; const Regex Template::PATcanon21[Ncanon2] = { String("char"), // 00 String("short"), String("unsigned"), String("signed"), String("int"), String("long"), String("float"), String("double"), String("complex"), String("complex"), String(""), // 10 String(""), String("bool"), String("std::Complex"), String("std::DComplex") }; const String Template::REPcanon2[Ncanon2] = { "Char", // 00 "Short", "uInt", "Int", "Int", "Long", "Float", "Double", "Complex", "DComplex", "", // 10 "", "Bool", "std::complex", "std::complex" }; // Make canonical numbers of 4 digits minimum const Regex Template::PATnmin[Nnmin] = { String("^[^[:digit:]]"), // 00 String("^[[:digit:]] "), String("^[[:digit:]][[:digit:]] "), String("^[[:digit:]][[:digit:]][[:digit:]] ") }; const String Template::REPnmin[Nnmin] = { "0000 ", // 00 "000", "00", "0" }; // Make canonical numbers of 4 digits maximum const Regex Template::PATnmax[Nnmax] = { String("^[[:digit:]][[:digit:]][[:digit:]][[:digit:]][[:digit:]]+ ") }; const Regex Template::REPnmax[Nnmax] = { String("[[:digit:]][[:digit:]][[:digit:]][[:digit:]] ") }; // Patterns to split off number and name const Regex Template::splitnum = String("^[[:digit:]]+ "); const Regex Template::splitnam = String("^[^ ]+ "); // Patterns to check the saved template line const Regex Template::sifRE("^#if"); const Regex Template::stemRE("^template"); const Regex Template::sconstRE("([(] *const|, *const|< *const)"); const Regex Template::sretRE1("^template class "); const Regex Template::sretRE2("^template [^ ]*[(]"); const Regex Template::sretRE3("^template <"); const Regex Template::sretRE4("[^t][^o][^r>]>[(]"); const Regex Template::stypedefRE("^typedef"); const Regex Template::sauxtemplRE("^AIPS_[A-Z0-9]*_AUX_TEMPLATES"); const Regex Template::snamespaceRE("^#namespace"); // Replacement patterns for ifs in saved line const String Template::PATinif[Ninif] = { String("& &"), // 00 String("= ="), String("<"), String("< ="), String(">") }; const String Template::REPinif[Ninif] = { "&&", // 00 "==", " < ", "<=", " >" }; // Tests for finding real templates for duplicate tests const Regex Template::classprelude("^.*template[[:space:]]*class[[:space:]]*"); const Regex Template::functionprelude("^.*template[[:space:]]*"); const Regex Template::forwardprelude("^.*template[[:space:]]*<"); const Regex Template::funcnameprelude("[^[:space:]]*[:(]"); const Regex Template::mylistprelude("^[[:space:]]*[[:digit:]]+: "); // Data to remove spaces at begin, end, make single, count/remove const const Regex Template::leadsp("^[[:space:]]+"); const Regex Template::endsp("[[:space:]]+$"); const Regex Template::mulsp("[[:space:]]+"); const Regex Template::constsp("const"); const String Template::nullsp; const String Template::singlesp(" "); // Patterns to make all typedefs comparisons for duplicates possible // Note that the first three should be in that position for run-time // change on some systems. const Regex Template::PATtypedef0[Ntypedef] = { String("[^[:alnum:]_]FitsLong[^[:alnum:]_]"), // 00 String("[^[:alnum:]_]lDouble[^[:alnum:]_]"), String("[^[[:alnum:]_]Long[^[:alnum:]_]"), String("[[:alnum:]_]DataStatus[[:alnum:]_]"), String("[[:alnum:]_]LogicalRecord[[:alnum:]_]"), String("[[:alnum:]_]TapeHeader[[:alnum:]_]"), String("[[:alnum:]_]Convolver[[:alnum:]_]"), String("[[:alnum:]_]Convolver][[:alnum:]_]"), String("[[:alnum:]_]AipsrcValue[[:alnum:]_]"), String("[[:alnum:]_]AipsrcValue[[:alnum:]_]"), String("[[:alnum:]_]AipsrcValue[[:alnum:]_]"), // 10 String("[[:alnum:]_]AipsrcVector[[:alnum:]_]"), String("[[:alnum:]_]AipsrcVector[[:alnum:]_]"), String("[[:alnum:]_]AipsrcVector[[:alnum:]_]"), String("[[:alnum:]_]AipsrcVector[[:alnum:]_]"), String("[[:alnum:]_]LogicalArrayElem[[:alnum:]_]"), String("[[:alnum:]_]Array[[:alnum:]_]"), String("[[:alnum:]_]MaskedArray[[:alnum:]_]"), String("[[:alnum:]_]Cube[[:alnum:]_]"), String("[[:alnum:]_]Matrix[[:alnum:]_]"), String("[[:alnum:]_]Vector[[:alnum:]_]"), // 20 String("[[:alnum:]_]MeasurementSet[[:alnum:]_]"), String("[[:alnum:]_]Quantum[[:alnum:]_]") }; const Regex Template::PATtypedef1[Ntypedef] = { String("FitsLong"), // 00 String("lDouble"), String("Long"), String("DataStatus"), String("LogicalRecord"), String("TapeHeader"), String("Convolver"), String("Convolver"), String("AipsrcValue"), String("AipsrcValue"), String("AipsrcValue"), // 10 String("AipsrcVector"), String("AipsrcVector"), String("AipsrcVector"), String("AipsrcVector"), String("LogicalArrayElem"), String("Array"), String("MaskedArray"), String("Cube"), String("Matrix"), String("Vector"), // 20 String("MeasurementSet"), String("Quantum") }; String Template::REPtypedef[Ntypedef] = { "Long", // 00 "lDouble", "Long", "DataStatusStructure", "LogicalRecordStructure", "TapeHeader", "DoubleConvolver", "FloatConvolver", "AipsrcBool", "AipsrcDouble", "AipsrcInt", // 10 "AipsrcVBool", "AipsrcVDouble", "AipsrcVInt", "AipsrcVString", "Bool", "LogicalArray", "MaskedArrayLogical", "LogicalCube", "LogicalMatrix", "LogicalVector", //20 "MS", "Quantity" }; // Name of repository files const String Template::reposName = "/_ReposFiller/templates"; //# Constructors Template::Template() : output_p(100), count_p(0), tcount_p(0), comout_p(100), comptr_p(100), ccount_p(0), isSplit_p(False), dcount_p(0), nstring_p(0), allstring_p(0), namstring_p(0), nval_p(0), tdflist_p(0), tdcount_p(0), tdlist_p(100), tdfile_p(100), tdline_p(100), tdname_p(0) { reset(); } Template::Template(const Vector &files) : output_p(100), count_p(0), tcount_p(0), comout_p(100), comptr_p(100), ccount_p(0), isSplit_p(False), dcount_p(0), nstring_p(0), allstring_p(0), namstring_p(0), nval_p(0), tdflist_p(0), tdcount_p(0), tdlist_p(100), tdfile_p(100), tdline_p(100), tdname_p(0) { reset(); read(files); } Template::Template(const String &filename) : output_p(100), count_p(0), tcount_p(0), comout_p(100), comptr_p(100), ccount_p(0), isSplit_p(False), dcount_p(0), nstring_p(0), allstring_p(0), namstring_p(0), nval_p(0), tdflist_p(0), tdcount_p(0), tdlist_p(100), tdfile_p(100), tdline_p(100), tdname_p(0) { reset(); read(filename); } //# Destructor Template::~Template() {} //# Member functions void Template::reset() { count_p = 0; tcount_p = 0; ccount_p = 0; isSplit_p = False; dcount_p = 0; tdcount_p = 0; tdflist_p.resize(0); // Make sure all (known) variable typedefs are catered for if (typeid(FitsLong) == typeid(Int)) REPtypedef[0] = "Int"; if (typeid(lDouble) == typeid(Double)) REPtypedef[1] = "Double"; if (typeid(Long) == typeid(Int)) REPtypedef[2] = "Int"; } void Template::read(const Vector &files) { for (uInt i=0; i < files.nelements(); i++) { // for each file... read(files(i)); } } void Template::read(const String &filename) { // Open and read file ifstream file(filename.chars(), ios::in); if (!file) { cerr << "Cannot open input file " << filename << endl; return; } // Save filename in list tdflist_p.resize(tdflist_p.nelements()+1); tdflist_p[tdflist_p.nelements()-1] = filename; String extracted; // a single input line String combine; // a full combined line uInt c1 = 0; // the input line count Bool ok(True); while (ok && (((extracted = ""), (ok = getline(file, extracted))) || !combine.empty())) { c1++; // Count input lines Bool err = False; // Skip empty lines if ((extracted.empty() || extracted.contains(spaces)) && ok) continue; // Check if correct first line if (combine.empty() && ok) { // Comment allowed if (extracted.contains(comment)) setComment(extracted, combine.empty()); // Start of entry allowed else if (extracted.contains(fileRE)) combine = extracted; else err = True; if (!err) continue; } // Handle regular extension lines if ((extracted.contains(ifRE) || extracted.contains(endifRE) || extracted.contains(elseRE) || extracted.contains(templateRE) || extracted.contains(contRE) || extracted.contains(typedefRE) || extracted.contains(auxtemplRE) || extracted.contains(namespaceRE)) && ok && !err) { // Replace a continuation include line with /=/ pattern if (extracted.contains(contRE)) extracted.gsub(contRE, String("/=/")); combine += String(" ") + extracted; // make one line // Find proper templates for list if (extracted.contains(templateRE)) { if (extracted.contains(forwardprelude)) continue; // skip forward declarations if (extracted.contains(mylistprelude)) { // special nnnn: list format extracted = extracted.after(mylistprelude); } else if (extracted.contains(classprelude)) { extracted = extracted.after(classprelude); // template class } else if (extracted.contains(functionprelude)) { extracted = extracted.after(functionprelude); // template global if (extracted.contains(funcnameprelude)) { extracted = extracted.from(funcnameprelude); } } else continue; // unknown entry if (!extracted.empty()) { // save the entry if (tdcount_p >= tdlist_p.nelements()) { tdlist_p.resize(tdcount_p+100); tdfile_p.resize(tdcount_p+100); tdline_p.resize(tdcount_p+100); } tdlist_p[tdcount_p] = extracted; tdfile_p[tdcount_p] = tdflist_p.nelements()-1; tdline_p[tdcount_p++] = c1; } } continue; } // Handle comment lines if (ok && !err && extracted.contains(comment)) { setComment(extracted, combine.empty()); continue; } // Handle an initial line if ((ok && !err && extracted.contains(fileRE)) || !ok) { if (!combine.empty()) setOutput(combine); combine = extracted; } else err = True; if (err) { cerr << "Warning: illegal entry commented out near line " << c1 << " in " << filename << ":\n\t" << extracted(0, ((extracted.length() <= 60) ? extracted.length() : 60)) << " ..." << endl; for (uInt j=0; j inx; Sort sort; sort.sortKey(allstring_p.storage(), TpString); sort.sortKey(nstring_p.storage(), TpString); // Sort and fill missing numbers sort.sort(inx, count_p); // Make numbers if (renumber) { String prev; uInt ident(0); for (uInt j=0; j mid) ? nval_p[inx(j)] : mid; j++; } mid = (mid/10)*10 + 10; } if (prev == namstring_p[inx(k)]) { if (nval_p[inx(k)] < 1000) { ostringstream text; text << mid; nstring_p[inx(k)] = String(text) + " "; nval_p[inx(k)] = mid; mid += 10; } else { for (Int j=k-1; j>=pid; j--) { if (nval_p[inx(k)] == nval_p[inx(j)]) { ostringstream text; text << mid; namstring_p[inx(k)] = String(text) + " "; nval_p[inx(k)] = mid; mid += 10; break; } } } } else { prev = ""; k--; } } } // Make new full line for (uInt j=0; j= 0 && comptr_p[j] < Int(count_p)) { for (uInt j3=0; j340) { os << w << v << endl; v = "= "; // Indicate follow-on include w = " "; // Indent for (Int i1=0; i10) { c--; w = " "; for (Int i1=0; i1= Int(count_p)) { c1++; os << comout_p[j2] << endl; } } if (cwarn) { cerr << "Warning: One or more possibly superfluous template arguments " "given.\n Run reident with the -v (verbose) switch to learn more" << endl; } } void Template::writeDup(ostream &os, const String &userFile, Bool isSys) { // Sort the name list Vector inx; Sort sort; sort.sortKey(tdname_p.storage(), TpString); sort.sort(inx, tdcount_p); uInt i(0); // Count the entries // Scan all entries for groups dcount_p = 0; while (i1) { // Check if -s switch given Bool doit = True; if (isSys) { doit = False; // Check if _ReposFiller mentioned for (uInt j=i; j= comout_p.nelements()) { comout_p.resize(ccount_p+100); comptr_p.resize(ccount_p+100); } comout_p[ccount_p] = txt; comptr_p[ccount_p] = count_p; if (atstart && count_p == 0) comptr_p[ccount_p] = -1; ccount_p++; } void Template::setOutput(const String &txt) { if (count_p >= output_p.nelements()) output_p.resize(count_p+100); output_p[count_p++] = txt; } } //# NAMESPACE CASACORE - END #endif