diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0ca27f0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,234 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +build/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Microsoft Azure ApplicationInsights config file +ApplicationInsights.config + +# Windows Store app package directory +AppPackages/ +BundleArtifacts/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe + +# FAKE - F# Make +.fake/ diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..4123a70 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,23 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": ".NET Core Launch (console)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + "program": "${workspaceRoot}/bin/Debug/netcoreapp1.0/dbf.dll", + "args": [], + "cwd": "${workspaceRoot}", + "externalConsole": false, + "stopAtEntry": false, + "internalConsoleOptions": "openOnSessionStart" + }, + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach", + "processId": "${command.pickProcess}" + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..adc6623 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,16 @@ +{ + "version": "0.1.0", + "command": "dotnet", + "isShellCommand": true, + "args": [], + "tasks": [ + { + "taskName": "build", + "args": [ + "${workspaceRoot}/project.json" + ], + "isBuildCommand": true, + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/Options.cs b/Options.cs new file mode 100644 index 0000000..3733e32 --- /dev/null +++ b/Options.cs @@ -0,0 +1,20 @@ +using CommandLine; +using CommandLine.Text; + +namespace Dbf +{ + public class Options + { + [Option(Default=true, HelpText="Print summary information")] + public bool Summary { get; set; } + + [Option(Default=false, HelpText="Print as CSV file")] + public bool Csv { get; set; } + + [Option(Default=true, HelpText="Whether to skip deleted records")] + public bool SkipDeleted { get; set; } + + [Option(Required=true, HelpText="Path to the DBF file")] + public string Filename { get; set; } + } +} \ No newline at end of file diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..7bdda29 --- /dev/null +++ b/Program.cs @@ -0,0 +1,104 @@ +using CommandLine; +using DbfDataReader; +using System; +using System.Linq; + +namespace Dbf +{ + public class Program + { + public static int Main(string[] args) + { + return Parser.Default.ParseArguments(args) + .MapResult( + options => RunAndReturnExitCode(options), + _ => 1); + } + + public static int RunAndReturnExitCode(Options options) + { + if (options.Csv) + { + PrintCsv(options); + } + else + { + PrintSummaryInfo(options); + } + + return 0; + } + + private static void PrintSummaryInfo(Options options) + { + using (var dbfTable = new DbfTable(options.Filename)) + { + var header = dbfTable.Header; + + Console.WriteLine($"Filename: {options.Filename}"); + Console.WriteLine($"Type: {header.VersionDescription}"); + Console.WriteLine($"Memo File: {dbfTable.Memo != null}"); + Console.WriteLine($"Records: {header.RecordCount}"); + Console.WriteLine(); + Console.WriteLine("Fields:"); + Console.WriteLine("Name Type Length Decimal"); + Console.WriteLine("------------------------------------------------------------------------------"); + + foreach (var dbfColumn in dbfTable.Columns) + { + var name = dbfColumn.Name; + var columnType = ((char)dbfColumn.ColumnType).ToString(); + var length = dbfColumn.Length.ToString(); + var decimalCount = dbfColumn.DecimalCount; + Console.WriteLine($"{name.PadRight(16)} {columnType.PadRight(10)} {length.PadRight(10)} {decimalCount}"); + } + } + } + + private static void PrintCsv(Options options) + { + using (var dbfTable = new DbfTable(options.Filename)) + { + var columnNames = string.Join(",", dbfTable.Columns.Select(c => c.Name)); + if (!options.SkipDeleted) + { + columnNames += ",Deleted"; + } + + Console.WriteLine(columnNames); + + var dbfRecord = new DbfRecord(dbfTable); + + while (dbfTable.Read(dbfRecord)) + { + if (options.SkipDeleted && dbfRecord.IsDeleted) + { + continue; + } + + var values = string.Join(",", dbfRecord.Values.Select(v => EscapeValue(v))); + if (!options.SkipDeleted) + { + values += $",{dbfRecord.IsDeleted}"; + } + + Console.WriteLine(values); + } + } + } + + private static string EscapeValue(IDbfValue dbfValue) + { + var value = dbfValue.ToString(); + if (dbfValue is DbfValueString) + { + if (value.Contains(",")) + { + value = $"\"{value}\""; + } + } + + return value; + } + } +} diff --git a/README.md b/README.md index e9753bd..5f5784b 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,15 @@ # dbf + Command line utility to display DBF info and contents + +``` +dbf 1.0.0 +Copyright Chris Richards + + --summary (Default: true) Print summary information + --csv (Default: false) Print as CSV file + --skipdeleted (Default: true) Whether to skip deleted records + --filename Required. Path to the DBF file + --help Display this help screen. + --version Display version information. +``` \ No newline at end of file diff --git a/project.json b/project.json new file mode 100644 index 0000000..e8aa699 --- /dev/null +++ b/project.json @@ -0,0 +1,42 @@ +{ + "version": "1.0.0-*", + "authors": [ "Chris Richards" ], + "copyright": "Copyright Chris Richards", + "description": "Command line utility to display DBF info and contents", + "packOptions": { + "tags": [ "dbf", "dBase", "xBase", "Clipper", "FoxPro" ], + "licenseUrl": "https://github.com/yellowfeather/dbf/blob/master/LICENSE", + "projectUrl": "https://github.com/yellowfeather/dbf", + "repository": { + "type": "git", + "url": "git://github.com/yellowfeather/dbf" + } + }, + + "buildOptions": { + "emitEntryPoint": true + }, + + "dependencies": { + "Microsoft.NETCore.App": { + "type": "platform", + "version": "1.1.0" + }, + "CommandLineParser": "2.1.1-beta", + "DbfDataReader": "0.4.0" + }, + + "frameworks": { + "netcoreapp1.1": { + "imports": "dnxcore50" + } + }, + "tooling": { + "defaultNamespace": "Dbf" + }, + // "runtimes": { + // "win10-x64": {}, + // "osx.10.10-x64": {}, + // "ubuntu.14.04-x64": {} + // } +}