// copyright (c) 2020-2023 Roberto Ceccarelli - Casasoft // http://strawberryfield.altervista.org // // This file is part of Casasoft Contemporary Carte de Visite Tools // https://github.com/strawberryfield/Contemporary_CDV // // Casasoft CCDV Tools is free software: // you can redistribute it and/or modify it // under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Casasoft CCDV Tools is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details. // // You should have received a copy of the GNU AGPL v.3 // along with Casasoft CCDV Tools. // If not, see <http://www.gnu.org/licenses/>.
#region constructors /// <summary> /// Gets the name of currently running assembly /// </summary> /// <returns></returns> publicstaticstring ExeName()=> Path.GetFileNameWithoutExtension(AppDomain.CurrentDomain.FriendlyName);
/// <summary> /// Constructor /// </summary> /// <param name="outputname">Default output file name</param> /// <param name="desc">brief description of the program</param> public CommandLine(string outputname, string desc =""):this(ExeName(), outputname, desc) { }
/// <summary> /// Constructor /// </summary> /// <param name="exename">Name of the program exe</param> /// <param name="outputname">Default output file name</param> /// <param name="desc">brief description of the program</param> public CommandLine(string exename, string outputname, string desc ="") {
colors =new();
Options =new();
baseOptions =new OptionSet { {"fillcolor=", $"set the color used to fill the images\n(default {sFillColor})", c => sFillColor = c }, { "bordercolor=",
$"set the color used to border the images\n(default {sBorderColor})",
c => sBorderColor = c }, {"dpi=", $"set output resolution (default {Dpi})", res => sDpi = res }, { "json=", @"parameters in json format,
use --helpjson for sample template
Text can be stored in a file instead of a string
The file must be referenced as '@filename'",
o => JSON = GetFileParameter(o) }, { "script=", @"c# script for custom processing,
use --helpscript for sample template
Text can be stored in a file instead of a string
The file must be referenced as '@filename'",
o => Script = GetFileParameter(o) }, {"o|output=", "set output dir/filename", o => OutputName = o }, {"extension=", $"file extension for output file (default '{Extension}')", e => Extension = e }, { "tag=", @"extra info for user scripts
Text can be stored in a file instead of a string
The file must be referenced as '@filename'",
o => Tag = GetFileParameter(o) }, {"nobanner", "suppress the banner", h => noBanner = h !=null}, {"h|help", "show this message and exit", h => shouldShowHelp = h !=null}, {"helpjson", "show json parameters template", h => shouldShowHelpJson = h !=null}, {"helpscript", "show script template", h => shouldShowHelpScript = h !=null}, {"man", "show the man page source and exit", h => shouldShowMan = h !=null}, {"colors", "list available colors by name", h => shouldShowColors = h !=null}, {"license", "show program license (AGPL 3.0)", h => shouldShowLicense = h !=null} }; } #endregion
/// <summary> /// Sets base options in derived classes /// </summary> publicvoid AddBaseOptions() { foreach(var opt in baseOptions) {
Options.Add(opt); } }
/// <summary> /// Does the dirty work /// </summary> /// <param name="args">command line arguments</param> /// <returns>true if nothing to (ie. help)</returns> publicvirtualbool Parse(string[] args) { try {
FilesList = Options.Parse(args); } catch(OptionException e) {
Console.Error.WriteLine($"{exeName}: {e.Message}");
Console.Error.WriteLine($"Try '{exeName} --help' for more informations."); returntrue; }
#region hooks /// <summary> /// Hook for extra help informations /// </summary> protectedvirtualvoid ExtraHelp(){}
/// <summary> /// Hook for extra man informations /// </summary> protectedvirtualstring ExtraMan()=>string.Empty; #endregion
#region texts /// <summary> /// Prints the welcome banner /// </summary> publicvirtualvoid WelcomeBanner()=> Console.WriteLine(WelcomeBannerText());
/// <summary> /// Text for welcome banner /// </summary> /// <returns></returns> publicvirtualstring WelcomeBannerText()=> $"Casasoft Contemporary Carte de Visite {exeName}\nCopyright (c) 2020-2023 Roberto Ceccarelli - Casasoft\n";
/// <summary> /// Colors syntax help /// </summary> protectedstring ColorsSyntax => @$"Colors can be written in any of these formats:
#rgb
#rrggbb
#rrggbbaa
#rrrrggggbbbb
#rrrrggggbbbbaaaa
colorname (use {exeName} --colors to see all available colors)";
privatestatic List<HelpUtils.ParItem> variables =new(){ new("CDV_OUTPATH","Base path for output files"), new("CDV_DPI","Resolution for output files"), new("CDV_FILL","Color used to fill images"), new("CDV_BORDER","Border color") };
/// <summary> /// Environment variables help /// </summary> protectedstring EnvVarsHelp => @$"The program can read values from these variables:
{HelpUtils.OptionsList(variables)}";
/// <summary> /// Environment variables markdown /// </summary> protectedstring EnvVarsMan => @$"The program can read values from these variables:
{HelpUtils.MDOptionsList(variables)}";
/// <summary> /// Text of man page in markdown format /// </summary> /// <returns></returns> protectedstring PrintMan() {
StringBuilder ret =new StringBuilder();
ret.AppendLine(
@$"% {exeName.ToUpper()}(1)
% Roberto Ceccarelli - Casasoft
% April 2023
## JSON
Parameters can also be passed with a json formatted string
using the following template:
~~~
{JsonTemplate()}
~~~
## ENVIRONMENT VARIABLES
{EnvVarsMan}
# SCRIPTING
You can add custom c# code, compiled at runtime, with the --script parameter.
You can call a property *engine* that exposes all the parameters passed
to the main program.
The following using are declared:
~~~
{Scripting.Compiler.Usings}
~~~
These are the signatures of the scriptable methods:
/// <summary> /// Prints a json schema for parameters /// </summary> /// <remarks> /// Should be overridden in specialized classes /// </remarks> /// <returns></returns> publicvirtualstring JsonTemplate() {
CommonParameters p =new(); return JsonSerializer.Serialize(p, new JsonSerializerOptions { WriteIndented =true}); }
/// <summary> /// Prints a script template /// </summary> /// <remarks> /// Should be overridden in specialized classes /// </remarks> /// <returns></returns> publicvirtualstring ScriptTemplate()=> $"// Script template for {exeName}\n"; #endregion
/// <summary> /// Gets string from filename.<br/> If the argument begins with '@' then the string is the name of the file /// containing the text /// </summary> /// <param name="p">parameter argument</param> /// <returns></returns> protectedstring GetFileParameter(string p) { if(!string.IsNullOrWhiteSpace(p)&& p[0]=='@') { string ret =string.Empty; int l = p.Length; if(l <2) {
Console.Error.WriteLine("Missing filename for '@' parameter"); } else { string filename = p.Substring(1); if(File.Exists(filename)) {
ret = File.ReadAllText(filename); } else {
Console.Error.WriteLine($"File '{filename}' not found."); } } return ret; } else { return p; } }
/// <summary> /// Get integer value from string /// </summary> /// <param name="val">input string</param> /// <param name="fallback">default value in case of parsing error</param> /// <param name="message">error message</param> /// <returns></returns> publicstaticint GetIntParameter(string val, int fallback, string message) { int ret; if(!int.TryParse(val, out ret)) {
Console.Error.WriteLine(string.Format(message, val));
ret = fallback; } return ret; }
/// <summary> /// sets the dpi value from command line string /// </summary> protectedvoid GetDPI() { if(!string.IsNullOrWhiteSpace(sDpi))
Dpi = GetIntParameter(sDpi, Dpi, "Incorrect dpi value '{0}'. Using default value."); }
/// <summary> /// Gets the color by a string /// </summary> /// <param name="color">name or components values</param> /// <returns><see cref="MagickColor"/></returns> protected MagickColor GetColor(string color) {
MagickColor ret = MagickColors.Transparent; if(!string.IsNullOrWhiteSpace(color)) {
MagickColor r = colors.GetColor(color); if(r is not null) {
ret = r; } else {
Console.Error.WriteLine($"Unknown color '{color}'\nTry {exeName} --colors"); } } else {
Console.Error.WriteLine("Invalid empty color"); } return ret; }