@@ -703,8 +703,88 @@ static void substEnvVarsInStrList(QStringList &sl)
703703
704704// --------------------------------------------------------------------------
705705
706+ inline bool qisspace (char c)
707+ {
708+ return c==' ' || c==' \t ' || c==' \n ' || c==' \r ' ;
709+ }
710+
711+ // Returns a quoted copy of this string, unless it is already quoted.
712+ // Note that trailing and leading whitespace is removed.
713+ QString quoted (QString &inpValue)
714+ {
715+ std::string rep = inpValue.toStdString ();
716+ size_t start=0 , sl=rep.size (), end=sl-1 ;
717+ while (start<sl && qisspace (rep[start])) start++; // skip over leading whitespace
718+ if (start==sl) return QString (); // only whitespace
719+ while (end>start && qisspace (rep[end])) end--; // skip over trailing whitespace
720+ bool needsQuotes=false ;
721+ size_t i=start;
722+ if (i<end && rep[i]!=' "' ) // stripped string has at least non-whitespace unquoted character
723+ {
724+ while (i<end && !needsQuotes) // check if the to be quoted part has at least one whitespace character
725+ {
726+ needsQuotes = rep[i] ==' -' ;
727+ needsQuotes |= qisspace (rep[i++]);
728+ }
729+ }
730+ std::string result = rep.substr (start,1 +end-start);
731+ if (needsQuotes)
732+ {
733+ result = " \" " + result + " \" " ;
734+ }
735+ return QString::fromUtf8 (result.c_str ());
736+ }
737+
738+ static void updateAttribute (InputString *attr, const char *key, QString &inpValue)
739+ {
740+ QString attrValue = attr->value ().toString ();
741+ std::string s = attrValue.toStdString ();
742+ // look for key\s*=
743+ QRegularExpression re (QString::fromLatin1 (key)+QString::fromLatin1 (R"( \s*=)" ));
744+ QRegularExpressionMatch match = re.match (attrValue);
745+ if (match.hasMatch ()) // replace existing attribute
746+ {
747+ size_t len = s.length ();
748+ size_t startPos = match.capturedStart ()+match.capturedLength (); // position after =
749+ size_t pos = startPos;
750+ while (pos<len && qisspace (s[pos])) pos++;
751+ if (pos<len && s[pos]==' "' ) // quoted value, search for end quote, ignoring escaped quotes
752+ {
753+ char pc=s[pos];
754+ pos++; // skip over start quote
755+ while (pos<len && (s[pos]!=' "' || (s[pos]==' "' && pc==' \\ ' ))) pc=s[pos++];
756+ if (pos<len) pos++; // skip over end quote
757+ }
758+ else // unquoted value, search for attribute separator (space,comma, or semicolon)
759+ {
760+ while (pos<len && s[pos]!=' ,' && s[pos]!=' ;' && !qisspace (s[pos])) pos++;
761+ }
762+ QString value;
763+ if (inpValue.isEmpty ())
764+ {
765+ value = attrValue.mid (startPos,pos-startPos);
766+ }
767+ else
768+ {
769+ value = inpValue;
770+ }
771+ // pos is now the position after the value, so replace the part between [start..pos) with the new value
772+ attrValue=attrValue.left (startPos)+quoted (value)+attrValue.mid (pos);
773+ }
774+ else // append new attribute
775+ {
776+ if (!inpValue.isEmpty ())
777+ {
778+ if (!attrValue.isEmpty ()) attrValue+=QString::fromLatin1 (" ," );
779+ attrValue+=QString::fromLatin1 (key)+QString::fromLatin1 (" =" )+quoted (inpValue);
780+ }
781+ }
782+ attr->setValue (attrValue);
783+ }
784+
706785static void upgradeConfig (const QHash<QString,Input*> &options)
707786{
787+ // check for presence of obsolete CLASS_DIAGRAM option and correct CLASS_GRAPH if needed
708788 auto it1 = options.find (QString::fromLatin1 (" CLASS_DIAGRAMS" ));
709789 auto it2 = options.find (QString::fromLatin1 (" HAVE_DOT" ));
710790 auto it3 = options.find (QString::fromLatin1 (" CLASS_GRAPH" ));
@@ -732,6 +812,118 @@ static void upgradeConfig(const QHash<QString,Input*> &options)
732812 }
733813 }
734814 }
815+
816+ // update TIMESTAMP based on HTML_TIMESTAMP and LATEX_TIMESTAMP
817+ auto HtmlTimestamp = options.find (QString::fromLatin1 (" HTML_TIMESTAMP" ));
818+ auto timestamp = options.find (QString::fromLatin1 (" TIMESTAMP" ));
819+ if (HtmlTimestamp!=options.end () && timestamp!=options.end ())
820+ {
821+ if ((*HtmlTimestamp)->kind ()==Input::Obsolete)
822+ {
823+ InputObsolete *htmlTimestamp_ = dynamic_cast <InputObsolete*>(*HtmlTimestamp);
824+ InputString *timestamp_ = dynamic_cast <InputString*>(*timestamp);
825+ if (htmlTimestamp_->orgKind ()==Input::Bool)
826+ {
827+ const QVariant &htmlTimestampValue = htmlTimestamp_->value ();
828+ bool isValid = false ;
829+ bool bTimestamp = InputBool::convertToBool (htmlTimestampValue,isValid);
830+ if (isValid && bTimestamp)
831+ {
832+ config_warn (" Changing TIMESTAMP option to YES because obsolete option HTML_TIMESTAMP was found and was set to YES.\n " );
833+ timestamp_->setValue (QString::fromLatin1 (" YES" ));
834+ }
835+ }
836+ }
837+ }
838+
839+ auto LatexTimestamp = options.find (QString::fromLatin1 (" LATEX_TIMESTAMP" ));
840+ if (LatexTimestamp!=options.end () && timestamp!=options.end ())
841+ {
842+ if ((*LatexTimestamp)->kind ()==Input::Obsolete)
843+ {
844+ InputObsolete *latexTimestamp_ = dynamic_cast <InputObsolete*>(*LatexTimestamp);
845+ InputString *timestamp_ = dynamic_cast <InputString*>(*timestamp);
846+ if (latexTimestamp_->orgKind ()==Input::Bool)
847+ {
848+ const QVariant &latexTimestampValue = latexTimestamp_->value ();
849+ bool isValid = false ;
850+ bool bTimestamp = InputBool::convertToBool (latexTimestampValue,isValid);
851+ if (isValid && bTimestamp)
852+ {
853+ config_warn (" Changing TIMESTAMP option to YES because obsolete option LATEX_TIMESTAMP was found and was set to YES.\n " );
854+ timestamp_->setValue (QString::fromLatin1 (" YES" ));
855+ }
856+ }
857+ }
858+ }
859+
860+ auto fontName = options.find (QString::fromLatin1 (" DOT_FONTNAME" ));
861+ auto fontSize = options.find (QString::fromLatin1 (" DOT_FONTSIZE" ));
862+ QString fontNameValue;
863+ QString fontSizeValue;
864+ // correct DOT_FONTNAME if needed
865+ if (fontName!=options.end ())
866+ {
867+ if ((*fontName)->kind ()==Input::Obsolete)
868+ {
869+ InputObsolete *fontName_ = dynamic_cast <InputObsolete*>(*fontName);
870+ fontNameValue = fontName_->value ().toString ();
871+ if (fontNameValue == QString::fromLatin1 (" FreeSans" ) ||
872+ fontNameValue == QString::fromLatin1 (" FreeSans.ttf" ))
873+ {
874+ config_warn (" doxygen no longer ships with the FreeSans font.\n "
875+ " You may want to clear or change DOT_FONTNAME.\n "
876+ " Otherwise you run the risk that the wrong font is being used for dot generated graphs.\n " );
877+ }
878+ }
879+ }
880+
881+ if (fontSize!=options.end ())
882+ {
883+ if ((*fontSize)->kind ()==Input::Obsolete)
884+ {
885+ InputObsolete *fontSize_ = dynamic_cast <InputObsolete*>(*fontSize);
886+ fontSizeValue = fontSize_->value ().toString ();
887+ }
888+ }
889+
890+ if (fontName!=options.end () || fontSize!=options.end ())
891+ {
892+ auto commonAttrOpt = options.find (QString::fromLatin1 (" DOT_COMMON_ATTR" ));
893+ auto edgeAttrOpt = options.find (QString::fromLatin1 (" DOT_EDGE_ATTR" ));
894+ if ((*commonAttrOpt)->kind ()==Input::String)
895+ {
896+ QString commonAttrValue;
897+ InputString *commonAttr_ = dynamic_cast <InputString*>(*commonAttrOpt);
898+ if ((*commonAttr_).stringMode ()==InputString::StringFree)
899+ {
900+ if (fontName!=options.end ())
901+ {
902+ updateAttribute (commonAttr_, " fontname" , fontNameValue);
903+ }
904+ if (fontSize!=options.end ())
905+ {
906+ updateAttribute (commonAttr_, " fontsize" , fontSizeValue);
907+ }
908+ }
909+ }
910+ if ((*edgeAttrOpt)->kind ()==Input::String)
911+ {
912+ QString edgeAttrValue;
913+ InputString *edgeAttr_ = dynamic_cast <InputString*>(*edgeAttrOpt);
914+ if ((*edgeAttr_).stringMode ()==InputString::StringFree)
915+ {
916+ if (fontName!=options.end ())
917+ {
918+ updateAttribute (edgeAttr_, " labelfontname" , fontNameValue);
919+ }
920+ if (fontSize!=options.end ())
921+ {
922+ updateAttribute (edgeAttr_, " labelfontsize" , fontSizeValue);
923+ }
924+ }
925+ }
926+ }
735927}
736928
737929// --------------------------------------------------------------------------
0 commit comments