/// <summary> /// Run,%ScriptFile%,<Section>[,PARAMS] /// </summary> /// <param name="cmd"></param> /// <returns></returns> public LogInfo[] RunExec(BakeryCommand cmd) { ArrayList logs = new ArrayList(); // Necessary operand : 2, optional operand : variable length const int necessaryOperandNum = 2; if (cmd.Operands.Length < necessaryOperandNum) { throw new InvalidOperandException("Necessary operands does not exist", cmd); } // Get necesssary operand string pluginFile = variables.Expand(cmd.Operands[0]); string rawPluginFile = cmd.Operands[0]; string sectionName = variables.Expand(cmd.Operands[1]); string rawSectoinName = cmd.Operands[1]; // Get optional operand string[] parameters = new string[cmd.Operands.Length - necessaryOperandNum]; if (necessaryOperandNum < cmd.Operands.Length) { Array.Copy(cmd.Operands, 2, parameters, 0, cmd.Operands.Length - necessaryOperandNum); } bool currentPlugin = false; if (String.Equals(rawPluginFile, "%PluginFile%", StringComparison.OrdinalIgnoreCase)) { currentPlugin = true; } else if (String.Equals(rawPluginFile, "%ScriptFile%", StringComparison.OrdinalIgnoreCase)) { currentPlugin = true; } if (currentPlugin) { if (!plugins[curPluginIdx].Sections.ContainsKey(sectionName)) { throw new InvalidOperandException(string.Concat("'", Path.GetFileName(pluginFile), "' does not have section '", sectionName, "'"), cmd); } // Branch to new section returnAddress.Push(new CommandAddress(cmd.Address.section, cmd.Address.line + 1, cmd.Address.secLength)); nextCommand = new CommandAddress(plugins[curPluginIdx].Sections[sectionName], 0, plugins[curPluginIdx].Sections[sectionName].SecLines.Length); currentSectionParams = parameters; // Exec utilizes [Variables] section of the plugin if (cmd.Opcode == Opcode.Exec) { } } cmd.SectionDepth += 1; // For proper log indentation logs.Add(new LogInfo(cmd, string.Concat("Running section '", sectionName, "'"), LogState.Success)); return(logs.ToArray(typeof(LogInfo)) as LogInfo[]); }
/// <summary> /// Hold command information, with address and subcommand /// </summary> /// <param name="opcode"></param> /// <param name="operands"></param> /// <param name="optional"></param> public BakeryCommand(string rawCode, Opcode opcode, string[] operands, CommandAddress address, BakeryCommand subCommand) { this.rawCode = rawCode; this.opcode = opcode; this.operands = operands; this.address = address; this.subCommand = subCommand; }
/// <summary> /// Run an plugin /// </summary> public void RunPlugin() { LoadDefaultPluginVariables(); PluginSection section = plugins[curPluginIdx].Sections["Process"]; nextCommand = new CommandAddress(section, 0, section.SecLines.Length); RunCommands(); return; }
/// <summary> /// Hold command information, with address and subcommand /// </summary> /// <param name="opcode"></param> /// <param name="operands"></param> /// <param name="optional"></param> public BakeryCommand(string rawCode, Opcode opcode, string[] operands, CommandAddress address, BakeryCommand subCommand, int sectionDepth) { this.rawCode = rawCode; this.opcode = opcode; this.operands = operands; this.address = address; this.subCommand = subCommand; this.sectionDepth = sectionDepth; }
/// <summary> /// Hold command information, with address /// </summary> /// <param name="opcode"></param> /// <param name="operands"></param> /// <param name="optional"></param> public BakeryCommand(string rawCode, Opcode opcode, string[] operands, CommandAddress address) { this.rawCode = rawCode; this.opcode = opcode; this.operands = operands; this.address = address; this.subCommand = null; this.sectionDepth = 0; }
/// <summary> /// Run array of commands. /// </summary> /// <param name="nextCommand"></param> private void RunCommands() { while (true) { if (!(nextCommand.line < nextCommand.secLength)) // End of section { currentSectionParams = new string[0]; BakeryCommand logCmd = new BakeryCommand("End of section", Opcode.None, new string[0], returnAddress.Count); string logMsg = string.Concat("Section '", nextCommand.section.SecName, "' End"); logger.Write(new LogInfo(logCmd, logMsg, LogState.Infomation)); try { nextCommand = returnAddress.Pop(); if (!(nextCommand.line < nextCommand.secLength)) // Is return address end of section? { continue; } } catch (InvalidOperationException) { // The Stack<T> is empty, terminate function break; } } // Fetch instructions int i = nextCommand.line; string rawCode = nextCommand.section.SecLines[i].Trim(); try { currentCommand = ParseCommand(rawCode, new CommandAddress(nextCommand.section, i, nextCommand.secLength)); try { ExecuteCommand(currentCommand, logger); } catch (InvalidOpcodeException e) { logger.Write(new LogInfo(e.Command, e.Message, LogState.Error)); } } catch (InvalidOpcodeException e) { currentCommand = new BakeryCommand(rawCode, Opcode.Unknown, new string[0]); logger.Write(new LogInfo(e.Command, e.Message, LogState.Error)); } catch (InvalidOperandException e) { currentCommand = new BakeryCommand(rawCode, Opcode.Unknown, new string[0]); logger.Write(new LogInfo(e.Command, e.Message, LogState.Error)); } nextCommand.line += 1; } logger.WriteVariables(variables); }
/// <summary> /// Parse raw command in string into BakeryCommand instance. /// </summary> /// <param name="rawCode"></param> /// <returns></returns> private BakeryCommand ParseCommand(string rawCode, CommandAddress address) { Opcode opcode = Opcode.None; ArrayList operandList = new ArrayList(); // Remove whitespace of rawCode's start and end rawCode = rawCode.Trim(); // Check if rawCode is Empty if (string.Equals(rawCode, string.Empty)) { return(new BakeryCommand(string.Empty, Opcode.None, new string[0], address, returnAddress.Count)); } // Comment Format : starts with '//' or '#', ';' if (rawCode.Substring(0, 2) == "//" || rawCode.Substring(0, 1) == "#" || rawCode.Substring(0, 1) == ";") { return(new BakeryCommand(rawCode, Opcode.Comment, new string[0], address, returnAddress.Count)); } // Splice with spaces string[] slices = rawCode.Split(','); // Parse opcode try { // https://msdn.microsoft.com/ko-kr/library/essfb559(v=vs.110).aspx Opcode opcodeValue = (Opcode)Enum.Parse(typeof(Opcode), slices[0].Trim(), true); if (Enum.IsDefined(typeof(Opcode), opcodeValue)) { if (opcodeValue != Opcode.None && opcodeValue != Opcode.Comment) { opcode = opcodeValue; } else { throw new InvalidOpcodeException("Unknown command \'" + slices[0].Trim() + "\'", new BakeryCommand(rawCode, Opcode.Unknown, new string[0], address)); } } else { throw new InvalidOpcodeException("Unknown command \'" + slices[0].Trim() + "\'", new BakeryCommand(rawCode, Opcode.Unknown, new string[0], address)); } } catch (ArgumentException) { throw new InvalidOpcodeException("Unknown command \'" + slices[0].Trim() + "\'", new BakeryCommand(rawCode, Opcode.Unknown, new string[0], address)); } // Do nothing // Check doublequote's occurence - must be 2n if (Helper.CountStringOccurrences(rawCode, "\"") % 2 == 1) { throw new InvalidCommandException("number of doublequotes must be times of 2"); } /// Parse operand ParseState state = ParseState.Normal; string tmpStr = string.Empty; for (int i = 1; i < slices.Length; i++) { // Remove whitespace slices[i] = slices[i].Trim(); // Check if operand is doublequoted int idx = slices[i].IndexOf("\""); if (idx == -1) // Do not have doublequote { switch (state) { case ParseState.Normal: // Add to operand operandList.Add(slices[i]); break; case ParseState.Merge: tmpStr = string.Concat(tmpStr, ",", slices[i]); break; default: throw new InternalParseException(); } } else if (idx == 0) // Startes with doublequote { // Merge this operand with next operand switch (state) { case ParseState.Normal: // Add to operand if (slices[i].IndexOf("\"", idx + 1) != -1) // This operand starts and end with doublequote { // Ex) FileCopy,"1 2.dll",34.dll operandList.Add(slices[i].Substring(1, slices[i].Length - 2)); // Remove doublequote } else { state = ParseState.Merge; tmpStr = string.Concat(slices[i].Substring(1)); // Remove doublequote } break; case ParseState.Merge: throw new InvalidOperandException(); default: throw new InternalParseException(); } } else if (idx == slices[i].Length - 1) // Endes with doublequote { switch (state) { case ParseState.Normal: // Add to operand throw new InvalidOperandException(); case ParseState.Merge: state = ParseState.Normal; tmpStr = string.Concat(tmpStr, ",", slices[i].Substring(0, slices[i].Length - 1)); // Remove doublequote operandList.Add(tmpStr); tmpStr = string.Empty; break; default: throw new InternalParseException(); } } else // doublequote is in the middle { throw new InvalidOperandException(); } } // doublequote is not matched by two! if (state == ParseState.Merge) { throw new InvalidOperandException("ParseState == Merge"); } string[] operands = operandList.ToArray(typeof(string)) as string[]; for (int i = 0; i < operands.Length; i++) { // Process Escape Characters operands[i] = operands[i].Replace(@"$#c", ","); operands[i] = operands[i].Replace(@"$#p", "%"); operands[i] = operands[i].Replace(@"$#q", "\""); operands[i] = operands[i].Replace(@"$#s", " "); operands[i] = operands[i].Replace(@"$#t", "\t"); operands[i] = operands[i].Replace(@"$#x", "\n"); operands[i] = operands[i].Replace(@"$#z", "\x00\x00"); } // forge BakeryCommand return(new BakeryCommand(rawCode, opcode, operands, address, returnAddress.Count)); }