diff --git a/ConfMan.IOB.CApp/ConfMan.IOB.CApp.csproj b/ConfMan.IOB.CApp/ConfMan.IOB.CApp.csproj
new file mode 100644
index 0000000..be160a5
--- /dev/null
+++ b/ConfMan.IOB.CApp/ConfMan.IOB.CApp.csproj
@@ -0,0 +1,14 @@
+
+
+
+ Exe
+ net6.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/ConfMan.IOB.CApp/Program.cs b/ConfMan.IOB.CApp/Program.cs
new file mode 100644
index 0000000..627b41c
--- /dev/null
+++ b/ConfMan.IOB.CApp/Program.cs
@@ -0,0 +1,105 @@
+// See https://aka.ms/new-console-template for more information
+using ConfMan.IOB.CApp;
+using Spectre.Console;
+using System.Net;
+
+AnsiConsole.Write(
+ new FigletText("ConfMan.IOB")
+ .LeftAligned()
+ .Color(Color.Blue1));
+var rule = new Rule("[green]IOB configuration file manager[/]");
+rule.Alignment = Justify.Left;
+AnsiConsole.Write(rule);
+
+
+AnsiConsole.WriteLine();
+var fileType = ".ini";
+AnsiConsole.MarkupLineInterpolated($"Conf file type: [yellow]{fileType}[/]");
+var typeOk = AnsiConsole.Confirm("Confermi tipo file?");
+while (!typeOk)
+{
+ fileType = AnsiConsole.Ask("Inserisci il type desiderato:");
+ AnsiConsole.WriteLine(fileType);
+ typeOk = AnsiConsole.Confirm("Confermi tipo file?");
+}
+// aggiungo "*" se mancasse...
+if (fileType.Substring(0, 1) != "*")
+{
+ fileType = $"*{fileType}";
+}
+AnsiConsole.MarkupLineInterpolated($"Confermato file type: [green]{fileType}[/]");
+
+//var path = new TextPath(@"C:\Steamware\IOB-WIN-NEXT\DATA\CONF");
+string sPath = @"C:\temp\DATA\CONF";
+var path = new TextPath(sPath);
+AnsiConsole.WriteLine($"Default conf path:");
+AnsiConsole.Write(path);
+//AnsiConsole.WriteLine();
+
+var fileList = Directory.GetFiles(sPath, fileType);
+AnsiConsole.MarkupLineInterpolated($"Trovati [yellow]{fileList.Count()}[/] file...");
+var pathOK = AnsiConsole.Confirm("Confermi il Path?");
+while (!pathOK)
+{
+ sPath = AnsiConsole.Ask("Inserisci il percorso completo:");
+ if (!string.IsNullOrEmpty(sPath))
+ {
+ path = new TextPath(sPath);
+ AnsiConsole.Write(path);
+ // verifico esista la directory...
+ if (!Directory.Exists(sPath))
+ {
+ AnsiConsole.MarkupLine("Attenzione: path inserito [red]non[/] valido!");
+ }
+ else
+ {
+ // recupero il numero di file ini cercati
+ fileList = Directory.GetFiles(sPath, fileType);
+ AnsiConsole.MarkupLineInterpolated($"Trovati [yellow]{fileList.Count()}[/] file...");
+ pathOK = AnsiConsole.Confirm("Confermi il Path?");
+ }
+ }
+}
+
+rule = new Rule("[green]TAGS[/] selection");
+rule.Alignment = Justify.Left;
+AnsiConsole.Write(rule);
+string hostName = Dns.GetHostName();
+var hostAddress = Dns.GetHostAddresses(hostName);
+string hostAddr = "";
+if (hostAddress != null)
+{
+ if (hostAddress.Count() > 1)
+ {
+ var ipList = hostAddress.Select(x => $"{x}").ToList();
+ hostAddr = AnsiConsole.Prompt(
+ new SelectionPrompt()
+ .Title("Selezione indirizzo [green]IP[/]")
+ .MoreChoicesText("[grey](Move up and down to reveal more)[/]")
+ .AddChoices(ipList));
+ }
+ else
+ {
+ hostAddr = $"{hostAddress[0]}";
+ }
+}
+var custName = AnsiConsole.Ask("Inserisci valore per [yellow]Customer[/]:","SteamWare");
+var HostOS = AnsiConsole.Ask("Inserisci valore per [yellow]OS[/]:","WIN");
+var HostName = AnsiConsole.Ask("Inserisci valore per [yellow]HostName[/]:", hostName);
+var HostAddr = AnsiConsole.Ask("Inserisci valore per [yellow]HostAddress (IP)[/]:", hostAddr);
+// salvo i tagList...
+Dictionary newTags = new Dictionary();
+newTags.Add("Customer", custName);
+newTags.Add("HostOS", HostOS);
+newTags.Add("HostName", HostName);
+newTags.Add("HostAddr", HostAddr);
+AnsiConsole.WriteLine();
+
+// ora processa tutti i file, andando ad aggiungere in coda i TAGS selezionati...
+foreach (var confFile in fileList)
+{
+ TagManager tMan = new TagManager(confFile);
+ tMan.addTagList(newTags);
+}
+
+return 1;
\ No newline at end of file
diff --git a/ConfMan.IOB.CApp/TagManager.cs b/ConfMan.IOB.CApp/TagManager.cs
new file mode 100644
index 0000000..23ca4d0
--- /dev/null
+++ b/ConfMan.IOB.CApp/TagManager.cs
@@ -0,0 +1,85 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ConfMan.IOB.CApp
+{
+ public class TagManager
+ {
+ protected string _filePath;
+ public TagManager(string filePath)
+ {
+ _filePath = filePath;
+ }
+
+ ///
+ /// Aggiunge i tag al file con cui è stato inizializzato
+ ///
+ ///
+ ///
+ public bool addTagList(Dictionary tags)
+ {
+ bool fatto = false;
+ // in primis vedo se ho tags da scrivere
+ if (tags.Count > 0)
+ {
+ // verifico file esista
+ if (File.Exists(_filePath))
+ {
+ // leggo file
+ var fileRows = File.ReadAllLines(_filePath);
+ //string fileContent = File.ReadAllText(_filePath);
+ bool tagFound = false;
+ string tagHead = "[TAGS]";
+ int currIdx = 0;
+ int rowTagIndex = 0;
+ foreach (var riga in fileRows)
+ {
+ if (riga.Contains(tagHead))
+ {
+ tagFound = true;
+ rowTagIndex = currIdx;
+ break;
+ }
+ currIdx++;
+ }
+ if (!tagFound)
+ {
+ fileRows.Append("");
+ fileRows.Append("; Tags manuali");
+ fileRows.Append(tagHead);
+ rowTagIndex = fileRows.Count() - 1;
+ }
+ fileRows.Append("");
+ int numRows = fileRows.Count();
+ // ora aggiungo le varie chiavi dal dizionario
+ foreach (var tag in tags)
+ {
+ bool rowChanged = false;
+ // cerco se ci fosse una riga precedente e la levo... vengono DOPO il tags finbo alla lunghezza massima precedente
+ for (int i = rowTagIndex; i < numRows; i++)
+ {
+ if (fileRows[i].Contains($"{tag.Key}="))
+ {
+ // sostituisco con vuoto
+ fileRows[i] = $"{tag.Key}={tag.Value}";
+ rowChanged = true;
+ }
+ }
+ // aggiungo tag in coda se no sostituito
+ if (!rowChanged)
+ {
+ fileRows.Append($"{tag.Key}={tag.Value}");
+ }
+ }
+ // salvo!
+ File.WriteAllLines(_filePath, fileRows);
+ fatto = true;
+ }
+ }
+ return fatto;
+ }
+ }
+}