diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/marshal.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/marshal.cc index b6e8aff94a..7e7ef1b194 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/marshal.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/marshal.cc @@ -1161,6 +1161,6 @@ ElementId ELEM_VAL = ElementId("val",8); ElementId ELEM_VALUE = ElementId("value",9); ElementId ELEM_VOID = ElementId("void",10); -ElementId ELEM_UNKNOWN = ElementId("XMLunknown",284); // Number serves as next open index +ElementId ELEM_UNKNOWN = ElementId("XMLunknown",285); // Number serves as next open index } // End namespace ghidra diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/options.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/options.cc index d5f2d5472e..877e1e2a12 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/options.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/options.cc @@ -60,6 +60,7 @@ ElementId ELEM_TOGGLERULE = ElementId("togglerule",209); ElementId ELEM_WARNING = ElementId("warning",210); ElementId ELEM_JUMPTABLEMAX = ElementId("jumptablemax",271); ElementId ELEM_NANIGNORE = ElementId("nanignore",272); +ElementId ELEM_BRACEFORMAT = ElementId("braceformat",284); /// If the parameter is "on" return \b true, if "off" return \b false. /// Any other value causes an exception. @@ -117,6 +118,7 @@ OptionDatabase::OptionDatabase(Architecture *g) registerOption(new OptionCommentHeader()); registerOption(new OptionCommentInstruction()); registerOption(new OptionIntegerFormat()); + registerOption(new OptionBraceFormat()); registerOption(new OptionCurrentAction()); registerOption(new OptionAllowContextSet()); registerOption(new OptionSetAction()); @@ -578,6 +580,47 @@ string OptionIntegerFormat::apply(Architecture *glb,const string &p1,const strin return "Integer format set to "+p1; } +/// \class OptionBraceFormat +/// \brief Set the brace formatting strategy for various types of code block +/// +/// The first parameter is the strategy name: +/// - \b same - For an opening brace on the same line +/// - \b next - For an opening brace on the next line +/// - \b skip - For an opening brace after a blank line +/// +/// The second parameter is the type of code block: +/// - \b function - For the main function body +/// - \b ifelse - For if/else blocks +/// - \b loop - For do/while/for loop blocks +/// - \b switch - For a switch block +string OptionBraceFormat::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const + +{ + PrintC *lng = dynamic_cast(glb->print); + if (lng == (PrintC *)0) + return "Can only set brace formatting for C language"; + Emit::brace_style style; + if (p2 == "same") + style = Emit::same_line; + else if (p2 == "next") + style = Emit::next_line; + else if (p2 == "skip") + style = Emit::skip_line; + else + throw ParseError("Unknown brace style: "+p2); + if (p1 == "function") + lng->setBraceFormatFunction(style); + else if (p1 == "ifelse") + lng->setBraceFormatIfElse(style); + else if (p1 == "loop") + lng->setBraceFormatLoop(style); + else if (p1 == "switch") + lng->setBraceFormatSwitch(style); + else + throw ParseError("Unknown brace format category: "+p1); + return "Brace formatting for " + p1 + " set to " + p2; +} + /// \class OptionSetAction /// \brief Establish a new root Action for the decompiler /// diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/options.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/options.hh index 2ff255c5c7..7a7f713b84 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/options.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/options.hh @@ -235,6 +235,12 @@ public: virtual string apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const; }; +class OptionBraceFormat : public ArchOption { +public: + OptionBraceFormat(void) { name = "braceformat"; } ///< Constructor + virtual string apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const; +}; + class OptionSetAction : public ArchOption { public: OptionSetAction(void) { name = "setaction"; } ///< Constructor diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/prettyprint.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/prettyprint.cc index f4c25bfdf4..459ee5c341 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/prettyprint.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/prettyprint.cc @@ -58,6 +58,38 @@ void Emit::spaces(int4 num,int4 bump) } } +int4 Emit::openBraceIndent(const string &brace,brace_style style) + +{ + if (style == same_line) + spaces(1); + else if (style == skip_line) { + tagLine(); + tagLine(); + } + else { + tagLine(); + } + int4 id = startIndent(); + print(brace); + return id; +} + +void Emit::openBrace(const string &brace,brace_style style) + +{ + if (style == same_line) + spaces(1); + else if (style == skip_line) { + tagLine(); + tagLine(); + } + else { + tagLine(); + } + print(brace); +} + EmitMarkup::~EmitMarkup(void) { diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/prettyprint.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/prettyprint.hh index e7f4a08da1..4b96b8cace 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/prettyprint.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/prettyprint.hh @@ -120,6 +120,13 @@ public: error_color = 9, ///< Indicates a warning or error state special_color = 10 ///< A token with special/highlighted meaning }; + + /// \brief Different brace formatting styles + enum brace_style { + same_line = 0, ///< Opening brace on the same line as if/do/while/for/switch + next_line = 1, ///< Opening brace is on next line + skip_line = 2 ///< Opening brace is two lines down + }; virtual ~Emit(void) {} ///< Destructor /// \brief Begin a whole document of output @@ -294,7 +301,7 @@ public: /// \brief Emit a \e case label constant /// - /// A string describing the \e switch variable value is emitted and starting PcodeOp of the \e case block. + /// A string describing the \e switch variable value and starting PcodeOp of the \e case block. /// \param name is the character data of the value /// \param hl indicates how the value should be highlighted /// \param op is the first PcodeOp in the \e case block @@ -436,6 +443,31 @@ public: /// \return \b true if the specific print callback is pending bool hasPendingPrint(PendPrint *pend) const { return (pendPrint == pend); } + /// \brief Emit an opening brace given a specific format and add an indent level + /// + /// The brace is emitted on the same line, or on a following line, + /// depending on the selected style. One level of indent is added. + /// \param brace is the string to display as the opening brace + /// \param style indicates how the brace should be formatted + /// \return the nesting id associated with the index + int4 openBraceIndent(const string &brace,brace_style style); + + /// \brief Emit an opening brace given a specific format + /// + /// The indent level is \e not increased. The brace is emitted on the same + /// line, or on a following line, depending on the selected style. + /// \param brace is the string to display as the opening brace + /// \param style indicates how the brace should be formatted + void openBrace(const string &brace,brace_style style); + + /// \brief Emit a closing brace and remove an indent level + /// + /// The brace is emitted on the next line. + /// \param brace is the string to display as the closing brace + /// \param id is nesting id of the indent being removed + void closeBraceIndent(const string &brace,int4 id) { + stopIndent(id); tagLine(); print(brace); + } }; /// \brief Emitter that associates markup with individual tokens @@ -1083,8 +1115,9 @@ inline void Emit::emitPending(void) { if (pendPrint != (PendPrint *)0) { - pendPrint->callback(this); - pendPrint = (PendPrint *)0; + PendPrint *tmp = pendPrint; + pendPrint = (PendPrint *)0; // Clear pending before callback + tmp->callback(this); } } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc index dc81ae4233..d0623559f9 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc @@ -1568,6 +1568,10 @@ void PrintC::resetDefaultsPrintC(void) option_nocasts = false; option_NULL = false; option_unplaced = false; + option_brace_func = Emit::skip_line; + option_brace_ifelse = Emit::same_line; + option_brace_loop = Emit::same_line; + option_brace_switch = Emit::same_line; setCStyleComments(); } @@ -2096,9 +2100,7 @@ void PrintC::emitStructDefinition(const TypeStruct *ct) emit->tagLine(); emit->print("typedef struct",EmitMarkup::keyword_color); - emit->spaces(1); - int4 id = emit->startIndent(); - emit->print(OPEN_CURLY); + int4 id = emit->openBraceIndent(OPEN_CURLY, Emit::same_line); emit->tagLine(); iter = ct->beginField(); while(iter!=ct->endField()) { @@ -2111,9 +2113,7 @@ void PrintC::emitStructDefinition(const TypeStruct *ct) emit->tagLine(); } } - emit->stopIndent(id); - emit->tagLine(); - emit->print(CLOSE_CURLY); + emit->closeBraceIndent(CLOSE_CURLY, id); emit->spaces(1); emit->print(ct->getDisplayName()); emit->print(SEMICOLON); @@ -2135,9 +2135,7 @@ void PrintC::emitEnumDefinition(const TypeEnum *ct) bool sign = (ct->getMetatype() == TYPE_INT); emit->tagLine(); emit->print("typedef enum",EmitMarkup::keyword_color); - emit->spaces(1); - int4 id = emit->startIndent(); - emit->print(OPEN_CURLY); + int4 id = emit->openBraceIndent(OPEN_CURLY, Emit::same_line); emit->tagLine(); iter = ct->beginEnum(); while(iter!=ct->endEnum()) { @@ -2153,9 +2151,7 @@ void PrintC::emitEnumDefinition(const TypeEnum *ct) emit->tagLine(); } popMod(); - emit->stopIndent(id); - emit->tagLine(); - emit->print(CLOSE_CURLY); + emit->closeBraceIndent(CLOSE_CURLY, id); emit->spaces(1); emit->print(ct->getDisplayName()); emit->print(SEMICOLON); @@ -2627,19 +2623,14 @@ void PrintC::docFunction(const Funcdata *fd) emitCommentFuncHeader(fd); emit->tagLine(); emitFunctionDeclaration(fd); // Causes us to enter function's scope - emit->tagLine(); - emit->tagLine(); - int4 id = emit->startIndent(); - emit->print(OPEN_CURLY); + int4 id = emit->openBraceIndent(OPEN_CURLY, option_brace_func); emitLocalVarDecls(fd); if (isSet(flat)) emitBlockGraph(&fd->getBasicBlocks()); else emitBlockGraph(&fd->getStructure()); popScope(); // Exit function's scope - emit->stopIndent(id); - emit->tagLine(); - emit->print(CLOSE_CURLY); + emit->closeBraceIndent(CLOSE_CURLY, id); emit->tagLine(); emit->endFunction(id1); emit->flush(); @@ -2852,15 +2843,14 @@ void PrintC::emitBlockCondition(const BlockCondition *bl) void PendingBrace::callback(Emit *emit) { - emit->print(PrintC::OPEN_CURLY); - indentId = emit->startIndent(); + indentId = emit->openBraceIndent(PrintC::OPEN_CURLY, style); } void PrintC::emitBlockIf(const BlockIf *bl) { const PcodeOp *op; - PendingBrace pendingBrace; + PendingBrace pendingBrace(option_brace_ifelse); if (isSet(pending_brace)) emit->setPendingPrint(&pendingBrace); @@ -2878,8 +2868,10 @@ void PrintC::emitBlockIf(const BlockIf *bl) condBlock->emit(this); popMod(); emitCommentBlockTree(condBlock); - if (emit->hasPendingPrint(&pendingBrace)) // If we issued a brace but it did not emit + if (emit->hasPendingPrint(&pendingBrace)) { // If we issued a brace but it did not emit emit->cancelPendingPrint(); // Cancel the brace in order to have "else if" syntax + emit->spaces(1); + } else emit->tagLine(); // Otherwise start the "if" on a new line @@ -2896,19 +2888,14 @@ void PrintC::emitBlockIf(const BlockIf *bl) } else { setMod(no_branch); - emit->spaces(1); - int4 id = emit->startIndent(); - emit->print(OPEN_CURLY); + int4 id = emit->openBraceIndent(OPEN_CURLY, option_brace_ifelse); int4 id1 = emit->beginBlock(bl->getBlock(1)); bl->getBlock(1)->emit(this); emit->endBlock(id1); - emit->stopIndent(id); - emit->tagLine(); - emit->print(CLOSE_CURLY); + emit->closeBraceIndent(CLOSE_CURLY, id); if (bl->getSize() == 3) { emit->tagLine(); emit->print(KEYWORD_ELSE,EmitMarkup::keyword_color); - emit->spaces(1); FlowBlock *elseBlock = bl->getBlock(2); if (elseBlock->getType() == FlowBlock::t_if) { // Attempt to merge the "else" and "if" syntax @@ -2918,22 +2905,17 @@ void PrintC::emitBlockIf(const BlockIf *bl) emit->endBlock(id2); } else { - int4 id2 = emit->startIndent(); - emit->print(OPEN_CURLY); + int4 id2 = emit->openBraceIndent(OPEN_CURLY, option_brace_ifelse); int4 id3 = emit->beginBlock(elseBlock); elseBlock->emit(this); emit->endBlock(id3); - emit->stopIndent(id2); - emit->tagLine(); - emit->print(CLOSE_CURLY); + emit->closeBraceIndent(CLOSE_CURLY, id2); } } } popMod(); if (pendingBrace.getIndentId() >= 0) { - emit->stopIndent(pendingBrace.getIndentId()); - emit->tagLine(); - emit->print(CLOSE_CURLY); + emit->closeBraceIndent(CLOSE_CURLY, pendingBrace.getIndentId()); } } @@ -2978,16 +2960,12 @@ void PrintC::emitForLoop(const BlockWhileDo *bl) emit->endStatement(id4); popMod(); emit->closeParen(CLOSE_PAREN,id1); - emit->spaces(1); - indent = emit->startIndent(); - emit->print(OPEN_CURLY); + indent = emit->openBraceIndent(OPEN_CURLY, option_brace_loop); setMod(no_branch); // Dont print goto at bottom of clause int4 id2 = emit->beginBlock(bl->getBlock(1)); bl->getBlock(1)->emit(this); emit->endBlock(id2); - emit->stopIndent(indent); - emit->tagLine(); - emit->print(CLOSE_CURLY); + emit->closeBraceIndent(CLOSE_CURLY, indent); popMod(); } @@ -3019,9 +2997,7 @@ void PrintC::emitBlockWhileDo(const BlockWhileDo *bl) emit->print(KEYWORD_TRUE,EmitMarkup::const_color); emit->spaces(1); emit->closeParen(CLOSE_PAREN,id1); - emit->spaces(1); - indent = emit->startIndent(); - emit->print(OPEN_CURLY); + indent = emit->openBraceIndent(OPEN_CURLY, option_brace_loop); pushMod(); setMod(no_branch); condBlock->emit(this); @@ -3050,17 +3026,13 @@ void PrintC::emitBlockWhileDo(const BlockWhileDo *bl) condBlock->emit(this); popMod(); emit->closeParen(CLOSE_PAREN,id1); - emit->spaces(1); - indent = emit->startIndent(); - emit->print(OPEN_CURLY); + indent = emit->openBraceIndent(OPEN_CURLY, option_brace_loop); } setMod(no_branch); // Dont print goto at bottom of clause int4 id2 = emit->beginBlock(bl->getBlock(1)); bl->getBlock(1)->emit(this); emit->endBlock(id2); - emit->stopIndent(indent); - emit->tagLine(); - emit->print(CLOSE_CURLY); + emit->closeBraceIndent(CLOSE_CURLY, indent); popMod(); } @@ -3075,18 +3047,14 @@ void PrintC::emitBlockDoWhile(const BlockDoWhile *bl) emitAnyLabelStatement(bl); emit->tagLine(); emit->print(KEYWORD_DO,EmitMarkup::keyword_color); - emit->spaces(1); - int4 id = emit->startIndent(); - emit->print(OPEN_CURLY); + int4 id = emit->openBraceIndent(OPEN_CURLY, option_brace_loop); pushMod(); int4 id2 = emit->beginBlock(bl->getBlock(0)); setMod(no_branch); bl->getBlock(0)->emit(this); emit->endBlock(id2); popMod(); - emit->stopIndent(id); - emit->tagLine(); - emit->print(CLOSE_CURLY); + emit->closeBraceIndent(CLOSE_CURLY, id); emit->spaces(1); op = bl->getBlock(0)->lastOp(); emit->tagOp(KEYWORD_WHILE,EmitMarkup::keyword_color,op); @@ -3107,15 +3075,11 @@ void PrintC::emitBlockInfLoop(const BlockInfLoop *bl) emitAnyLabelStatement(bl); emit->tagLine(); emit->print(KEYWORD_DO,EmitMarkup::keyword_color); - emit->spaces(1); - int4 id = emit->startIndent(); - emit->print(OPEN_CURLY); + int4 id = emit->openBraceIndent(OPEN_CURLY, option_brace_loop); int4 id1 = emit->beginBlock(bl->getBlock(0)); bl->getBlock(0)->emit(this); emit->endBlock(id1); - emit->stopIndent(id); - emit->tagLine(); - emit->print(CLOSE_CURLY); + emit->closeBraceIndent(CLOSE_CURLY, id); emit->spaces(1); op = bl->getBlock(0)->lastOp(); emit->tagOp(KEYWORD_WHILE,EmitMarkup::keyword_color,op); @@ -3333,8 +3297,7 @@ void PrintC::emitBlockSwitch(const BlockSwitch *bl) setMod(only_branch|comma_separate); bl->getSwitchBlock()->emit(this); popMod(); - emit->spaces(1); - emit->print(OPEN_CURLY); + emit->openBrace(OPEN_CURLY,option_brace_switch); for(int4 i=0;igetNumCaseBlocks();++i) { emitSwitchCase(i,bl); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh index 91f1197711..4373b58b4f 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh @@ -148,6 +148,10 @@ protected: bool option_nocasts; ///< Don't print a cast if \b true bool option_unplaced; ///< Set to \b true if we should display unplaced comments bool option_hide_exts; ///< Set to \b true if we should hide implied extension operations + Emit::brace_style option_brace_func; ///< How function declaration braces should be formatted + Emit::brace_style option_brace_ifelse; ///< How braces for if/else blocks are formatted + Emit::brace_style option_brace_loop; ///< How braces for loop blocks are formatted + Emit::brace_style option_brace_switch; ///< How braces for switch blocks are formatted string nullToken; ///< Token to use for 'null' string sizeSuffix; ///< Characters to print to indicate a \e long integer token CommentSorter commsorter; ///< Container/organizer for comments in the current function @@ -238,6 +242,10 @@ public: void setCPlusPlusStyleComments(void) { setCommentDelimeter("// ","",true); } ///< Set c++-style "//" comment delimiters void setDisplayUnplaced(bool val) { option_unplaced = val; } ///< Toggle whether \e unplaced comments are displayed in the header void setHideImpliedExts(bool val) { option_hide_exts = val; } ///< Toggle whether implied extensions are hidden + void setBraceFormatFunction(Emit::brace_style style) { option_brace_func = style; } ///< Set how function declarations are formatted + void setBraceFormatIfElse(Emit::brace_style style) { option_brace_ifelse = style; } ///< Set how if/else blocks are formatted + void setBraceFormatLoop(Emit::brace_style style) { option_brace_loop = style; } ///< Set how loop blocks are formatted + void setBraceFormatSwitch(Emit::brace_style style) { option_brace_switch = style; } ///< Set how switch blocks are formatted virtual ~PrintC(void) {} virtual void resetDefaults(void); virtual void initializeFromArchitecture(void); @@ -341,8 +349,9 @@ public: /// The open brace can be canceled if the block decides it wants to use "else if" syntax. class PendingBrace : public PendPrint { int4 indentId; ///< Id associated with the new indent level + Emit::brace_style style; ///< Style to use for pending brace public: - PendingBrace(void) { indentId = -1; } ///< Constructor + PendingBrace(Emit::brace_style s) { indentId = -1; style = s; } ///< Constructor int4 getIndentId(void) const { return indentId; } ///< If commands have been issued, returns the new indent level id. virtual void callback(Emit *emit); }; diff --git a/Ghidra/Features/Decompiler/src/main/doc/decompileplugin.xml b/Ghidra/Features/Decompiler/src/main/doc/decompileplugin.xml index 11c1c94a03..31cc4bb79a 100644 --- a/Ghidra/Features/Decompiler/src/main/doc/decompileplugin.xml +++ b/Ghidra/Features/Decompiler/src/main/doc/decompileplugin.xml @@ -39,7 +39,7 @@ plug-in enabled, but if it is disabled for some reason, it can be enabled from within a Code Browser by selecting the - File -> Configure... + File -> Configure menu option, then clicking on the Configure link under the Ghidra Core section and checking the box next to @@ -3269,6 +3269,36 @@ + + Brace Format for <kind-of> blocks + + + Choose how braces are placed after function declarations, or other kinds of code blocks in Decompiler output. + Formatting can be controlled for: + + + function blocks - the main function bodies + if/else blocks - blocks delineated by the if and else keywords + loop blocks - blocks delineated by the for, do, and while keywords + switch blocks - blocks delineated by the switch keyword + + + The different formatting options primarily control how the opening brace is displayed relative to the line containing + the declaration or keyword starting the block. The formatting options are: + + + Same line - opening brace placed on same line + Next line - opening brace placed on the next line + Skip one line - opening brace placed on line after a blank line + + + + + The "Same line" option is consistent with K & R code formatting style. The "Next line" option is consistent with + the Allman formatting style. + + + Color Default diff --git a/Ghidra/Features/Decompiler/src/main/help/help/topics/DecompilePlugin/DecompilerOptions.html b/Ghidra/Features/Decompiler/src/main/help/help/topics/DecompilePlugin/DecompilerOptions.html index a2996b1cd7..a59fceb8df 100644 --- a/Ghidra/Features/Decompiler/src/main/help/help/topics/DecompilePlugin/DecompilerOptions.html +++ b/Ghidra/Features/Decompiler/src/main/help/help/topics/DecompilePlugin/DecompilerOptions.html @@ -436,6 +436,47 @@

+Brace Format for <kind-of> blocks +
+
+

+ Choose how braces are placed after function declarations, or other kinds of code blocks in Decompiler output. + Formatting can be controlled for: +

+
+
    +
  • +function blocks - the main function bodies
  • +
  • +if/else blocks - blocks delineated by the if and else keywords
  • +
  • +loop blocks - blocks delineated by the for, do, and while keywords
  • +
  • +switch blocks - blocks delineated by the switch keyword
  • +
+
+

+ The different formatting options primarily control how the opening brace is displayed relative to the line containing + the declaration or keyword starting the block. The formatting options are: +

+
+
    +
  • +Same line - opening brace placed on same line
  • +
  • +Next line - opening brace placed on the next line
  • +
  • +Skip one line - opening brace placed on line after a blank line
  • +
+
+

+

+

+ The "Same line" option is consistent with K & R code formatting style. The "Next line" option is consistent with + the Allman formatting style. +

+
+
Color Default
diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileOptions.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileOptions.java index 0800d12c9a..a7eb7c227d 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileOptions.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileOptions.java @@ -217,6 +217,54 @@ public class DecompileOptions { private final static boolean NOCAST_OPTIONDEFAULT = false; // Must match PrintC::resetDefaultsPrintC private boolean noCastPrint; + public enum BraceStyle { + + Same("same", "Same line"), Next("next", "Next line"), Skip("skip", "Skip one line"); + + private String label; + private String optionString; + + private BraceStyle(String optString, String label) { + this.label = label; + this.optionString = optString; + } + + public String getOptionString() { + return optionString; + } + + @Override + public String toString() { + return label; + } + } + + private final static String BRACEFUNCTION_OPTIONSTRING = + "Display.Brace format for function blocks"; + private final static String BRACEFUNCTION_OPTIONDESCRIPTION = + "Where the opening brace is displayed, after a function declaration"; + private final static BraceStyle BRACEFUNCTION_OPTIONDEFAULT = BraceStyle.Skip; + private BraceStyle braceFunction; + + private final static String BRACEIFELSE_OPTIONSTRING = + "Display.Brace format for if/else blocks"; + private final static String BRACEIFELSE_OPTIONDESCRIPTION = + "Where the opening brace is displayed, for an if/else code block"; + private final static BraceStyle BRACEIFELSE_OPTIONDEFAULT = BraceStyle.Same; + private BraceStyle braceIfElse; + + private final static String BRACELOOP_OPTIONSTRING = "Display.Brace format for loop blocks"; + private final static String BRACELOOP_OPTIONDESCRIPTION = + "Where the opening brace is displayed, for the body of a loop"; + private final static BraceStyle BRACELOOP_OPTIONDEFAULT = BraceStyle.Same; + private BraceStyle braceLoop; + + private final static String BRACESWITCH_OPTIONSTRING = "Display.Brace format for switch blocks"; + private final static String BRACESWITCH_OPTIONDESCRIPTION = + "Where the opening brace is displayed, for the body of a switch statement"; + private final static BraceStyle BRACESWITCH_OPTIONDEFAULT = BraceStyle.Same; + private BraceStyle braceSwitch; + private final static String MAXWIDTH_OPTIONSTRING = "Display.Maximum characters in a code line"; private final static String MAXWIDTH_OPTIONDESCRIPTION = "Maximum number of characters allowed per line before before line breaks are forced."; @@ -452,6 +500,10 @@ public class DecompileOptions { aliasBlock = ALIASBLOCK_OPTIONDEFAULT; conventionPrint = CONVENTION_OPTIONDEFAULT; noCastPrint = NOCAST_OPTIONDEFAULT; + braceFunction = BRACEFUNCTION_OPTIONDEFAULT; + braceIfElse = BRACEIFELSE_OPTIONDEFAULT; + braceLoop = BRACELOOP_OPTIONDEFAULT; + braceSwitch = BRACESWITCH_OPTIONDEFAULT; maxwidth = MAXWIDTH_OPTIONDEFAULT; indentwidth = INDENTWIDTH_OPTIONDEFAULT; commentindent = COMMENTINDENT_OPTIONDEFAULT; @@ -512,6 +564,10 @@ public class DecompileOptions { aliasBlock = opt.getEnum(ALIASBLOCK_OPTIONSTRING, ALIASBLOCK_OPTIONDEFAULT); conventionPrint = opt.getBoolean(CONVENTION_OPTIONSTRING, CONVENTION_OPTIONDEFAULT); noCastPrint = opt.getBoolean(NOCAST_OPTIONSTRING, NOCAST_OPTIONDEFAULT); + braceFunction = opt.getEnum(BRACEFUNCTION_OPTIONSTRING, BRACEFUNCTION_OPTIONDEFAULT); + braceIfElse = opt.getEnum(BRACEIFELSE_OPTIONSTRING, BRACEIFELSE_OPTIONDEFAULT); + braceLoop = opt.getEnum(BRACELOOP_OPTIONSTRING, BRACELOOP_OPTIONDEFAULT); + braceSwitch = opt.getEnum(BRACESWITCH_OPTIONSTRING, BRACESWITCH_OPTIONDEFAULT); maxwidth = opt.getInt(MAXWIDTH_OPTIONSTRING, MAXWIDTH_OPTIONDEFAULT); indentwidth = opt.getInt(INDENTWIDTH_OPTIONSTRING, INDENTWIDTH_OPTIONDEFAULT); commentindent = opt.getInt(COMMENTINDENT_OPTIONSTRING, COMMENTINDENT_OPTIONDEFAULT); @@ -642,6 +698,18 @@ public class DecompileOptions { opt.registerOption(NOCAST_OPTIONSTRING, NOCAST_OPTIONDEFAULT, new HelpLocation(HelpTopics.DECOMPILER, "DisplayDisableCasts"), NOCAST_OPTIONDESCRIPTION); + opt.registerOption(BRACEFUNCTION_OPTIONSTRING, BRACEFUNCTION_OPTIONDEFAULT, + new HelpLocation(HelpTopics.DECOMPILER, "DisplayBraceFormatting"), + BRACEFUNCTION_OPTIONDESCRIPTION); + opt.registerOption(BRACEIFELSE_OPTIONSTRING, BRACEIFELSE_OPTIONDEFAULT, + new HelpLocation(HelpTopics.DECOMPILER, "DisplayBraceFormatting"), + BRACEIFELSE_OPTIONDESCRIPTION); + opt.registerOption(BRACELOOP_OPTIONSTRING, BRACELOOP_OPTIONDEFAULT, + new HelpLocation(HelpTopics.DECOMPILER, "DisplayBraceFormatting"), + BRACELOOP_OPTIONDESCRIPTION); + opt.registerOption(BRACESWITCH_OPTIONSTRING, BRACESWITCH_OPTIONDEFAULT, + new HelpLocation(HelpTopics.DECOMPILER, "DisplayBraceFormatting"), + BRACESWITCH_OPTIONDESCRIPTION); opt.registerOption(MAXWIDTH_OPTIONSTRING, MAXWIDTH_OPTIONDEFAULT, new HelpLocation(HelpTopics.DECOMPILER, "DisplayMaxChar"), MAXWIDTH_OPTIONDESCRIPTION); opt.registerOption(INDENTWIDTH_OPTIONSTRING, INDENTWIDTH_OPTIONDEFAULT, @@ -826,6 +894,19 @@ public class DecompileOptions { if (noCastPrint != NOCAST_OPTIONDEFAULT) { appendOption(encoder, ELEM_NOCASTPRINTING, noCastPrint ? "on" : "off", "", ""); } + if (braceFunction != BRACEFUNCTION_OPTIONDEFAULT) { + appendOption(encoder, ELEM_BRACEFORMAT, "function", braceFunction.getOptionString(), + ""); + } + if (braceIfElse != BRACEIFELSE_OPTIONDEFAULT) { + appendOption(encoder, ELEM_BRACEFORMAT, "ifelse", braceIfElse.getOptionString(), ""); + } + if (braceLoop != BRACELOOP_OPTIONDEFAULT) { + appendOption(encoder, ELEM_BRACEFORMAT, "loop", braceLoop.getOptionString(), ""); + } + if (braceSwitch != BRACESWITCH_OPTIONDEFAULT) { + appendOption(encoder, ELEM_BRACEFORMAT, "switch", braceSwitch.getOptionString(), ""); + } if (maxwidth != MAXWIDTH_OPTIONDEFAULT) { appendOption(encoder, ELEM_MAXLINEWIDTH, Integer.toString(maxwidth), "", ""); } @@ -884,6 +965,66 @@ public class DecompileOptions { encoder.closeElement(ELEM_OPTIONSLIST); } + /** + * @return the brace formatting style for function bodies + */ + public BraceStyle getFunctionBraceFormat() { + return braceFunction; + } + + /** + * Set how braces are formatted around a function body + * @param style is the formatting style + */ + public void setFunctionBraceFormat(BraceStyle style) { + this.braceFunction = style; + } + + /** + * @return the brace formatting style for if/else code blocks + */ + public BraceStyle getIfElseBraceFormat() { + return braceIfElse; + } + + /** + * Set how braces are formatted around an if/else code block + * @param style is the formatting style + */ + public void setIfElseBraceFormat(BraceStyle style) { + this.braceIfElse = style; + } + + /** + * @return the brace formatting style for loop bodies + */ + public BraceStyle getLoopBraceFormat() { + return braceLoop; + } + + /** + * Set how braces are formatted a loop body + * @param style is the formatting style + */ + public void setLoopBraceFormat(BraceStyle style) { + this.braceLoop = style; + } + + /** + * @return the brace formatting style for switch blocks + */ + public BraceStyle getSwitchBraceFormat() { + return braceSwitch; + } + + /** + * Set how braces are formatted around a switch block + * @param style is the formatting style + */ + public void setSwitchBraceFormat(BraceStyle style) { + this.braceSwitch = style; + } + /** * @return the maximum number of characters the decompiler displays in a single line of output */ diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/ElementId.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/ElementId.java index c47b4b17bb..51bfc12ef3 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/ElementId.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/ElementId.java @@ -314,6 +314,8 @@ public record ElementId(String name, int id) { public static final ElementId ELEM_TOGGLERULE = new ElementId("togglerule", 209); public static final ElementId ELEM_WARNING = new ElementId("warning", 210); + public static final ElementId ELEM_BRACEFORMAT = new ElementId("braceformat", 284); + // jumptable public static final ElementId ELEM_BASICOVERRIDE = new ElementId("basicoverride", 211); public static final ElementId ELEM_DEST = new ElementId("dest", 212); @@ -439,5 +441,5 @@ public record ElementId(String name, int id) { public static final ElementId ELEM_JOIN_PER_PRIMITIVE = new ElementId("join_per_primitive", 283); - public static final ElementId ELEM_UNKNOWN = new ElementId("XMLunknown", 284); + public static final ElementId ELEM_UNKNOWN = new ElementId("XMLunknown", 285); }