/** * Call this method to generate sql code for a UMLClassifier. * @param c the class to generate code for */ void SQLWriter::writeClass(UMLClassifier *c) { UMLEntity* e = c->asUMLEntity(); if (!e) { uError() << "Invalid cast from" << c->baseTypeStr() << "'" << c->name() << "' to UMLEntity*"; return; } m_pEntity = e; QString entityname = cleanName(m_pEntity->name()); //find an appropriate name for our file QString fileName = findFileName(m_pEntity, QLatin1String(".sql")); if (fileName.isEmpty()) { emit codeGenerated(m_pEntity, false); return; } QFile file; if (!openFile(file, fileName)) { emit codeGenerated(m_pEntity, false); return; } //Start generating the code!! QTextStream sql(&file); //try to find a heading file (license, coments, etc) QString str; str = getHeadingFile(QLatin1String(".sql")); if (!str.isEmpty()) { str.replace(QRegExp(QLatin1String("%filename%")), fileName); str.replace(QRegExp(QLatin1String("%filepath%")), file.fileName()); sql << str << m_endl; } //Write class Documentation if there is somthing or if force option if (forceDoc() || !m_pEntity->doc().isEmpty()) { sql << m_endl << "--" << m_endl; sql << "-- TABLE: " << entityname << m_endl; sql << formatDoc(m_pEntity->doc(),QLatin1String("-- ")); sql << "-- " << m_endl << m_endl; } // write all entity attributes UMLEntityAttributeList entAttList = m_pEntity->getEntityAttributes(); sql << "CREATE TABLE " << entityname << " ("; printEntityAttributes(sql, entAttList); sql << m_endl << ");" << m_endl; // auto increments UMLEntityAttributeList autoIncrementList; foreach(UMLEntityAttribute* entAtt, entAttList) { autoIncrementList.append(entAtt); }
void JSWriter::writeOperations(QString classname, UMLOperationList *opList, QTextStream &js) { UMLOperation *op; UMLAttribute *at; for(op = opList->first(); op; op = opList->next()) { UMLAttributeList atl = op->getParmList(); //write method doc if we have doc || if at least one of the params has doc bool writeDoc = forceDoc() || !op->getDoc().isEmpty(); for (at = atl.first(); at; at = atl.next()) writeDoc |= !at->getDoc().isEmpty(); if( writeDoc ) //write method documentation { js << "/**" << m_endl << formatDoc(op->getDoc()," * "); for (at = atl.first(); at; at = atl.next()) //write parameter documentation { if(forceDoc() || !at->getDoc().isEmpty()) { js << " * @param " + cleanName(at->getName())<<m_endl; js << formatDoc(at->getDoc()," * "); } }//end for : write parameter documentation js << " */" << m_endl; }//end if : write method documentation js << classname << ".prototype." << cleanName(op->getName()) << " = function " << "("; int i = atl.count(); int j=0; for (at = atl.first(); at ;at = atl.next(),j++) { js << cleanName(at->getName()) << (!(at->getInitialValue().isEmpty()) ? (QString(" = ")+at->getInitialValue()) : QString("")) << ((j < i-1)?", ":""); } js << ")" << m_endl << "{" << m_endl << m_indentation << m_endl << "}" << m_endl; js << m_endl << m_endl; }//end for }
void JSWriter::writeAssociation(QString& classname, UMLAssociationList& assocList , QTextStream &js) { for (UMLAssociation *a = assocList.first(); a; a = assocList.next()) { // association side Uml::Role_Type role = (a->getObject(Uml::A)->getName() == classname ? Uml::B : Uml::A); QString roleName(cleanName(a->getRoleName(role))); if (!roleName.isEmpty()) { // association doc if (forceDoc() || !a->getDoc().isEmpty()) { js << m_indentation << "/**" << m_endl << formatDoc(a->getDoc(), m_indentation + " * ") << m_indentation << " */" << m_endl; } // role doc if (forceDoc() || !a->getRoleDoc(role).isEmpty()) { js << m_indentation << "/**" << m_endl << formatDoc(a->getRoleDoc(role), m_indentation + " * ") << m_indentation << " */" << m_endl; } bool okCvt; int nMulti = a->getMulti(role).toInt(&okCvt,10); bool isNotMulti = a->getMulti(role).isEmpty() || (okCvt && nMulti == 1); QString typeName(cleanName(a->getObject(role)->getName())); if (isNotMulti) js << m_indentation << "this.m_" << roleName << " = new " << typeName << "();" << m_endl; else js << m_indentation << "this.m_" << roleName << " = new Array();" << m_endl; // role visibility } } }
XL::Tree *ExtractDoc::DoInfix(XL::Infix *what) // ---------------------------------------------------------------------------- // Extract the documentation (/** **/) from an Infix // ---------------------------------------------------------------------------- { // There are two specifics kind of Infix : the "->" that define a transformation // and ":" on the left side of "->" that define a parameter bool def = (what->name.find("->") != std::string::npos); if (def) { params_tree = 0; symbol.clear(); syntax.clear(); params.clear(); if (XL::Name *name = what->left->AsName()) symbol = name->value; } bool param = params_tree > 0 && (what->name.find(":") != std::string::npos); XL::Text *c = NULL; text comment = ""; XL::CommentsInfo *info = what->GetInfo<XL::CommentsInfo>(); if (info) comment = extract(info->before); if (def ) params_tree++; XL::Tree *left = what->left->Do(this); if (def) params_tree--; if (!def && left && (c = left->AsText())) comment += c->value; XL::Tree *right = what->right->Do(this); if (right && (c = right->AsText())) comment += c->value; if (info) comment+= extract(info->after); if (param) { addParam(what->left->AsName(), what->right->AsName(), &comment); } if (def) { formatSyntax(what->left); return new XL::Text(formatDoc(&comment)); } return new XL::Text(comment,"",""); }
void CSharpWriter::writeAttribute(QString doc, Uml::Visibility visibility, bool isStatic, QString typeName, QString name, QString initialValue, bool asProperty, QTextStream &cs) { if (forceDoc() || !doc.isEmpty()) { cs << m_container_indent << m_indentation << "/// <summary>" << m_endl; cs << formatDoc(doc, m_container_indent + m_indentation + "/// "); cs << m_container_indent << m_indentation << "/// </summary>" << m_endl; } cs << m_container_indent << m_indentation; cs << visibility.toString() << " "; if (isStatic) cs << "static "; //Variable type with/without namespace path cs << typeName << " "; cs << cleanName(name); // FIXME: may need a GUI switch to not generate as Property? // Generate as Property if not private if (asProperty) { cs << m_endl; cs << m_container_indent << m_indentation << "{" << m_endl; cs << m_container_indent << m_indentation << m_indentation << "get" << m_endl; cs << m_container_indent << m_indentation << m_indentation << "{" << m_endl; cs << m_container_indent << m_indentation << m_indentation << m_indentation << "return m_" << cleanName(name) << ";" << m_endl; cs << m_container_indent << m_indentation << m_indentation << "}" << m_endl; cs << m_container_indent << m_indentation << m_indentation << "set" << m_endl; cs << m_container_indent << m_indentation << m_indentation << "{" << m_endl; cs << m_container_indent << m_indentation << m_indentation << m_indentation << "m_" << cleanName(name) << " = value;" << m_endl; cs << m_container_indent << m_indentation << m_indentation << "}" << m_endl; cs << m_container_indent << m_indentation << "}" << m_endl; cs << m_container_indent << m_indentation << "private "; if (isStatic) cs << "static "; cs << typeName << " m_" << cleanName(name); } if (!initialValue.isEmpty()) cs << " = " << initialValue; cs << ";" << m_endl << m_endl; }
void CSharpWriter::writeOperations(UMLOperationList opList, QTextStream &cs, bool isInterface /* = false */, bool isOverride /* = false */, bool generateErrorStub /* = false */) { for (UMLOperation *op=opList.first(); op ; op=opList.next()) { UMLAttributeList atl = op->getParmList(); UMLAttribute *at; //write method doc if we have doc || if at least one of the params has doc bool writeDoc = forceDoc() || !op->getDoc().isEmpty(); for (at = atl.first(); at; at = atl.next()) { writeDoc |= !at->getDoc().isEmpty(); } //write method documentation if (writeDoc && !isOverride) { cs << m_container_indent << m_indentation << "/// <summary>" << m_endl; cs << formatDoc(op->getDoc(), m_container_indent + m_indentation + "/// "); cs << m_container_indent << m_indentation << "/// </summary>" << m_endl; //write parameter documentation for (at = atl.first(); at; at = atl.next()) { if (forceDoc() || !at->getDoc().isEmpty()) { cs << m_container_indent << m_indentation << "/// <param name=\"" << cleanName(at->getName()) << "\">"; //removing newlines from parameter doc cs << formatDoc(at->getDoc(), "").replace("\n", " ").remove('\r').replace(QRegExp(" $"), ""); cs << "</param>" << m_endl; } } // FIXME: "returns" should contain documentation, not type. cs << m_container_indent << m_indentation << "/// <returns>"; if (! op->getTypeName().isEmpty()) { cs << makeLocalTypeName(op); } cs << "</returns>" << m_endl; } // method visibility cs << m_container_indent << m_indentation; if (!isInterface) { if (!isOverride) { if (op->getAbstract()) cs << "abstract "; cs << op->getVisibility().toString() << " "; if (op->getStatic()) cs << "static "; } else { // method overriding an abstract parent cs << op->getVisibility().toString() << " override "; if (op->getStatic()) cs << "static "; } } // return type (unless constructor, destructor) if (!op->isLifeOperation()) { if (op->getTypeName().isEmpty()) { cs << "void "; } else { cs << makeLocalTypeName(op) << " "; } } // method name cs << cleanName(op->getName()) << "("; // method parameters int i= atl.count(); int j=0; for (at = atl.first(); at; at = atl.next(), j++) { cs << makeLocalTypeName(at) << " " << cleanName(at->getName()); // no initial values in C# //<< (!(at->getInitialValue().isEmpty()) ? // (QString(" = ")+at->getInitialValue()) : // QString("")) cs << ((j < i-1)?", ":""); } cs << ")"; //FIXME: how to control generation of error stub? if (!isInterface && (!op->getAbstract() || isOverride)) { cs << m_endl << m_container_indent << m_indentation << "{" << m_endl; if (generateErrorStub) { cs << m_container_indent << m_indentation << m_indentation; cs << "throw new Exception(\"The method or operation is not implemented.\");" << m_endl; } cs << m_container_indent << m_indentation << "}" << m_endl; } else { cs << ';' << m_endl; } cs << m_endl; } }
void CSharpWriter::writeClass(UMLClassifier *c) { if (!c) { kDebug()<<"Cannot write class of NULL concept!" << endl; return; } QString classname = cleanName(c->getName()); //find an appropriate name for our file QString fileName = findFileName(c, ".cs"); if (fileName.isEmpty()) { emit codeGenerated(c, false); return; } QFile filecs; if (!openFile(filecs, fileName)) { emit codeGenerated(c, false); return; } QTextStream cs(&filecs); ////////////////////////////// //Start generating the code!! ///////////////////////////// //try to find a heading file (license, coments, etc) QString str; str = getHeadingFile(".cs"); if (!str.isEmpty()) { str.replace(QRegExp("%filename%"),fileName); str.replace(QRegExp("%filepath%"),filecs.name()); cs<<str<<m_endl; } UMLDoc *umldoc = UMLApp::app()->getDocument(); UMLFolder *logicalView = umldoc->getRootFolder(Uml::mt_Logical); // write generic includes cs << "using System;" << m_endl; cs << "using System.Text;" << m_endl; cs << "using System.Collections;" << m_endl; cs << "using System.Collections.Generic;" << m_endl << m_endl; //write includes and namespace UMLPackage *container = c->getUMLPackage(); if (container == logicalView) container = NULL; UMLPackageList includes; findObjectsRelated(c, includes); m_seenIncludes.clear(); //m_seenIncludes.append(logicalView); if (includes.count()) { UMLPackage *p; for (UMLPackageListIt it(includes); (p = it.current()) != NULL; ++it) { UMLClassifier *cl = dynamic_cast<UMLClassifier*>(p); if (cl) p = cl->getUMLPackage(); if (p != logicalView && m_seenIncludes.findRef(p) == -1 && p != container) { cs << "using " << p->getFullyQualifiedName(".") << ";" << m_endl; m_seenIncludes.append(p); } } cs << m_endl; } m_container_indent = ""; if (container) { cs << "namespace " << container->getFullyQualifiedName(".") << m_endl; cs << "{" << m_endl << m_endl; m_container_indent = m_indentation; m_seenIncludes.append(container); } //Write class Documentation if there is somthing or if force option if (forceDoc() || !c->getDoc().isEmpty()) { cs << m_container_indent << "/// <summary>" << m_endl; cs << formatDoc(c->getDoc(), m_container_indent + "/// " ); cs << m_container_indent << "/// </summary>" << m_endl ; } UMLClassifierList superclasses = c->getSuperClasses(); UMLAssociationList aggregations = c->getAggregations(); UMLAssociationList compositions = c->getCompositions(); UMLAssociationList realizations = c->getRealizations(); bool isInterface = c->isInterface(); m_unnamedRoles = 1; cs << m_container_indent << "public "; //check if it is an interface or regular class if (isInterface) { cs << "interface " << classname; } else { //check if class is abstract and / or has abstract methods if (c->getAbstract() || c->hasAbstractOps()) cs << "abstract "; cs << "class " << classname << (superclasses.count() > 0 ? " : ":""); // write baseclass, ignore interfaces, write error on multiple inheritance if (superclasses.count() > 0) { UMLClassifier *obj; int supers = 0; for (obj = superclasses.first(); obj; obj = superclasses.next()) { if (!obj->isInterface()) { if (supers > 0) { cs << " // AND "; } cs << cleanName(obj->getName()); supers++; } } if (supers > 1) { cs << m_endl << "//WARNING: C# does not support multiple inheritance but there is more than 1 superclass defined in your UML model!" << m_endl; } } //check for realizations UMLAssociationList realizations = c->getRealizations(); UMLAssociation *a; if (!realizations.isEmpty()) { for (a = realizations.first(); a; a = realizations.next()) { UMLClassifier *real = (UMLClassifier*)a->getObject(Uml::B); if(real != c) { // write list of realizations cs << ", " << real->getName(); } } } } cs << m_endl << m_container_indent << '{' << m_endl; //associations if (forceSections() || !aggregations.isEmpty()) { cs << m_endl << m_container_indent << m_indentation << "#region Aggregations" << m_endl << m_endl; writeAssociatedAttributes(aggregations, c, cs); cs << m_endl << m_container_indent << m_indentation << "#endregion" << m_endl; } //compositions if (forceSections() || !compositions.isEmpty()) { cs << m_endl << m_container_indent << m_indentation << "#region Compositions" << m_endl << m_endl; writeAssociatedAttributes(compositions, c, cs); cs << m_endl << m_container_indent << m_indentation << "#endregion" << m_endl; } //attributes // FIXME: C# allows Properties in interface! if (!isInterface) writeAttributes(c, cs); //operations writeOperations(c, cs); //finish file cs << m_endl << m_container_indent << "}" << m_endl << m_endl; // close class if (container) { cs << "} // end of namespace " << container->getFullyQualifiedName(".") << m_endl << m_endl; } //close files and notfiy we are done filecs.close(); emit codeGenerated(c, true); }
void JSWriter::writeClass(UMLClassifier *c) { if(!c) { kDebug()<<"Cannot write class of NULL concept!" << endl; return; } QString classname = cleanName(c->getName()); QString fileName = c->getName().lower(); //find an appropriate name for our file fileName = findFileName(c,".js"); if (fileName.isEmpty()) { emit codeGenerated(c, false); return; } QFile filejs; if(!openFile(filejs, fileName)) { emit codeGenerated(c, false); return; } QTextStream js(&filejs); ////////////////////////////// //Start generating the code!! ///////////////////////////// //try to find a heading file (license, coments, etc) QString str; str = getHeadingFile(".js"); if(!str.isEmpty()) { str.replace(QRegExp("%filename%"),fileName); str.replace(QRegExp("%filepath%"),filejs.name()); js << str << m_endl; } //write includes UMLPackageList includes; findObjectsRelated(c,includes); for (UMLPackage *conc = includes.first(); conc; conc = includes.next()) { QString headerName = findFileName(conc, ".js"); if ( !headerName.isEmpty() ) { js << "#include \"" << headerName << "\"" << m_endl; } } js << m_endl; //Write class Documentation if there is somthing or if force option if(forceDoc() || !c->getDoc().isEmpty()) { js << m_endl << "/**" << m_endl; js << " * class " << classname << m_endl; js << formatDoc(c->getDoc()," * "); js << " */" << m_endl << m_endl; } //check if class is abstract and / or has abstract methods if(c->getAbstract() && !hasAbstractOps(c)) js << "/******************************* Abstract Class ****************************" << m_endl << " " << classname << " does not have any pure virtual methods, but its author" << m_endl << " defined it as an abstract class, so you should not use it directly." << m_endl << " Inherit from it instead and create only objects from the derived classes" << m_endl << "*****************************************************************************/" << m_endl << m_endl; js << classname << " = function ()" << m_endl; js << "{" << m_endl; js << m_indentation << "this._init ();" << m_endl; js << "}" << m_endl; js << m_endl; UMLClassifierList superclasses = c->getSuperClasses(); for (UMLClassifier *obj = superclasses.first(); obj; obj = superclasses.next()) { js << classname << ".prototype = new " << cleanName(obj->getName()) << " ();" << m_endl; } js << m_endl; if (! c->isInterface()) { UMLAttributeList atl = c->getAttributeList(); js << "/**" << m_endl; QString temp = "_init sets all " + classname + " attributes to their default value." " Make sure to call this method within your class constructor"; js << formatDoc(temp, " * "); js << " */" << m_endl; js << classname << ".prototype._init = function ()" << m_endl; js << "{" << m_endl; for(UMLAttribute *at = atl.first(); at ; at = atl.next()) { if (forceDoc() || !at->getDoc().isEmpty()) { js << m_indentation << "/**" << m_endl << formatDoc(at->getDoc(), m_indentation + " * ") << m_indentation << " */" << m_endl; } if(!at->getInitialValue().isEmpty()) { js << m_indentation << "this.m_" << cleanName(at->getName()) << " = " << at->getInitialValue() << ";" << m_endl; } else { js << m_indentation << "this.m_" << cleanName(at->getName()) << " = \"\";" << m_endl; } } } //associations UMLAssociationList aggregations = c->getAggregations(); if (forceSections() || !aggregations.isEmpty ()) { js << m_endl << m_indentation << "/**Aggregations: */" << m_endl; writeAssociation(classname, aggregations , js ); } UMLAssociationList compositions = c->getCompositions(); if( forceSections() || !compositions.isEmpty()) { js << m_endl << m_indentation << "/**Compositions: */" << m_endl; writeAssociation(classname, compositions , js ); } js << m_endl; js << "}" << m_endl; js << m_endl; //operations UMLOperationList ops(c->getOpList()); writeOperations(classname, &ops, js); js << m_endl; //finish file //close files and notfiy we are done filejs.close(); emit codeGenerated(c, true); }
void SQLWriter::writeClass(UMLClassifier *c) { if(!c) { kDebug()<<"Cannot write class of NULL concept!" << endl; return; } const bool isClass = !c->isInterface(); QString classname = cleanName(c->getName()); //find an appropriate name for our file QString fileName = findFileName(c, ".sql"); if (fileName.isEmpty()) { emit codeGenerated(c, false); return; } QFile file; if( !openFile(file, fileName) ) { emit codeGenerated(c, false); return; } //Start generating the code!! QTextStream sql(&file); //try to find a heading file (license, coments, etc) QString str; str = getHeadingFile(".sql"); if(!str.isEmpty()) { str.replace(QRegExp("%filename%"),fileName); str.replace(QRegExp("%filepath%"),file.name()); sql<<str<<m_endl; } //Write class Documentation if there is somthing or if force option if(forceDoc() || !c->getDoc().isEmpty()) { sql << m_endl << "--" << m_endl; sql<<"-- TABLE: "<<classname<<m_endl; sql<<formatDoc(c->getDoc(),"-- "); sql << "-- " << m_endl << m_endl; } sql << "CREATE TABLE "<< classname << " ( " << m_endl; if (isClass) writeAttributes(c, sql); sql << m_endl << ");" << m_endl; QMap<UMLAssociation*,UMLAssociation*> constraintMap; // so we don't repeat constraint UMLAssociationList aggregations = c->getAggregations(); if( forceSections() || !aggregations.isEmpty() ) { for(UMLAssociation* a = aggregations.first(); a; a = aggregations.next()) { UMLObject *objA = a->getObject(Uml::A); UMLObject *objB = a->getObject(Uml::B); if (objA->getID() == c->getID() && objB->getID() != c->getID()) continue; constraintMap[a] = a; } } QMap<UMLAssociation*,UMLAssociation*>::Iterator itor = constraintMap.begin(); for (;itor != constraintMap.end();itor++) { UMLAssociation* a = itor.data(); sql << "ALTER TABLE "<< classname << " ADD CONSTRAINT " << a->getName() << " FOREIGN KEY (" << a->getRoleName(Uml::B) << ") REFERENCES " << a->getObject(Uml::A)->getName() << " (" << a->getRoleName(Uml::A) << ");" << m_endl; } file.close(); emit codeGenerated(c, true); }
void dumpConfigDoc () { printf( "Instrument Properties:\n" " Below is a list of available property-value pairs and their default\n" " values. The default value is omitted \"(-)\" for properties which\n" " contain an array of values.\n" " \n" " The type identifiers are:\n" " 'S': text-string, 'I': integer, 'F': float, 'D': double-precision float.\n" " \n" " Properties marked with an asterisk (*), are available as MIDI CC\n" " functions. When used as CC, the values 0-127 (MIDI data) is mapped\n" " to a range of values appropriate to the function.\n" " In config-files or on the command-line you must you the type as\n" " specified e.g. \"osc.temperament=gear60 osc.wiring-crosstalk=0.2\"\n" "\n" ); formatDoc("Main", mainDoc()); formatDoc("MIDI Parser", midiDoc()); formatDoc("MIDI Program Parser", pgmDoc()); formatDoc("Tone Generator", oscDoc()); formatDoc("Vibrato Effect", scannerDoc()); formatDoc("Preamp/Overdrive Effect", ampDoc()); formatDoc("Leslie Cabinet Effect", whirlDoc()); formatDoc("Reverb Effect", reverbDoc()); #ifdef HAVE_ZITACONVOLVE formatDoc("Convolution Reverb Effect", convolutionDoc()); #endif printf("Filter Types (for Leslie):\n"); int i; for (i=0;i<9;i++) { printf(" %d %s\n", i, filterTypeNames[i]); } printf("Note that the gain parameter does not apply to type 0 Low-Pass-Filters.\n\n"); printf( "Additional MIDI Control-Command Functions:\n" " These properties can not be modified directly, but are meant to be mapped\n" " to MIDI-controllers (see \"General Information\" above)\n" " e.g. \"midi.controller.upper.70=upper.drawbar16\".\n" ); printf( " {upper|lower|pedal}.drawbar<NUM> I* (-)\n" " where <NUM> is one of [16, 513, 8, 4, 223, 2, 135 , 113, 1].\n" " Set MIDI-Controller IDs to adjust given drawbar. --\n" " The range is inversely mapped to the position of the drawbar, so that fader-like controllers work in reverse, like real drawbars. Note that the MIDI controller values are quantized into 0 ... 8 to correspond to the nine discrete positions of the original drawbar system:\n" " 0:8 (loudest), 1-15:7, 16-31:6, 32-47:5, 48-63:4, 64-79:3, 80-92:2, 96-110:1, 111-127:0(off)\n" " rotary.speed-preset I* (-)\n" " set horn and drum speed; 0-stop, 1:slow, 2:fast\n" " rotary.speed-toggle I* (-)\n" " toggle rotary.speed-preset between 1/2\n" " rotary.speed-select I* (-)\n" " low-level access function 0..8 (3^2 combinations) [stop/slow/fast]^[horn|drum]\n" " swellpedal1 D* (0.7)\n" " set swell pedal gain\n" " swellpedal2 D* (0.7)\n" " identical to swellpedal1\n" " vibrato.knob I* (0)\n" " <22:vibrato1, <44:chorus1, <66:vibrato2, <88:chorus2, <110vibrato3, >=110:chorus3\n" " vibrato.routing I* (0)\n" " <32:off, <64:lower, <96:upper, >=96:both\n" " vibrato.upper I* (0)\n" " <64:off, >=64 on \n" " vibrato.lower I* (0)\n" " <64:off, >=64 on \n" " percussion.enable I* (0)\n" " <16:off, <63:normal, <112:soft, >=112:off\n" " percussion.decay I* (0)\n" " <64: fast-decay, >=64 slow decay\n" " percussion.harmonic I* (0)\n" " <64: third harmonic, >=64 second harmonic\n" " overdrive.enable I* (0)\n" " <64: disable overdrive, >=64 enable overdrive\n" ); printf("\n"); }