aboutsummaryrefslogtreecommitdiff
path: root/src/ProtoGen/GeneratorOptions.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/ProtoGen/GeneratorOptions.cs')
-rw-r--r--src/ProtoGen/GeneratorOptions.cs181
1 files changed, 172 insertions, 9 deletions
diff --git a/src/ProtoGen/GeneratorOptions.cs b/src/ProtoGen/GeneratorOptions.cs
index 1f3d8f2b..8781c5ec 100644
--- a/src/ProtoGen/GeneratorOptions.cs
+++ b/src/ProtoGen/GeneratorOptions.cs
@@ -1,4 +1,5 @@
#region Copyright notice and license
+
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://github.com/jskeet/dotnet-protobufs/
@@ -30,13 +31,17 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
#endregion
+using System;
using System.Collections.Generic;
using System.IO;
+using System.Text.RegularExpressions;
+using Google.ProtocolBuffers.DescriptorProtos;
+using Google.ProtocolBuffers.Descriptors;
namespace Google.ProtocolBuffers.ProtoGen {
-
/// <summary>
/// All the configuration required for the generator - where to generate
/// output files, the location of input files etc. While this isn't immutable
@@ -44,8 +49,6 @@ namespace Google.ProtocolBuffers.ProtoGen {
/// the generator.
/// </summary>
public sealed class GeneratorOptions {
-
- public string OutputDirectory { get; set; }
public IList<string> InputFiles { get; set; }
/// <summary>
@@ -58,19 +61,23 @@ namespace Google.ProtocolBuffers.ProtoGen {
public bool TryValidate(out IList<string> reasons) {
List<string> tmpReasons = new List<string>();
+ ParseArguments(tmpReasons);
+
// Output directory validation
- if (string.IsNullOrEmpty(OutputDirectory)) {
+ if (string.IsNullOrEmpty(FileOptions.OutputDirectory)) {
tmpReasons.Add("No output directory specified");
- } else {
- if (!Directory.Exists(OutputDirectory)) {
- tmpReasons.Add("Specified output directory (" + OutputDirectory + " doesn't exist.");
+ }
+ else {
+ if (!Directory.Exists(FileOptions.OutputDirectory)) {
+ tmpReasons.Add("Specified output directory (" + FileOptions.OutputDirectory + " doesn't exist.");
}
}
// Input file validation (just in terms of presence)
if (InputFiles == null || InputFiles.Count == 0) {
tmpReasons.Add("No input files specified");
- } else {
+ }
+ else {
foreach (string input in InputFiles) {
FileInfo fi = new FileInfo(input);
if (!fi.Exists) {
@@ -99,5 +106,161 @@ namespace Google.ProtocolBuffers.ProtoGen {
throw new InvalidOptionsException(reasons);
}
}
+
+ // Raw arguments, used to provide defaults for proto file options
+ public IList<string> Arguments { get; set; }
+
+ [Obsolete("Please use GeneratorOptions.FileOptions.OutputDirectory instead")]
+ public string OutputDirectory {
+ get { return FileOptions.OutputDirectory; }
+ set {
+ CSharpFileOptions.Builder bld = FileOptions.ToBuilder();
+ bld.OutputDirectory = value;
+ FileOptions = bld.Build();
+ }
+ }
+
+ private static readonly Regex ArgMatch = new Regex(@"^[-/](?<name>[\w_]+?)[:=](?<value>.*)$");
+ private CSharpFileOptions fileOptions;
+
+ public CSharpFileOptions FileOptions {
+ get { return fileOptions ?? (fileOptions = CSharpFileOptions.DefaultInstance); }
+ set { fileOptions = value; }
+ }
+
+ private void ParseArguments(IList<string> tmpReasons) {
+ bool doHelp = Arguments.Count == 0;
+
+ InputFiles = new List<string>();
+ CSharpFileOptions.Builder builder = FileOptions.ToBuilder();
+ Dictionary<string, FieldDescriptor> fields =
+ new Dictionary<string, FieldDescriptor>(StringComparer.OrdinalIgnoreCase);
+ foreach (FieldDescriptor fld in builder.DescriptorForType.Fields) {
+ fields.Add(fld.Name, fld);
+ }
+
+ foreach (string argument in Arguments) {
+ if (StringComparer.OrdinalIgnoreCase.Equals("-help", argument) ||
+ StringComparer.OrdinalIgnoreCase.Equals("/help", argument) ||
+ StringComparer.OrdinalIgnoreCase.Equals("-?", argument) ||
+ StringComparer.OrdinalIgnoreCase.Equals("/?", argument)) {
+ doHelp = true;
+ break;
+ }
+
+ Match m = ArgMatch.Match(argument);
+ if (m.Success) {
+ FieldDescriptor fld;
+ string name = m.Groups["name"].Value;
+ string value = m.Groups["value"].Value;
+
+ if (fields.TryGetValue(name, out fld)) {
+ object obj;
+ if (TryCoerceType(value, fld, out obj, tmpReasons)) {
+ builder[fld] = obj;
+ }
+ }
+ else if (!File.Exists(argument)) {
+ doHelp = true;
+ tmpReasons.Add("Unknown argument '" + name + "'.");
+ }
+ else {
+ InputFiles.Add(argument);
+ }
+ }
+ else {
+ InputFiles.Add(argument);
+ }
+ }
+
+ if (doHelp || InputFiles.Count == 0) {
+ tmpReasons.Add("Arguments:");
+ foreach (KeyValuePair<string, FieldDescriptor> field in fields) {
+ tmpReasons.Add(String.Format("-{0}=[{1}]", field.Key, field.Value.FieldType));
+ }
+ tmpReasons.Add("followed by one or more file paths.");
+ }
+ else {
+ FileOptions = builder.Build();
+ }
+ }
+
+ private static bool TryCoerceType(string text, FieldDescriptor field, out object value, IList<string> tmpReasons) {
+ value = null;
+
+ switch (field.FieldType) {
+ case FieldType.Int32:
+ case FieldType.SInt32:
+ case FieldType.SFixed32:
+ value = Int32.Parse(text);
+ break;
+
+ case FieldType.Int64:
+ case FieldType.SInt64:
+ case FieldType.SFixed64:
+ value = Int64.Parse(text);
+ break;
+
+ case FieldType.UInt32:
+ case FieldType.Fixed32:
+ value = UInt32.Parse(text);
+ break;
+
+ case FieldType.UInt64:
+ case FieldType.Fixed64:
+ value = UInt64.Parse(text);
+ break;
+
+ case FieldType.Float:
+ value = float.Parse(text);
+ break;
+
+ case FieldType.Double:
+ value = Double.Parse(text);
+ break;
+
+ case FieldType.Bool:
+ value = Boolean.Parse(text);
+ break;
+
+ case FieldType.String:
+ value = text;
+ break;
+
+ case FieldType.Enum: {
+ EnumDescriptor enumType = field.EnumType;
+
+ int number;
+ if (int.TryParse(text, out number)) {
+ value = enumType.FindValueByNumber(number);
+ if (value == null) {
+ tmpReasons.Add(
+ "Enum type \"" + enumType.FullName +
+ "\" has no value with number " + number + ".");
+ return false;
+ }
+ }
+ else {
+ value = enumType.FindValueByName(text);
+ if (value == null) {
+ tmpReasons.Add(
+ "Enum type \"" + enumType.FullName +
+ "\" has no value named \"" + text + "\".");
+ return false;
+ }
+ }
+
+ break;
+ }
+
+ case FieldType.Bytes:
+ case FieldType.Message:
+ case FieldType.Group:
+ tmpReasons.Add("Unhandled field type " + field.FieldType.ToString() + ".");
+ return false;
+ }
+
+ return true;
+ }
}
-}
+} \ No newline at end of file