mirror of
https://github.com/fadden/6502bench.git
synced 2025-04-13 09:37:10 +00:00
Initial file commit
This commit is contained in:
parent
469eb49c4a
commit
2c6212404d
312
.gitignore
vendored
Normal file
312
.gitignore
vendored
Normal file
@ -0,0 +1,312 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# 6502bench-specific stuff
|
||||
SourceGen/SourceGen-settings
|
||||
SourceGen/PluginDll
|
||||
DIST_Debug
|
||||
DIST_release
|
||||
|
||||
|
||||
# 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/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
|
||||
# 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
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
**/Properties/launchSettings.json
|
||||
|
||||
*_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
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# 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
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# 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
|
||||
# Note: 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
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# 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
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
|
||||
# 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
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# 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
|
||||
*.ndf
|
||||
|
||||
# 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
|
||||
node_modules/
|
||||
|
||||
# Typescript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# 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
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
|
||||
# CodeRush
|
||||
.cr/
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
92
Asm65/Address.cs
Normal file
92
Asm65/Address.cs
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Asm65 {
|
||||
public static class Address {
|
||||
/// <summary>
|
||||
/// Converts a 16- or 24-bit address to a string.
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <returns></returns>
|
||||
public static string AddressToString(int addr, bool always24) {
|
||||
if (!always24 && addr < 65536) {
|
||||
return addr.ToString("x4");
|
||||
} else {
|
||||
return (addr >> 16).ToString("x2") + "/" + (addr & 0xffff).ToString("x4");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses and validates a 16- or 24-bit address, expressed in hexadecimal. Bits
|
||||
/// 16-23 may be specified with a slash.
|
||||
///
|
||||
/// The following all evaluate to the same thing: 1000, $1000, 0x1000, 00/1000.
|
||||
/// </summary>
|
||||
/// <param name="addrStr">String to validate.</param>
|
||||
/// <param name="max">Maximum valid address value.</param>
|
||||
/// <param name="addr">Integer form.</param>
|
||||
/// <returns>True if the address is valid.</returns>
|
||||
public static bool ParseAddress(string addrStr, int max, out int addr) {
|
||||
string trimStr = addrStr.Trim(); // strip whitespace
|
||||
if (trimStr.Length < 1) {
|
||||
addr = -1;
|
||||
return false;
|
||||
}
|
||||
if (trimStr[0] == '$') {
|
||||
trimStr = trimStr.Remove(0, 1);
|
||||
}
|
||||
|
||||
int slashIndex = trimStr.IndexOf('/');
|
||||
try {
|
||||
if (slashIndex < 0) {
|
||||
addr = Convert.ToInt32(trimStr, 16);
|
||||
if (addr < 0 || addr > max) {
|
||||
Debug.WriteLine("Simple value out of range");
|
||||
addr = -1;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
string[] splitStr = trimStr.Split('/');
|
||||
if (splitStr.Length == 2) {
|
||||
int addr1 = Convert.ToInt32(splitStr[0], 16);
|
||||
int addr2 = Convert.ToInt32(splitStr[1], 16);
|
||||
addr = (addr1 << 16) | addr2;
|
||||
// Check components separately to catch overflow.
|
||||
if (addr1 < 0 || addr1 > 255 || addr2 < 0 || addr2 > 65535 ||
|
||||
addr > max) {
|
||||
Debug.WriteLine("Slash value out of range");
|
||||
addr = -1;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
addr = -1;
|
||||
}
|
||||
}
|
||||
} catch (Exception) {
|
||||
// Thrown from Convert.ToInt32
|
||||
//Debug.WriteLine("ValidateAddress: conversion of '" + addrStr + "' failed: " +
|
||||
// ex.Message);
|
||||
addr = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
//Debug.WriteLine("Conv " + addrStr + " --> " + addr.ToString("x6"));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
26
Asm65/Asm65.csproj
Normal file
26
Asm65/Asm65.csproj
Normal file
@ -0,0 +1,26 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\CommonUtil\CommonUtil.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Properties\Resources.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Properties\Resources.resx">
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
1184
Asm65/CpuDef.cs
Normal file
1184
Asm65/CpuDef.cs
Normal file
File diff suppressed because it is too large
Load Diff
819
Asm65/Formatter.cs
Normal file
819
Asm65/Formatter.cs
Normal file
@ -0,0 +1,819 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
|
||||
using AddressMode = Asm65.OpDef.AddressMode;
|
||||
|
||||
namespace Asm65 {
|
||||
/// <summary>
|
||||
/// Functions used for formatting bits of 65xx code into human-readable form.
|
||||
///
|
||||
/// There are a variety of ways to format a given thing, based on personal preference
|
||||
/// (e.g. whether opcodes are upper- or lower-case) and assembler syntax requirements.
|
||||
///
|
||||
/// The functions in this class serve two purposes: (1) produce consistent output
|
||||
/// throughout the program; (2) cache format strings and other components to reduce
|
||||
/// string manipulation overhead. Note the caching is per-Formatter, so it's best to
|
||||
/// create just one and share it around.
|
||||
///
|
||||
/// The configuration of a Formatter may not be altered once created. This is important
|
||||
/// in situations where we compute output size in one pass and generate it in another,
|
||||
/// because it guarantees that a given Formatter object will produce the same number of
|
||||
/// lines of output.
|
||||
///
|
||||
/// NOTE: if the CpuDef changes, the cached values in the Formatter will become invalid.
|
||||
/// Discard the Formatter and create a new one. (This could be fixed by keying off of
|
||||
/// the OpDef instead of OpDef.Opcode, but that's less convenient.)
|
||||
/// </summary>
|
||||
public class Formatter {
|
||||
/// <summary>
|
||||
/// Various format configuration options. Fill one of these out and pass it to
|
||||
/// the Formatter constructor.
|
||||
/// </summary>
|
||||
public struct FormatConfig {
|
||||
// alpha case for some case-insensitive items
|
||||
public bool mUpperHexDigits; // display hex values in upper case?
|
||||
public bool mUpperOpcodes; // display opcodes in upper case?
|
||||
public bool mUpperPseudoOpcodes; // display pseudo-opcodes in upper case?
|
||||
public bool mUpperOperandA; // display acc operand in upper case?
|
||||
public bool mUpperOperandS; // display stack operand in upper case?
|
||||
public bool mUpperOperandXY; // display index register operand in upper case?
|
||||
public bool mAddSpaceLongComment; // insert space after delimiter for long comments?
|
||||
|
||||
// functional changes to assembly output
|
||||
public bool mSuppressHexNotation; // omit '$' before hex digits
|
||||
|
||||
public bool mAllowHighAsciiCharConst; // can we do high-ASCII character constants?
|
||||
// (this might need to be generalized)
|
||||
|
||||
public string mForceAbsOpcodeSuffix; // these may be null or empty
|
||||
public string mForceAbsOperandPrefix;
|
||||
public string mForceLongOpcodeSuffix;
|
||||
public string mForceLongOperandPrefix;
|
||||
|
||||
public string mEndOfLineCommentDelimiter; // usually ';'
|
||||
public string mFullLineCommentDelimiterBase; // usually ';' or '*', WITHOUT extra space
|
||||
public string mBoxLineCommentDelimiter; // usually blank or ';'
|
||||
|
||||
// miscellaneous
|
||||
public bool mHexDumpAsciiOnly; // disallow non-ASCII chars in hex dumps?
|
||||
|
||||
public enum CharConvMode { Unknown = 0, PlainAscii, HighLowAscii };
|
||||
public CharConvMode mHexDumpCharConvMode; // character conversion mode for dumps
|
||||
|
||||
public enum ExpressionMode { Unknown = 0, Simple, Merlin };
|
||||
public ExpressionMode mExpressionMode; // symbol rendering mode
|
||||
|
||||
// Deserialization helper.
|
||||
public static ExpressionMode ParseExpressionMode(string str) {
|
||||
ExpressionMode em = ExpressionMode.Simple;
|
||||
if (!string.IsNullOrEmpty(str)) {
|
||||
if (Enum.TryParse<ExpressionMode>(str, out ExpressionMode pem)) {
|
||||
em = pem;
|
||||
}
|
||||
}
|
||||
return em;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly char[] sHexCharsLower = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
|
||||
};
|
||||
private static readonly char[] sHexCharsUpper = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Formatter configuration options. Fixed at construction time.
|
||||
/// </summary>
|
||||
private FormatConfig mFormatConfig;
|
||||
|
||||
/// <summary>
|
||||
/// Get a copy of the format config.
|
||||
/// </summary>
|
||||
public FormatConfig Config { get { return mFormatConfig; } }
|
||||
|
||||
// Bits and pieces.
|
||||
char mHexFmtChar;
|
||||
string mHexPrefix;
|
||||
char mAccChar;
|
||||
char mXregChar;
|
||||
char mYregChar;
|
||||
char mSregChar;
|
||||
|
||||
// Format string for offsets.
|
||||
private string mOffset20Format;
|
||||
|
||||
// Format strings for addresses.
|
||||
private string mAddrFormatNoBank;
|
||||
private string mAddrFormatWithBank;
|
||||
|
||||
// Generated opcode strings. The index is the bitwise OR of the opcode value and
|
||||
// the disambiguation value. In most cases this just helps us avoid calling
|
||||
// ToUpper incessantly.
|
||||
private Dictionary<int, string> mOpcodeStrings = new Dictionary<int, string>();
|
||||
|
||||
// Generated pseudo-opcode strings.
|
||||
private Dictionary<string, string> mPseudoOpStrings = new Dictionary<string, string>();
|
||||
|
||||
// Generated format strings for operands. The index is the bitwise OR of the
|
||||
// address mode and the disambiguation value.
|
||||
private Dictionary<int, string> mOperandFormats = new Dictionary<int, string>();
|
||||
|
||||
// Generated format strings for bytes.
|
||||
private const int MAX_BYTE_DUMP = 4;
|
||||
private string[] mByteDumpFormats = new string[MAX_BYTE_DUMP];
|
||||
|
||||
// Generated format strings for hex values.
|
||||
private string[] mHexValueFormats = new string[4];
|
||||
|
||||
private string mFullLineCommentDelimiterPlus;
|
||||
|
||||
// Buffer to use when generating hex dump lines.
|
||||
private char[] mHexDumpBuffer;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A 16-character array with 0-9a-f, for hex conversions. The letters will be
|
||||
/// upper or lower case, per the format config.
|
||||
/// </summary>
|
||||
public char[] HexDigits {
|
||||
get {
|
||||
return mFormatConfig.mUpperHexDigits ? sHexCharsUpper : sHexCharsLower;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// String to put between the operand and the end-of-line comment.
|
||||
/// </summary>
|
||||
public string EndOfLineCommentDelimiter {
|
||||
get { return mFormatConfig.mEndOfLineCommentDelimiter; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// String to put at the start of a line with a full-line comment.
|
||||
/// </summary>
|
||||
public string FullLineCommentDelimiter {
|
||||
get { return mFullLineCommentDelimiterPlus; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// String to put at the start of a line that has a box comment. This is usually
|
||||
/// blank, as it's only needed if the assembler doesn't recognize the box character
|
||||
/// as a comment.
|
||||
/// </summary>
|
||||
public string BoxLineCommentDelimiter {
|
||||
get { return mFormatConfig.mBoxLineCommentDelimiter; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When formatting a symbol with an offset, if this flag is set, generate code that
|
||||
/// assumes the assembler applies the adjustment, then shifts the result. If not,
|
||||
/// assume the assembler shifts the operand before applying the adjustment.
|
||||
/// </summary>
|
||||
public FormatConfig.ExpressionMode ExpressionMode {
|
||||
get { return mFormatConfig.mExpressionMode; }
|
||||
}
|
||||
|
||||
|
||||
public Formatter(FormatConfig config) {
|
||||
mFormatConfig = config;
|
||||
if (mFormatConfig.mEndOfLineCommentDelimiter == null) {
|
||||
mFormatConfig.mEndOfLineCommentDelimiter = string.Empty;
|
||||
}
|
||||
if (mFormatConfig.mFullLineCommentDelimiterBase == null) {
|
||||
mFormatConfig.mFullLineCommentDelimiterBase = string.Empty;
|
||||
}
|
||||
if (mFormatConfig.mBoxLineCommentDelimiter == null) {
|
||||
mFormatConfig.mBoxLineCommentDelimiter = string.Empty;
|
||||
}
|
||||
|
||||
if (mFormatConfig.mAddSpaceLongComment) {
|
||||
mFullLineCommentDelimiterPlus = mFormatConfig.mFullLineCommentDelimiterBase + " ";
|
||||
} else {
|
||||
mFullLineCommentDelimiterPlus = mFormatConfig.mFullLineCommentDelimiterBase;
|
||||
}
|
||||
|
||||
Reset();
|
||||
|
||||
// Prep the static parts of the hex dump buffer.
|
||||
mHexDumpBuffer = new char[73];
|
||||
for (int i = 0; i < mHexDumpBuffer.Length; i++) {
|
||||
mHexDumpBuffer[i] = ' ';
|
||||
}
|
||||
mHexDumpBuffer[6] = ':';
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the pieces we use to build format strings.
|
||||
/// </summary>
|
||||
private void Reset() {
|
||||
// Clear old data. (No longer needed.)
|
||||
//mAddrFormatNoBank = mAddrFormatWithBank = null;
|
||||
//mOffset20Format = null;
|
||||
//mOpcodeStrings.Clear();
|
||||
//mPseudoOpStrings.Clear();
|
||||
//mOperandFormats.Clear();
|
||||
//for (int i = 0; i < MAX_BYTE_DUMP; i++) {
|
||||
// mByteDumpFormats[i] = null;
|
||||
//}
|
||||
|
||||
if (mFormatConfig.mUpperHexDigits) {
|
||||
mHexFmtChar = 'X';
|
||||
} else {
|
||||
mHexFmtChar = 'x';
|
||||
}
|
||||
if (mFormatConfig.mSuppressHexNotation) {
|
||||
mHexPrefix = "";
|
||||
} else {
|
||||
mHexPrefix = "$";
|
||||
}
|
||||
if (mFormatConfig.mUpperOperandA) {
|
||||
mAccChar = 'A';
|
||||
} else {
|
||||
mAccChar = 'a';
|
||||
}
|
||||
if (mFormatConfig.mUpperOperandXY) {
|
||||
mXregChar = 'X';
|
||||
mYregChar = 'Y';
|
||||
} else {
|
||||
mXregChar = 'x';
|
||||
mYregChar = 'y';
|
||||
}
|
||||
if (mFormatConfig.mUpperOperandS) {
|
||||
mSregChar = 'S';
|
||||
} else {
|
||||
mSregChar = 's';
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats a 24-bit offset value as hex.
|
||||
/// </summary>
|
||||
/// <param name="offset">Offset to format.</param>
|
||||
/// <returns>Formatted string.</returns>
|
||||
public string FormatOffset24(int offset) {
|
||||
if (string.IsNullOrEmpty(mOffset20Format)) {
|
||||
mOffset20Format = "+{0:" + mHexFmtChar + "6}";
|
||||
}
|
||||
return string.Format(mOffset20Format, offset & 0x0fffff);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats a value in hexadecimal. The width is padded with zeroes to make the
|
||||
/// length even (so it'll be $00, $0100, $010000, etc.) If minDigits is nonzero,
|
||||
/// additional zeroes may be added.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to format, up to 32 bits.</param>
|
||||
/// <param name="minDigits">Minimum width, in printed digits (e.g. 4 is "0000").</param>
|
||||
/// <returns>Formatted string.</returns>
|
||||
public string FormatHexValue(int value, int minDigits) {
|
||||
int width = minDigits > 2 ? minDigits : 2;
|
||||
if (width < 8 && value > 0xffffff) {
|
||||
width = 8;
|
||||
} else if (width < 6 && value > 0xffff) {
|
||||
width = 6;
|
||||
} else if (width < 4 && value > 0xff) {
|
||||
width = 4;
|
||||
}
|
||||
int index = (width / 2) - 1;
|
||||
if (mHexValueFormats[index] == null) {
|
||||
mHexValueFormats[index] = mHexFmtChar + width.ToString();
|
||||
}
|
||||
return mHexPrefix + value.ToString(mHexValueFormats[index]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Format a value as a number in the specified base.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to format.</param>
|
||||
/// <param name="numBase">Numeric base (2, 10, or 16).</param>
|
||||
/// <returns>Formatted string.</returns>
|
||||
public string FormatValueInBase(int value, int numBase) {
|
||||
switch (numBase) {
|
||||
case 2:
|
||||
return FormatBinaryValue(value, 8);
|
||||
case 10:
|
||||
return FormatDecimalValue(value);
|
||||
case 16:
|
||||
return FormatHexValue(value, 2);
|
||||
default:
|
||||
Debug.Assert(false);
|
||||
return "???";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats a value as decimal.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to convert.</param>
|
||||
/// <returns>Formatted string.</returns>
|
||||
public string FormatDecimalValue(int value) {
|
||||
return value.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats a value in binary, padding with zeroes so the length is a multiple of 8.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to convert.</param>
|
||||
/// <param name="minDigits">Minimum width, in printed digits. Will be rounded up to
|
||||
/// a multiple of 8.</param>
|
||||
/// <returns>Formatted string.</returns>
|
||||
public string FormatBinaryValue(int value, int minDigits) {
|
||||
string binaryStr = Convert.ToString(value, 2);
|
||||
int desiredWidth = ((binaryStr.Length + 7) / 8) * 8;
|
||||
if (desiredWidth < minDigits) {
|
||||
desiredWidth = ((minDigits + 7) / 8) * 8;
|
||||
}
|
||||
return '%' + binaryStr.PadLeft(desiredWidth, '0');
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats a value as an ASCII character, surrounded by quotes. Must be a valid
|
||||
/// low- or high-ASCII value.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to format.</param>
|
||||
/// <returns>Formatted string.</returns>
|
||||
private string FormatAsciiChar(int value) {
|
||||
Debug.Assert(CommonUtil.TextUtil.IsHiLoAscii(value));
|
||||
char ch = (char)(value & 0x7f);
|
||||
bool hiAscii = ((value & 0x80) != 0);
|
||||
|
||||
StringBuilder sb;
|
||||
int method = -1;
|
||||
switch (method) {
|
||||
case 0:
|
||||
default:
|
||||
// Convention is from Merlin: single quote for low-ASCII, double-quote
|
||||
// for high-ASCII. Add a backslash if we're quoting the delimiter.
|
||||
sb = new StringBuilder(4);
|
||||
char quoteChar = ((value & 0x80) == 0) ? '\'' : '"';
|
||||
sb.Append(quoteChar);
|
||||
if (quoteChar == ch) {
|
||||
sb.Append('\\');
|
||||
}
|
||||
sb.Append(ch);
|
||||
sb.Append(quoteChar);
|
||||
break;
|
||||
case 1:
|
||||
// Convention is similar to Merlin, but with curly-quotes so it doesn't
|
||||
// look weird when quoting ' or ".
|
||||
sb = new StringBuilder(3);
|
||||
sb.Append(hiAscii ? '\u201c' : '\u2018');
|
||||
sb.Append(ch);
|
||||
sb.Append(hiAscii ? '\u201d' : '\u2019');
|
||||
break;
|
||||
case 2:
|
||||
// Always use apostrophe, but follow it with an up-arrow to indicate
|
||||
// that it's high-ASCII.
|
||||
sb = new StringBuilder(4);
|
||||
sb.Append("'");
|
||||
sb.Append(ch);
|
||||
sb.Append("'");
|
||||
if (hiAscii) {
|
||||
sb.Append('\u21e1'); // UPWARDS DASHED ARROW
|
||||
//sb.Append('\u2912'); // UPWARDS ARROW TO BAR
|
||||
}
|
||||
break;
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats a value as an ASCII character, if possible, or as a hex value.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to format.</param>
|
||||
/// <returns>Formatted string.</returns>
|
||||
public string FormatAsciiOrHex(int value) {
|
||||
bool hiAscii = ((value & 0x80) != 0);
|
||||
if (hiAscii && !mFormatConfig.mAllowHighAsciiCharConst) {
|
||||
return FormatHexValue(value, 2);
|
||||
} else if (CommonUtil.TextUtil.IsHiLoAscii(value)) {
|
||||
return FormatAsciiChar(value);
|
||||
} else {
|
||||
return FormatHexValue(value, 2);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats a 16- or 24-bit address value. This is intended for the left column
|
||||
/// of something (hex dump, code listing), not as an operand.
|
||||
/// </summary>
|
||||
/// <param name="address">Address to format.</param>
|
||||
/// <param name="showBank">Set to true for CPUs with 24-bit address spaces.</param>
|
||||
/// <returns>Formatted string.</returns>
|
||||
public string FormatAddress(int address, bool showBank) {
|
||||
if (mAddrFormatNoBank == null) {
|
||||
mAddrFormatNoBank = "{0:" + mHexFmtChar + "4}";
|
||||
mAddrFormatWithBank = "{0:" + mHexFmtChar + "2}/{1:" + mHexFmtChar + "4}";
|
||||
}
|
||||
if (showBank) {
|
||||
return string.Format(mAddrFormatWithBank, address >> 16, address & 0xffff);
|
||||
} else {
|
||||
return string.Format(mAddrFormatNoBank, address & 0xffff);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats an adjustment, as "+decimal" or "-decimal". If no adjustment
|
||||
/// is required, an empty string is returned.
|
||||
/// </summary>
|
||||
/// <param name="adjValue">Adjustment value.</param>
|
||||
/// <returns>Formatted string.</returns>
|
||||
public string FormatAdjustment(int adjValue) {
|
||||
if (adjValue == 0) {
|
||||
return string.Empty;
|
||||
}
|
||||
// This formats in decimal with a leading '+' or '-'. To avoid adding a plus
|
||||
// on zero, we'd use "+#;-#;0", but we took care of the zero case above.
|
||||
return adjValue.ToString("+0;-#");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats the instruction opcode mnemonic, and caches the result.
|
||||
///
|
||||
/// It may be necessary to modify the mnemonic for some assemblers, e.g. LDA from a
|
||||
/// 24-bit address might need to be LDAL, even if the high byte is nonzero.
|
||||
/// </summary>
|
||||
/// <param name="op">Opcode to format</param>
|
||||
/// <param name="wdis">Width disambiguation specifier.</param>
|
||||
/// <returns>Formatted string.</returns>
|
||||
public string FormatOpcode(OpDef op, OpDef.WidthDisambiguation wdis) {
|
||||
// TODO(someday): using op.Opcode as the key is a bad idea, as the operation may
|
||||
// not be the same on different CPUs. We currently rely on the caller to discard
|
||||
// the Formatter when the CPU definition changes. We'd be better off keying off of
|
||||
// the OpDef object and factoring wdis in some other way.
|
||||
int key = op.Opcode | ((int)wdis << 8);
|
||||
if (!mOpcodeStrings.TryGetValue(key, out string opcodeStr)) {
|
||||
// Not found, generate value.
|
||||
opcodeStr = FormatMnemonic(op.Mnemonic, wdis);
|
||||
|
||||
// Memoize.
|
||||
mOpcodeStrings[key] = opcodeStr;
|
||||
}
|
||||
return opcodeStr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats the string as an opcode mnemonic.
|
||||
///
|
||||
/// It may be necessary to modify the mnemonic for some assemblers, e.g. LDA from a
|
||||
/// 24-bit address might need to be LDAL, even if the high byte is nonzero.
|
||||
/// </summary>
|
||||
/// <param name="mnemonic">Instruction mnemonic string.</param>
|
||||
/// <param name="wdis">Width disambiguation specifier.</param>
|
||||
/// <returns></returns>
|
||||
public string FormatMnemonic(string mnemonic, OpDef.WidthDisambiguation wdis) {
|
||||
string opcodeStr = mnemonic;
|
||||
if (wdis == OpDef.WidthDisambiguation.ForceAbs) {
|
||||
if (!string.IsNullOrEmpty(mFormatConfig.mForceAbsOpcodeSuffix)) {
|
||||
opcodeStr += mFormatConfig.mForceAbsOpcodeSuffix;
|
||||
}
|
||||
} else if (wdis == OpDef.WidthDisambiguation.ForceLong ||
|
||||
wdis == OpDef.WidthDisambiguation.ForceLongMaybe) {
|
||||
if (!string.IsNullOrEmpty(mFormatConfig.mForceLongOpcodeSuffix)) {
|
||||
opcodeStr += mFormatConfig.mForceLongOpcodeSuffix;
|
||||
}
|
||||
} else {
|
||||
Debug.Assert(wdis == OpDef.WidthDisambiguation.None);
|
||||
}
|
||||
if (mFormatConfig.mUpperOpcodes) {
|
||||
opcodeStr = opcodeStr.ToUpperInvariant();
|
||||
}
|
||||
return opcodeStr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates an operand format.
|
||||
/// </summary>
|
||||
/// <param name="addrMode">Addressing mode.</param>
|
||||
/// <returns>Format string.</returns>
|
||||
private string GenerateOperandFormat(OpDef.AddressMode addrMode,
|
||||
OpDef.WidthDisambiguation wdis) {
|
||||
string fmt;
|
||||
string wdisStr = string.Empty;
|
||||
|
||||
if (wdis == OpDef.WidthDisambiguation.ForceAbs) {
|
||||
if (!string.IsNullOrEmpty(mFormatConfig.mForceAbsOperandPrefix)) {
|
||||
wdisStr = mFormatConfig.mForceAbsOperandPrefix;
|
||||
}
|
||||
} else if (wdis == OpDef.WidthDisambiguation.ForceLong) {
|
||||
if (!string.IsNullOrEmpty(mFormatConfig.mForceLongOperandPrefix)) {
|
||||
wdisStr = mFormatConfig.mForceLongOperandPrefix;
|
||||
}
|
||||
} else if (wdis == OpDef.WidthDisambiguation.ForceLongMaybe) {
|
||||
// Don't add a width disambiguator to an operand that is unambiguously long.
|
||||
} else {
|
||||
Debug.Assert(wdis == OpDef.WidthDisambiguation.None);
|
||||
}
|
||||
|
||||
switch (addrMode) {
|
||||
case AddressMode.Abs:
|
||||
case AddressMode.AbsLong:
|
||||
case AddressMode.BlockMove:
|
||||
case AddressMode.StackAbs:
|
||||
case AddressMode.DP:
|
||||
case AddressMode.PCRel:
|
||||
case AddressMode.PCRelLong: // BRL
|
||||
case AddressMode.StackInt: // BRK/COP
|
||||
case AddressMode.StackPCRelLong: // PER
|
||||
case AddressMode.WDM:
|
||||
fmt = wdisStr + "{0}";
|
||||
break;
|
||||
case AddressMode.AbsIndexX:
|
||||
case AddressMode.AbsIndexXLong:
|
||||
case AddressMode.DPIndexX:
|
||||
fmt = wdisStr + "{0}," + mXregChar;
|
||||
break;
|
||||
case AddressMode.DPIndexY:
|
||||
case AddressMode.AbsIndexY:
|
||||
fmt = wdisStr + "{0}," + mYregChar;
|
||||
break;
|
||||
case AddressMode.AbsIndexXInd:
|
||||
case AddressMode.DPIndexXInd:
|
||||
fmt = wdisStr + "({0}," + mXregChar + ")";
|
||||
break;
|
||||
case AddressMode.AbsInd:
|
||||
case AddressMode.DPInd:
|
||||
case AddressMode.StackDPInd: // PEI
|
||||
fmt = "({0})";
|
||||
break;
|
||||
case AddressMode.AbsIndLong:
|
||||
case AddressMode.DPIndLong:
|
||||
// IIgs monitor uses "()" for AbsIndLong, E&L says "[]". Assemblers
|
||||
// seem to expect the latter.
|
||||
fmt = "[{0}]";
|
||||
break;
|
||||
case AddressMode.Acc:
|
||||
fmt = "" + mAccChar;
|
||||
break;
|
||||
case AddressMode.DPIndIndexY:
|
||||
fmt = "({0})," + mYregChar;
|
||||
break;
|
||||
case AddressMode.DPIndIndexYLong:
|
||||
fmt = "[{0}]," + mYregChar;
|
||||
break;
|
||||
case AddressMode.Imm:
|
||||
case AddressMode.ImmLongA:
|
||||
case AddressMode.ImmLongXY:
|
||||
fmt = "#{0}";
|
||||
break;
|
||||
case AddressMode.Implied:
|
||||
case AddressMode.StackPull:
|
||||
case AddressMode.StackPush:
|
||||
case AddressMode.StackRTI:
|
||||
case AddressMode.StackRTL:
|
||||
case AddressMode.StackRTS:
|
||||
fmt = "";
|
||||
break;
|
||||
case AddressMode.StackRel:
|
||||
fmt = "{0}," + mSregChar;
|
||||
break;
|
||||
case AddressMode.StackRelIndIndexY:
|
||||
fmt = "({0}," + mSregChar + ")," + mYregChar;
|
||||
break;
|
||||
|
||||
case AddressMode.Unknown:
|
||||
default:
|
||||
Debug.Assert(false);
|
||||
fmt = "???";
|
||||
break;
|
||||
}
|
||||
|
||||
return fmt;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats a pseudo-opcode.
|
||||
/// </summary>
|
||||
/// <param name="opstr">Pseudo-op string to format.</param>
|
||||
/// <returns>Formatted string.</returns>
|
||||
public string FormatPseudoOp(string opstr) {
|
||||
if (!mPseudoOpStrings.TryGetValue(opstr, out string result)) {
|
||||
if (mFormatConfig.mUpperPseudoOpcodes) {
|
||||
result = mPseudoOpStrings[opstr] = opstr.ToUpperInvariant();
|
||||
} else {
|
||||
result = mPseudoOpStrings[opstr] = opstr;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats the instruction operand.
|
||||
/// </summary>
|
||||
/// <param name="op">Opcode definition (needed for address mode).</param>
|
||||
/// <param name="contents">Label or numeric operand value.</param>
|
||||
/// <param name="wdis">Width disambiguation value.</param>
|
||||
/// <returns>Formatted string.</returns>
|
||||
public string FormatOperand(OpDef op, string contents, OpDef.WidthDisambiguation wdis) {
|
||||
Debug.Assert(((int)op.AddrMode & 0xff) == (int) op.AddrMode);
|
||||
int key = (int) op.AddrMode | ((int)wdis << 8);
|
||||
|
||||
if (!mOperandFormats.TryGetValue(key, out string format)) {
|
||||
format = mOperandFormats[key] = GenerateOperandFormat(op.AddrMode, wdis);
|
||||
}
|
||||
return string.Format(format, contents);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a format string for N hex bytes.
|
||||
/// </summary>
|
||||
/// <param name="len">Number of bytes to handle in the format.</param>
|
||||
private void GenerateByteFormat(int len) {
|
||||
Debug.Assert(len <= MAX_BYTE_DUMP);
|
||||
|
||||
StringBuilder sb = new StringBuilder(len * 6);
|
||||
for (int i = 0; i < len; i++) {
|
||||
//. e.g. "{0:x2}"
|
||||
sb.Append("{" + i + ":" + mHexFmtChar + "2}");
|
||||
}
|
||||
mByteDumpFormats[len - 1] = sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats 1-4 bytes as hex values.
|
||||
/// </summary>
|
||||
/// <param name="data">Data source.</param>
|
||||
/// <param name="offset">Start offset within data array.</param>
|
||||
/// <param name="length">Number of bytes to print. Fewer than this many may
|
||||
/// actually appear.</param>
|
||||
/// <returns>Formatted data string.</returns>
|
||||
public string FormatBytes(byte[] data, int offset, int length) {
|
||||
Debug.Assert(length > 0);
|
||||
int printLen = length < MAX_BYTE_DUMP ? length : MAX_BYTE_DUMP;
|
||||
if (string.IsNullOrEmpty(mByteDumpFormats[printLen - 1])) {
|
||||
GenerateByteFormat(printLen);
|
||||
}
|
||||
string format = mByteDumpFormats[printLen - 1];
|
||||
string result;
|
||||
|
||||
// The alternative is to allocate a temporary object[] and copy the integers
|
||||
// into it, which requires boxing. We know we're only printing 1-4 bytes, so
|
||||
// it's easier to just handle each case individually.
|
||||
switch (printLen) {
|
||||
case 1:
|
||||
result = string.Format(format, data[offset]);
|
||||
break;
|
||||
case 2:
|
||||
result = string.Format(format, data[offset], data[offset + 1]);
|
||||
break;
|
||||
case 3:
|
||||
result = string.Format(format,
|
||||
data[offset], data[offset + 1], data[offset + 2]);
|
||||
break;
|
||||
case 4:
|
||||
result = string.Format(format,
|
||||
data[offset], data[offset + 1], data[offset + 2], data[offset + 3]);
|
||||
break;
|
||||
default:
|
||||
result = "INTERNAL ERROR";
|
||||
break;
|
||||
}
|
||||
if (length > printLen) {
|
||||
result += "...";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats an end-of-line comment, prepending an end-of-line comment delimiter.
|
||||
/// </summary>
|
||||
/// <param name="comment">Comment string; may be empty.</param>
|
||||
/// <returns>Formatted string.</returns>
|
||||
public string FormatEolComment(string comment) {
|
||||
if (string.IsNullOrEmpty(comment) ||
|
||||
string.IsNullOrEmpty(mFormatConfig.mEndOfLineCommentDelimiter)) {
|
||||
return comment;
|
||||
} else {
|
||||
return mFormatConfig.mEndOfLineCommentDelimiter + comment;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats a collection of bytes as a dense hex string.
|
||||
/// </summary>
|
||||
/// <param name="data">Data source.</param>
|
||||
/// <param name="offset">Start offset within data array.</param>
|
||||
/// <param name="length">Number of bytes to print.</param>
|
||||
/// <returns>Formatted data string.</returns>
|
||||
public string FormatDenseHex(byte[] data, int offset, int length) {
|
||||
char[] hexChars = mFormatConfig.mUpperHexDigits ? sHexCharsUpper : sHexCharsLower;
|
||||
char[] text = new char[length * 2];
|
||||
for (int i = 0; i < length; i++) {
|
||||
byte val = data[offset + i];
|
||||
text[i * 2] = hexChars[val >> 4];
|
||||
text[i * 2 + 1] = hexChars[val & 0x0f];
|
||||
}
|
||||
return new string(text);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats up to 16 bytes of data into a single line hex dump, in this format:
|
||||
/// <pre>012345: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff 0123456789abcdef</pre>
|
||||
/// </summary>
|
||||
/// <param name="data">Reference to data.</param>
|
||||
/// <param name="offset">Start offset.</param>
|
||||
/// <returns>Formatted string.</returns>
|
||||
public string FormatHexDump(byte[] data, int offset) {
|
||||
FormatHexDumpCommon(data, offset);
|
||||
// this is the only allocation
|
||||
return new string(mHexDumpBuffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats up to 16 bytes of data into a single line hex dump. The output is
|
||||
/// appended to the StringBuilder.
|
||||
/// </summary>
|
||||
/// <param name="data">Reference to data.</param>
|
||||
/// <param name="offset">Start offset.</param>
|
||||
/// <param name="sb">StringBuilder that receives output.</param>
|
||||
public void FormatHexDump(byte[] data, int offset, StringBuilder sb) {
|
||||
FormatHexDumpCommon(data, offset);
|
||||
sb.Append(mHexDumpBuffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats up to 16 bytes of data into mHexDumpBuffer.
|
||||
/// </summary>
|
||||
private void FormatHexDumpCommon(byte[] data, int offset) {
|
||||
Debug.Assert(offset >= 0 && offset < data.Length);
|
||||
Debug.Assert(data.Length < (1 << 24));
|
||||
const int dataCol = 8;
|
||||
const int asciiCol = 57;
|
||||
|
||||
char[] hexChars = mFormatConfig.mUpperHexDigits ? sHexCharsUpper : sHexCharsLower;
|
||||
char[] outBuf = mHexDumpBuffer;
|
||||
|
||||
// address field
|
||||
int addr = offset;
|
||||
for (int i = 5; i >= 0; i--) {
|
||||
outBuf[i] = hexChars[addr & 0x0f];
|
||||
addr >>= 4;
|
||||
}
|
||||
|
||||
// hex digits and characters
|
||||
int length = Math.Min(16, data.Length - offset);
|
||||
int index;
|
||||
for (index = 0; index < length; index++) {
|
||||
byte val = data[offset + index];
|
||||
outBuf[dataCol + index * 3] = hexChars[val >> 4];
|
||||
outBuf[dataCol + index * 3 + 1] = hexChars[val & 0x0f];
|
||||
outBuf[asciiCol + index] = CharConv(val);
|
||||
}
|
||||
|
||||
// for partial line, clear out previous contents
|
||||
for (; index < 16; index++) {
|
||||
outBuf[dataCol + index * 3] =
|
||||
outBuf[dataCol + index * 3 + 1] =
|
||||
outBuf[asciiCol + index] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a byte into printable form according to the current hex dump
|
||||
/// character conversion mode.
|
||||
/// </summary>
|
||||
/// <param name="val">Value to convert.</param>
|
||||
/// <returns>Printable character.</returns>
|
||||
private char CharConv(byte val) {
|
||||
char ch;
|
||||
if (mFormatConfig.mHexDumpCharConvMode == FormatConfig.CharConvMode.HighLowAscii) {
|
||||
ch = (char)(val & 0x7f);
|
||||
} else {
|
||||
ch = (char)val;
|
||||
}
|
||||
if (CommonUtil.TextUtil.IsPrintableAscii(ch)) {
|
||||
return ch;
|
||||
} else if (mFormatConfig.mHexDumpAsciiOnly) {
|
||||
return '.';
|
||||
} else {
|
||||
// These values makes the hex dump ListView freak out.
|
||||
//if (ch < 0x20) {
|
||||
// return (char)(ch + '\u2400'); // Unicode "control pictures" block
|
||||
//}
|
||||
//return '\ufffd'; // Unicode "replacement character"
|
||||
|
||||
//return '\u00bf'; // INVERTED QUESTION MARK
|
||||
return '\u00b7'; // MIDDLE DOT
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
56
Asm65/Helper.cs
Normal file
56
Asm65/Helper.cs
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Asm65 {
|
||||
/// <summary>
|
||||
/// Small utility functions.
|
||||
/// </summary>
|
||||
public static class Helper {
|
||||
/// <summary>
|
||||
/// Computes the target address of an 8-bit relative branch instruction.
|
||||
/// </summary>
|
||||
/// <param name="addr">24-bit address of branch instruction opcode.</param>
|
||||
/// <param name="branchOffset">Branch operand.</param>
|
||||
/// <returns>Target address.</returns>
|
||||
public static int RelOffset8(int addr, sbyte branchOffset) {
|
||||
// Branch is relative to the start of the following instruction, so add 2.
|
||||
// Branches wrap around the current bank (in both directions), and the target
|
||||
// is in the same bank as source addr.
|
||||
Debug.Assert(addr >= 0 && addr <= 0xffffff);
|
||||
int target = (addr + 2 + branchOffset) & 0xffff;
|
||||
target |= addr & 0x7fff0000;
|
||||
return target;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes the target address of a 16-bit relative branch instruction.
|
||||
/// </summary>
|
||||
/// <param name="addr">24-bit address of branch instruction opcode.</param>
|
||||
/// <param name="branchOffset">Branch operand.</param>
|
||||
/// <returns>Target address.</returns>
|
||||
public static int RelOffset16(int addr, short branchOffset) {
|
||||
// Branch is relative to the start of the following instruction, so add 3.
|
||||
// Branches wrap around the current bank (in both directions), and the target
|
||||
// is in the same bank as source addr.
|
||||
Debug.Assert(addr >= 0 && addr <= 0xffffff);
|
||||
int target = (addr + 3 + branchOffset) & 0xffff;
|
||||
target |= addr & 0x7fff0000;
|
||||
return target;
|
||||
}
|
||||
}
|
||||
}
|
78
Asm65/Label.cs
Normal file
78
Asm65/Label.cs
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Asm65 {
|
||||
/// <summary>
|
||||
/// Utility classes for working with labels.
|
||||
///
|
||||
/// The decision of whether to treat labels as case-sensitive or case-insensitive is
|
||||
/// encapsulated here. All code should be case-preserving, but the comparison method
|
||||
/// and "normal form" are defined here.
|
||||
/// </summary>
|
||||
public class Label {
|
||||
// Arbitrary choice for SourceGen. Different assemblers have different limits.
|
||||
public const int MAX_LABEL_LEN = 32;
|
||||
|
||||
public const bool LABELS_CASE_SENSITIVE = true;
|
||||
|
||||
/// <summary>
|
||||
/// String comparer to use when comparing labels.
|
||||
///
|
||||
/// We may want case-insensitive string compares, and we want the "invariant culture"
|
||||
/// version for consistent results across users in multiple locales. (The labels are
|
||||
/// expected to be ASCII strings, so the latter isn't crucial unless we change the
|
||||
/// allowed set.)
|
||||
/// </summary>
|
||||
public static readonly StringComparer LABEL_COMPARER = LABELS_CASE_SENSITIVE ?
|
||||
StringComparer.InvariantCulture :
|
||||
StringComparer.InvariantCultureIgnoreCase;
|
||||
|
||||
/// <summary>
|
||||
/// Regex pattern for a valid label.
|
||||
///
|
||||
/// ASCII-only, starts with letter or underscore, followed by at least
|
||||
/// one alphanumeric or underscore. Some assemblers may allow single-letter
|
||||
/// labels, but I don't want to risk confusion with A/S/X/Y. So either we
|
||||
/// reserve those, or we just mandate a two-character minimum.
|
||||
/// </summary>
|
||||
private static string sValidLabelPattern = @"^[a-zA-Z_][a-zA-Z0-9_]+$";
|
||||
private static Regex sValidLabelCharRegex = new Regex(sValidLabelPattern);
|
||||
|
||||
/// <summary>
|
||||
/// Validates a label, confirming that it is correctly formed.
|
||||
/// </summary>
|
||||
/// <param name="label">Label to validate.</param>
|
||||
/// <returns>True if the label is correctly formed.</returns>
|
||||
public static bool ValidateLabel(string label) {
|
||||
if (label.Length > MAX_LABEL_LEN) {
|
||||
return false;
|
||||
}
|
||||
MatchCollection matches = sValidLabelCharRegex.Matches(label);
|
||||
return matches.Count == 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns "normal form" of label. This matches LABEL_COMPARER behavior.
|
||||
/// </summary>
|
||||
/// <param name="label">Label to transform.</param>
|
||||
/// <returns>Transformed label.</returns>
|
||||
public static string ToNormal(string label) {
|
||||
return LABELS_CASE_SENSITIVE ? label : label.ToUpperInvariant();
|
||||
}
|
||||
}
|
||||
}
|
60
Asm65/Number.cs
Normal file
60
Asm65/Number.cs
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Asm65 {
|
||||
public class Number {
|
||||
/// <summary>
|
||||
/// Parses an integer in a variety of formats (hex, decimal, binary).
|
||||
///
|
||||
/// Trim whitespace before calling here.
|
||||
/// </summary>
|
||||
/// <param name="str">String to parse.</param>
|
||||
/// <param name="val">Integer value of string.</param>
|
||||
/// <param name="intBase">What base the string was in (2, 10, or 16).</param>
|
||||
/// <returns>True if the parsing was successful.</returns>
|
||||
public static bool TryParseInt(string str, out int val, out int intBase) {
|
||||
if (string.IsNullOrEmpty(str)) {
|
||||
val = intBase = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (str[0] == '$') {
|
||||
intBase = 16;
|
||||
str = str.Substring(1); // Convert functions don't like '$'
|
||||
} else if (str.Length > 2 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
|
||||
intBase = 16;
|
||||
} else if (str[0] == '%') {
|
||||
intBase = 2;
|
||||
str = str.Substring(1); // Convert functions don't like '%'
|
||||
} else {
|
||||
intBase = 10; // try it as decimal
|
||||
}
|
||||
|
||||
try {
|
||||
val = Convert.ToInt32(str, intBase);
|
||||
//Debug.WriteLine("GOT " + val + " - " + intBase);
|
||||
} catch (Exception) {
|
||||
//Debug.WriteLine("TryParseInt failed on '" + str + "': " + ex.Message);
|
||||
val = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
3225
Asm65/OpDef.cs
Normal file
3225
Asm65/OpDef.cs
Normal file
File diff suppressed because it is too large
Load Diff
738
Asm65/OpDescription.cs
Normal file
738
Asm65/OpDescription.cs
Normal file
@ -0,0 +1,738 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Asm65 {
|
||||
/// <summary>
|
||||
/// Human-readable text describing instructions.
|
||||
///
|
||||
/// The expectation is that the long description will include information about all
|
||||
/// address modes and any differences in behavior between CPUs. So there will be one
|
||||
/// entry per instruction mnemonic, and one global table for all CPUs, rather than one
|
||||
/// entry per opcode and one instance per CpuDef.
|
||||
///
|
||||
/// There may, however, be different instances for different Cultures. Also, the 65816
|
||||
/// traditionally splits JSR/JSL and JMP/JML, so in that case there will be two entries
|
||||
/// for the same instruction.
|
||||
/// </summary>
|
||||
public class OpDescription {
|
||||
private Dictionary<string, string> mShortDescriptions;
|
||||
|
||||
private Dictionary<string, string> mLongDescriptions;
|
||||
|
||||
private Dictionary<OpDef.AddressMode, string> mAddressModeDescriptions;
|
||||
|
||||
private Dictionary<OpDef.CycleMod, string> mCycleModDescriptions;
|
||||
|
||||
private OpDescription(Dictionary<string, string> sd, Dictionary<string, string> ld,
|
||||
Dictionary<OpDef.AddressMode, string> am, Dictionary<OpDef.CycleMod, string> cm) {
|
||||
mShortDescriptions = sd;
|
||||
mLongDescriptions = ld;
|
||||
mAddressModeDescriptions = am;
|
||||
mCycleModDescriptions = cm;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an OpDescription instance for the requested region.
|
||||
/// </summary>
|
||||
/// <param name="region">TBD</param>
|
||||
public static OpDescription GetOpDescription(string region) {
|
||||
// ignoring region for now
|
||||
return new OpDescription(sShort_enUS, sLong_enUS, sAddrMode_enUS, sCycleMod_enUS);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Short description of instruction, e.g. "Load Accumulator".
|
||||
/// </summary>
|
||||
/// <param name="mnemonic">Instruction mnemonic.</param>
|
||||
/// <returns>Short description string, or empty string if not found.</returns>
|
||||
public string GetShortDescription(string mnemonic) {
|
||||
if (mShortDescriptions.TryGetValue(mnemonic, out string desc)) {
|
||||
return desc;
|
||||
} else {
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Long description of instruction. May span multiple lines, with embedded CRLF at
|
||||
/// paragraph breaks.
|
||||
/// </summary>
|
||||
/// <param name="mnemonic">Instruction mnemonic.</param>
|
||||
/// <returns>Long description string, or empty string if not found.</returns>
|
||||
public string GetLongDescription(string mnemonic) {
|
||||
if (mLongDescriptions.TryGetValue(mnemonic, out string desc)) {
|
||||
return desc;
|
||||
} else {
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Address mode short description.
|
||||
/// </summary>
|
||||
/// <param name="addrMode">Address mode to look up.</param>
|
||||
/// <returns>Description string, or an empty string for instructions
|
||||
/// with implied address modes.</returns>
|
||||
public string GetAddressModeDescription(OpDef.AddressMode addrMode) {
|
||||
if (mAddressModeDescriptions.TryGetValue(addrMode, out string desc)) {
|
||||
return desc;
|
||||
} else {
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cycle modifier description.
|
||||
/// </summary>
|
||||
/// <param name="modBit">A single-bit item from the CycleMod enum.</param>
|
||||
/// <returns>Description string, or question marks if not found.</returns>
|
||||
public string GetCycleModDescription(OpDef.CycleMod modBit) {
|
||||
if (mCycleModDescriptions.TryGetValue(modBit, out string desc)) {
|
||||
return desc;
|
||||
} else {
|
||||
return "???";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Short descriptions, USA English.
|
||||
///
|
||||
/// Text is adapted from instruction summaries in Eyes & Lichty, which are slightly
|
||||
/// shorter than those in the CPU data sheet.
|
||||
/// </summary>
|
||||
private static Dictionary<string, string> sShort_enUS = new Dictionary<string, string>() {
|
||||
{ OpName.ADC, "Add With Carry" },
|
||||
{ OpName.AND, "AND Accumulator With Memory" },
|
||||
{ OpName.ASL, "Shift Memory or Accumulator Left" },
|
||||
{ OpName.BCC, "Branch If Carry Clear" },
|
||||
{ OpName.BCS, "Branch If Carry Set" },
|
||||
{ OpName.BEQ, "Branch If Equal" },
|
||||
{ OpName.BIT, "Test Memory Against Accumulator" },
|
||||
{ OpName.BMI, "Branch If Minus" },
|
||||
{ OpName.BNE, "Branch If Not Equal" },
|
||||
{ OpName.BPL, "Branch If Plus" },
|
||||
{ OpName.BRA, "Branch Always" },
|
||||
{ OpName.BRK, "Software Break" },
|
||||
{ OpName.BRL, "Branch Always Long" },
|
||||
{ OpName.BVC, "Branch If Overflow Clear" },
|
||||
{ OpName.BVS, "Branch If Overflow Set" },
|
||||
{ OpName.CLC, "Clear Carry Flag" },
|
||||
{ OpName.CLD, "Clear Decimal Flag" },
|
||||
{ OpName.CLI, "Clear Interrupt Disable Flag" },
|
||||
{ OpName.CLV, "Clear Overflow Flag" },
|
||||
{ OpName.CMP, "Compare Accumulator With Memory" },
|
||||
{ OpName.COP, "Co-Processor" },
|
||||
{ OpName.CPX, "Compare Index X With Memory" },
|
||||
{ OpName.CPY, "Compare Index Y With Memory" },
|
||||
{ OpName.DEC, "Decrement Accumulator" },
|
||||
{ OpName.DEX, "Decrement Index X" },
|
||||
{ OpName.DEY, "Decrement Index Y" },
|
||||
{ OpName.EOR, "XOR Accumulator With Memory" },
|
||||
{ OpName.INC, "Increment Accumulator" },
|
||||
{ OpName.INX, "Increment Index X" },
|
||||
{ OpName.INY, "Increment Index Y" },
|
||||
{ OpName.JMP, "Jump" },
|
||||
{ OpName.JSL, "Jump to Subroutine Long" },
|
||||
{ OpName.JSR, "Jump to Subroutine" },
|
||||
{ OpName.LDA, "Load Accumulator from Memory" },
|
||||
{ OpName.LDX, "Load Index X from Memory" },
|
||||
{ OpName.LDY, "Load Index Y from Memory" },
|
||||
{ OpName.LSR, "Logical Shift Memory or Accumulator Right" },
|
||||
{ OpName.MVN, "Block Move Next" },
|
||||
{ OpName.MVP, "Block Move Previous" },
|
||||
{ OpName.NOP, "No Operation" },
|
||||
{ OpName.ORA, "OR Accumulator With Memory" },
|
||||
{ OpName.PEA, "Push Effective Absolute Address" },
|
||||
{ OpName.PEI, "Push Effective Indirect Address" },
|
||||
{ OpName.PER, "Push Effective Relative Indirect Address" },
|
||||
{ OpName.PHA, "Push Accumulator" },
|
||||
{ OpName.PHB, "Push Data Bank Register" },
|
||||
{ OpName.PHD, "Push Direct Page Register" },
|
||||
{ OpName.PHK, "Push Program Bank Register" },
|
||||
{ OpName.PHP, "Push Processor Status Register" },
|
||||
{ OpName.PHX, "Push Index Register X" },
|
||||
{ OpName.PHY, "Push Index Register Y" },
|
||||
{ OpName.PLA, "Pull Accumulator" },
|
||||
{ OpName.PLB, "Pull Data Bank Register" },
|
||||
{ OpName.PLD, "Pull Direct Page Register" },
|
||||
{ OpName.PLP, "Pull Processor Status Register" },
|
||||
{ OpName.PLX, "Pull Index Register X" },
|
||||
{ OpName.PLY, "Pull Index Register Y" },
|
||||
{ OpName.REP, "Reset Status Bits" },
|
||||
{ OpName.ROL, "Rotate Memory or Accumulator Left" },
|
||||
{ OpName.ROR, "Rotate Memory or Accumulator Right" },
|
||||
{ OpName.RTI, "Return from Interrupt" },
|
||||
{ OpName.RTL, "Return from Subroutine Long" },
|
||||
{ OpName.RTS, "Return from Subroutine" },
|
||||
{ OpName.SBC, "Subtract With Borrow" },
|
||||
{ OpName.SEC, "Set Carry Flag" },
|
||||
{ OpName.SED, "Set Decimal Flag" },
|
||||
{ OpName.SEI, "Set Interrupt Disable Flag" },
|
||||
{ OpName.SEP, "Set Status Bits" },
|
||||
{ OpName.STA, "Store Accumulator to Memory" },
|
||||
{ OpName.STP, "Stop Processor" },
|
||||
{ OpName.STX, "Store Index X to Memory" },
|
||||
{ OpName.STY, "Store Index Y to Memory" },
|
||||
{ OpName.STZ, "Store Zero to Memory" },
|
||||
{ OpName.TAX, "Transfer Accumulator to Index X" },
|
||||
{ OpName.TAY, "Transfer Accumulator to Index Y" },
|
||||
{ OpName.TCD, "Transfer 16-Bit Accumulator to Direct Page Register" },
|
||||
{ OpName.TCS, "Transfer Accumulator to Stack Pointer" },
|
||||
{ OpName.TDC, "Transfer Direct Page Register to 16-Bit Accumulator" },
|
||||
{ OpName.TRB, "Test and Reset Memory Bits" },
|
||||
{ OpName.TSB, "Test and Set Memory Bits" },
|
||||
{ OpName.TSC, "Transfer Stack Pointer to 16-Bit Accumulator" },
|
||||
{ OpName.TSX, "Transfer Stack Pointer to Index X" },
|
||||
{ OpName.TXA, "Transfer Index X to Accumulator" },
|
||||
{ OpName.TXS, "Transfer Index X to Stack Pointer" },
|
||||
{ OpName.TXY, "Transfer Index X to Index Y" },
|
||||
{ OpName.TYA, "Transfer Index Y to Accumulator" },
|
||||
{ OpName.TYX, "Transfer Index Y to Index X" },
|
||||
{ OpName.WAI, "Wait for Interrupt" },
|
||||
{ OpName.WDM, "Future Expansion" },
|
||||
{ OpName.XBA, "Exchange Accumulator B and A" },
|
||||
{ OpName.XCE, "Exchange Carry and Emulation Bits" },
|
||||
|
||||
// MOS 6502 undocumented ops
|
||||
{ OpName.ANC, "AND Accumulator With Value and Set Carry" },
|
||||
{ OpName.ANE, "Transfer Index X to Accumulator and AND" },
|
||||
{ OpName.ARR, "AND and Rotate Right" },
|
||||
{ OpName.ASR, "AND and Shift Right" },
|
||||
{ OpName.DCP, "Decrement and Compare" },
|
||||
{ OpName.DOP, "Double-Byte NOP" },
|
||||
{ OpName.HLT, "Halt CPU" },
|
||||
{ OpName.ISB, "Increment and Subtract" },
|
||||
{ OpName.LAE, "Load Acc, X, and Stack Pointer with Memory AND Stack Pointer" },
|
||||
{ OpName.LAX, "Load Accumulator and Index X" },
|
||||
{ OpName.LXA, "OR, AND, and Transfer to X" },
|
||||
{ OpName.RLA, "Rotate Left and AND" },
|
||||
{ OpName.RRA, "Rotate Right and Add" },
|
||||
{ OpName.SAX, "Store Accumulator AND Index X" }, // AXS
|
||||
{ OpName.SBX, "AND Acc With Index X, Subtract, and Store in X" }, // SAX
|
||||
{ OpName.SHA, "AND Acc With Index X and High Byte, and Store" }, // AXA
|
||||
{ OpName.SHS, "AND Acc with Index X, Transfer to Stack, AND High Byte" }, // TAS
|
||||
{ OpName.SHX, "AND Acc With Index X and High Byte, and Store" }, // XAS
|
||||
{ OpName.SHY, "AND Acc With Index Y and High Byte, and Store" }, // SAY
|
||||
{ OpName.SLO, "Shift Left and OR" },
|
||||
{ OpName.SRE, "Shift right and EOR" },
|
||||
{ OpName.TOP, "Triple-Byte NOP" },
|
||||
|
||||
// WDC 65C02 undocumented
|
||||
{ OpName.LDD, "Load and Discard" },
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Long descriptions, USA English.
|
||||
/// </summary>
|
||||
private static Dictionary<string, string> sLong_enUS = new Dictionary<string, string>() {
|
||||
{ OpName.ADC,
|
||||
"Adds the accumulator and a value in memory, storing the result in the " +
|
||||
"accumulator. Adds one if the carry is set."
|
||||
},
|
||||
{ OpName.AND,
|
||||
"Performs a bitwise AND of the accumulator with a value in memory, storing " +
|
||||
"the result in the accumulator."
|
||||
},
|
||||
{ OpName.ASL,
|
||||
"Shifts memory or the accumulator one bit left. The low bit is set to zero, " +
|
||||
"and the carry flag receives the high bit."
|
||||
},
|
||||
{ OpName.BCC,
|
||||
"Branches to a relative address if the processor carry flag (C) is zero. " +
|
||||
"Sometimes referred to as Branch If Less Than, or BLT."
|
||||
},
|
||||
{ OpName.BCS,
|
||||
"Branches to a relative address if the processor carry flag (C) is one. " +
|
||||
"Sometimes referred to as Branch If Greater Than or Equal, or BGE."
|
||||
},
|
||||
{ OpName.BEQ,
|
||||
"Branches to a relative address if the processor zero flag (Z) is one."
|
||||
},
|
||||
{ OpName.BIT,
|
||||
"Sets processor flags based on the result of two operations. The N and V flags " +
|
||||
"are set according to bits 7 and 6, and the Z flag is set based on an AND of " +
|
||||
"the accumulator and memory. However, when used with immediate addressing, " +
|
||||
"the N and V flags are not affected."
|
||||
},
|
||||
{ OpName.BMI,
|
||||
"Branches to a relative address if the processor negative flag (N) is one."
|
||||
},
|
||||
{ OpName.BNE,
|
||||
"Branches to a relative address if the processor zero flag (Z) is zero."
|
||||
},
|
||||
{ OpName.BPL,
|
||||
"Branches to a relative address if the processor negative flag (N) is zero."
|
||||
},
|
||||
{ OpName.BRA,
|
||||
"Branches to a relative address."
|
||||
},
|
||||
{ OpName.BRK,
|
||||
"Pushes state onto the stack, and jumps to the software break vector at " +
|
||||
"$fffe-ffff. While this is technically a single-byte instruction, the " +
|
||||
"program counter pushed onto the stack is incremented by two."
|
||||
},
|
||||
{ OpName.BRL,
|
||||
"Branches to a long relative address."
|
||||
},
|
||||
{ OpName.BVC,
|
||||
"Branches to a relative address if the processor overflow flag (V) is zero."
|
||||
},
|
||||
{ OpName.BVS,
|
||||
"Branches to a relative address if the processor overflow flag (V) is one."
|
||||
},
|
||||
{ OpName.CLC,
|
||||
"Sets the processor carry flag (C) to zero."
|
||||
},
|
||||
{ OpName.CLD,
|
||||
"Sets the processor decimal flag (D) to zero."
|
||||
},
|
||||
{ OpName.CLI,
|
||||
"Sets the processor interrupt disable flag (I) to zero."
|
||||
},
|
||||
{ OpName.CLV,
|
||||
"Sets the processor overflow flag (V) to zero."
|
||||
},
|
||||
{ OpName.CMP,
|
||||
"Subtracts the value specified by the operand from the contents of the " +
|
||||
"accumulator. Sets the carry, zero, and negative flags, but does not alter " +
|
||||
"memory or the accumulator."
|
||||
},
|
||||
{ OpName.COP,
|
||||
"Pushes state onto the stack, and jumps to the software interrupt vector at " +
|
||||
"$fff4-fff5."
|
||||
},
|
||||
{ OpName.CPX,
|
||||
"Subtracts the value specified by the operand from the contents of the " +
|
||||
"X register. Sets the carry, zero, and negative flags, but does not alter " +
|
||||
"memory or the X register."
|
||||
},
|
||||
{ OpName.CPY,
|
||||
"Subtracts the value specified by the operand from the contents of the " +
|
||||
"Y register. Sets the carry, zero, and negative flags, but does not alter " +
|
||||
"memory or the Y register."
|
||||
},
|
||||
{ OpName.DEC,
|
||||
"Decrements the contents of the location specified by the operand by one."
|
||||
},
|
||||
{ OpName.DEX,
|
||||
"Decrements the X register by one."
|
||||
},
|
||||
{ OpName.DEY,
|
||||
"Decrements the Y register by one."
|
||||
},
|
||||
{ OpName.EOR,
|
||||
"Performs a bitwise EOR of the accumulator with a value in memory, storing " +
|
||||
"the result in the accumulator."
|
||||
},
|
||||
{ OpName.INC,
|
||||
"Increments the contents of the location specified by the operand by one."
|
||||
},
|
||||
{ OpName.INX,
|
||||
"Increments the X register by one."
|
||||
},
|
||||
{ OpName.INY,
|
||||
"Increments the Y register by one."
|
||||
},
|
||||
{ OpName.JML,
|
||||
"Branches to a long absolute address."
|
||||
},
|
||||
{ OpName.JMP,
|
||||
"Branches to an absolute address."
|
||||
},
|
||||
{ OpName.JSL,
|
||||
"Branches to a long absolute address after pushing the current address onto " +
|
||||
"the stack. The value pushed is the address of the last operand byte."
|
||||
},
|
||||
{ OpName.JSR,
|
||||
"Branches to an absolute address after pushing the current address onto " +
|
||||
"the stack. The value pushed is the address of the last operand byte."
|
||||
},
|
||||
{ OpName.LDA,
|
||||
"Loads the accumulator from memory."
|
||||
},
|
||||
{ OpName.LDX,
|
||||
"Loads the X register from memory."
|
||||
},
|
||||
{ OpName.LDY,
|
||||
"Loads the Y register from memory."
|
||||
},
|
||||
{ OpName.LSR,
|
||||
"Shifts memory or the accumulator one bit right. The high bit is set to zero, " +
|
||||
"and the carry flag receives the low bit."
|
||||
},
|
||||
{ OpName.MVN,
|
||||
"Moves a block of memory, starting from a low address and incrementing. " +
|
||||
"The source and destination addresses are in the X and Y registers, " +
|
||||
"respectively. The accumulator holds the number of bytes to move minus 1, " +
|
||||
"and the source and destination banks are specified by the operands."
|
||||
},
|
||||
{ OpName.MVP,
|
||||
"Moves a block of memory, starting from a high address and decrementing. " +
|
||||
"The source and destination addresses are in the X and Y registers, " +
|
||||
"respectively. The accumulator holds the number of bytes to move minus 1, " +
|
||||
"and the source and destination banks are specified by the operands."
|
||||
},
|
||||
{ OpName.NOP,
|
||||
"No operation."
|
||||
},
|
||||
{ OpName.ORA,
|
||||
"Performs a bitwise OR of the accumulator with a value in memory, storing " +
|
||||
"the result in the accumulator."
|
||||
},
|
||||
{ OpName.PEA,
|
||||
"Pushes the 16-bit operand onto the stack. This always pushes two bytes, " +
|
||||
"regardless of the M/X processor flags."
|
||||
},
|
||||
{ OpName.PEI,
|
||||
"Pushes a 16-bit value from the direct page onto the stack."
|
||||
},
|
||||
{ OpName.PER,
|
||||
"Converts a relative offset to an absolute address, and pushes it onto the stack."
|
||||
},
|
||||
{ OpName.PHA,
|
||||
"Pushes the accumulator onto the stack."
|
||||
},
|
||||
{ OpName.PHB,
|
||||
"Pushes the data bank register onto the stack."
|
||||
},
|
||||
{ OpName.PHD,
|
||||
"Pushes the direct page register onto the stack."
|
||||
},
|
||||
{ OpName.PHK,
|
||||
"Pushes the program bank register onto the stack."
|
||||
},
|
||||
{ OpName.PHP,
|
||||
"Pushes the processor status register onto the stack."
|
||||
},
|
||||
{ OpName.PHX,
|
||||
"Pushes the X register onto the stack."
|
||||
},
|
||||
{ OpName.PHY,
|
||||
"Pushes the Y register onto the stack."
|
||||
},
|
||||
{ OpName.PLA,
|
||||
"Pulls the accumulator off of the stack."
|
||||
},
|
||||
{ OpName.PLB,
|
||||
"Pulls the data bank register off of the stack."
|
||||
},
|
||||
{ OpName.PLD,
|
||||
"Pulls the direct page register off of the stack."
|
||||
},
|
||||
{ OpName.PLP,
|
||||
"Pulls the processor status register off of the stack."
|
||||
},
|
||||
{ OpName.PLX,
|
||||
"Pulls the X register off of the stack."
|
||||
},
|
||||
{ OpName.PLY,
|
||||
"Pulls the Y register off of the stack."
|
||||
},
|
||||
{ OpName.REP,
|
||||
"Sets specific bits in the processor status register to zero."
|
||||
},
|
||||
{ OpName.ROL,
|
||||
"Rotates memory or the accumulator one bit left. The low bit is set to the " +
|
||||
"carry flag, and the carry flag receives the high bit."
|
||||
},
|
||||
{ OpName.ROR,
|
||||
"Rotates memory or the accumulator one bit right. The high bit is set to the " +
|
||||
"carry flag, and the carry flag receives the low bit."
|
||||
},
|
||||
{ OpName.RTI,
|
||||
"Pulls the status register and return address from the stack, and jumps " +
|
||||
"to the exact address pulled (note this is different from RTL/RTS)."
|
||||
},
|
||||
{ OpName.RTL,
|
||||
"Pulls the 24-bit return address from the stack, increments it, and jumps to it."
|
||||
},
|
||||
{ OpName.RTS,
|
||||
"Pulls the 16-bit return address from the stack, increments it, and jumps to it."
|
||||
},
|
||||
{ OpName.SBC,
|
||||
"Subtracts the value specified by the operand from the contents of the " +
|
||||
"accumulator, and leaves the result in the accumulator. Sets the carry, " +
|
||||
"zero, and negative flags."
|
||||
},
|
||||
{ OpName.SEC,
|
||||
"Sets the processor carry flag (C) to one."
|
||||
},
|
||||
{ OpName.SED,
|
||||
"Sets the processor decimal flag (D) to one."
|
||||
},
|
||||
{ OpName.SEI,
|
||||
"Sets the processor interrupt disable flag (I) to one."
|
||||
},
|
||||
{ OpName.SEP,
|
||||
"Sets specific bits in the processor status register to one."
|
||||
},
|
||||
{ OpName.STA,
|
||||
"Stores the value in the accumulator into memory."
|
||||
},
|
||||
{ OpName.STP,
|
||||
"Stops the processor until a CPU reset occurs."
|
||||
},
|
||||
{ OpName.STX,
|
||||
"Stores the value in the X register into memory."
|
||||
},
|
||||
{ OpName.STY,
|
||||
"Stores the value in the Y register into memory."
|
||||
},
|
||||
{ OpName.STZ,
|
||||
"Stores zero into memory."
|
||||
},
|
||||
{ OpName.TAX,
|
||||
"Transfers the contents of the accumulator to the X register."
|
||||
},
|
||||
{ OpName.TAY,
|
||||
"Transfers the contents of the accumulator to the Y register."
|
||||
},
|
||||
{ OpName.TCD,
|
||||
"Transfers the 16-bit accumulator to the direct page register."
|
||||
},
|
||||
{ OpName.TCS,
|
||||
"Transfers the 16-bit accumulator to the stack pointer register."
|
||||
},
|
||||
{ OpName.TDC,
|
||||
"Transfers the direct page register to the 16-bit accumulator."
|
||||
},
|
||||
{ OpName.TRB,
|
||||
"Logically ANDs the complement of the value in the accumulator with a value " +
|
||||
"in memory, and stores it in memory. This can be used to clear specific bits " +
|
||||
"in memory."
|
||||
},
|
||||
{ OpName.TSB,
|
||||
"Logically ORs the value in the accumulator with a value in memory, and " +
|
||||
"stores it in memory. This can be used to set specific bits in memory."
|
||||
},
|
||||
{ OpName.TSC,
|
||||
"Transfers the stack pointer register to the 16-bit accumulator."
|
||||
},
|
||||
{ OpName.TSX,
|
||||
"Transfers the stack pointer register to the X register."
|
||||
},
|
||||
{ OpName.TXA,
|
||||
"Transfers the X register to the accumulator."
|
||||
},
|
||||
{ OpName.TXS,
|
||||
"Transfers the X register to the stack pointer register."
|
||||
},
|
||||
{ OpName.TXY,
|
||||
"Transfers the X register to the Y register."
|
||||
},
|
||||
{ OpName.TYA,
|
||||
"Transfers the Y register to the accumulator."
|
||||
},
|
||||
{ OpName.TYX,
|
||||
"Transfers the Y register to the X register."
|
||||
},
|
||||
{ OpName.WAI,
|
||||
"Stalls the processor until an interrupt is received. If the interrupt " +
|
||||
"disable flag (I) is set to one, execution will continue with the next " +
|
||||
"instruction rather than calling through an interrupt vector."
|
||||
},
|
||||
{ OpName.WDM,
|
||||
"Reserved for future expansion. (Behaves as a two-byte NOP.)"
|
||||
},
|
||||
{ OpName.XBA,
|
||||
"Swaps the high and low bytes in the 16-bit accumulator. Sometimes referred " +
|
||||
"to as SWA."
|
||||
},
|
||||
{ OpName.XCE,
|
||||
"Exchanges carry and emulation bits."
|
||||
},
|
||||
|
||||
//
|
||||
// 6502 undocumented instructions.
|
||||
//
|
||||
// References:
|
||||
// http://www.ffd2.com/fridge/docs/6502-NMOS.extra.opcodes
|
||||
// http://nesdev.com/undocumented_opcodes.txt
|
||||
//
|
||||
{ OpName.ANC,
|
||||
"AND byte with accumulator. If result is negative then carry is set." +
|
||||
"\r\n\r\nAlt mnemonic: AAC"
|
||||
},
|
||||
{ OpName.ANE,
|
||||
"Transfer X register to accumulator, then AND accumulator with value." +
|
||||
"\r\n\r\nAlt mnemonic: XAA"
|
||||
},
|
||||
{ OpName.ARR,
|
||||
"AND byte with accumulator, then rotate one bit right. Equivalent to " +
|
||||
"AND + ROR."
|
||||
},
|
||||
{ OpName.ASR,
|
||||
"AND byte with accumulator, then shift right one bit. Equivalent to AND + LSR." +
|
||||
"\r\n\r\nAlt mnemonic: ALR"
|
||||
},
|
||||
{ OpName.DCP,
|
||||
"Decrement memory location, then compare result to accumulator. Equivalent " +
|
||||
"to DEC + CMP." +
|
||||
"\r\n\r\nAlt mnemonic: DCM"
|
||||
},
|
||||
{ OpName.DOP,
|
||||
"Double-byte no-operation." +
|
||||
"\r\n\r\nAlt mnemonic: NOP / SKB"
|
||||
},
|
||||
{ OpName.HLT,
|
||||
"Crash the CPU, halting execution and ignoring interrupts." +
|
||||
"\r\n\r\nAlt mnemonic: KIL / JAM"
|
||||
},
|
||||
{ OpName.ISB,
|
||||
"Increment memory, then subtract memory from accumulator with borrow. " +
|
||||
"Equivalent to INC + SBC." +
|
||||
"\r\n\r\nAlt mnemonic: ISC / INS"
|
||||
},
|
||||
{ OpName.LAE,
|
||||
"AND memory with stack pointer, then transfer result to accumulator, " +
|
||||
"X register, and stack pointer. (Note: possibly unreliable.)" +
|
||||
"\r\n\r\nAlt mnemonic: LAR / LAS"
|
||||
},
|
||||
{ OpName.LAX,
|
||||
"Load accumulator and X register from memory. Equivalent to LDA + LDX."
|
||||
},
|
||||
{ OpName.LXA,
|
||||
"ORs accumulator with a value, ANDs result with immediate value, then stores " +
|
||||
"the result in accumulator and X register." +
|
||||
"Equivalent to ORA + AND + TAX." +
|
||||
"\r\n\r\nAlt mnemonic: ATX / OAL"
|
||||
},
|
||||
{ OpName.RLA,
|
||||
"Rotate memory one bit left, then AND accumulator with memory. Equivalent " +
|
||||
"to ROL + AND."
|
||||
},
|
||||
{ OpName.RRA,
|
||||
"Rotate memory one bit right, then add accumulator to memory with carry. " +
|
||||
"Equivalent to ROR + ADC."
|
||||
},
|
||||
{ OpName.SAX,
|
||||
"AND X register with accumulator, without changing the contents of either " +
|
||||
"register, subtract an immediate value, then store result in X register." +
|
||||
"\r\n\r\nAlt mnemonic: AAX / AXS"
|
||||
},
|
||||
{ OpName.SBX,
|
||||
"AND X register with accumulator and transfer to X register, then " +
|
||||
"subtract byte from X register without borrow." +
|
||||
"\r\n\r\nAlt mnemonic: AXS / SAX"
|
||||
},
|
||||
{ OpName.SHA,
|
||||
"AND X register with accumulator, then AND result with 7 and store." +
|
||||
"\r\n\r\nAlt mnemonic: AXA"
|
||||
},
|
||||
{ OpName.SHS,
|
||||
"AND X register with accumulator, without changing the contents of either" +
|
||||
"register, and transfer to stack pointer. Then " +
|
||||
"AND stack pointer with high byte of operand + 1." +
|
||||
"\r\n\r\nAlt mnemonic: XAS / TAS"
|
||||
},
|
||||
{ OpName.SHX,
|
||||
"AND X register with the high byte of the argument + 1, and store the result." +
|
||||
"\r\n\r\nAlt mnemonic: SXA / XAS"
|
||||
},
|
||||
{ OpName.SHY,
|
||||
"AND Y register with the high byte of the argument + 1, and store the result." +
|
||||
"\r\n\r\nAlt mnemonic: SYA / SAY"
|
||||
},
|
||||
{ OpName.SLO,
|
||||
"Shift memory left one bit, then OR accumulator with memory. Equivalent to " +
|
||||
"ASL + ORA." +
|
||||
"\r\n\r\nAlt mnemonic: ASO"
|
||||
},
|
||||
{ OpName.SRE,
|
||||
"Shift memory right one bit, then EOR accumulator with memory. Equivalent to " +
|
||||
"LSR + EOR." +
|
||||
"\r\n\r\nAlt mnemonic: LSE"
|
||||
},
|
||||
{ OpName.TOP,
|
||||
"Triple-byte no-operation. This actually performs a load." +
|
||||
"\r\n\r\nAlt mnemonic: NOP / SKW"
|
||||
},
|
||||
|
||||
//
|
||||
// 65C02 undocumented instructions.
|
||||
//
|
||||
{ OpName.LDD,
|
||||
"Load and Discard. Usually a no-op, but the activity on the address bus " +
|
||||
"can affect memory-mapped I/O."
|
||||
},
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Address mode short descriptions, USA English.
|
||||
/// </summary>
|
||||
private static Dictionary<OpDef.AddressMode, string> sAddrMode_enUS =
|
||||
new Dictionary<OpDef.AddressMode, string>() {
|
||||
{ OpDef.AddressMode.Abs, "Absolute" },
|
||||
{ OpDef.AddressMode.AbsInd, "Absolute Indirect" },
|
||||
{ OpDef.AddressMode.AbsIndLong, "Absolute Indirect Long" },
|
||||
{ OpDef.AddressMode.AbsIndexX, "Absolute Indexed X" },
|
||||
{ OpDef.AddressMode.AbsIndexXInd, "Absolute Indexed X Indirect" },
|
||||
{ OpDef.AddressMode.AbsIndexXLong, "Absolute Indexed X Long" },
|
||||
{ OpDef.AddressMode.AbsIndexY, "Absolute Indexed Y" },
|
||||
{ OpDef.AddressMode.AbsLong, "Absolute Long" },
|
||||
{ OpDef.AddressMode.Acc, "Accumulator" },
|
||||
{ OpDef.AddressMode.BlockMove, "Block Move" },
|
||||
{ OpDef.AddressMode.DP, "Direct Page" },
|
||||
{ OpDef.AddressMode.DPInd, "Direct Page Indirect" },
|
||||
{ OpDef.AddressMode.DPIndIndexY, "Direct Page Indirect Indexed Y" },
|
||||
{ OpDef.AddressMode.DPIndIndexYLong, "Direct Page Indirect Indexed Y Long" },
|
||||
{ OpDef.AddressMode.DPIndLong, "Direct Page Indirect Long" },
|
||||
{ OpDef.AddressMode.DPIndexX, "Direct Page Indexed X" },
|
||||
{ OpDef.AddressMode.DPIndexXInd, "Direct Page Indexed X Indirect" },
|
||||
{ OpDef.AddressMode.DPIndexY, "Direct Page Indexed Y" },
|
||||
{ OpDef.AddressMode.Imm, "Immediate" },
|
||||
{ OpDef.AddressMode.ImmLongA, "Immediate" },
|
||||
{ OpDef.AddressMode.ImmLongXY, "Immediate" },
|
||||
{ OpDef.AddressMode.Implied, "" },
|
||||
{ OpDef.AddressMode.PCRel, "PC Relative" },
|
||||
{ OpDef.AddressMode.PCRelLong, "PC Relative Long" },
|
||||
{ OpDef.AddressMode.StackAbs, "Stack Absolute" },
|
||||
{ OpDef.AddressMode.StackDPInd, "Stack Direct Page Indirect" },
|
||||
{ OpDef.AddressMode.StackInt, "" },
|
||||
{ OpDef.AddressMode.StackPCRelLong, "Stack PC Relative Long" },
|
||||
{ OpDef.AddressMode.StackPull, "" },
|
||||
{ OpDef.AddressMode.StackPush, "" },
|
||||
{ OpDef.AddressMode.StackRTI, "" },
|
||||
{ OpDef.AddressMode.StackRTL, "" },
|
||||
{ OpDef.AddressMode.StackRTS, "" },
|
||||
{ OpDef.AddressMode.StackRel, "" },
|
||||
{ OpDef.AddressMode.StackRelIndIndexY, "Stack Relative Indirect Index Y" },
|
||||
{ OpDef.AddressMode.WDM, "" }
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Cycle modifier descriptions. These are intended to be very terse.
|
||||
/// </summary>
|
||||
private static Dictionary<OpDef.CycleMod, string> sCycleMod_enUS =
|
||||
new Dictionary<OpDef.CycleMod, string>() {
|
||||
{ OpDef.CycleMod.OneIfM0, "+1 if M=0" },
|
||||
{ OpDef.CycleMod.TwoIfM0, "+2 if M=0" },
|
||||
{ OpDef.CycleMod.OneIfX0, "+1 if X=0" },
|
||||
{ OpDef.CycleMod.OneIfDpNonzero, "+1 if DL != 0" },
|
||||
{ OpDef.CycleMod.OneIfIndexPage, "+1 if index across page" },
|
||||
{ OpDef.CycleMod.OneIfD1, "+1 if D=1 on 65C02" },
|
||||
{ OpDef.CycleMod.OneIfBranchTaken, "+1 if branch taken" },
|
||||
{ OpDef.CycleMod.OneIfBranchPage, "+1 if branch across page unless E=0" },
|
||||
{ OpDef.CycleMod.OneIfE0, "+1 if E=0" },
|
||||
{ OpDef.CycleMod.OneIf65C02, "+1 if 65C02" },
|
||||
{ OpDef.CycleMod.MinusOneIfNoPage, "-1 if 65C02 and not across page" },
|
||||
{ OpDef.CycleMod.BlockMove, "+7 per byte" },
|
||||
};
|
||||
}
|
||||
}
|
148
Asm65/OpName.cs
Normal file
148
Asm65/OpName.cs
Normal file
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
|
||||
namespace Asm65 {
|
||||
/// <summary>
|
||||
/// String constants for opcodes. These are not (and should not be) localized. They
|
||||
/// must be lower-case.
|
||||
/// </summary>
|
||||
public static class OpName {
|
||||
// NOTE: these all happen to be three characters, but I don't think we want to
|
||||
// guarantee that. On the 65816 some mnemonics are extended (e.g. LDAL for LDA with
|
||||
// a 24-bit operand), but that's assembler-specific and handled elsewhere.
|
||||
public const string Unknown = "???";
|
||||
public const string ADC = "adc";
|
||||
public const string AND = "and";
|
||||
public const string ASL = "asl";
|
||||
public const string BCC = "bcc";
|
||||
public const string BCS = "bcs";
|
||||
public const string BEQ = "beq";
|
||||
public const string BIT = "bit";
|
||||
public const string BMI = "bmi";
|
||||
public const string BNE = "bne";
|
||||
public const string BPL = "bpl";
|
||||
public const string BRA = "bra";
|
||||
public const string BRK = "brk";
|
||||
public const string BRL = "brl";
|
||||
public const string BVC = "bvc";
|
||||
public const string BVS = "bvs";
|
||||
public const string CLC = "clc";
|
||||
public const string CLD = "cld";
|
||||
public const string CLI = "cli";
|
||||
public const string CLV = "clv";
|
||||
public const string CMP = "cmp";
|
||||
public const string COP = "cop";
|
||||
public const string CPX = "cpx";
|
||||
public const string CPY = "cpy";
|
||||
public const string DEC = "dec";
|
||||
public const string DEX = "dex";
|
||||
public const string DEY = "dey";
|
||||
public const string EOR = "eor";
|
||||
public const string INC = "inc";
|
||||
public const string INX = "inx";
|
||||
public const string INY = "iny";
|
||||
public const string JML = "jml";
|
||||
public const string JMP = "jmp";
|
||||
public const string JSL = "jsl";
|
||||
public const string JSR = "jsr";
|
||||
public const string LDA = "lda";
|
||||
public const string LDX = "ldx";
|
||||
public const string LDY = "ldy";
|
||||
public const string LSR = "lsr";
|
||||
public const string MVN = "mvn";
|
||||
public const string MVP = "mvp";
|
||||
public const string NOP = "nop";
|
||||
public const string ORA = "ora";
|
||||
public const string PEA = "pea";
|
||||
public const string PEI = "pei";
|
||||
public const string PER = "per";
|
||||
public const string PHA = "pha";
|
||||
public const string PHB = "phb";
|
||||
public const string PHD = "phd";
|
||||
public const string PHK = "phk";
|
||||
public const string PHP = "php";
|
||||
public const string PHX = "phx";
|
||||
public const string PHY = "phy";
|
||||
public const string PLA = "pla";
|
||||
public const string PLB = "plb";
|
||||
public const string PLD = "pld";
|
||||
public const string PLP = "plp";
|
||||
public const string PLX = "plx";
|
||||
public const string PLY = "ply";
|
||||
public const string REP = "rep";
|
||||
public const string ROL = "rol";
|
||||
public const string ROR = "ror";
|
||||
public const string RTI = "rti";
|
||||
public const string RTL = "rtl";
|
||||
public const string RTS = "rts";
|
||||
public const string SBC = "sbc";
|
||||
public const string SEC = "sec";
|
||||
public const string SED = "sed";
|
||||
public const string SEI = "sei";
|
||||
public const string SEP = "sep";
|
||||
public const string STA = "sta";
|
||||
public const string STP = "stp";
|
||||
public const string STX = "stx";
|
||||
public const string STY = "sty";
|
||||
public const string STZ = "stz";
|
||||
public const string TAX = "tax";
|
||||
public const string TAY = "tay";
|
||||
public const string TCD = "tcd";
|
||||
public const string TCS = "tcs";
|
||||
public const string TDC = "tdc";
|
||||
public const string TRB = "trb";
|
||||
public const string TSB = "tsb";
|
||||
public const string TSC = "tsc";
|
||||
public const string TSX = "tsx";
|
||||
public const string TXA = "txa";
|
||||
public const string TXS = "txs";
|
||||
public const string TXY = "txy";
|
||||
public const string TYA = "tya";
|
||||
public const string TYX = "tyx";
|
||||
public const string WAI = "wai";
|
||||
public const string WDM = "wdm";
|
||||
public const string XBA = "xba";
|
||||
public const string XCE = "xce";
|
||||
|
||||
// Undocumented 6502 instructions.
|
||||
public const string ANC = "anc";
|
||||
public const string ANE = "ane";
|
||||
public const string ARR = "arr";
|
||||
public const string ASR = "asr";
|
||||
public const string DCP = "dcp";
|
||||
public const string DOP = "dop";
|
||||
public const string HLT = "hlt";
|
||||
public const string ISB = "isb";
|
||||
public const string LAE = "lae";
|
||||
public const string LAX = "lax";
|
||||
public const string LXA = "lxa";
|
||||
public const string RLA = "rla";
|
||||
public const string RRA = "rra";
|
||||
public const string SAX = "sax";
|
||||
public const string SBX = "sbx";
|
||||
public const string SHA = "sha";
|
||||
public const string SHS = "shs";
|
||||
public const string SHX = "shx";
|
||||
public const string SHY = "shy";
|
||||
public const string SLO = "slo";
|
||||
public const string SRE = "sre";
|
||||
public const string TOP = "top";
|
||||
|
||||
// Undocumented 65C02 instructions.
|
||||
public const string LDD = "ldd";
|
||||
}
|
||||
}
|
73
Asm65/Properties/Resources.Designer.cs
generated
Normal file
73
Asm65/Properties/Resources.Designer.cs
generated
Normal file
@ -0,0 +1,73 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace Asm65.Properties {
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
public class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
public static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Asm65.Properties.Resources", typeof(Resources).GetTypeInfo().Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
public static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Fourth time.
|
||||
/// </summary>
|
||||
public static string TEST_STRING {
|
||||
get {
|
||||
return ResourceManager.GetString("TEST_STRING", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
123
Asm65/Properties/Resources.resx
Normal file
123
Asm65/Properties/Resources.resx
Normal file
@ -0,0 +1,123 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="TEST_STRING" xml:space="preserve">
|
||||
<value>Fourth time</value>
|
||||
</data>
|
||||
</root>
|
328
Asm65/StatusFlags.cs
Normal file
328
Asm65/StatusFlags.cs
Normal file
@ -0,0 +1,328 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace Asm65 {
|
||||
/// <summary>
|
||||
/// Status flag holder. Each flag may be known to be zero, known to be one, or
|
||||
/// hold an indeterminate value (represented as a negative number).
|
||||
///
|
||||
/// For the 65802/65816, we also keep track of the E flag (emulation bit), even though
|
||||
/// that's not actually held in the P register.
|
||||
///
|
||||
/// Note this is a value type, not a reference type.
|
||||
///
|
||||
/// The default value is UNSPECIFIED for all bits.
|
||||
/// </summary>
|
||||
public struct StatusFlags {
|
||||
private TriState16 mState;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Flag bits, from processor status register definition. The 'e' (emulation)
|
||||
/// flag from the 65816 is tacked onto the end.
|
||||
///
|
||||
/// The enumerated value matches the bit number in the P register.
|
||||
/// </summary>
|
||||
public enum FlagBits {
|
||||
C = 0,
|
||||
Z = 1,
|
||||
I = 2,
|
||||
D = 3,
|
||||
B = 4, // all CPUs except 65802/65816 in native mode
|
||||
X = 4, // 65802/65816 in native mode
|
||||
M = 5, // 65802/65816 in native mode (always 1 on other CPUs)
|
||||
V = 6,
|
||||
N = 7,
|
||||
E = 8 // not actually part of P-reg; accessible only through XCE
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default value (all flags UNSPECIFIED). A newly-created array of StatusFlags will
|
||||
/// all have this value.
|
||||
/// </summary>
|
||||
public static readonly StatusFlags DefaultValue =
|
||||
new StatusFlags { mState = new TriState16(0, 0) };
|
||||
|
||||
/// <summary>
|
||||
/// All flags are INDETERMINATE.
|
||||
/// </summary>
|
||||
public static readonly StatusFlags AllIndeterminate =
|
||||
new StatusFlags() { mState = new TriState16(0x01ff, 0x01ff) };
|
||||
|
||||
public int C {
|
||||
get {
|
||||
return mState.GetBit((int)FlagBits.C);
|
||||
}
|
||||
set {
|
||||
if (value == 0) {
|
||||
mState.SetZero((int)FlagBits.C);
|
||||
} else if (value == 1) {
|
||||
mState.SetOne((int)FlagBits.C);
|
||||
} else if (value == TriState16.UNSPECIFIED) {
|
||||
mState.SetUnspecified((int)FlagBits.C);
|
||||
} else {
|
||||
mState.SetIndeterminate((int)FlagBits.C);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int Z {
|
||||
get {
|
||||
return mState.GetBit((int)FlagBits.Z);
|
||||
}
|
||||
set {
|
||||
if (value == 0) {
|
||||
mState.SetZero((int)FlagBits.Z);
|
||||
} else if (value == 1) {
|
||||
mState.SetOne((int)FlagBits.Z);
|
||||
} else if (value == TriState16.UNSPECIFIED) {
|
||||
mState.SetUnspecified((int)FlagBits.Z);
|
||||
} else {
|
||||
mState.SetIndeterminate((int)FlagBits.Z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int I {
|
||||
get {
|
||||
return mState.GetBit((int)FlagBits.I);
|
||||
}
|
||||
set {
|
||||
if (value == 0) {
|
||||
mState.SetZero((int)FlagBits.I);
|
||||
} else if (value == 1) {
|
||||
mState.SetOne((int)FlagBits.I);
|
||||
} else if (value == TriState16.UNSPECIFIED) {
|
||||
mState.SetUnspecified((int)FlagBits.I);
|
||||
} else {
|
||||
mState.SetIndeterminate((int)FlagBits.I);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int D {
|
||||
get {
|
||||
return mState.GetBit((int)FlagBits.D);
|
||||
}
|
||||
set {
|
||||
if (value == 0) {
|
||||
mState.SetZero((int)FlagBits.D);
|
||||
} else if (value == 1) {
|
||||
mState.SetOne((int)FlagBits.D);
|
||||
} else if (value == TriState16.UNSPECIFIED) {
|
||||
mState.SetUnspecified((int)FlagBits.D);
|
||||
} else {
|
||||
mState.SetIndeterminate((int)FlagBits.D);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int X {
|
||||
get {
|
||||
return mState.GetBit((int)FlagBits.X);
|
||||
}
|
||||
set {
|
||||
if (value == 0) {
|
||||
mState.SetZero((int)FlagBits.X);
|
||||
} else if (value == 1) {
|
||||
mState.SetOne((int)FlagBits.X);
|
||||
} else if (value == TriState16.UNSPECIFIED) {
|
||||
mState.SetUnspecified((int)FlagBits.X);
|
||||
} else {
|
||||
mState.SetIndeterminate((int)FlagBits.X);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int M {
|
||||
get {
|
||||
return mState.GetBit((int)FlagBits.M);
|
||||
}
|
||||
set {
|
||||
if (value == 0) {
|
||||
mState.SetZero((int)FlagBits.M);
|
||||
} else if (value == 1) {
|
||||
mState.SetOne((int)FlagBits.M);
|
||||
} else if (value == TriState16.UNSPECIFIED) {
|
||||
mState.SetUnspecified((int)FlagBits.M);
|
||||
} else {
|
||||
mState.SetIndeterminate((int)FlagBits.M);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int V {
|
||||
get {
|
||||
return mState.GetBit((int)FlagBits.V);
|
||||
}
|
||||
set {
|
||||
if (value == 0) {
|
||||
mState.SetZero((int)FlagBits.V);
|
||||
} else if (value == 1) {
|
||||
mState.SetOne((int)FlagBits.V);
|
||||
} else if (value == TriState16.UNSPECIFIED) {
|
||||
mState.SetUnspecified((int)FlagBits.V);
|
||||
} else {
|
||||
mState.SetIndeterminate((int)FlagBits.V);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int N {
|
||||
get {
|
||||
return mState.GetBit((int)FlagBits.N);
|
||||
}
|
||||
set {
|
||||
if (value == 0) {
|
||||
mState.SetZero((int)FlagBits.N);
|
||||
} else if (value == 1) {
|
||||
mState.SetOne((int)FlagBits.N);
|
||||
} else if (value == TriState16.UNSPECIFIED) {
|
||||
mState.SetUnspecified((int)FlagBits.N);
|
||||
} else {
|
||||
mState.SetIndeterminate((int)FlagBits.N);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int E {
|
||||
get {
|
||||
return mState.GetBit((int)FlagBits.E);
|
||||
}
|
||||
set {
|
||||
if (value == 0) {
|
||||
mState.SetZero((int)FlagBits.E);
|
||||
} else if (value == 1) {
|
||||
mState.SetOne((int)FlagBits.E);
|
||||
} else if (value == TriState16.UNSPECIFIED) {
|
||||
mState.SetUnspecified((int)FlagBits.E);
|
||||
} else {
|
||||
mState.SetIndeterminate((int)FlagBits.E);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int GetBit(FlagBits index) {
|
||||
return mState.GetBit((int) index);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the current processor status flags are configured for a short
|
||||
/// (8-bit) accumulator.
|
||||
/// </summary>
|
||||
public bool ShortM {
|
||||
get {
|
||||
// E==1 --> true (we're in emulation mode)
|
||||
// E==0 || E==? : native / assumed native
|
||||
// M==1 || M==? --> true (native mode, configured short or assumed short)
|
||||
// M==0 --> false (native mode, configured long)
|
||||
return (E == 1) || (M != 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the current processor status flags are configured for short
|
||||
/// (8-bit) X/Y registers.
|
||||
/// </summary>
|
||||
public bool ShortX {
|
||||
get {
|
||||
// (same logic as ShortM)
|
||||
return (E == 1) || (X != 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Access the value as a single integer. Used for serialization.
|
||||
/// </summary>
|
||||
public int AsInt {
|
||||
get {
|
||||
return mState.AsInt;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the value from an integer. Used for serialization.
|
||||
/// </summary>
|
||||
public static StatusFlags FromInt(int value) {
|
||||
if ((value & ~0x01ff01ff) != 0) {
|
||||
throw new InvalidOperationException("Bad StatusFlags value " +
|
||||
value.ToString("x8"));
|
||||
}
|
||||
StatusFlags newFlags = new StatusFlags();
|
||||
newFlags.mState.AsInt = value;
|
||||
return newFlags;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Merge a set of status flags into this one.
|
||||
/// </summary>
|
||||
public void Merge(StatusFlags other) {
|
||||
mState.Merge(other.mState);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies flags, overwriting existing values. This will set one or more flags
|
||||
/// to 0, 1, or indeterminate. Unspecified (0/0) values have no effect.
|
||||
///
|
||||
/// This is useful when merging "overrides" in.
|
||||
/// </summary>
|
||||
public void Apply(StatusFlags overrides) {
|
||||
mState.Apply(overrides.mState);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a string representation of the flags.
|
||||
/// </summary>
|
||||
/// <param name="showMXE">If set, include the 'E' flag, and show M/X.</param>
|
||||
public string ToString(bool showMXE) {
|
||||
StringBuilder sb = new StringBuilder(showMXE ? 10 : 8);
|
||||
sb.Append("-?nN"[N + 2]);
|
||||
sb.Append("-?vV"[V + 2]);
|
||||
sb.Append(showMXE ? "-?mM"[M + 2] : '-');
|
||||
sb.Append(showMXE ? "-?xX"[X + 2] : '-');
|
||||
sb.Append("-?dD"[D + 2]);
|
||||
sb.Append("-?iI"[I + 2]);
|
||||
sb.Append("-?zZ"[Z + 2]);
|
||||
sb.Append("-?cC"[C + 2]);
|
||||
if (showMXE) {
|
||||
sb.Append(' ');
|
||||
sb.Append("-?eE"[E + 2]);
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
|
||||
public static bool operator ==(StatusFlags a, StatusFlags b) {
|
||||
return a.mState == b.mState;
|
||||
}
|
||||
public static bool operator !=(StatusFlags a, StatusFlags b) {
|
||||
return !(a == b);
|
||||
}
|
||||
public override bool Equals(object obj) {
|
||||
return obj is StatusFlags && this == (StatusFlags)obj;
|
||||
}
|
||||
public override int GetHashCode() {
|
||||
return mState.GetHashCode();
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return ToString(true);
|
||||
// + " [" + mState.ToString() + "]"
|
||||
}
|
||||
}
|
||||
}
|
172
Asm65/TriState16.cs
Normal file
172
Asm65/TriState16.cs
Normal file
@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Asm65 {
|
||||
/// <summary>
|
||||
/// A value with 16 tri-state bits.
|
||||
/// </summary>
|
||||
public struct TriState16 {
|
||||
/// <summary>
|
||||
/// Two 16-bit values. The low 16 bits indicate that bit N is zero, the high
|
||||
/// 16 bits indicate that bit N is one. If neither or both are set, the value
|
||||
/// is undetermined and could be either.
|
||||
///
|
||||
/// While 0/0 and 1/1 both represent an indeterminate value, they're not equivalent.
|
||||
/// When two values are merged, a 0/0 bit has no effect on the result, while
|
||||
/// a 1/1 bit will force the merged bit to be indeterminate. We use UNSPECIFIED for
|
||||
/// 0/0 and INDETERMINATE for 1/1.
|
||||
///
|
||||
/// The default value for new instances is UNSPECIFIED for all bits.
|
||||
/// </summary>
|
||||
private ushort mZero, mOne;
|
||||
|
||||
public const int INDETERMINATE = -1;
|
||||
public const int UNSPECIFIED = -2;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor; sets initial zero/one values.
|
||||
/// </summary>
|
||||
/// <param name="zeroes">16-bit value, with bits set for each known-zero.</param>
|
||||
/// <param name="ones">16-bit value, with bits set for each known-one.</param>
|
||||
public TriState16(ushort zeroes, ushort ones) {
|
||||
mZero = zeroes;
|
||||
mOne = ones;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Access the value as a single integer. Used for serialization.
|
||||
/// </summary>
|
||||
public int AsInt {
|
||||
get {
|
||||
return (int)mZero | ((int)mOne << 16);
|
||||
}
|
||||
set {
|
||||
mZero = (ushort) value;
|
||||
mOne = (ushort) (value >> 16);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets bit N to zero.
|
||||
/// </summary>
|
||||
public void SetZero(int bit) {
|
||||
Debug.Assert(bit >= 0 && bit < 16);
|
||||
|
||||
// clear 1-flag, set 0-flag
|
||||
//mValue = (mValue & ~(1U << (bit + 16))) | (1U << bit);
|
||||
mZero |= (ushort) (1U << bit);
|
||||
mOne &= (ushort) ~(1U << bit);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets bit N to one.
|
||||
/// </summary>
|
||||
public void SetOne(int bit) {
|
||||
Debug.Assert(bit >= 0 && bit < 16);
|
||||
|
||||
// clear 0-flag, set 1-flag
|
||||
//mValue = (mValue & ~(1U << bit)) | (1U << (bit + 16));
|
||||
mZero &= (ushort)~(1U << bit);
|
||||
mOne |= (ushort)(1U << bit);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets bit N to indeterminate.
|
||||
/// </summary>
|
||||
public void SetIndeterminate(int bit) {
|
||||
Debug.Assert(bit >= 0 && bit < 16);
|
||||
|
||||
// set both flags
|
||||
mZero |= (ushort)(1U << bit);
|
||||
mOne |= (ushort)(1U << bit);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets bit N to unspecified.
|
||||
/// </summary>
|
||||
public void SetUnspecified(int bit) {
|
||||
Debug.Assert(bit >= 0 && bit < 16);
|
||||
|
||||
// clear both flags
|
||||
mZero &= (ushort)~(1U << bit);
|
||||
mOne &= (ushort)~(1U << bit);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Merges bit states.
|
||||
/// </summary>
|
||||
/// <param name="other">Value to merge in.</param>
|
||||
public void Merge(TriState16 other) {
|
||||
//mValue |= other.mValue;
|
||||
mZero |= other.mZero;
|
||||
mOne |= other.mOne;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies a set of bits to an existing set, overriding any bits that aren't set
|
||||
/// to "unspecified" in the input.
|
||||
/// </summary>
|
||||
public void Apply(TriState16 overrides) {
|
||||
ushort mask = (ushort) ~(overrides.mZero | overrides.mOne);
|
||||
mZero = (ushort)((mZero & mask) | overrides.mZero);
|
||||
mOne = (ushort)((mOne & mask) | overrides.mOne);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns 0, 1, -1, or -2 depending on whether the specified bit is 0, 1,
|
||||
/// indeterminate, or unspecified.
|
||||
/// </summary>
|
||||
public int GetBit(int bit) {
|
||||
bool zero = ((mZero >> bit) & 0x01) != 0;
|
||||
bool one = ((mOne >> bit) & 0x01) != 0;
|
||||
if (zero ^ one) {
|
||||
// Only one of the bits is set.
|
||||
if (one) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
// Both or neither are set.
|
||||
if (zero) {
|
||||
return INDETERMINATE;
|
||||
} else {
|
||||
return UNSPECIFIED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static bool operator ==(TriState16 a, TriState16 b) {
|
||||
return a.mZero == b.mZero && a.mOne == b.mOne;
|
||||
}
|
||||
public static bool operator !=(TriState16 a, TriState16 b) {
|
||||
return !(a == b);
|
||||
}
|
||||
public override bool Equals(object obj) {
|
||||
return obj is TriState16 && this == (TriState16)obj;
|
||||
}
|
||||
public override int GetHashCode() {
|
||||
return (mOne << 16) | mZero;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return mZero.ToString("x4") + "-" + mOne.ToString("x4");
|
||||
}
|
||||
}
|
||||
}
|
6
CodeLab/App.config
Normal file
6
CodeLab/App.config
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
|
||||
</startup>
|
||||
</configuration>
|
84
CodeLab/CodeLab.csproj
Normal file
84
CodeLab/CodeLab.csproj
Normal file
@ -0,0 +1,84 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{3B66ABD8-7129-4D2B-B48E-B03FEC835CE1}</ProjectGuid>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<RootNamespace>CodeLab</RootNamespace>
|
||||
<AssemblyName>CodeLab</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Deployment" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="MainWindow.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="MainWindow.Designer.cs">
|
||||
<DependentUpon>MainWindow.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<EmbeddedResource Include="MainWindow.resx">
|
||||
<DependentUpon>MainWindow.cs</DependentUpon>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
<DesignTime>True</DesignTime>
|
||||
</Compile>
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
</None>
|
||||
<Compile Include="Properties\Settings.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
142
CodeLab/Form1.resx
Normal file
142
CodeLab/Form1.resx
Normal file
@ -0,0 +1,142 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>132, 17</value>
|
||||
</metadata>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="SuperSplitButton.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG
|
||||
YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9
|
||||
0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw
|
||||
bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc
|
||||
VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9
|
||||
c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32
|
||||
Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo
|
||||
mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+
|
||||
kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D
|
||||
TgDQASA1MVpwzwAAAABJRU5ErkJggg==
|
||||
</value>
|
||||
</data>
|
||||
</root>
|
46
CodeLab/MainWindow.Designer.cs
generated
Normal file
46
CodeLab/MainWindow.Designer.cs
generated
Normal file
@ -0,0 +1,46 @@
|
||||
namespace WorkBench
|
||||
{
|
||||
partial class MainWindow
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// MainWindow
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(284, 261);
|
||||
this.Name = "MainWindow";
|
||||
this.Text = "6502bench";
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
20
CodeLab/MainWindow.cs
Normal file
20
CodeLab/MainWindow.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace WorkBench
|
||||
{
|
||||
public partial class MainWindow : Form
|
||||
{
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
120
CodeLab/MainWindow.resx
Normal file
120
CodeLab/MainWindow.resx
Normal file
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
22
CodeLab/Program.cs
Normal file
22
CodeLab/Program.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace WorkBench
|
||||
{
|
||||
static class Program
|
||||
{
|
||||
/// <summary>
|
||||
/// The main entry point for the application.
|
||||
/// </summary>
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
Application.Run(new MainWindow());
|
||||
}
|
||||
}
|
||||
}
|
36
CodeLab/Properties/AssemblyInfo.cs
Normal file
36
CodeLab/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("WorkBench")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("WorkBench")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2017")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("3b66abd8-7129-4d2b-b48e-b03fec835ce1")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
63
CodeLab/Properties/Resources.Designer.cs
generated
Normal file
63
CodeLab/Properties/Resources.Designer.cs
generated
Normal file
@ -0,0 +1,63 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace CodeLab.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CodeLab.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
117
CodeLab/Properties/Resources.resx
Normal file
117
CodeLab/Properties/Resources.resx
Normal file
@ -0,0 +1,117 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
26
CodeLab/Properties/Settings.Designer.cs
generated
Normal file
26
CodeLab/Properties/Settings.Designer.cs
generated
Normal file
@ -0,0 +1,26 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace CodeLab.Properties {
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.6.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
|
||||
public static Settings Default {
|
||||
get {
|
||||
return defaultInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
7
CodeLab/Properties/Settings.settings
Normal file
7
CodeLab/Properties/Settings.settings
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
|
||||
<Profiles>
|
||||
<Profile Name="(Default)" />
|
||||
</Profiles>
|
||||
<Settings />
|
||||
</SettingsFile>
|
1
CodeLab/README.md
Normal file
1
CodeLab/README.md
Normal file
@ -0,0 +1 @@
|
||||
This is just a place-holder. Nothing to see here.
|
109
CommonUtil/CRC32.cs
Normal file
109
CommonUtil/CRC32.cs
Normal file
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
namespace CommonUtil {
|
||||
/// <summary>
|
||||
/// Compute a standard CRC-32 (polynomial 0xedb88320, or
|
||||
/// x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1).
|
||||
/// </summary>
|
||||
public static class CRC32 {
|
||||
private static readonly uint[] sTable = ComputeTable();
|
||||
|
||||
private const uint INVERT = 0xffffffff;
|
||||
|
||||
/// <summary>
|
||||
/// Generates 256-entry CRC table.
|
||||
/// </summary>
|
||||
/// <returns>Table.</returns>
|
||||
private static uint[] ComputeTable() {
|
||||
uint[] table = new uint[256];
|
||||
|
||||
uint poly = 0xedb88320;
|
||||
for (int i = 0; i < 256; i++) {
|
||||
uint val = (uint) i;
|
||||
for (int j = 0; j < 8; j++) {
|
||||
val = (val & 1) != 0 ? poly ^ (val >> 1) : val >> 1;
|
||||
}
|
||||
table[i] = val;
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes a CRC on part of a buffer of data.
|
||||
/// </summary>
|
||||
/// <param name="crc">Previously computed CRC value. Initially zero.</param>
|
||||
/// <param name="buffer">Data to compute CRC on.</param>
|
||||
/// <param name="offset">Start offset within buffer.</param>
|
||||
/// <param name="count">Number of bytes to process.</param>
|
||||
/// <returns>New CRC value.</returns>
|
||||
public static uint OnBuffer(uint crc, byte[] buffer, int offset, int count) {
|
||||
crc = crc ^ INVERT;
|
||||
while (count-- != 0) {
|
||||
crc = sTable[(crc ^ buffer[offset]) & 0xff] ^ (crc >> 8);
|
||||
offset++;
|
||||
}
|
||||
return crc ^ INVERT;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes a CRC on a buffer of data.
|
||||
/// </summary>
|
||||
/// <param name="crc">Previously computed CRC value. Initially zero.</param>
|
||||
/// <param name="buffer">Data to compute CRC on.</param>
|
||||
/// <returns>New CRC value.</returns>
|
||||
public static uint OnWholeBuffer(uint crc, byte[] buffer) {
|
||||
return OnBuffer(crc, buffer, 0, buffer.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes a CRC on an entire file.
|
||||
/// </summary>
|
||||
/// <param name="pathName">Full path to file to open.</param>
|
||||
/// <param name="ocrc">Receives the CRC.</param>
|
||||
/// <returns>True on success, false on file error.</returns>
|
||||
public static bool OnWholeFile(string pathName, out uint ocrc) {
|
||||
try {
|
||||
using (FileStream fs = File.Open(pathName, FileMode.Open, FileAccess.Read)) {
|
||||
byte[] buffer = new byte[8192];
|
||||
uint crc = 0;
|
||||
long remain = fs.Length;
|
||||
while (remain != 0) {
|
||||
int toRead = (remain < buffer.Length) ? (int)remain : buffer.Length;
|
||||
int actual = fs.Read(buffer, 0, toRead);
|
||||
if (toRead != actual) {
|
||||
throw new IOException("Expected " + toRead + ", got " + actual);
|
||||
}
|
||||
|
||||
crc = OnBuffer(crc, buffer, 0, toRead);
|
||||
remain -= toRead;
|
||||
}
|
||||
|
||||
ocrc = crc;
|
||||
return true;
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
Debug.WriteLine("Fail: " + ioe);
|
||||
ocrc = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
22
CommonUtil/CommonUtil.csproj
Normal file
22
CommonUtil/CommonUtil.csproj
Normal file
@ -0,0 +1,22 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Properties\Resources.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Properties\Resources.resx">
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
40
CommonUtil/Container.cs
Normal file
40
CommonUtil/Container.cs
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace CommonUtil {
|
||||
public class Container {
|
||||
/// <summary>
|
||||
/// Compares two lists of strings to see if their contents are equal. The lists
|
||||
/// must contain the same strings, in the same order.
|
||||
/// </summary>
|
||||
/// <param name="l1">List #1.</param>
|
||||
/// <param name="l2">List #2.</param>
|
||||
/// <param name="comparer">String comparer (e.g. StringComparer.InvariantCulture). If
|
||||
/// null, the default string comparer is used.</param>
|
||||
/// <returns>True if the lists are equal.</returns>
|
||||
public static bool StringListEquals(IList<string> l1, IList<string>l2,
|
||||
StringComparer comparer) {
|
||||
// Quick check for reference equality.
|
||||
if (l1 == l2) {
|
||||
return true;
|
||||
}
|
||||
return Enumerable.SequenceEqual<string>(l1, l2, comparer);
|
||||
}
|
||||
}
|
||||
}
|
233
CommonUtil/DebugLog.cs
Normal file
233
CommonUtil/DebugLog.cs
Normal file
@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace CommonUtil {
|
||||
/// <summary>
|
||||
/// Debug log facility, with priority levels and time stamps.
|
||||
///
|
||||
/// The logs are held in memory. The internal storage expands as logs are added
|
||||
/// until the maximum size is reached, then switches to circular buffering. This
|
||||
/// minimizes overhead for small logs while avoiding infinite expansion.
|
||||
/// </summary>
|
||||
public class DebugLog {
|
||||
/// <summary>
|
||||
/// Log priority levels, in ascending order. "Silent" is only used as an argument
|
||||
/// when setting the minimum priority level.
|
||||
/// </summary>
|
||||
public enum Priority {
|
||||
Verbose = 0, Debug, Info, Warning, Error, Silent
|
||||
}
|
||||
|
||||
private static char[] sSingleLetter = { 'V', 'D', 'I', 'W', 'E', 'S' };
|
||||
|
||||
/// <summary>
|
||||
/// Holds a single log entry.
|
||||
/// </summary>
|
||||
private struct LogEntry {
|
||||
public DateTime mWhen;
|
||||
public Priority mPriority;
|
||||
public string mText;
|
||||
|
||||
public LogEntry(Priority prio, string msg) {
|
||||
mWhen = DateTime.Now;
|
||||
mPriority = prio;
|
||||
mText = msg;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Log collection.
|
||||
/// </summary>
|
||||
private List<LogEntry> mEntries = new List<LogEntry>();
|
||||
private int mTopEntry = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Date/time when the log object was created. Used for relative time display mode.
|
||||
/// </summary>
|
||||
private DateTime mStartWhen;
|
||||
|
||||
/// <summary>
|
||||
/// If set, display time stamps as relative time rather than absolute.
|
||||
/// </summary>
|
||||
private bool mShowRelTime = false;
|
||||
|
||||
/// <summary>
|
||||
/// Minimum priority level. Anything below this is ignored.
|
||||
/// </summary>
|
||||
private Priority mMinPriority = Priority.Debug;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum number of lines we'll hold in memory. This is a simple measure
|
||||
/// to keep the process from expanding without bound.
|
||||
/// </summary>
|
||||
private int mMaxLines = 100000;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor. Configures min priority to Info.
|
||||
/// </summary>
|
||||
public DebugLog() : this(Priority.Info) { }
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="prio">Minimum log priority level.</param>
|
||||
public DebugLog(Priority prio) {
|
||||
mMinPriority = prio;
|
||||
mStartWhen = DateTime.Now;
|
||||
LogI("Log started at " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss zzz"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the message priority threshold. Messages below the specified priority
|
||||
/// will be ignored.
|
||||
/// </summary>
|
||||
/// <param name="prio">Minimum priority value.</param>
|
||||
public void SetMinPriority(Priority prio) {
|
||||
mMinPriority = prio;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the "show relative time" flag. If set, the timestamp in the log is
|
||||
/// relative to when the log object was created, instead of wall-clock time.
|
||||
/// </summary>
|
||||
/// <param name="showRelTime"></param>
|
||||
public void SetShowRelTime(bool showRelTime) {
|
||||
mShowRelTime = showRelTime;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if a message logged at the specified priority would be accepted.
|
||||
/// </summary>
|
||||
/// <param name="prio"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsLoggable(Priority prio) {
|
||||
return prio >= mMinPriority;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all entries.
|
||||
/// </summary>
|
||||
public void Clear() {
|
||||
mEntries.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a message to the log buffer.
|
||||
/// </summary>
|
||||
/// <param name="prio">Log priority.</param>
|
||||
/// <param name="message">Message to log.</param>
|
||||
public void Log(Priority prio, string message) {
|
||||
if (prio < mMinPriority) {
|
||||
return;
|
||||
}
|
||||
LogEntry ent = new LogEntry(prio, message);
|
||||
if (mEntries.Count < mMaxLines) {
|
||||
// Still growing.
|
||||
mEntries.Add(ent);
|
||||
} else {
|
||||
// Circular replacement. Adding to the end then removing [0] has
|
||||
// significant performance issues.
|
||||
mEntries[mTopEntry++] = ent;
|
||||
if (mTopEntry == mMaxLines) {
|
||||
mTopEntry = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void LogV(string message) {
|
||||
Log(Priority.Verbose, message);
|
||||
}
|
||||
public void LogD(string message) {
|
||||
Log(Priority.Debug, message);
|
||||
}
|
||||
public void LogI(string message) {
|
||||
Log(Priority.Info, message);
|
||||
}
|
||||
public void LogW(string message) {
|
||||
Log(Priority.Warning, message);
|
||||
}
|
||||
public void LogE(string message) {
|
||||
Log(Priority.Error, message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dumps the contents of the log to a file.
|
||||
/// </summary>
|
||||
/// <param name="pathName">Full or partial pathname.</param>
|
||||
public void WriteToFile(string pathName) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
using (StreamWriter sw = new StreamWriter(pathName, false, Encoding.UTF8)) {
|
||||
for (int i = mTopEntry; i < mEntries.Count; i++) {
|
||||
WriteEntry(sw, mEntries[i], sb);
|
||||
}
|
||||
for (int i = 0; i < mTopEntry; i++) {
|
||||
WriteEntry(sw, mEntries[i], sb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a single entry to a file. Pass in a StringBuilder so we don't have
|
||||
/// to create a new one every time.
|
||||
/// </summary>
|
||||
private void WriteEntry(StreamWriter sw, LogEntry ent, StringBuilder sb) {
|
||||
sb.Clear();
|
||||
FormatEntry(ent, sb);
|
||||
sw.WriteLine(sb.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats an entry, appending the text to the provided StringBuilder.
|
||||
/// </summary>
|
||||
private void FormatEntry(LogEntry ent, StringBuilder sb) {
|
||||
if (mShowRelTime) {
|
||||
sb.Append((ent.mWhen - mStartWhen).ToString(@"mm\:ss\.fff"));
|
||||
} else {
|
||||
sb.Append(ent.mWhen.ToString(@"hh\:mm\:ss\.fff"));
|
||||
}
|
||||
sb.Append(' ');
|
||||
sb.Append(sSingleLetter[(int)ent.mPriority]);
|
||||
sb.Append(' ');
|
||||
sb.Append(ent.mText);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dumps the contents of the log to a string. This is intended for display in a
|
||||
/// text box, so lines are separated with CRLF.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string WriteToString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = mTopEntry; i < mEntries.Count; i++) {
|
||||
FormatEntry(mEntries[i], sb);
|
||||
sb.Append("\r\n");
|
||||
}
|
||||
for (int i = 0; i < mTopEntry; i++) {
|
||||
FormatEntry(mEntries[i], sb);
|
||||
sb.Append("\r\n");
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return "DebugLog has " + mEntries.Count + " entries";
|
||||
}
|
||||
}
|
||||
}
|
136
CommonUtil/FileLoadReport.cs
Normal file
136
CommonUtil/FileLoadReport.cs
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CommonUtil {
|
||||
/// <summary>
|
||||
/// File load item, identifying the location, severity, and details of the issue.
|
||||
/// </summary>
|
||||
public class FileLoadItem {
|
||||
public const int NO_LINE = -1;
|
||||
public const int NO_COLUMN = -1;
|
||||
|
||||
public enum Type {
|
||||
Unknown = 0,
|
||||
Notice,
|
||||
Warning,
|
||||
Error
|
||||
}
|
||||
|
||||
public int Line { get; private set; }
|
||||
public int Column { get; private set; }
|
||||
public Type MsgType { get; private set; }
|
||||
public string Message { get; private set; }
|
||||
|
||||
public FileLoadItem(int line, int col, Type msgType, string msg) {
|
||||
Line = line;
|
||||
Column = col;
|
||||
MsgType = msgType; ;
|
||||
Message = msg;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A structured collection of errors and warnings generated when reading data from a file.
|
||||
/// </summary>
|
||||
public class FileLoadReport : IEnumerable<FileLoadItem> {
|
||||
// List of items. Currently unsorted; items will appear in the order they were added.
|
||||
private List<FileLoadItem> mItems = new List<FileLoadItem>();
|
||||
|
||||
public string FileName { get; private set; }
|
||||
public bool HasWarnings { get; private set; }
|
||||
public bool HasErrors { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="fileName">Name of file being loaded. This is just for output; this
|
||||
/// class doesn't actually try to access the file.</param>
|
||||
public FileLoadReport(string fileName) {
|
||||
FileName = fileName;
|
||||
}
|
||||
|
||||
public IEnumerator<FileLoadItem> GetEnumerator() {
|
||||
return mItems.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() {
|
||||
return mItems.GetEnumerator();
|
||||
}
|
||||
|
||||
public int Count { get { return mItems.Count; } }
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new message to the report.
|
||||
/// </summary>
|
||||
/// <param name="isWarn">Is this a warning or an error?</param>
|
||||
/// <param name="msg">Human-readable message.</param>
|
||||
public void Add(FileLoadItem.Type msgType, string msg) {
|
||||
Add(FileLoadItem.NO_LINE, FileLoadItem.NO_COLUMN, msgType, msg);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new message to the report.
|
||||
/// </summary>
|
||||
/// <param name="line">Line where the issue was seen.</param>
|
||||
/// <param name="col">Column where the problem starts, or NO_COLUMN.</param>
|
||||
/// <param name="isWarn">Is this a warning or an error?</param>
|
||||
/// <param name="msg">Human-readable message.</param>
|
||||
public void Add(int line, int col, FileLoadItem.Type msgType, string msg) {
|
||||
mItems.Add(new FileLoadItem(line, col, msgType, msg));
|
||||
switch (msgType) {
|
||||
case FileLoadItem.Type.Warning:
|
||||
HasWarnings = true;
|
||||
break;
|
||||
case FileLoadItem.Type.Error:
|
||||
HasErrors = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats the entire collection into a single multi-line string.
|
||||
/// </summary>
|
||||
/// <returns>Formatted string.</returns>
|
||||
public string Format() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (mItems.Count > 0) {
|
||||
sb.AppendFormat("File {0}:\r\n", FileName);
|
||||
}
|
||||
foreach (FileLoadItem item in mItems) {
|
||||
if (item.Line != FileLoadItem.NO_LINE && item.Column != FileLoadItem.NO_COLUMN) {
|
||||
sb.AppendFormat(" Line {0}.{1}: {2}: {3}\r\n", item.Line, item.Column,
|
||||
item.MsgType.ToString().ToLower(), item.Message);
|
||||
} else if (item.Line != FileLoadItem.NO_LINE) {
|
||||
sb.AppendFormat(" Line {0}: {1}: {2}\r\n", item.Line,
|
||||
item.MsgType.ToString().ToLower(), item.Message);
|
||||
} else {
|
||||
// Capitalized form looks nicer here.
|
||||
sb.AppendFormat(" {0}: {1}\r\n", item.MsgType.ToString(), item.Message);
|
||||
}
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return "FileLoadReport: count=" + mItems.Count + " hasWarn=" +
|
||||
HasWarnings + " hasErr=" + HasErrors;
|
||||
}
|
||||
}
|
||||
}
|
141
CommonUtil/FileUtil.cs
Normal file
141
CommonUtil/FileUtil.cs
Normal file
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace CommonUtil {
|
||||
public static class FileUtil {
|
||||
/// <summary>
|
||||
/// Compares the contents of a file against a byte array.
|
||||
/// </summary>
|
||||
/// <param name="expected">Expected data values.</param>
|
||||
/// <param name="pathName">Pathname of file to inspect.</param>
|
||||
/// <param name="badOffset">Offset of first mismatch. If this is equal to expected.Length
|
||||
/// or File(pathName).Length, then the contents were equal but one source stopped
|
||||
/// early. The badFileVal parameter will be zero.</param>
|
||||
/// <param name="badFileVal">Mismatched value, from the file.</param>
|
||||
/// <returns>True if the contents match, false if not.</returns>
|
||||
public static bool CompareBinaryFile(byte[] expected, string pathName,
|
||||
out int badOffset, out byte badFileVal) {
|
||||
badOffset = -1;
|
||||
badFileVal = 0;
|
||||
|
||||
int chunkOffset = 0;
|
||||
byte[] buffer = new byte[65536];
|
||||
using (FileStream fs = File.Open(pathName, FileMode.Open, FileAccess.Read)) {
|
||||
//if (fs.Length != expected.Length) {
|
||||
// return false;
|
||||
//}
|
||||
int fileRemain = (int)fs.Length;
|
||||
|
||||
while (fileRemain != 0) {
|
||||
int toRead = Math.Min(buffer.Length, fileRemain);
|
||||
int actual = fs.Read(buffer, 0, toRead);
|
||||
if (actual != toRead) {
|
||||
// File I/O problem; unexpected.
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < toRead; i++) {
|
||||
if (chunkOffset + i >= expected.Length) {
|
||||
// File on disk was too long.
|
||||
Debug.Assert(fs.Length > expected.Length);
|
||||
badOffset = chunkOffset + i;
|
||||
return false;
|
||||
}
|
||||
if (expected[chunkOffset + i] != buffer[i]) {
|
||||
badOffset = chunkOffset + i;
|
||||
badFileVal = buffer[i];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
fileRemain -= toRead;
|
||||
chunkOffset += toRead;
|
||||
}
|
||||
|
||||
if (fs.Length != expected.Length) {
|
||||
Debug.Assert(fs.Length < expected.Length);
|
||||
badOffset = (int) fs.Length;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares two text files line-by-line. Ignores line termination characters.
|
||||
/// Assumes UTF-8 encoding.
|
||||
/// </summary>
|
||||
/// <param name="pathName1">Full path of first file.</param>
|
||||
/// <param name="pathName2">Full path of second file.</param>
|
||||
/// <param name="firstDiffLine">Line number of first differing line.</param>
|
||||
/// <param name="line1">Differing line from first file.</param>
|
||||
/// <param name="line2">Differing line from second file.</param>
|
||||
/// <returns>True if the files are equal.</returns>
|
||||
public static bool CompareTextFiles(string pathName1, string pathName2,
|
||||
out int firstDiffLine, out string line1, out string line2) {
|
||||
int line = 0;
|
||||
using (StreamReader sr1 = new StreamReader(pathName1, Encoding.UTF8)) {
|
||||
using (StreamReader sr2 = new StreamReader(pathName2, Encoding.UTF8)) {
|
||||
while (true) {
|
||||
// ReadLine strips the EOL char(s)
|
||||
string str1 = sr1.ReadLine();
|
||||
string str2 = sr2.ReadLine();
|
||||
line++;
|
||||
if (str1 != str2) {
|
||||
firstDiffLine = line;
|
||||
line1 = str1;
|
||||
line2 = str2;
|
||||
return false;
|
||||
}
|
||||
if (str1 == null) {
|
||||
Debug.Assert(str2 == null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
firstDiffLine = -1;
|
||||
line1 = line2 = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the destination file is missing or older than the source file.
|
||||
/// This can be used do decide whether it's necessary to copy srcFile over.
|
||||
/// </summary>
|
||||
/// <param name="dstFile">File of interest.</param>
|
||||
/// <param name="srcFile">File to compare dates with.</param>
|
||||
/// <returns>True if dstFile is missing or older than srcFile.</returns>
|
||||
public static bool FileMissingOrOlder(string dstFile, string srcFile) {
|
||||
FileInfo fid = new FileInfo(dstFile);
|
||||
if (!fid.Exists) {
|
||||
return true; // not there
|
||||
}
|
||||
FileInfo fis = new FileInfo(srcFile);
|
||||
if (!fis.Exists) {
|
||||
return false; // nothing to compare against
|
||||
}
|
||||
|
||||
return (fid.LastWriteTimeUtc < fis.LastWriteTimeUtc);
|
||||
}
|
||||
}
|
||||
}
|
32
CommonUtil/Misc.cs
Normal file
32
CommonUtil/Misc.cs
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace CommonUtil {
|
||||
public static class Misc {
|
||||
// Given a type, dump all namespaces found in the same assembly.
|
||||
// https://stackoverflow.com/a/1549216/294248
|
||||
public static void DumpNamespacesInAssembly(Type type) {
|
||||
Console.WriteLine("Assembly: " + type.Assembly.Location);
|
||||
Type[] typeList = type.Assembly.GetTypes();
|
||||
var namespaces = typeList.Select(t => t.Namespace).Distinct();
|
||||
foreach (string ns in namespaces) {
|
||||
Console.WriteLine(" " + ns);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
108
CommonUtil/Properties/Resources.Designer.cs
generated
Normal file
108
CommonUtil/Properties/Resources.Designer.cs
generated
Normal file
@ -0,0 +1,108 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace CommonUtil.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
public class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
public static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CommonUtil.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
public static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to File not found.
|
||||
/// </summary>
|
||||
public static string ERR_FILE_NOT_FOUND {
|
||||
get {
|
||||
return ResourceManager.GetString("ERR_FILE_NOT_FOUND", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Invalid address.
|
||||
/// </summary>
|
||||
public static string ERR_INVALID_ADDRESS {
|
||||
get {
|
||||
return ResourceManager.GetString("ERR_INVALID_ADDRESS", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Invalid numeric constant.
|
||||
/// </summary>
|
||||
public static string ERR_INVALID_NUMERIC_CONSTANT {
|
||||
get {
|
||||
return ResourceManager.GetString("ERR_INVALID_NUMERIC_CONSTANT", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Syntax error.
|
||||
/// </summary>
|
||||
public static string ERR_SYNTAX {
|
||||
get {
|
||||
return ResourceManager.GetString("ERR_SYNTAX", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to -.-.-.
|
||||
/// </summary>
|
||||
public static string NO_VERSION {
|
||||
get {
|
||||
return ResourceManager.GetString("NO_VERSION", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
135
CommonUtil/Properties/Resources.resx
Normal file
135
CommonUtil/Properties/Resources.resx
Normal file
@ -0,0 +1,135 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="ERR_FILE_NOT_FOUND" xml:space="preserve">
|
||||
<value>File not found</value>
|
||||
</data>
|
||||
<data name="ERR_INVALID_ADDRESS" xml:space="preserve">
|
||||
<value>Invalid address</value>
|
||||
</data>
|
||||
<data name="ERR_INVALID_NUMERIC_CONSTANT" xml:space="preserve">
|
||||
<value>Invalid numeric constant</value>
|
||||
</data>
|
||||
<data name="ERR_SYNTAX" xml:space="preserve">
|
||||
<value>Syntax error</value>
|
||||
</data>
|
||||
<data name="NO_VERSION" xml:space="preserve">
|
||||
<value>-.-.-</value>
|
||||
</data>
|
||||
</root>
|
426
CommonUtil/RangeSet.cs
Normal file
426
CommonUtil/RangeSet.cs
Normal file
@ -0,0 +1,426 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace CommonUtil {
|
||||
/// <summary>
|
||||
/// Compact representation of a set of integers that tend to be adjacent.
|
||||
///
|
||||
/// <para>The default enumeration is a series of integers, not a series of ranges. Use
|
||||
/// RangeListIterator to get the latter.</para>
|
||||
///
|
||||
/// <para>Most operations operate in log(N) time, where N is the number of
|
||||
/// regions.</para>
|
||||
/// </summary>
|
||||
public class RangeSet : IEnumerable<int> {
|
||||
/// <summary>
|
||||
/// List of ranges, in sorted order.
|
||||
/// </summary>
|
||||
private List<Range> mRangeList = new List<Range>();
|
||||
|
||||
/// <summary>
|
||||
/// Number of values in the set.
|
||||
/// </summary>
|
||||
public int Count { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// For unit tests: return the number of Range elements in the list.
|
||||
/// </summary>
|
||||
public int DebugRangeCount { get { return mRangeList.Count; } }
|
||||
|
||||
/// <summary>
|
||||
/// Represents a contiguous range of values.
|
||||
/// </summary>
|
||||
public struct Range {
|
||||
/// <summary>
|
||||
/// Lowest value (inclusive).
|
||||
/// </summary>
|
||||
public int Low { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Highest value (inclusive).
|
||||
/// </summary>
|
||||
public int High { get; set; }
|
||||
|
||||
public Range(int low, int high) {
|
||||
Debug.Assert(low <= high);
|
||||
Low = low;
|
||||
High = high;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the specified value falls in this range.
|
||||
/// </summary>
|
||||
public bool Contains(int val) {
|
||||
return (val >= Low && val <= High);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Iterator definition.
|
||||
/// </summary>
|
||||
private class RangeSetIterator : IEnumerator {
|
||||
/// <summary>
|
||||
/// The RangeSet we're iterating over.
|
||||
/// </summary>
|
||||
private RangeSet mSet;
|
||||
|
||||
// Index of current Range element in mSet.mRangeList.
|
||||
private int mListIndex = -1;
|
||||
|
||||
// Current range, extracted from mRangeList.
|
||||
private Range mCurrentRange;
|
||||
|
||||
// Current value in mCurrentRange.
|
||||
private int mCurrentVal;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="set">RangeSet to iterate over.</param>
|
||||
public RangeSetIterator(RangeSet set) {
|
||||
mSet = set;
|
||||
Reset();
|
||||
}
|
||||
|
||||
// IEnumerator: current element
|
||||
public object Current {
|
||||
get {
|
||||
if (mListIndex < 0) {
|
||||
// not started
|
||||
return null;
|
||||
}
|
||||
return mCurrentVal;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Puts the next range in the list in mCurrentRange.
|
||||
/// </summary>
|
||||
/// <returns>True on success, false if we reached the end of the list.</returns>
|
||||
private bool GetNextRange() {
|
||||
mListIndex++; // increments to 0 on first invocation
|
||||
if (mListIndex == mSet.mRangeList.Count) {
|
||||
// no more ranges
|
||||
return false;
|
||||
}
|
||||
|
||||
mCurrentRange = mSet.mRangeList[mListIndex];
|
||||
mCurrentVal = mCurrentRange.Low;
|
||||
return true;
|
||||
}
|
||||
|
||||
// IEnumerator: move to the next element, returning false if there isn't one
|
||||
public bool MoveNext() {
|
||||
if (mListIndex < 0) {
|
||||
// just started
|
||||
return GetNextRange();
|
||||
} else {
|
||||
// iterating within range object
|
||||
mCurrentVal++;
|
||||
if (mCurrentVal > mCurrentRange.High) {
|
||||
// finished with this one, move on to the next
|
||||
return GetNextRange();
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IEnumerator: reset state
|
||||
public void Reset() {
|
||||
mListIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// General constructor. Creates an empty set.
|
||||
/// </summary>
|
||||
public RangeSet() {
|
||||
Count = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs set from an iterator.
|
||||
/// </summary>
|
||||
/// <param name="iter">Iterator that generates a set of integers in ascending order.</param>
|
||||
public RangeSet(IEnumerator iter) : this() {
|
||||
if (!iter.MoveNext()) {
|
||||
return;
|
||||
}
|
||||
int first = (int) iter.Current;
|
||||
Count++;
|
||||
Range curRange = new Range(first, first);
|
||||
|
||||
while (iter.MoveNext()) {
|
||||
int val = (int) iter.Current;
|
||||
Count++;
|
||||
if (val == curRange.High + 1) {
|
||||
// Add to current range.
|
||||
curRange.High = val;
|
||||
} else {
|
||||
// Not contiguous, create new range.
|
||||
mRangeList.Add(curRange);
|
||||
curRange = new Range(val, val);
|
||||
}
|
||||
}
|
||||
|
||||
mRangeList.Add(curRange);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates through the range list, returning Range objects.
|
||||
/// </summary>
|
||||
public IEnumerator<Range> RangeListIterator {
|
||||
get { return mRangeList.GetEnumerator(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all values from the set.
|
||||
/// </summary>
|
||||
public void Clear() {
|
||||
mRangeList.Clear();
|
||||
Count = 0;
|
||||
}
|
||||
|
||||
// IEnumerable: get an enumerator instance that returns integer values
|
||||
public IEnumerator GetEnumerator() {
|
||||
return new RangeSetIterator(this);
|
||||
}
|
||||
|
||||
// IEnumerable<int>
|
||||
IEnumerator<int> IEnumerable<int>.GetEnumerator() {
|
||||
return (IEnumerator<int>)GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the range that contains "val", or an appropriate place in the list to
|
||||
/// insert a new range.
|
||||
/// </summary>
|
||||
/// <param name="val">Value to find.</param>
|
||||
/// <returns>The index of the matching element, or a negative value indicating
|
||||
/// the index to insert at. 2C doesn't support negative 0, so the insertion
|
||||
/// index will be incremented before negation.</returns>
|
||||
private int FindValue(int val) {
|
||||
int low = 0;
|
||||
int high = mRangeList.Count - 1;
|
||||
while (low <= high) {
|
||||
int mid = (low + high) / 2;
|
||||
Range midRange = mRangeList[mid];
|
||||
|
||||
if (midRange.Contains(val)) {
|
||||
// found it
|
||||
return mid;
|
||||
} else if (val < midRange.Low) {
|
||||
// too big, move the high end in
|
||||
high = mid - 1;
|
||||
} else if (val > midRange.High) {
|
||||
// too small, move the low end in
|
||||
low = mid + 1;
|
||||
} else {
|
||||
// WTF... list not sorted?
|
||||
throw new Exception("Bad binary search");
|
||||
}
|
||||
}
|
||||
|
||||
// Not found, insert before "low".
|
||||
return -(low + 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether val is a member of the set.
|
||||
/// </summary>
|
||||
/// <param name="val">Value to check.</param>
|
||||
/// <returns>True if the value is a member of the set.</returns>
|
||||
public bool Contains(int val) {
|
||||
return (FindValue(val) >= 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a value to the set. If the value is already present, nothing changes.
|
||||
/// </summary>
|
||||
/// <param name="val">Value to add.</param>
|
||||
public void Add(int val) {
|
||||
int listIndex = FindValue(val);
|
||||
if (listIndex >= 0) {
|
||||
// Already present in set.
|
||||
return;
|
||||
}
|
||||
Count++;
|
||||
|
||||
if (mRangeList.Count == 0) {
|
||||
// Empty list, skip the gymnastics.
|
||||
mRangeList.Add(new Range(val, val));
|
||||
return;
|
||||
}
|
||||
|
||||
// Negate and decrement to get insertion index. This value may == Count if
|
||||
// the value is higher than all current members.
|
||||
listIndex = -listIndex - 1;
|
||||
|
||||
if (listIndex > 0 && mRangeList[listIndex - 1].High == val - 1) {
|
||||
// Expand prior range. Check to see if it blends into next.
|
||||
if (listIndex < mRangeList.Count && mRangeList[listIndex].Low == val + 1) {
|
||||
// Combine ranges.
|
||||
Range prior = mRangeList[listIndex - 1];
|
||||
Range next = mRangeList[listIndex];
|
||||
Debug.Assert(prior.High + 2 == next.Low);
|
||||
prior.High = next.High;
|
||||
mRangeList[listIndex - 1] = prior;
|
||||
mRangeList.RemoveAt(listIndex);
|
||||
} else {
|
||||
// Nope, just expand the prior range.
|
||||
Range prior = mRangeList[listIndex - 1];
|
||||
Debug.Assert(prior.High == val - 1);
|
||||
prior.High = val;
|
||||
mRangeList[listIndex - 1] = prior;
|
||||
}
|
||||
} else if (listIndex < mRangeList.Count && mRangeList[listIndex].Low == val + 1) {
|
||||
// Expand next range.
|
||||
Range next = mRangeList[listIndex];
|
||||
Debug.Assert(next.Low == val + 1);
|
||||
next.Low = val;
|
||||
mRangeList[listIndex] = next;
|
||||
} else {
|
||||
// Add a new single-entry element.
|
||||
mRangeList.Insert(listIndex, new Range(val, val));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a range of contiguous values to the set.
|
||||
/// </summary>
|
||||
/// <param name="low">Lowest value (inclusive).</param>
|
||||
/// <param name="high">Highest value (inclusive).</param>
|
||||
public void AddRange(int low, int high) {
|
||||
// There's probably some very efficient way to do this. Keeping it simple for now.
|
||||
for (int i = low; i <= high; i++) {
|
||||
Add(i);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a value from the set. If the value is not present, nothing changes.
|
||||
/// </summary>
|
||||
/// <param name="val">Value to remove.</param>
|
||||
public void Remove(int val) {
|
||||
int listIndex = FindValue(val);
|
||||
if (listIndex < 0) {
|
||||
// not found
|
||||
return;
|
||||
}
|
||||
|
||||
Count--;
|
||||
|
||||
Range rng = mRangeList[listIndex];
|
||||
if (rng.Low == val && rng.High == val) {
|
||||
// Single-value range. Remove.
|
||||
mRangeList.RemoveAt(listIndex);
|
||||
} else if (rng.Low == val) {
|
||||
// We're at the low end, reduce range.
|
||||
rng.Low = val + 1;
|
||||
mRangeList[listIndex] = rng;
|
||||
} else if (rng.High == val) {
|
||||
// We're at the high end, reduce range.
|
||||
rng.High = val - 1;
|
||||
mRangeList[listIndex] = rng;
|
||||
} else {
|
||||
// We're in the middle, split the range.
|
||||
Range next = new Range(val + 1, rng.High);
|
||||
rng.High = val - 1;
|
||||
mRangeList[listIndex] = rng;
|
||||
mRangeList.Insert(listIndex + 1, next);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Internal test function.
|
||||
/// </summary>
|
||||
private static bool CheckRangeSet(RangeSet set, int expectedRanges, int[] expected) {
|
||||
if (set.DebugRangeCount != expectedRanges) {
|
||||
Debug.WriteLine("Expected " + expectedRanges + " ranges, got " +
|
||||
set.DebugRangeCount);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compare actual vs. expected. If we have more actual than expected we'll
|
||||
// throw on the array access.
|
||||
int expIndex = 0;
|
||||
foreach (int val in set) {
|
||||
if (val != expected[expIndex]) {
|
||||
Debug.WriteLine("Expected " + expected[expIndex] + ", got " + val);
|
||||
return false;
|
||||
}
|
||||
expIndex++;
|
||||
}
|
||||
|
||||
// See if we have more expected than actual.
|
||||
if (expIndex != expected.Length) {
|
||||
Debug.WriteLine("Expected " + expected.Length + " elements, found " + expIndex);
|
||||
return false;
|
||||
}
|
||||
|
||||
// The count is maintained separately, so check it.
|
||||
if (set.Count != expected.Length) {
|
||||
Debug.WriteLine("Expected Count=" + expected.Length + ", got " + set.Count);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes unit tests.
|
||||
/// </summary>
|
||||
/// <returns>True if all goes well.</returns>
|
||||
public static bool Test() {
|
||||
bool result = true;
|
||||
|
||||
RangeSet one = new RangeSet();
|
||||
one.Add(7);
|
||||
one.Add(5);
|
||||
one.Add(3);
|
||||
one.Add(9);
|
||||
one.Add(7);
|
||||
one.Add(8);
|
||||
one.Add(2);
|
||||
one.Add(4);
|
||||
result &= CheckRangeSet(one, 2, new int[] { 2, 3, 4, 5, 7, 8, 9 });
|
||||
|
||||
one.Remove(2);
|
||||
one.Remove(9);
|
||||
one.Remove(4);
|
||||
result &= CheckRangeSet(one, 3, new int[] { 3, 5, 7, 8 });
|
||||
|
||||
one.Clear();
|
||||
one.AddRange(10, 15);
|
||||
result &= CheckRangeSet(one, 1, new int[] { 10, 11, 12, 13, 14, 15 });
|
||||
|
||||
one.Add(-1);
|
||||
one.Add(0);
|
||||
one.Add(-2);
|
||||
result &= CheckRangeSet(one, 2, new int[] { -2, -1, 0, 10, 11, 12, 13, 14, 15 });
|
||||
|
||||
Debug.WriteLine("RangeSet: test complete (ok=" + result + ")");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
63
CommonUtil/RawData.cs
Normal file
63
CommonUtil/RawData.cs
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace CommonUtil {
|
||||
public class RawData {
|
||||
/// <summary>
|
||||
/// Extracts an integer from the data stream.
|
||||
/// </summary>
|
||||
/// <param name="data">Raw data stream.</param>
|
||||
/// <param name="offset">Start offset.</param>
|
||||
/// <param name="width">Word width, which may be 1-4 bytes.</param>
|
||||
/// <param name="isBigEndian">True if word is in big-endian order.</param>
|
||||
/// <returns>Value found.</returns>
|
||||
public static int GetWord(byte[] data, int offset, int width, bool isBigEndian) {
|
||||
if (width < 1 || width > 4 || offset + width > data.Length) {
|
||||
throw new ArgumentOutOfRangeException("GetWord(offset=" + offset + " width=" +
|
||||
width + "), data.Length=" + data.Length);
|
||||
}
|
||||
if (isBigEndian) {
|
||||
switch (width) {
|
||||
case 1:
|
||||
return data[offset];
|
||||
case 2:
|
||||
return (data[offset] << 8) | data[offset + 1];
|
||||
case 3:
|
||||
return (data[offset] << 16) | (data[offset + 1] << 8) | data[offset + 2];
|
||||
case 4:
|
||||
return (data[offset] << 24) | (data[offset + 1] << 16) |
|
||||
(data[offset + 2] << 8) | data[offset + 3];
|
||||
}
|
||||
} else {
|
||||
switch (width) {
|
||||
case 1:
|
||||
return data[offset];
|
||||
case 2:
|
||||
return data[offset] | (data[offset + 1] << 8);
|
||||
case 3:
|
||||
return data[offset] | (data[offset + 1] << 8) | (data[offset + 2] << 16);
|
||||
case 4:
|
||||
return data[offset] | (data[offset + 1] << 8) | (data[offset + 2] << 16) |
|
||||
data[offset + 3] << 24;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception("GetWord(): should not be here");
|
||||
}
|
||||
}
|
||||
}
|
222
CommonUtil/ShellCommand.cs
Normal file
222
CommonUtil/ShellCommand.cs
Normal file
@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace CommonUtil {
|
||||
/// <summary>
|
||||
/// Execute a shell command and return stdout/stderr.
|
||||
///
|
||||
/// Returning stdout/stderr separately loses the interleave, but it's unclear whether
|
||||
/// that gets lost anyway with output buffering and the asynchronous I/O facility.
|
||||
/// </summary>
|
||||
public class ShellCommand {
|
||||
// These were handy:
|
||||
// https://stackoverflow.com/a/32872174/294248
|
||||
// https://stackoverflow.com/a/18616369/294248
|
||||
// https://stackoverflow.com/a/7334029/294248
|
||||
// https://stackoverflow.com/a/5187715/294248
|
||||
|
||||
private const int CMD_TIMEOUT_MS = 10000; // 10 sec
|
||||
private bool USE_CMD_EXE = false;
|
||||
|
||||
/// <summary>
|
||||
/// Filename of shell command to execute.
|
||||
/// </summary>
|
||||
public string CommandFileName { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Arguments to pass to command. Individual arguments are separated by spaces.
|
||||
/// If an argument may contain spaces (e.g. it's a filename), surround it with
|
||||
/// double quotes (").
|
||||
/// </summary>
|
||||
public string Arguments { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Working directory for command. The directory will be changed for the
|
||||
/// command only.
|
||||
/// </summary>
|
||||
public string WorkDirectory { get; private set; }
|
||||
|
||||
public Dictionary<string, string> EnvVars { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The full command line, for display purposes. This is just CommandFileName + Arguments
|
||||
/// unless some funny business is going on under the hood.
|
||||
/// </summary>
|
||||
public string FullCommandLine { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Output from stdout.
|
||||
/// </summary>
|
||||
public string Stdout { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Output from stderr.
|
||||
/// </summary>
|
||||
public string Stderr { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Command exit code. Will be 0 on success.
|
||||
/// </summary>
|
||||
public int ExitCode { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Buffers for gathering stdout/stderr.
|
||||
/// </summary>
|
||||
private StringBuilder mStdout, mStderr;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="commandFileName">Filename of command to execute.</param>
|
||||
/// <param name="arguments">Command arguments, separated by spaces. Surround args with
|
||||
/// embedded spaces with double quotes. Pass empty string if no args.</param>
|
||||
/// <param name="workDir">Working directory for command. Pass an empty string if you
|
||||
/// want to use the default.</param>
|
||||
/// <param name="env">Dictionary of values to set in the shell environment.</param>
|
||||
public ShellCommand(string commandFileName, string arguments, string workDir,
|
||||
Dictionary<string, string> env) {
|
||||
Debug.Assert(commandFileName != null);
|
||||
Debug.Assert(arguments != null);
|
||||
Debug.Assert(workDir != null);
|
||||
|
||||
CommandFileName = commandFileName;
|
||||
Arguments = arguments;
|
||||
WorkDirectory = workDir;
|
||||
EnvVars = env;
|
||||
|
||||
ExitCode = -100;
|
||||
|
||||
mStdout = new StringBuilder();
|
||||
mStderr = new StringBuilder();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute the command.
|
||||
/// </summary>
|
||||
/// <returns>Process exit code. 0 on success.</returns>
|
||||
public void Execute() {
|
||||
// Works for full paths to command, but not for shell stuff like "dir".
|
||||
FileInfo fi = new FileInfo(CommandFileName);
|
||||
if (!fi.Exists) {
|
||||
Debug.WriteLine("Warning: file '" + CommandFileName + "' does not exist");
|
||||
}
|
||||
|
||||
ProcessStartInfo psi = new ProcessStartInfo();
|
||||
if (USE_CMD_EXE) {
|
||||
// Run inside cmd.exe on Windows.
|
||||
psi.FileName = "cmd.exe";
|
||||
psi.Arguments = "/C " + CommandFileName +
|
||||
(string.IsNullOrEmpty(Arguments) ? "" : " " + Arguments);
|
||||
} else {
|
||||
psi.FileName = CommandFileName;
|
||||
psi.Arguments = Arguments;
|
||||
}
|
||||
FullCommandLine = psi.FileName + " " + psi.Arguments;
|
||||
psi.CreateNoWindow = true;
|
||||
psi.RedirectStandardInput = true;
|
||||
psi.RedirectStandardOutput = true;
|
||||
psi.RedirectStandardError = true;
|
||||
psi.UseShellExecute = false; // required for stdin/stdout redirect
|
||||
if (!string.IsNullOrEmpty(WorkDirectory)) {
|
||||
psi.WorkingDirectory = WorkDirectory;
|
||||
}
|
||||
|
||||
if (EnvVars != null) {
|
||||
foreach (KeyValuePair<string, string> kvp in EnvVars) {
|
||||
Debug.WriteLine("ENV: " + kvp.Key + "=" + kvp.Value);
|
||||
psi.Environment.Add(kvp);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
using (Process process = Process.Start(psi)) {
|
||||
process.OutputDataReceived += (sendingProcess, outLine) =>
|
||||
mStdout.AppendLine(outLine.Data);
|
||||
process.ErrorDataReceived += (sendingProcess, errLine) =>
|
||||
mStderr.AppendLine(errLine.Data);
|
||||
process.BeginOutputReadLine();
|
||||
process.BeginErrorReadLine();
|
||||
|
||||
// Close stdin so interactive programs don't stall.
|
||||
process.StandardInput.Close();
|
||||
|
||||
// I'm calling with a (fairly long) timeout, just in case.
|
||||
process.WaitForExit(CMD_TIMEOUT_MS);
|
||||
if (!process.HasExited) {
|
||||
Debug.WriteLine("Process stalled, killing");
|
||||
process.Kill();
|
||||
}
|
||||
|
||||
// WaitForExit(timeout) can return before the async stdout/stderr stuff
|
||||
// has completed. Calling it without a timeout ensures correct behavior.
|
||||
process.WaitForExit();
|
||||
|
||||
// This will be zero on success. I've seen 1 when the command wasn't
|
||||
// found, and -1 when the process was killed.
|
||||
ExitCode = process.ExitCode;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
// This can happen if the command doesn't exist.
|
||||
ExitCode = -2000;
|
||||
Stdout = string.Empty;
|
||||
Stderr = "Failed to execute command: " + FullCommandLine + "\r\n" + ex.ToString();
|
||||
return;
|
||||
}
|
||||
|
||||
Stdout = mStdout.ToString();
|
||||
Stderr = mStderr.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens a tab in the system web browser for the specified URL.
|
||||
///
|
||||
/// NOTE: on Windows 10, as of 2018/09/02, this loses the anchor (the "#thing" at the
|
||||
/// end of the URL). Chasing through various stackoverflow posts, it appears the
|
||||
/// only way around this is to invoke the specific browser (which you dredge out of
|
||||
/// the Registry).
|
||||
/// </summary>
|
||||
public static void OpenUrl(string url) {
|
||||
// See https://stackoverflow.com/a/43232486/294248
|
||||
// The idea is to see if Start() will just do it, and if it doesn't then fall
|
||||
// back on something platform-specific. I don't know if this is actually
|
||||
// necessary -- I suspect Mono will do the right thing.
|
||||
try {
|
||||
Process.Start(url);
|
||||
} catch {
|
||||
// hack because of this: https://github.com/dotnet/corefx/issues/10361
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
|
||||
url = url.Replace("&", "^&");
|
||||
Process.Start(new ProcessStartInfo("cmd", $"/c start {url}") {
|
||||
CreateNoWindow = true
|
||||
});
|
||||
} else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) {
|
||||
Process.Start("xdg-open", url);
|
||||
} else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) {
|
||||
Process.Start("open", url);
|
||||
} else {
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
199
CommonUtil/TaskTimer.cs
Normal file
199
CommonUtil/TaskTimer.cs
Normal file
@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
|
||||
namespace CommonUtil {
|
||||
/// <summary>
|
||||
/// Collects timestamps from a series of events. Events may be nested, but may not overlap.
|
||||
/// A summary of task durations can be written to a log.
|
||||
/// </summary>
|
||||
public class TaskTimer {
|
||||
// TODO(maybe): create a start/end pair that works with a "using" directive to ensure
|
||||
// that a given item is always closed.
|
||||
|
||||
/// <summary>
|
||||
/// Timed task info.
|
||||
/// </summary>
|
||||
private class TimedItem {
|
||||
public string mTag;
|
||||
public int mIndentLevel;
|
||||
public DateTime mStartWhen;
|
||||
public DateTime mEndWhen;
|
||||
|
||||
public TimedItem(string tag, int indentLevel) {
|
||||
mTag = tag;
|
||||
mIndentLevel = indentLevel;
|
||||
mStartWhen = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List of items. They are ordered by when the tasks ended.
|
||||
/// </summary>
|
||||
private List<TimedItem> mItems = new List<TimedItem>();
|
||||
|
||||
/// <summary>
|
||||
/// Indentation level. Cosmetic.
|
||||
/// </summary>
|
||||
private int mIndentLevel = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Place where next record is to be inserted.
|
||||
///
|
||||
/// We keep inserting records ahead of whatever we inserted last, only advancing
|
||||
/// the insertion point when we close a record. Essentially a stack that moves
|
||||
/// forward when you pop() instead of removing the element. This lets us handle
|
||||
/// nested tasks correctly.
|
||||
/// </summary>
|
||||
private int mInsertPoint = 0;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Resets object to initial state.
|
||||
/// </summary>
|
||||
public void Clear() {
|
||||
mItems.Clear();
|
||||
mIndentLevel = mInsertPoint = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a start record for a task.
|
||||
/// </summary>
|
||||
/// <param name="tag">Task tag.</param>
|
||||
public void StartTask(string tag) {
|
||||
TimedItem ti = new TimedItem(tag, mIndentLevel);
|
||||
mItems.Insert(mInsertPoint, ti);
|
||||
mIndentLevel++;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes out a record. The tag must match the most recently started task.
|
||||
/// </summary>
|
||||
/// <param name="tag">Task tag.</param>
|
||||
public void EndTask(string tag) {
|
||||
TimedItem lastItem = mItems[mInsertPoint];
|
||||
if (lastItem.mTag != tag) {
|
||||
Debug.WriteLine("ERROR: tag mismatch: " + tag + " vs. " + lastItem.mTag);
|
||||
Debug.Assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
lastItem.mEndWhen = DateTime.Now;
|
||||
mIndentLevel--;
|
||||
mInsertPoint++;
|
||||
Debug.Assert(mIndentLevel >= 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prints the timing data into a log object.
|
||||
/// </summary>
|
||||
/// <param name="log">Output destination.</param>
|
||||
/// <param name="msg">Header message.</param>
|
||||
public void DumpTimes(string msg, DebugLog log) {
|
||||
if (mItems.Count == 0) {
|
||||
return;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(msg)) {
|
||||
log.LogI(msg);
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int lastIndent = 0;
|
||||
foreach (TimedItem ti in mItems) {
|
||||
sb.Clear();
|
||||
FormatItem(ti, ref lastIndent, sb);
|
||||
log.LogI(sb.ToString());
|
||||
}
|
||||
|
||||
//DateTime firstStart = mItems[0].mStartWhen;
|
||||
//DateTime lastEnd = mItems[mItems.Count - 1].mEndWhen;
|
||||
//log.LogI(" Total: " + (lastEnd - firstStart).TotalMilliseconds + " ms");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prints the timing data into the debug log.
|
||||
/// </summary>
|
||||
/// <param name="msg">Header message.</param>
|
||||
public void DumpTimes(string msg) {
|
||||
if (mItems.Count == 0) {
|
||||
return;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(msg)) {
|
||||
Debug.WriteLine(msg);
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int lastIndent = 0;
|
||||
foreach (TimedItem ti in mItems) {
|
||||
sb.Clear();
|
||||
FormatItem(ti, ref lastIndent, sb);
|
||||
Debug.WriteLine(sb.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prints the timing data into a string with newlines.
|
||||
/// </summary>
|
||||
/// <param name="log">Output destination.</param>
|
||||
/// <param name="msg">Header message.</param>
|
||||
public string DumpToString(string msg) {
|
||||
if (mItems.Count == 0) {
|
||||
return msg;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
#if DEBUG
|
||||
sb.Append("[NOTE: debug build -- assertions and extra checks are enabled]\r\n\r\n");
|
||||
#endif
|
||||
if (!string.IsNullOrEmpty(msg)) {
|
||||
sb.Append(msg);
|
||||
sb.Append("\r\n\r\n");
|
||||
}
|
||||
int lastIndent = 0;
|
||||
foreach (TimedItem ti in mItems) {
|
||||
FormatItem(ti, ref lastIndent, sb);
|
||||
sb.Append("\r\n");
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Formats the specified item, appending it to the StringBuilder.
|
||||
/// </summary>
|
||||
/// <param name="ti">Item to format.</param>
|
||||
/// <param name="lastIndent">Previous indentation level.</param>
|
||||
/// <param name="sb">StringBuilder to append to.</param>
|
||||
private void FormatItem(TimedItem ti, ref int lastIndent, StringBuilder sb) {
|
||||
for (int i = 0; i <= ti.mIndentLevel - 1; i++) {
|
||||
sb.Append("| ");
|
||||
}
|
||||
if (lastIndent < ti.mIndentLevel) {
|
||||
//sb.Append("/-");
|
||||
sb.Append("/ ");
|
||||
} else /*if (lastIndent == ti.mIndentLevel)*/ {
|
||||
sb.Append("| ");
|
||||
}
|
||||
sb.Append(ti.mTag);
|
||||
sb.Append(": ");
|
||||
sb.Append((ti.mEndWhen - ti.mStartWhen).TotalMilliseconds.ToString());
|
||||
sb.Append(" ms");
|
||||
|
||||
lastIndent = ti.mIndentLevel;
|
||||
}
|
||||
}
|
||||
}
|
241
CommonUtil/TextUtil.cs
Normal file
241
CommonUtil/TextUtil.cs
Normal file
@ -0,0 +1,241 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace CommonUtil {
|
||||
/// <summary>
|
||||
/// Text utility functions.
|
||||
/// </summary>
|
||||
public static class TextUtil {
|
||||
// 100 spaces, useful when padding things out.
|
||||
private const string SPACES = " " +
|
||||
" ";
|
||||
private static readonly char[] CSV_ESCAPE_CHARS = { ',', '"' };
|
||||
private const string NonPrintableAsciiPattern = @"[^\u0020-\u007e]";
|
||||
private static Regex sNonPrintableAsciiRegex = new Regex(NonPrintableAsciiPattern);
|
||||
|
||||
/// <summary>
|
||||
/// Converts a string to an ASCII-only string, replacing iso-latin characters
|
||||
/// with their ASCII equivalents. This may change the length of the string.
|
||||
///
|
||||
/// For example, "¿Dónde está Über bären?" becomes "Donde esta Uber baren?".
|
||||
/// </summary>
|
||||
/// <param name="inString"></param>
|
||||
/// <returns>Converted string.</returns>
|
||||
public static string LatinToAscii(string inString) {
|
||||
// https://stackoverflow.com/questions/140422/
|
||||
var newStringBuilder = new StringBuilder();
|
||||
newStringBuilder.Append(inString.Normalize(NormalizationForm.FormKD)
|
||||
.Where(x => x < 128)
|
||||
.ToArray());
|
||||
return newStringBuilder.ToString();
|
||||
|
||||
// Alternatively?
|
||||
// System.Text.Encoding.ASCII.GetString(
|
||||
// System.Text.Encoding.GetEncoding(1251).GetBytes(text))
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the value is valid high- or low-ASCII.
|
||||
/// </summary>
|
||||
/// <param name="val">Value to test.</param>
|
||||
/// <returns>True if val is valid ASCII.</returns>
|
||||
public static bool IsHiLoAscii(int val) {
|
||||
return (val >= 0x20 && val < 0x7f) || (val >= 0xa0 && val < 0xff);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the character is printable ASCII.
|
||||
/// </summary>
|
||||
/// <param name="ch">Character to evaluate.</param>
|
||||
/// <returns>True if the character is printable ASCII.</returns>
|
||||
public static bool IsPrintableAscii(char ch) {
|
||||
return ch >= 0x20 && ch < 0x7f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the string has nothing but printable ASCII characters in it.
|
||||
/// </summary>
|
||||
/// <param name="str">String to evaluate.</param>
|
||||
/// <returns>True if all characters are printable ASCII.</returns>
|
||||
public static bool IsPrintableAscii(string str) {
|
||||
// Linq version: return str.Any(c => c < 0x20 || c > 0x7e);
|
||||
|
||||
MatchCollection matches = sNonPrintableAsciiRegex.Matches(str);
|
||||
return matches.Count == 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts high-ASCII bytes to a string.
|
||||
/// </summary>
|
||||
/// <param name="data">Array of bytes with ASCII data.</param>
|
||||
/// <param name="offset">Start offset.</param>
|
||||
/// <param name="length">String length.</param>
|
||||
/// <returns>Converted string.</returns>
|
||||
public static string HighAsciiToString(byte[] data, int offset, int length) {
|
||||
StringBuilder sb = new StringBuilder(length);
|
||||
for (int i = offset; i < offset + length; i++) {
|
||||
sb.Append((char)(data[i] & 0x7f));
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Trims whitespace off the end of a StringBuilder.
|
||||
/// </summary>
|
||||
/// <param name="sb">StringBuilder reference.</param>
|
||||
public static void TrimEnd(StringBuilder sb) {
|
||||
const string WSPC = " \t\r\n";
|
||||
int len = sb.Length;
|
||||
while (WSPC.IndexOf(sb[len - 1]) >= 0) {
|
||||
len--;
|
||||
}
|
||||
sb.Length = len;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replaces all occurrences of a string with another string, but only if they appear
|
||||
/// outside quoted text. Useful for replacing structural bits of a JSON string without
|
||||
/// messing with the quoted items. Assumes that quoted quotes (backslash-quote) only
|
||||
/// appear inside quoted text.
|
||||
/// </summary>
|
||||
/// <param name="inStr"></param>
|
||||
/// <param name="findStr"></param>
|
||||
/// <param name="repStr"></param>
|
||||
public static string NonQuoteReplace(string inStr, string findStr, string repStr) {
|
||||
// There's probably a better way to do this...
|
||||
StringBuilder sb = new StringBuilder(inStr.Length + inStr.Length / 20);
|
||||
int cmpLen = findStr.Length;
|
||||
bool findStrQuote = findStr.Contains('\"'); // find/rep str switches to in-quote
|
||||
Debug.Assert(findStrQuote == repStr.Contains('\"'));
|
||||
|
||||
bool inQuote = false;
|
||||
for (int i = 0; i < inStr.Length; i++) {
|
||||
char ch = inStr[i];
|
||||
if (inQuote) {
|
||||
// Check to see if the double-quote is quoted. It's safe to back up
|
||||
// one because we don't start in-quote.
|
||||
if (ch == '\"' && inStr[i-1] != '\\') {
|
||||
inQuote = false;
|
||||
} else {
|
||||
// in quoted text, keep going
|
||||
}
|
||||
sb.Append(ch);
|
||||
} else {
|
||||
if (string.Compare(inStr, i, findStr, 0, cmpLen) == 0) {
|
||||
sb.Append(repStr);
|
||||
i += cmpLen - 1;
|
||||
inQuote = findStrQuote;
|
||||
} else {
|
||||
if (ch == '"') {
|
||||
// There are no quoted-quotes outside of quotes, so we don't need
|
||||
// to check for a '\'.
|
||||
inQuote = true;
|
||||
}
|
||||
sb.Append(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pads a string with trailing spaces so that the total length of the line, including
|
||||
/// previous contents, is the length specified. One trailing space will be added even
|
||||
/// if the string's length is >= toLen.
|
||||
///
|
||||
/// You must begin with an empty StringBuilder at the start of each line.
|
||||
/// </summary>
|
||||
/// <param name="sb">StringBuilder to append to.</param>
|
||||
/// <param name="str">String to add.</param>
|
||||
/// <param name="toLen">Total line width to pad to.</param>
|
||||
public static void AppendPaddedString(StringBuilder sb, string str, int toLen) {
|
||||
if (str == null) {
|
||||
str = string.Empty;
|
||||
}
|
||||
int newLen = sb.Length + str.Length;
|
||||
if (newLen >= toLen) {
|
||||
sb.Append(str);
|
||||
sb.Append(' ');
|
||||
} else {
|
||||
sb.Append(str);
|
||||
// would be nice to avoid this allocation/copy
|
||||
sb.Append(SPACES.Substring(0, toLen - newLen));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Escapes a string for CSV.
|
||||
/// </summary>
|
||||
/// <param name="str">String to process.</param>
|
||||
/// <returns>Escaped string, or an empty string if the input was null.</returns>
|
||||
public static string EscapeCSV(string str) {
|
||||
if (str == null) {
|
||||
return string.Empty;
|
||||
}
|
||||
bool needQuote = (str.IndexOfAny(CSV_ESCAPE_CHARS) >= 0);
|
||||
if (needQuote) {
|
||||
return '"' + str.Replace("\"", "\"\"") + '"';
|
||||
} else {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes an integer array into a string.
|
||||
/// </summary>
|
||||
/// <param name="values">Array to serialize.</param>
|
||||
/// <returns>Serialized data.</returns>
|
||||
public static string SerializeIntArray(int[] values) {
|
||||
StringBuilder sb = new StringBuilder(64);
|
||||
sb.Append("int[]");
|
||||
for (int i = 0; i < values.Length; i++) {
|
||||
sb.Append(',');
|
||||
sb.Append(values[i]);
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes an integer array from a string.
|
||||
/// </summary>
|
||||
/// <param name="cereal"></param>
|
||||
/// <returns></returns>
|
||||
public static int[] DeserializeIntArray(string cereal) {
|
||||
string[] splitted = cereal.Split(',');
|
||||
if (splitted.Length == 0) {
|
||||
throw new Exception("Bad serialized int[]");
|
||||
}
|
||||
if (splitted[0] != "int[]") {
|
||||
throw new Exception("Bad serialized int[], started with " + splitted[0]);
|
||||
}
|
||||
int[] arr = new int[splitted.Length - 1];
|
||||
try {
|
||||
for (int i = 1; i < splitted.Length; i++) {
|
||||
arr[i - 1] = int.Parse(splitted[i]);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new Exception("Bad serialized int[]: " + ex.Message);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
}
|
||||
}
|
511
CommonUtil/TypedRangeSet.cs
Normal file
511
CommonUtil/TypedRangeSet.cs
Normal file
@ -0,0 +1,511 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace CommonUtil {
|
||||
/// <summary>
|
||||
/// Compact representation of a set of typed integers that tend to be adjacent.
|
||||
/// We expect there to be relatively few different types of things.
|
||||
///
|
||||
/// <para>The default enumeration is a series of integers, not a series of ranges. Use
|
||||
/// RangeListIterator to get the latter.</para>
|
||||
///
|
||||
/// <para>Most operations operate in log(N) time, where N is the number of
|
||||
/// regions.</para>
|
||||
/// </summary>
|
||||
public class TypedRangeSet : IEnumerable<TypedRangeSet.Tuple> {
|
||||
/// <summary>
|
||||
/// List of ranges, in sorted order.
|
||||
/// </summary>
|
||||
private List<TypedRange> mRangeList = new List<TypedRange>();
|
||||
|
||||
/// <summary>
|
||||
/// Number of values in the set.
|
||||
/// </summary>
|
||||
public int Count { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the number of Range elements in the list.
|
||||
/// </summary>
|
||||
public int RangeCount { get { return mRangeList.Count; } }
|
||||
|
||||
/// <summary>
|
||||
/// Represents a contiguous range of values.
|
||||
/// </summary>
|
||||
public struct TypedRange {
|
||||
/// <summary>
|
||||
/// Lowest value (inclusive).
|
||||
/// </summary>
|
||||
public int Low { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Highest value (inclusive).
|
||||
/// </summary>
|
||||
public int High { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Value type in this range.
|
||||
/// </summary>
|
||||
public int Type { get; set; }
|
||||
|
||||
public TypedRange(int low, int high, int type) {
|
||||
Debug.Assert(low <= high);
|
||||
Low = low;
|
||||
High = high;
|
||||
Type = type;
|
||||
}
|
||||
|
||||
public bool Contains(int val) {
|
||||
return (val >= Low && val <= High);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Value + type pair. Returned from foreach enumerator.
|
||||
/// </summary>
|
||||
public struct Tuple {
|
||||
public int Value;
|
||||
public int Type;
|
||||
|
||||
public Tuple(int value, int type) {
|
||||
Value = value;
|
||||
Type = type;
|
||||
}
|
||||
|
||||
public static bool operator ==(Tuple a, Tuple b) {
|
||||
return a.Value == b.Value && a.Type == b.Type;
|
||||
}
|
||||
public static bool operator !=(Tuple a, Tuple b) {
|
||||
return !(a == b);
|
||||
}
|
||||
public override bool Equals(object obj) {
|
||||
return obj is Tuple && this == (Tuple)obj;
|
||||
}
|
||||
public override int GetHashCode() {
|
||||
return Value ^ Type;
|
||||
}
|
||||
public override string ToString() {
|
||||
return Value + " (" + Type + ")";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Iterator definition.
|
||||
/// </summary>
|
||||
private class TypedRangeSetIterator : IEnumerator<Tuple> {
|
||||
/// <summary>
|
||||
/// The TypedRangeSet we're iterating over.
|
||||
/// </summary>
|
||||
private TypedRangeSet mSet;
|
||||
|
||||
// Index of current Range element in mSet.mRangeList.
|
||||
private int mListIndex = -1;
|
||||
|
||||
// Current range, extracted from mRangeList.
|
||||
private TypedRange mCurrentRange;
|
||||
|
||||
// Current value in mCurrentRange.
|
||||
private int mCurrentVal;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="set">TypedRangeSet to iterate over.</param>
|
||||
public TypedRangeSetIterator(TypedRangeSet set) {
|
||||
mSet = set;
|
||||
Reset();
|
||||
}
|
||||
|
||||
// IEnumerator: current element
|
||||
public object Current {
|
||||
get {
|
||||
if (mListIndex < 0) {
|
||||
// not started
|
||||
return null;
|
||||
}
|
||||
return new Tuple(mCurrentVal, mCurrentRange.Type);
|
||||
}
|
||||
}
|
||||
|
||||
// IEnumerator<Tuple>
|
||||
Tuple IEnumerator<Tuple>.Current {
|
||||
get {
|
||||
return (Tuple)Current;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Puts the next range in the list in mCurrentRange.
|
||||
/// </summary>
|
||||
/// <returns>True on success, false if we reached the end of the list.</returns>
|
||||
private bool GetNextRange() {
|
||||
mListIndex++; // increments to 0 on first invocation
|
||||
if (mListIndex == mSet.mRangeList.Count) {
|
||||
// no more ranges
|
||||
return false;
|
||||
}
|
||||
|
||||
mCurrentRange = mSet.mRangeList[mListIndex];
|
||||
mCurrentVal = mCurrentRange.Low;
|
||||
return true;
|
||||
}
|
||||
|
||||
// IEnumerator: move to the next element, returning false if there isn't one
|
||||
public bool MoveNext() {
|
||||
if (mListIndex < 0) {
|
||||
// just started
|
||||
return GetNextRange();
|
||||
} else {
|
||||
// iterating within range object
|
||||
mCurrentVal++;
|
||||
if (mCurrentVal > mCurrentRange.High) {
|
||||
// finished with this one, move on to the next
|
||||
return GetNextRange();
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IEnumerator: reset state
|
||||
public void Reset() {
|
||||
mListIndex = -1;
|
||||
}
|
||||
|
||||
// IEnumerator<Tuple>
|
||||
public void Dispose() {
|
||||
mSet = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Constructor. Creates an empty set.
|
||||
/// </summary>
|
||||
public TypedRangeSet() {
|
||||
Count = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates through the range list, returning Range objects.
|
||||
/// </summary>
|
||||
public IEnumerator<TypedRange> RangeListIterator {
|
||||
get { return mRangeList.GetEnumerator(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all values from the set.
|
||||
/// </summary>
|
||||
public void Clear() {
|
||||
mRangeList.Clear();
|
||||
Count = 0;
|
||||
}
|
||||
|
||||
// IEnumerable: get an enumerator instance that returns integer values
|
||||
public IEnumerator GetEnumerator() {
|
||||
return new TypedRangeSetIterator(this);
|
||||
}
|
||||
|
||||
// IEnumerable<Tuple>
|
||||
IEnumerator<Tuple> IEnumerable<Tuple>.GetEnumerator() {
|
||||
return (IEnumerator<Tuple>)GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the range that contains "val", or an appropriate place in the list to
|
||||
/// insert a new range.
|
||||
/// </summary>
|
||||
/// <param name="val">Value to find.</param>
|
||||
/// <returns>The index of the matching element, or a negative value indicating
|
||||
/// the index to insert at. 2C doesn't support negative 0, so the insertion
|
||||
/// index will be incremented before negation.</returns>
|
||||
private int FindValue(int val) {
|
||||
int low = 0;
|
||||
int high = mRangeList.Count - 1;
|
||||
while (low <= high) {
|
||||
int mid = (low + high) / 2;
|
||||
TypedRange midRange = mRangeList[mid];
|
||||
|
||||
if (midRange.Contains(val)) {
|
||||
// found it
|
||||
return mid;
|
||||
} else if (val < midRange.Low) {
|
||||
// too big, move the high end in
|
||||
high = mid - 1;
|
||||
} else if (val > midRange.High) {
|
||||
// too small, move the low end in
|
||||
low = mid + 1;
|
||||
} else {
|
||||
// WTF... list not sorted?
|
||||
throw new Exception("Bad binary search");
|
||||
}
|
||||
}
|
||||
|
||||
// Not found, insert before "low".
|
||||
return -(low + 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether val is a member of the set.
|
||||
/// </summary>
|
||||
/// <param name="val">Value to check.</param>
|
||||
/// <returns>True if the value is a member of the set.</returns>
|
||||
public bool Contains(int val) {
|
||||
return (FindValue(val) >= 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of the specified value.
|
||||
/// </summary>
|
||||
/// <param name="val">Value to query.</param>
|
||||
/// <param name="type">Receives the type, or -1 if the value is not in the set.</param>
|
||||
/// <returns>True if the value is in the set.</returns>
|
||||
public bool GetType(int val, out int type) {
|
||||
int listIndex = FindValue(val);
|
||||
if (listIndex >= 0) {
|
||||
type = mRangeList[listIndex].Type;
|
||||
return true;
|
||||
} else {
|
||||
type = -1;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds or changes a value to the set. If the value is already present and has
|
||||
/// a matching type, nothing changes.
|
||||
/// </summary>
|
||||
/// <param name="val">Value to add.</param>
|
||||
/// <param name="type">Value's type.</param>
|
||||
public void Add(int val, int type) {
|
||||
int listIndex = FindValue(val);
|
||||
if (listIndex >= 0) {
|
||||
// Value is present in set, check type.
|
||||
if (mRangeList[listIndex].Type == type) {
|
||||
// It's a match, do nothing.
|
||||
return;
|
||||
}
|
||||
|
||||
// Wrong type. Remove previous entry, then fall through to add new.
|
||||
Remove(val);
|
||||
listIndex = FindValue(val); // get insertion point
|
||||
}
|
||||
Count++;
|
||||
|
||||
if (mRangeList.Count == 0) {
|
||||
// Empty list, skip the gymnastics.
|
||||
mRangeList.Add(new TypedRange(val, val, type));
|
||||
return;
|
||||
}
|
||||
|
||||
// Negate and decrement to get insertion index. This value may == Count if
|
||||
// the value is higher than all current members.
|
||||
listIndex = -listIndex - 1;
|
||||
|
||||
if (listIndex > 0 && mRangeList[listIndex - 1].High == val - 1 &&
|
||||
mRangeList[listIndex - 1].Type == type) {
|
||||
// Expand prior range. Check to see if it blends into next as well.
|
||||
if (listIndex < mRangeList.Count && mRangeList[listIndex].Low == val + 1 &&
|
||||
mRangeList[listIndex].Type == type) {
|
||||
// Combine ranges.
|
||||
TypedRange prior = mRangeList[listIndex - 1];
|
||||
TypedRange next = mRangeList[listIndex];
|
||||
Debug.Assert(prior.High + 2 == next.Low);
|
||||
prior.High = next.High;
|
||||
mRangeList[listIndex - 1] = prior;
|
||||
mRangeList.RemoveAt(listIndex);
|
||||
} else {
|
||||
// Nope, just expand the prior range.
|
||||
TypedRange prior = mRangeList[listIndex - 1];
|
||||
Debug.Assert(prior.High == val - 1);
|
||||
prior.High = val;
|
||||
mRangeList[listIndex - 1] = prior;
|
||||
}
|
||||
} else if (listIndex < mRangeList.Count && mRangeList[listIndex].Low == val + 1 &&
|
||||
mRangeList[listIndex].Type == type) {
|
||||
// Expand next range.
|
||||
TypedRange next = mRangeList[listIndex];
|
||||
Debug.Assert(next.Low == val + 1);
|
||||
next.Low = val;
|
||||
mRangeList[listIndex] = next;
|
||||
} else {
|
||||
// Nothing adjacent, add a new single-entry element.
|
||||
mRangeList.Insert(listIndex, new TypedRange(val, val, type));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a range of contiguous values to the set.
|
||||
/// </summary>
|
||||
/// <param name="low">Lowest value (inclusive).</param>
|
||||
/// <param name="high">Highest value (inclusive).</param>
|
||||
/// <param name="high">Value type.</param>
|
||||
public void AddRange(int low, int high, int type) {
|
||||
// There's probably some very efficient way to do this. Keeping it simple for now.
|
||||
for (int i = low; i <= high; i++) {
|
||||
Add(i, type);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a value from the set. If the value is not present, nothing changes.
|
||||
/// </summary>
|
||||
/// <param name="val">Value to remove.</param>
|
||||
public void Remove(int val) {
|
||||
int listIndex = FindValue(val);
|
||||
if (listIndex < 0) {
|
||||
// not found
|
||||
return;
|
||||
}
|
||||
|
||||
Count--;
|
||||
|
||||
TypedRange rng = mRangeList[listIndex];
|
||||
if (rng.Low == val && rng.High == val) {
|
||||
// Single-value range. Remove.
|
||||
mRangeList.RemoveAt(listIndex);
|
||||
} else if (rng.Low == val) {
|
||||
// We're at the low end, reduce range.
|
||||
rng.Low = val + 1;
|
||||
mRangeList[listIndex] = rng;
|
||||
} else if (rng.High == val) {
|
||||
// We're at the high end, reduce range.
|
||||
rng.High = val - 1;
|
||||
mRangeList[listIndex] = rng;
|
||||
} else {
|
||||
// We're in the middle, split the range.
|
||||
TypedRange next = new TypedRange(val + 1, rng.High, rng.Type);
|
||||
rng.High = val - 1;
|
||||
mRangeList[listIndex] = rng;
|
||||
mRangeList.Insert(listIndex + 1, next);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Internal test function.
|
||||
/// </summary>
|
||||
private static bool CheckTypedRangeSet(TypedRangeSet set, int expectedRanges,
|
||||
Tuple[] expected) {
|
||||
if (set.RangeCount != expectedRanges) {
|
||||
Debug.WriteLine("Expected " + expectedRanges + " ranges, got " +
|
||||
set.RangeCount);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compare actual vs. expected. If we have more actual than expected we'll
|
||||
// throw on the array access.
|
||||
int expIndex = 0;
|
||||
foreach (TypedRangeSet.Tuple val in set) {
|
||||
if (val != expected[expIndex]) {
|
||||
Debug.WriteLine("Expected " + expected[expIndex] + ", got " + val);
|
||||
return false;
|
||||
}
|
||||
expIndex++;
|
||||
}
|
||||
|
||||
// See if we have more expected than actual.
|
||||
if (expIndex != expected.Length) {
|
||||
Debug.WriteLine("Expected " + expected.Length + " elements, found " + expIndex);
|
||||
return false;
|
||||
}
|
||||
|
||||
// The count is maintained separately, so check it.
|
||||
if (set.Count != expected.Length) {
|
||||
Debug.WriteLine("Expected Count=" + expected.Length + ", got " + set.Count);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes unit tests.
|
||||
/// </summary>
|
||||
/// <returns>True if all goes well.</returns>
|
||||
public static bool Test() {
|
||||
bool result = true;
|
||||
|
||||
TypedRangeSet one = new TypedRangeSet();
|
||||
one.Add(7, 100);
|
||||
one.Add(5, 100);
|
||||
one.Add(3, 100);
|
||||
one.Add(9, 100);
|
||||
one.Add(7, 100);
|
||||
one.Add(8, 100);
|
||||
one.Add(2, 100);
|
||||
one.Add(4, 100);
|
||||
result &= CheckTypedRangeSet(one, 2, new Tuple[] {
|
||||
new Tuple(2, 100),
|
||||
new Tuple(3, 100),
|
||||
new Tuple(4, 100),
|
||||
new Tuple(5, 100),
|
||||
new Tuple(7, 100),
|
||||
new Tuple(8, 100),
|
||||
new Tuple(9, 100) });
|
||||
|
||||
one.Remove(2);
|
||||
one.Remove(9);
|
||||
one.Remove(4);
|
||||
result &= CheckTypedRangeSet(one, 3, new Tuple[] {
|
||||
new Tuple(3, 100),
|
||||
new Tuple(5, 100),
|
||||
new Tuple(7, 100),
|
||||
new Tuple(8, 100) });
|
||||
|
||||
one.Clear();
|
||||
one.Add(1, 200);
|
||||
one.Add(3, 100);
|
||||
one.Add(7, 100);
|
||||
one.Add(5, 100);
|
||||
one.Add(9, 100);
|
||||
one.Add(6, 100);
|
||||
one.Add(8, 100);
|
||||
one.Add(6, 200);
|
||||
one.Add(2, 200);
|
||||
one.Add(4, 300);
|
||||
one.Add(4, 100);
|
||||
result &= CheckTypedRangeSet(one, 4, new Tuple[] {
|
||||
new Tuple(1, 200),
|
||||
new Tuple(2, 200),
|
||||
new Tuple(3, 100),
|
||||
new Tuple(4, 100),
|
||||
new Tuple(5, 100),
|
||||
new Tuple(6, 200),
|
||||
new Tuple(7, 100),
|
||||
new Tuple(8, 100),
|
||||
new Tuple(9, 100) });
|
||||
|
||||
one.Add(6, 100);
|
||||
result &= CheckTypedRangeSet(one, 2, new Tuple[] {
|
||||
new Tuple(1, 200),
|
||||
new Tuple(2, 200),
|
||||
new Tuple(3, 100),
|
||||
new Tuple(4, 100),
|
||||
new Tuple(5, 100),
|
||||
new Tuple(6, 100),
|
||||
new Tuple(7, 100),
|
||||
new Tuple(8, 100),
|
||||
new Tuple(9, 100) });
|
||||
|
||||
Debug.WriteLine("TypedRangeSet: test complete (ok=" + result + ")");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
192
CommonUtil/Version.cs
Normal file
192
CommonUtil/Version.cs
Normal file
@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace CommonUtil {
|
||||
/// <summary>
|
||||
/// Version number container. Instances are immutable.
|
||||
///
|
||||
/// See https://semver.org/ for explanation of system.
|
||||
/// </summary>
|
||||
public struct Version {
|
||||
// Must be in ascending order, e.g. Alpha release comes before Beta.
|
||||
public enum PreRelType { Dev, Alpha, Beta, Final };
|
||||
|
||||
/// <summary>
|
||||
/// Major version number.
|
||||
/// </summary>
|
||||
public int Major { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Minor version number.
|
||||
/// </summary>
|
||||
public int Minor { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Bug fix release number.
|
||||
/// </summary>
|
||||
public int Patch { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Software grade, for pre-release versions.
|
||||
/// </summary>
|
||||
public PreRelType PreReleaseType { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Pre-release version.
|
||||
/// </summary>
|
||||
public int PreRelease { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Version instance to use when no version information is available. This will
|
||||
/// always compare as less than a "real" version.
|
||||
/// </summary>
|
||||
public static readonly Version NO_VERSION = new Version(-1, -1, -1);
|
||||
|
||||
/// <summary>
|
||||
/// Shortcut for comparing vs. NO_VERSION.
|
||||
/// </summary>
|
||||
public bool IsValid {
|
||||
get {
|
||||
return this != NO_VERSION;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Version(int major, int minor) :
|
||||
this(major, minor, 0, PreRelType.Final, 0) { }
|
||||
|
||||
public Version(int major, int minor, int patch) :
|
||||
this(major, minor, patch, PreRelType.Final, 0) { }
|
||||
|
||||
public Version(int major, int minor, int patch, PreRelType preRelType, int preRel) {
|
||||
Debug.Assert(preRelType != PreRelType.Final || preRel == 0);
|
||||
Major = major;
|
||||
Minor = minor;
|
||||
Patch = patch;
|
||||
PreReleaseType = preRelType;
|
||||
PreRelease = preRel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to parse the argument into version components.
|
||||
/// </summary>
|
||||
/// <param name="str">Version string.</param>
|
||||
/// <returns>New Version object, or NO_VERSION on parsing failure.</returns>
|
||||
public static Version Parse(string str) {
|
||||
try {
|
||||
int major, minor, patch;
|
||||
major = minor = patch = 0;
|
||||
|
||||
string[] parts = str.Split(new char[] { '.', '-' });
|
||||
major = int.Parse(parts[0]);
|
||||
if (parts.Length > 1) {
|
||||
minor = int.Parse(parts[1]);
|
||||
}
|
||||
if (parts.Length > 2) {
|
||||
patch = int.Parse(parts[2]);
|
||||
}
|
||||
// parse the preRel thing someday
|
||||
return new Version(major, minor, patch);
|
||||
} catch (Exception ex) {
|
||||
Debug.WriteLine("Version parse failed: '" + str + "': " + ex.Message);
|
||||
return NO_VERSION;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static bool operator ==(Version a, Version b) {
|
||||
return a.Major == b.Major && a.Minor == b.Minor && a.Patch == b.Patch &&
|
||||
a.PreReleaseType == b.PreReleaseType && a.PreRelease == b.PreRelease;
|
||||
}
|
||||
public static bool operator !=(Version a, Version b) {
|
||||
return !(a == b);
|
||||
}
|
||||
public override bool Equals(object obj) {
|
||||
return obj is Version && this == (Version)obj;
|
||||
}
|
||||
public override int GetHashCode() {
|
||||
return Major * 10000 + Minor * 1000 + Patch * 100 +
|
||||
(int)PreReleaseType * 10 + PreRelease;
|
||||
}
|
||||
|
||||
public static bool operator <(Version a, Version b) {
|
||||
if (a.Major != b.Major) {
|
||||
return a.Major < b.Major;
|
||||
}
|
||||
if (a.Minor != b.Minor) {
|
||||
return a.Minor < b.Minor;
|
||||
}
|
||||
if (a.Patch != b.Patch) {
|
||||
return a.Patch < b.Patch;
|
||||
}
|
||||
if (a.PreReleaseType != b.PreReleaseType) {
|
||||
return (int)a.PreReleaseType < (int)b.PreReleaseType;
|
||||
}
|
||||
if (a.PreRelease != b.PreRelease) {
|
||||
return a.PreRelease < b.PreRelease;
|
||||
}
|
||||
Debug.Assert(a == b);
|
||||
return false;
|
||||
}
|
||||
public static bool operator >(Version a, Version b) {
|
||||
return b < a;
|
||||
}
|
||||
public static bool operator <=(Version a, Version b) {
|
||||
return a == b || a < b;
|
||||
}
|
||||
public static bool operator >=(Version a, Version b) {
|
||||
return a == b || a > b;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
if (this == NO_VERSION) {
|
||||
return Properties.Resources.NO_VERSION;
|
||||
} else if (PreReleaseType == PreRelType.Final) {
|
||||
return string.Format("{0}.{1}.{2}", Major, Minor, Patch);
|
||||
} else {
|
||||
return string.Format("{0}.{1}.{2}-{3}{4}", Major, Minor, Patch,
|
||||
PreReleaseType.ToString().ToLower(), PreRelease);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simple unit test.
|
||||
/// </summary>
|
||||
public static bool Test() {
|
||||
bool ok = true;
|
||||
|
||||
Version checkVers = new Version(1, 2, 3, PreRelType.Beta, 4);
|
||||
Version sameVers = new Version(1, 2, 3, PreRelType.Beta, 4);
|
||||
ok &= (checkVers == sameVers);
|
||||
ok &= (checkVers <= sameVers);
|
||||
ok &= (checkVers >= sameVers);
|
||||
ok &= (!(checkVers < sameVers));
|
||||
ok &= (!(checkVers > sameVers));
|
||||
|
||||
ok &= (checkVers != new Version(1, 2, 3));
|
||||
ok &= (checkVers < new Version(1, 2, 3));
|
||||
ok &= (checkVers > new Version(1, 2, 3, PreRelType.Beta, 3));
|
||||
ok &= (checkVers < new Version(2, 0));
|
||||
ok &= (checkVers > new Version(1, 2, 2));
|
||||
ok &= (checkVers < new Version(1, 3, 1));
|
||||
|
||||
Debug.WriteLine("Version struct test complete (ok=" + ok + ")");
|
||||
return ok;
|
||||
}
|
||||
}
|
||||
}
|
49
CommonWinForms/CommonWinForms.csproj
Normal file
49
CommonWinForms/CommonWinForms.csproj
Normal file
@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{08EC328D-078E-4236-B574-BE6B3FD85915}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>CommonWinForms</RootNamespace>
|
||||
<AssemblyName>CommonWinForms</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>TRACE;DEBUG;BUILD_FOR_WINDOWS</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;BUILD_FOR_WINDOWS</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="NativeMethods.cs" />
|
||||
<Compile Include="WinFormsExtensions.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
85
CommonWinForms/NativeMethods.cs
Normal file
85
CommonWinForms/NativeMethods.cs
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
|
||||
#if BUILD_FOR_WINDOWS // I don't know if other platforms will emulate the LVITEM stuff
|
||||
namespace CommonWinForms {
|
||||
// From https://stackoverflow.com/questions/1019388/
|
||||
|
||||
/// <summary>
|
||||
/// Unpleasant hackery to make "select all" faster. With 500K items it takes about 24
|
||||
/// seconds to select everything individually, and there isn't a better way. With this
|
||||
/// it only takes a few milliseconds.
|
||||
/// </summary>
|
||||
public class NativeMethods {
|
||||
private const int LVM_FIRST = 0x1000;
|
||||
private const int LVM_SETITEMSTATE = LVM_FIRST + 43;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
public struct LVITEM {
|
||||
public int mask;
|
||||
public int iItem;
|
||||
public int iSubItem;
|
||||
public int state;
|
||||
public int stateMask;
|
||||
[MarshalAs(UnmanagedType.LPTStr)]
|
||||
public string pszText;
|
||||
public int cchTextMax;
|
||||
public int iImage;
|
||||
public IntPtr lParam;
|
||||
public int iIndent;
|
||||
public int iGroupId;
|
||||
public int cColumns;
|
||||
public IntPtr puColumns;
|
||||
};
|
||||
|
||||
[DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]
|
||||
public static extern IntPtr SendMessageLVItem(IntPtr hWnd, int msg, int wParam, ref LVITEM lvi);
|
||||
|
||||
/// <summary>
|
||||
/// Select all rows on the given listview
|
||||
/// </summary>
|
||||
/// <param name="list">The listview whose items are to be selected</param>
|
||||
public static void SelectAllItems(ListView list) {
|
||||
NativeMethods.SetItemState(list, -1, 2, 2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deselect all rows on the given listview
|
||||
/// </summary>
|
||||
/// <param name="list">The listview whose items are to be deselected</param>
|
||||
public static void DeselectAllItems(ListView list) {
|
||||
NativeMethods.SetItemState(list, -1, 2, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the item state on the given item
|
||||
/// </summary>
|
||||
/// <param name="list">The listview whose item's state is to be changed</param>
|
||||
/// <param name="itemIndex">The index of the item to be changed</param>
|
||||
/// <param name="mask">Which bits of the value are to be set?</param>
|
||||
/// <param name="value">The value to be set</param>
|
||||
public static void SetItemState(ListView list, int itemIndex, int mask, int value) {
|
||||
LVITEM lvItem = new LVITEM();
|
||||
lvItem.stateMask = mask;
|
||||
lvItem.state = value;
|
||||
SendMessageLVItem(list.Handle, LVM_SETITEMSTATE, itemIndex, ref lvItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif //BUILD_FOR_WINDOWS
|
36
CommonWinForms/Properties/AssemblyInfo.cs
Normal file
36
CommonWinForms/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("CommonWinForms")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("CommonWinForms")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2018")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("08ec328d-078e-4236-b574-be6b3fd85915")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
121
CommonWinForms/WinFormsExtensions.cs
Normal file
121
CommonWinForms/WinFormsExtensions.cs
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace CommonWinForms {
|
||||
/// <summary>
|
||||
/// Overload RichTextBox.AppendText() with a version that takes a color as an argument.
|
||||
///
|
||||
/// From https://stackoverflow.com/a/1926822/294248
|
||||
/// </summary>
|
||||
public static class RichTextBoxExtensions {
|
||||
public static void AppendText(this RichTextBox box, string text, Color color) {
|
||||
box.SelectionStart = box.TextLength;
|
||||
box.SelectionLength = 0;
|
||||
box.SelectionColor = color;
|
||||
box.AppendText(text);
|
||||
box.SelectionColor = box.ForeColor;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add functions to select and deselect all items.
|
||||
/// </summary>
|
||||
public static class ListViewExtensions {
|
||||
/// <summary>
|
||||
/// Selects all items in the list view.
|
||||
/// </summary>
|
||||
public static void SelectAll(this ListView listView) {
|
||||
// Neither I nor the Internet can figure out how to do this efficiently for
|
||||
// large lists without P/Invoke interop. With 554253 lines, it takes 24.3 seconds
|
||||
// to select each item individually, but only 4 milliseconds to do it through an
|
||||
// LVITEM. The latter causes a single VirtualItemsSelectionRangeChanged event
|
||||
// instead of 554K ItemSelectionChanged events.
|
||||
//
|
||||
// https://stackoverflow.com/questions/9039989/
|
||||
// https://stackoverflow.com/questions/1019388/
|
||||
|
||||
#if BUILD_FOR_WINDOWS // defined in our project properties
|
||||
NativeMethods.SelectAllItems(listView);
|
||||
#else
|
||||
try {
|
||||
Application.UseWaitCursor = true;
|
||||
Cursor.Current = Cursors.WaitCursor;
|
||||
listView.BeginUpdate();
|
||||
int max = listView.VirtualListSize;
|
||||
for (int i = 0; i < max; i++) {
|
||||
//codeListView.Items[i].Selected = true;
|
||||
listView.SelectedIndices.Add(i);
|
||||
}
|
||||
} finally {
|
||||
listView.EndUpdate();
|
||||
Application.UseWaitCursor = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deselects all items in the list view.
|
||||
/// </summary>
|
||||
public static void DeselectAll(this ListView listView) {
|
||||
// This is as fast as the native DeselectAllItems(), so just use it.
|
||||
listView.SelectedIndices.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the double-buffered status of the list view.
|
||||
/// </summary>
|
||||
public static void SetDoubleBuffered(this ListView listView, bool enable) {
|
||||
WinFormsUtil.SetDoubleBuffered(listView, enable);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified item is visible in the list view.
|
||||
/// </summary>
|
||||
public static bool IsItemVisible(this ListView listView, ListViewItem item) {
|
||||
Rectangle lvBounds = listView.ClientRectangle;
|
||||
if (listView.HeaderStyle != ColumnHeaderStyle.None) {
|
||||
// Need to factor the header height out. There's no easy way to do that,
|
||||
// but the header should be (almost) the same height as an item.
|
||||
// https://stackoverflow.com/q/538906/294248
|
||||
int headerHeight = item.Bounds.Height + 5; // 5 is magic, will probably break
|
||||
lvBounds = new Rectangle(lvBounds.X, lvBounds.Y + headerHeight,
|
||||
lvBounds.Width, lvBounds.Height - headerHeight);
|
||||
}
|
||||
//Console.WriteLine("IsVis LV: " + lvBounds + " IT: " +
|
||||
// item.GetBounds(ItemBoundsPortion.Entire));
|
||||
return lvBounds.IntersectsWith(item.GetBounds(ItemBoundsPortion.Entire));
|
||||
}
|
||||
}
|
||||
|
||||
public static class WinFormsUtil {
|
||||
/// <summary>
|
||||
/// Sets the "DoubleBuffered" property on a Control. For some reason the
|
||||
/// property is defined as "protected", but I don't want to subclass a ListView
|
||||
/// just so I can enable double-buffering.
|
||||
/// </summary>
|
||||
/// <param name="ctrl">Control to update.</param>
|
||||
/// <param name="enable">New state.</param>
|
||||
public static void SetDoubleBuffered(Control ctrl, bool enable) {
|
||||
System.Reflection.PropertyInfo prop = ctrl.GetType().GetProperty("DoubleBuffered",
|
||||
System.Reflection.BindingFlags.Instance |
|
||||
System.Reflection.BindingFlags.NonPublic);
|
||||
prop.SetValue(ctrl, enable, null);
|
||||
}
|
||||
}
|
||||
}
|
BIN
ImageSrc/SourceGenIcon.ico
Normal file
BIN
ImageSrc/SourceGenIcon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 139 KiB |
BIN
ImageSrc/SourceGenIcon.xcf
Normal file
BIN
ImageSrc/SourceGenIcon.xcf
Normal file
Binary file not shown.
BIN
ImageSrc/SourceGenIconSmall.ico
Normal file
BIN
ImageSrc/SourceGenIconSmall.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.2 KiB |
BIN
ImageSrc/left-arrow.png
Normal file
BIN
ImageSrc/left-arrow.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 156 B |
BIN
ImageSrc/left-arrow.xcf
Normal file
BIN
ImageSrc/left-arrow.xcf
Normal file
Binary file not shown.
BIN
ImageSrc/right-arrow.png
Normal file
BIN
ImageSrc/right-arrow.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 155 B |
6
MakeDist/App.config
Normal file
6
MakeDist/App.config
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
|
||||
</startup>
|
||||
</configuration>
|
103
MakeDist/CopyProgress.Designer.cs
generated
Normal file
103
MakeDist/CopyProgress.Designer.cs
generated
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
namespace MakeDist {
|
||||
partial class CopyProgress {
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing) {
|
||||
if (disposing && (components != null)) {
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent() {
|
||||
this.progressRichTextBox = new System.Windows.Forms.RichTextBox();
|
||||
this.cancelButton = new System.Windows.Forms.Button();
|
||||
this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// progressRichTextBox
|
||||
//
|
||||
this.progressRichTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.progressRichTextBox.Location = new System.Drawing.Point(13, 13);
|
||||
this.progressRichTextBox.Name = "progressRichTextBox";
|
||||
this.progressRichTextBox.ReadOnly = true;
|
||||
this.progressRichTextBox.Size = new System.Drawing.Size(459, 507);
|
||||
this.progressRichTextBox.TabIndex = 0;
|
||||
this.progressRichTextBox.Text = "";
|
||||
//
|
||||
// cancelButton
|
||||
//
|
||||
this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.cancelButton.Location = new System.Drawing.Point(397, 526);
|
||||
this.cancelButton.Name = "cancelButton";
|
||||
this.cancelButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.cancelButton.TabIndex = 1;
|
||||
this.cancelButton.Text = "Cancel";
|
||||
this.cancelButton.UseVisualStyleBackColor = true;
|
||||
this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click);
|
||||
//
|
||||
// backgroundWorker1
|
||||
//
|
||||
this.backgroundWorker1.WorkerReportsProgress = true;
|
||||
this.backgroundWorker1.WorkerSupportsCancellation = true;
|
||||
this.backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork);
|
||||
this.backgroundWorker1.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(this.backgroundWorker1_ProgressChanged);
|
||||
this.backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);
|
||||
//
|
||||
// CopyProgress
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.CancelButton = this.cancelButton;
|
||||
this.ClientSize = new System.Drawing.Size(484, 561);
|
||||
this.Controls.Add(this.cancelButton);
|
||||
this.Controls.Add(this.progressRichTextBox);
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "CopyProgress";
|
||||
this.ShowInTaskbar = false;
|
||||
this.Text = "CopyDistFiles";
|
||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.CopyProgress_FormClosing);
|
||||
this.Load += new System.EventHandler(this.CopyProgress_Load);
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.RichTextBox progressRichTextBox;
|
||||
private System.Windows.Forms.Button cancelButton;
|
||||
private System.ComponentModel.BackgroundWorker backgroundWorker1;
|
||||
}
|
||||
}
|
134
MakeDist/CopyProgress.cs
Normal file
134
MakeDist/CopyProgress.cs
Normal file
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using CommonWinForms;
|
||||
|
||||
namespace MakeDist {
|
||||
public partial class CopyProgress : Form {
|
||||
/// <summary>
|
||||
/// Progress message, with colorful text. This is generated by the worker thread and
|
||||
/// passed to the UI thread.
|
||||
/// </summary>
|
||||
public class ProgressMessage {
|
||||
public string Text { get; private set; }
|
||||
public Color Color { get; private set; }
|
||||
public bool HasColor { get { return Color.A != 0; } }
|
||||
|
||||
public ProgressMessage(string msg) : this(msg, Color.FromArgb(0, 0, 0, 0)) { }
|
||||
|
||||
public ProgressMessage(string msg, Color color) {
|
||||
Text = msg;
|
||||
Color = color;
|
||||
}
|
||||
}
|
||||
|
||||
private bool mClosedWhileRunning;
|
||||
|
||||
// Copy parameters.
|
||||
private FileCopier.BuildType mBuildType;
|
||||
private bool mCopyTestFiles;
|
||||
|
||||
|
||||
public CopyProgress(FileCopier.BuildType buildType, bool copyTestFiles) {
|
||||
InitializeComponent();
|
||||
|
||||
this.Size = new Size(1200, 600);
|
||||
|
||||
mBuildType = buildType;
|
||||
mCopyTestFiles = copyTestFiles;
|
||||
}
|
||||
|
||||
private void CopyProgress_Load(object sender, EventArgs e) {
|
||||
backgroundWorker1.RunWorkerAsync();
|
||||
}
|
||||
|
||||
private void CopyProgress_FormClosing(object sender, FormClosingEventArgs e) {
|
||||
if (backgroundWorker1.IsBusy) {
|
||||
backgroundWorker1.CancelAsync();
|
||||
DialogResult = DialogResult.Cancel;
|
||||
|
||||
// First close attempt is converted to a cancel.
|
||||
if (!mClosedWhileRunning) {
|
||||
e.Cancel = true;
|
||||
mClosedWhileRunning = true;
|
||||
}
|
||||
} else {
|
||||
DialogResult = DialogResult.OK;
|
||||
}
|
||||
}
|
||||
|
||||
private void cancelButton_Click(object sender, EventArgs e) {
|
||||
if (backgroundWorker1.IsBusy) {
|
||||
backgroundWorker1.CancelAsync();
|
||||
} else {
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) {
|
||||
BackgroundWorker worker = sender as BackgroundWorker;
|
||||
|
||||
FileCopier copier = new FileCopier(mBuildType, mCopyTestFiles);
|
||||
e.Result = copier.CopyAllFiles(worker);
|
||||
}
|
||||
|
||||
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) {
|
||||
if (e.UserState is ProgressMessage) {
|
||||
ProgressMessage msg = e.UserState as ProgressMessage;
|
||||
if (msg.HasColor) {
|
||||
progressRichTextBox.AppendText(msg.Text, msg.Color);
|
||||
} else {
|
||||
// plain foreground text color
|
||||
progressRichTextBox.AppendText(msg.Text);
|
||||
}
|
||||
progressRichTextBox.SelectionStart = progressRichTextBox.Text.Length;
|
||||
progressRichTextBox.ScrollToCaret();
|
||||
} else {
|
||||
if (!string.IsNullOrEmpty((string)e.UserState)) {
|
||||
Debug.WriteLine("Weird progress: " + e.UserState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void backgroundWorker1_RunWorkerCompleted(object sender,
|
||||
RunWorkerCompletedEventArgs e) {
|
||||
if (e.Cancelled) {
|
||||
Debug.WriteLine("Test halted -- user cancellation");
|
||||
} else if (e.Error != null) {
|
||||
// test harness shouldn't be throwing errors like this
|
||||
Debug.WriteLine("Test failed: " + e.Error.ToString());
|
||||
progressRichTextBox.AppendText("\r\n");
|
||||
progressRichTextBox.AppendText(e.Error.ToString());
|
||||
progressRichTextBox.SelectionStart = progressRichTextBox.Text.Length;
|
||||
progressRichTextBox.ScrollToCaret();
|
||||
} else {
|
||||
bool ok = (bool)e.Result;
|
||||
Debug.WriteLine("Tests complete, success=" + ok);
|
||||
}
|
||||
|
||||
if (mClosedWhileRunning) {
|
||||
Close();
|
||||
}
|
||||
|
||||
cancelButton.Text = "Close";
|
||||
}
|
||||
}
|
||||
}
|
123
MakeDist/CopyProgress.resx
Normal file
123
MakeDist/CopyProgress.resx
Normal file
@ -0,0 +1,123 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="backgroundWorker1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
</root>
|
316
MakeDist/FileCopier.cs
Normal file
316
MakeDist/FileCopier.cs
Normal file
@ -0,0 +1,316 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace MakeDist {
|
||||
public class FileCopier {
|
||||
private const string SOURCEGEN_DIRNAME = "SourceGen";
|
||||
|
||||
/// <summary>
|
||||
/// Type of build to gather files for.
|
||||
/// </summary>
|
||||
public enum BuildType { Unknown, Release, Debug };
|
||||
|
||||
private enum SourceFileSpec {
|
||||
Unknown = 0,
|
||||
All,
|
||||
List,
|
||||
RegressionTests,
|
||||
AsmSources,
|
||||
NotBins,
|
||||
}
|
||||
|
||||
private class CopySpec {
|
||||
public string SourceDir { get; private set; }
|
||||
public string DestDir { get; private set; }
|
||||
public SourceFileSpec FileSpec { get; private set; }
|
||||
public bool IsRecursive { get; private set; }
|
||||
public string[] FileList { get; private set; }
|
||||
|
||||
public CopySpec(string srcDir, string dstDir, SourceFileSpec spec, bool recursive,
|
||||
string[] fileList) {
|
||||
SourceDir = srcDir;
|
||||
DestDir = dstDir;
|
||||
FileSpec = spec;
|
||||
IsRecursive = recursive;
|
||||
FileList = fileList;
|
||||
}
|
||||
}
|
||||
|
||||
private static CopySpec[] sMainSpec = {
|
||||
new CopySpec(".", ".",
|
||||
SourceFileSpec.List, false, new string[] { "README.md" }),
|
||||
new CopySpec("Asm65/bin/{BUILD_TYPE}/netstandard2.0/", ".",
|
||||
SourceFileSpec.List, false, new string[] { "Asm65.dll" }),
|
||||
new CopySpec("CommonUtil/bin/{BUILD_TYPE}/netstandard2.0/", ".",
|
||||
SourceFileSpec.List, false, new string[] { "CommonUtil.dll" }),
|
||||
new CopySpec("CommonWinForms/bin/{BUILD_TYPE}/", ".",
|
||||
SourceFileSpec.List, false, new string[] { "CommonWinForms.dll" }),
|
||||
new CopySpec("PluginCommon/bin/{BUILD_TYPE}/netstandard2.0/", ".",
|
||||
SourceFileSpec.List, false, new string[] { "PluginCommon.dll" }),
|
||||
new CopySpec("SourceGen/bin/{BUILD_TYPE}/", ".",
|
||||
SourceFileSpec.List, false, new string[] { "SourceGen.exe" }),
|
||||
new CopySpec("SourceGen/RuntimeData", "RuntimeData",
|
||||
SourceFileSpec.NotBins, true, null),
|
||||
new CopySpec("SourceGen/Examples", "Examples",
|
||||
SourceFileSpec.All, true, null),
|
||||
};
|
||||
private static CopySpec[] sTestSpec = {
|
||||
new CopySpec("SourceGen/SGTestData", "SGTestData",
|
||||
SourceFileSpec.RegressionTests, false, null),
|
||||
new CopySpec("SourceGen/SGTestData", "SGTestData",
|
||||
SourceFileSpec.List, false, new string[] { "README.md" }),
|
||||
new CopySpec("SourceGen/SGTestData/Expected", "SGTestData/Expected",
|
||||
SourceFileSpec.AsmSources, false, null),
|
||||
new CopySpec("SourceGen/SGTestData/Source", "SGTestData/Source",
|
||||
SourceFileSpec.AsmSources, false, null),
|
||||
new CopySpec("SourceGen/SGTestData/FunkyProjects", "SGTestData/FunkyProjects",
|
||||
SourceFileSpec.All, false, null),
|
||||
};
|
||||
|
||||
private static string sBasePath;
|
||||
|
||||
// We want all of the regression test binaries, plus the .sym65, .dis65, and .cs,
|
||||
// but nothing with an underscore in the part before the extension.
|
||||
private const string TestCasePattern = @"^\d\d\d\d-[A-Za-z0-9-]+(\..*)?$";
|
||||
private static Regex sTestCaseRegex = new Regex(TestCasePattern);
|
||||
|
||||
|
||||
private BuildType mBuildType;
|
||||
private bool mCopyTestFiles;
|
||||
private BackgroundWorker mWorker;
|
||||
|
||||
|
||||
public FileCopier(BuildType buildType, bool copyTestFiles) {
|
||||
mBuildType = buildType;
|
||||
mCopyTestFiles = copyTestFiles;
|
||||
}
|
||||
|
||||
private void ReportProgress(string msg) {
|
||||
mWorker.ReportProgress(0, new CopyProgress.ProgressMessage(msg + "\r\n"));
|
||||
}
|
||||
|
||||
private void ReportProgress(string msg, Color color) {
|
||||
mWorker.ReportProgress(0, new CopyProgress.ProgressMessage(msg + "\r\n", color));
|
||||
}
|
||||
|
||||
private void ReportErrMsg(string msg) {
|
||||
ReportProgress(msg, Color.Red);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Main entry point.
|
||||
/// </summary>
|
||||
/// <param name="worker">Background task interface object.</param>
|
||||
/// <returns>True on success.</returns>
|
||||
public bool CopyAllFiles(BackgroundWorker worker) {
|
||||
mWorker = worker;
|
||||
|
||||
ReportProgress("Preparing... build type is " + mBuildType + ", test files are " +
|
||||
(mCopyTestFiles ? "" : "NOT ") + "included.");
|
||||
|
||||
string buildStr = mBuildType.ToString();
|
||||
string basePath = FindBasePath();
|
||||
Debug.Assert(basePath != null);
|
||||
string distPath = Path.Combine(basePath, "DIST_" + buildStr);
|
||||
|
||||
// TODO(maybe): recursively delete distPath
|
||||
|
||||
if (!CopySpecList(sMainSpec, basePath, distPath, buildStr)) {
|
||||
return false;
|
||||
}
|
||||
if (mCopyTestFiles) {
|
||||
if (!CopySpecList(sTestSpec, basePath, distPath, buildStr)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool CopySpecList(CopySpec[] specList, string basePath, string distPath,
|
||||
string buildStr) {
|
||||
foreach (CopySpec cs in specList) {
|
||||
string srcDir = Path.GetFullPath(Path.Combine(basePath,
|
||||
cs.SourceDir.Replace("{BUILD_TYPE}", buildStr)));
|
||||
string dstDir = Path.GetFullPath(Path.Combine(distPath, cs.DestDir));
|
||||
|
||||
ReportProgress("Scanning [" + cs.FileSpec + "] " + srcDir);
|
||||
|
||||
if (!CopyBySpec(srcDir, dstDir, cs.FileSpec, cs.FileList, cs.IsRecursive)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool CopyBySpec(string srcDir, string dstDir, SourceFileSpec sfspec,
|
||||
string[] specFileList, bool isRecursive) {
|
||||
if (!EnsureDirectoryExists(dstDir)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
string[] fileList;
|
||||
if (sfspec == SourceFileSpec.List) {
|
||||
fileList = specFileList;
|
||||
} else {
|
||||
fileList = Directory.GetFiles(srcDir);
|
||||
}
|
||||
|
||||
foreach (string str in fileList) {
|
||||
// Spec list is filenames, GetFiles is paths; convert to simple filename.
|
||||
string fileName = Path.GetFileName(str);
|
||||
|
||||
switch (sfspec) {
|
||||
case SourceFileSpec.All:
|
||||
case SourceFileSpec.List:
|
||||
// keep all
|
||||
break;
|
||||
case SourceFileSpec.NotBins:
|
||||
// Mostly this means "skip obj and bin dirs", which happens later.
|
||||
// Rather than specify everything we do want, just omit this one thing.
|
||||
if (fileName == "RuntimeData.csproj") {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case SourceFileSpec.AsmSources:
|
||||
if (!fileName.ToUpperInvariant().EndsWith(".S")) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case SourceFileSpec.RegressionTests:
|
||||
MatchCollection matches = sTestCaseRegex.Matches(fileName);
|
||||
if (matches.Count != 1) {
|
||||
continue;
|
||||
}
|
||||
// Could probably do this with regex... but why.
|
||||
if (fileName.StartsWith("1") && fileName.EndsWith(".dis65")) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Unsupported spec " + sfspec);
|
||||
}
|
||||
|
||||
string srcPath = Path.Combine(srcDir, fileName);
|
||||
string dstPath = Path.Combine(dstDir, fileName);
|
||||
if (!CopyFile(srcPath, dstPath)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isRecursive) {
|
||||
string[] dirList = Directory.GetDirectories(srcDir);
|
||||
|
||||
foreach (string str in dirList) {
|
||||
string dirFileName = Path.GetFileName(str);
|
||||
if (sfspec == SourceFileSpec.NotBins &&
|
||||
(dirFileName == "obj" || dirFileName == "bin")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!CopyBySpec(Path.Combine(srcDir, dirFileName),
|
||||
Path.Combine(dstDir, dirFileName),
|
||||
sfspec, specFileList, isRecursive)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool EnsureDirectoryExists(string dirPath) {
|
||||
if (Directory.Exists(dirPath)) {
|
||||
return true;
|
||||
}
|
||||
if (File.Exists(dirPath)) {
|
||||
ReportErrMsg("File exists and is not directory: " + dirPath);
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
Directory.CreateDirectory(dirPath);
|
||||
ReportProgress(" Created " + dirPath);
|
||||
} catch (Exception ex) {
|
||||
ReportErrMsg("Failed creating directory " + dirPath + ": " + ex.Message);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool CopyFile(string srcPath, string dstPath) {
|
||||
// Poll cancel button.
|
||||
if (mWorker.CancellationPending) {
|
||||
ReportErrMsg("Cancel\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
ReportProgress(" Copy " + srcPath + " --> " + dstPath);
|
||||
|
||||
try {
|
||||
File.Copy(srcPath, dstPath, true);
|
||||
} catch (Exception ex) {
|
||||
ReportErrMsg("Failed: " + ex.Message);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the base directory of the 6502bench installation.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private static string FindBasePath() {
|
||||
if (sBasePath != null) {
|
||||
return sBasePath;
|
||||
}
|
||||
|
||||
string exeName = Process.GetCurrentProcess().MainModule.FileName;
|
||||
string baseDir = Path.GetDirectoryName(exeName);
|
||||
if (string.IsNullOrEmpty(baseDir)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
string tryPath;
|
||||
|
||||
// Use the SourceGen directory as a sentinel.
|
||||
tryPath = Path.Combine(baseDir, SOURCEGEN_DIRNAME);
|
||||
if (Directory.Exists(tryPath)) {
|
||||
sBasePath = Path.GetFullPath(tryPath);
|
||||
return sBasePath;
|
||||
}
|
||||
|
||||
string upThree = Path.GetDirectoryName(
|
||||
Path.GetDirectoryName(Path.GetDirectoryName(baseDir)));
|
||||
tryPath = Path.Combine(upThree, SOURCEGEN_DIRNAME);
|
||||
if (Directory.Exists(tryPath)) {
|
||||
sBasePath = Path.GetFullPath(upThree);
|
||||
return sBasePath;
|
||||
}
|
||||
|
||||
Debug.WriteLine("Unable to find RuntimeData dir near " + exeName);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
162
MakeDist/MakeDist.Designer.cs
generated
Normal file
162
MakeDist/MakeDist.Designer.cs
generated
Normal file
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
namespace MakeDist {
|
||||
partial class MakeDist {
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing) {
|
||||
if (disposing && (components != null)) {
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent() {
|
||||
this.descriptionLabel = new System.Windows.Forms.Label();
|
||||
this.distributionTypeGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.releaseDistRadio = new System.Windows.Forms.RadioButton();
|
||||
this.debugDistRadio = new System.Windows.Forms.RadioButton();
|
||||
this.includeTestsCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.goButton = new System.Windows.Forms.Button();
|
||||
this.cancelButton = new System.Windows.Forms.Button();
|
||||
this.distributionTypeGroupBox.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// descriptionLabel
|
||||
//
|
||||
this.descriptionLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.descriptionLabel.Location = new System.Drawing.Point(13, 13);
|
||||
this.descriptionLabel.Name = "descriptionLabel";
|
||||
this.descriptionLabel.Size = new System.Drawing.Size(371, 35);
|
||||
this.descriptionLabel.TabIndex = 0;
|
||||
this.descriptionLabel.Text = "This program gathers up all the files needed for a 6502bench distribution. A full" +
|
||||
" debug or release build should be performed before running this.";
|
||||
//
|
||||
// distributionTypeGroupBox
|
||||
//
|
||||
this.distributionTypeGroupBox.Controls.Add(this.releaseDistRadio);
|
||||
this.distributionTypeGroupBox.Controls.Add(this.debugDistRadio);
|
||||
this.distributionTypeGroupBox.Location = new System.Drawing.Point(16, 51);
|
||||
this.distributionTypeGroupBox.Name = "distributionTypeGroupBox";
|
||||
this.distributionTypeGroupBox.Size = new System.Drawing.Size(120, 67);
|
||||
this.distributionTypeGroupBox.TabIndex = 1;
|
||||
this.distributionTypeGroupBox.TabStop = false;
|
||||
this.distributionTypeGroupBox.Text = "Distribution Type";
|
||||
//
|
||||
// releaseDistRadio
|
||||
//
|
||||
this.releaseDistRadio.AutoSize = true;
|
||||
this.releaseDistRadio.Location = new System.Drawing.Point(7, 20);
|
||||
this.releaseDistRadio.Name = "releaseDistRadio";
|
||||
this.releaseDistRadio.Size = new System.Drawing.Size(64, 17);
|
||||
this.releaseDistRadio.TabIndex = 0;
|
||||
this.releaseDistRadio.TabStop = true;
|
||||
this.releaseDistRadio.Text = "Release";
|
||||
this.releaseDistRadio.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// debugDistRadio
|
||||
//
|
||||
this.debugDistRadio.AutoSize = true;
|
||||
this.debugDistRadio.Location = new System.Drawing.Point(7, 43);
|
||||
this.debugDistRadio.Name = "debugDistRadio";
|
||||
this.debugDistRadio.Size = new System.Drawing.Size(57, 17);
|
||||
this.debugDistRadio.TabIndex = 1;
|
||||
this.debugDistRadio.TabStop = true;
|
||||
this.debugDistRadio.Text = "Debug";
|
||||
this.debugDistRadio.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// includeTestsCheckBox
|
||||
//
|
||||
this.includeTestsCheckBox.AutoSize = true;
|
||||
this.includeTestsCheckBox.Location = new System.Drawing.Point(16, 125);
|
||||
this.includeTestsCheckBox.Name = "includeTestsCheckBox";
|
||||
this.includeTestsCheckBox.Size = new System.Drawing.Size(153, 17);
|
||||
this.includeTestsCheckBox.TabIndex = 2;
|
||||
this.includeTestsCheckBox.Text = "Include regression test files";
|
||||
this.includeTestsCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// goButton
|
||||
//
|
||||
this.goButton.Location = new System.Drawing.Point(192, 59);
|
||||
this.goButton.Name = "goButton";
|
||||
this.goButton.Size = new System.Drawing.Size(88, 47);
|
||||
this.goButton.TabIndex = 3;
|
||||
this.goButton.Text = "BUILD";
|
||||
this.goButton.UseVisualStyleBackColor = true;
|
||||
this.goButton.Click += new System.EventHandler(this.goButton_Click);
|
||||
//
|
||||
// cancelButton
|
||||
//
|
||||
this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.cancelButton.Location = new System.Drawing.Point(309, 120);
|
||||
this.cancelButton.Name = "cancelButton";
|
||||
this.cancelButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.cancelButton.TabIndex = 4;
|
||||
this.cancelButton.Text = "Close";
|
||||
this.cancelButton.UseVisualStyleBackColor = true;
|
||||
this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click);
|
||||
//
|
||||
// MakeDist
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.CancelButton = this.cancelButton;
|
||||
this.ClientSize = new System.Drawing.Size(396, 155);
|
||||
this.Controls.Add(this.cancelButton);
|
||||
this.Controls.Add(this.goButton);
|
||||
this.Controls.Add(this.includeTestsCheckBox);
|
||||
this.Controls.Add(this.distributionTypeGroupBox);
|
||||
this.Controls.Add(this.descriptionLabel);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Fixed3D;
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "MakeDist";
|
||||
this.Text = "6502bench Distribution Maker";
|
||||
this.Load += new System.EventHandler(this.MakeDist_Load);
|
||||
this.distributionTypeGroupBox.ResumeLayout(false);
|
||||
this.distributionTypeGroupBox.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Label descriptionLabel;
|
||||
private System.Windows.Forms.GroupBox distributionTypeGroupBox;
|
||||
private System.Windows.Forms.RadioButton releaseDistRadio;
|
||||
private System.Windows.Forms.RadioButton debugDistRadio;
|
||||
private System.Windows.Forms.CheckBox includeTestsCheckBox;
|
||||
private System.Windows.Forms.Button goButton;
|
||||
private System.Windows.Forms.Button cancelButton;
|
||||
}
|
||||
}
|
||||
|
47
MakeDist/MakeDist.cs
Normal file
47
MakeDist/MakeDist.cs
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace MakeDist {
|
||||
public partial class MakeDist : Form {
|
||||
public MakeDist() {
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void MakeDist_Load(object sender, EventArgs e) {
|
||||
releaseDistRadio.Checked = true;
|
||||
}
|
||||
|
||||
private void goButton_Click(object sender, EventArgs e) {
|
||||
FileCopier.BuildType buildType;
|
||||
if (releaseDistRadio.Checked) {
|
||||
buildType = FileCopier.BuildType.Release;
|
||||
} else {
|
||||
buildType = FileCopier.BuildType.Debug;
|
||||
}
|
||||
bool copyTestFiles = includeTestsCheckBox.Checked;
|
||||
|
||||
CopyProgress dlg = new CopyProgress(buildType, copyTestFiles);
|
||||
dlg.ShowDialog();
|
||||
dlg.Dispose();
|
||||
}
|
||||
|
||||
private void cancelButton_Click(object sender, EventArgs e) {
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
99
MakeDist/MakeDist.csproj
Normal file
99
MakeDist/MakeDist.csproj
Normal file
@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{2415F337-2CE2-42E0-A8A7-4127FEEC94C4}</ProjectGuid>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<RootNamespace>MakeDist</RootNamespace>
|
||||
<AssemblyName>MakeDist</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<Deterministic>true</Deterministic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Deployment" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="CopyProgress.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="CopyProgress.Designer.cs">
|
||||
<DependentUpon>CopyProgress.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="FileCopier.cs" />
|
||||
<Compile Include="MakeDist.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="MakeDist.Designer.cs">
|
||||
<DependentUpon>MakeDist.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<EmbeddedResource Include="CopyProgress.resx">
|
||||
<DependentUpon>CopyProgress.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="MakeDist.resx">
|
||||
<DependentUpon>MakeDist.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
</None>
|
||||
<Compile Include="Properties\Settings.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\CommonWinForms\CommonWinForms.csproj">
|
||||
<Project>{08ec328d-078e-4236-b574-be6b3fd85915}</Project>
|
||||
<Name>CommonWinForms</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
120
MakeDist/MakeDist.resx
Normal file
120
MakeDist/MakeDist.resx
Normal file
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
31
MakeDist/Program.cs
Normal file
31
MakeDist/Program.cs
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace MakeDist {
|
||||
static class Program {
|
||||
/// <summary>
|
||||
/// The main entry point for the application.
|
||||
/// </summary>
|
||||
[STAThread]
|
||||
static void Main() {
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
Application.Run(new MakeDist());
|
||||
}
|
||||
}
|
||||
}
|
36
MakeDist/Properties/AssemblyInfo.cs
Normal file
36
MakeDist/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("MakeDist")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("MakeDist")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2018")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("2415f337-2ce2-42e0-a8a7-4127feec94c4")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
62
MakeDist/Properties/Resources.Designer.cs
generated
Normal file
62
MakeDist/Properties/Resources.Designer.cs
generated
Normal file
@ -0,0 +1,62 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace MakeDist.Properties {
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if ((resourceMan == null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MakeDist.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
117
MakeDist/Properties/Resources.resx
Normal file
117
MakeDist/Properties/Resources.resx
Normal file
@ -0,0 +1,117 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
26
MakeDist/Properties/Settings.Designer.cs
generated
Normal file
26
MakeDist/Properties/Settings.Designer.cs
generated
Normal file
@ -0,0 +1,26 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace MakeDist.Properties {
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
|
||||
public static Settings Default {
|
||||
get {
|
||||
return defaultInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
7
MakeDist/Properties/Settings.settings
Normal file
7
MakeDist/Properties/Settings.settings
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
|
||||
<Profiles>
|
||||
<Profile Name="(Default)" />
|
||||
</Profiles>
|
||||
<Settings />
|
||||
</SettingsFile>
|
134
PluginCommon/Interfaces.cs
Normal file
134
PluginCommon/Interfaces.cs
Normal file
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PluginCommon {
|
||||
/// <summary>
|
||||
/// Script "plugins" must implement this interface.
|
||||
/// </summary>
|
||||
public interface IPlugin {
|
||||
/// <summary>
|
||||
/// Identification string. Contents are arbitrary, but should briefly identify the
|
||||
/// purpose of the plugin, e.g. "Apple II ProDOS 8 MLI call handler". It may
|
||||
/// contain version information, but should not be expected to be machine-readable.
|
||||
/// </summary>
|
||||
string Identifier { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this plugin checks JSR/JSL for inline data.
|
||||
/// </summary>
|
||||
//bool HasInlineDataAnalyzer { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the plugin with an application reference and a buffer with file
|
||||
/// data. Called before each analysis pass.
|
||||
///
|
||||
/// In the current implementation, the file data will be the same every time,
|
||||
/// because plugins are discarded when a project is closed. However, this may
|
||||
/// change if we add a descramble feature.
|
||||
/// </summary>
|
||||
/// <param name="appRef">Reference to application interface.</param>
|
||||
/// <param name="fileData">65xx code and data.</param>
|
||||
/// <param name="platSyms">Platform symbols, in no particular order.</param>
|
||||
void Prepare(IApplication appRef, byte[] fileData, List<PlatSym> platSyms);
|
||||
|
||||
/// <summary>
|
||||
/// Checks to see if code/data near a JSR instruction should be formatted.
|
||||
///
|
||||
/// The file data is guaranteed to hold the JSR (offset + 2).
|
||||
/// </summary>
|
||||
/// <param name="offset">Offset of the JSR instruction.</param>
|
||||
/// <param name="noContinue">Set to true if the JSR doesn't actually return.</param>
|
||||
void CheckJsr(int offset, out bool noContinue);
|
||||
|
||||
/// <summary>
|
||||
/// Checks to see if code/data near a JSL instruction should be formatted.
|
||||
///
|
||||
/// The file data is guaranteed to hold the JSL (offset + 3).
|
||||
/// </summary>
|
||||
/// <param name="offset">Offset of the JSL instruction.</param>
|
||||
/// <param name="noContinue">Set to true if the JSL doesn't actually return.</param>
|
||||
void CheckJsl(int offset, out bool noContinue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interfaces provided by the application for use by plugins.
|
||||
/// </summary>
|
||||
public interface IApplication {
|
||||
/// <summary>
|
||||
/// Sends a debug message to the application. This can be useful when debugging scripts.
|
||||
/// (Use DEBUG > Show Analyzer Output to view it.)
|
||||
/// </summary>
|
||||
/// <param name="msg">Message to send.</param>
|
||||
void DebugLog(string msg);
|
||||
|
||||
/// <summary>
|
||||
/// Specifies operand formatting.
|
||||
/// </summary>
|
||||
/// <param name="offset">File offset of opcode.</param>
|
||||
/// <param name="subType">Sub-type. Must be appropriate for NumericLE.</param>
|
||||
/// <param name="label">Optional symbolic label.</param>
|
||||
/// <returns>True if the change was made, false if it was rejected.</returns>
|
||||
bool SetOperandFormat(int offset, DataSubType subType, string label);
|
||||
|
||||
/// <summary>
|
||||
/// Formats file data as inline data.
|
||||
/// </summary>
|
||||
/// <param name="offset">File offset.</param>
|
||||
/// <param name="length">Length of item.</param>
|
||||
/// <param name="type">Type of item. Must be NumericLE, NumericBE, or Dense.</param>
|
||||
/// <param name="subType">Sub-type. Must be appropriate for type.</param>
|
||||
/// <param name="label">Optional symbolic label.</param>
|
||||
/// <returns>True if the change was made, false if it was rejected.</returns>
|
||||
bool SetInlineDataFormat(int offset, int length, DataType type,
|
||||
DataSubType subType, string label);
|
||||
|
||||
// Might want to add:
|
||||
// int AddressToOffset(int address) // returns 24-bit offset, or -1 if outside file
|
||||
// int OffsetToAddress(int offset) // returns 24-bit address
|
||||
// (although we could also just pass the address map in at Prepare() -- more efficient
|
||||
// if this gets called frequently)
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Data format type.
|
||||
/// </summary>
|
||||
public enum DataType {
|
||||
Unknown = 0,
|
||||
NumericLE,
|
||||
NumericBE,
|
||||
String,
|
||||
Dense,
|
||||
Fill
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Data format sub-type.
|
||||
/// </summary>
|
||||
public enum DataSubType {
|
||||
// No sub-type specified.
|
||||
None = 0,
|
||||
|
||||
// For NumericLE/BE
|
||||
Hex,
|
||||
Decimal,
|
||||
Binary,
|
||||
Ascii,
|
||||
Address,
|
||||
Symbol
|
||||
}
|
||||
}
|
84
PluginCommon/PlatSym.cs
Normal file
84
PluginCommon/PlatSym.cs
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace PluginCommon {
|
||||
/// <summary>
|
||||
/// Symbols loaded from platform symbol files, for use in extension scripts.
|
||||
///
|
||||
/// Instances are immutable.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class PlatSym {
|
||||
public string Label { get; private set; }
|
||||
public int Value { get; private set; }
|
||||
public string Tag { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Nullary constructor, for deserialization.
|
||||
/// </summary>
|
||||
private PlatSym() { }
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="label">Symbol label.</param>
|
||||
/// <param name="value">Symbol value.</param>
|
||||
/// <param name="tag">Symbol group tag.</param>
|
||||
public PlatSym(string label, int value, string tag) {
|
||||
Label = label;
|
||||
Value = value;
|
||||
Tag = tag;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a dictionary of platform symbols, keyed by value. Only symbols with
|
||||
/// a matching tag are included. If more than one symbol has the same value, only
|
||||
/// one will be included; which one it will be is undefined.
|
||||
/// </summary>
|
||||
/// <param name="platSyms">List of platform symbols to select from.</param>
|
||||
/// <param name="tag">Tag to match, or null to collect all symbols.</param>
|
||||
/// <param name="appRef">Application reference, for debug log output.</param>
|
||||
/// <returns></returns>
|
||||
public static Dictionary<int, PlatSym> GenerateValueList(List<PlatSym> platSyms,
|
||||
string tag, IApplication appRef) {
|
||||
Dictionary<int, PlatSym> dict = new Dictionary<int, PlatSym>();
|
||||
|
||||
foreach (PlatSym ps in platSyms) {
|
||||
if (tag == null || tag == ps.Tag) {
|
||||
try {
|
||||
dict.Add(ps.Value, ps);
|
||||
} catch (ArgumentException) {
|
||||
appRef.DebugLog("WARNING: GenerateValueList: multiple entries with " +
|
||||
"value " + ps.Value.ToString("x4"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dict.Count == 0) {
|
||||
appRef.DebugLog("PlatSym: no symbols found for tag=" + tag);
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return Label + "=" + Value.ToString("x4") + " [" + Tag + "]";
|
||||
}
|
||||
}
|
||||
}
|
11
PluginCommon/PluginCommon.csproj
Normal file
11
PluginCommon/PluginCommon.csproj
Normal file
@ -0,0 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\CommonUtil\CommonUtil.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
205
PluginCommon/PluginManager.cs
Normal file
205
PluginCommon/PluginManager.cs
Normal file
@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
|
||||
namespace PluginCommon {
|
||||
/// <summary>
|
||||
/// Manages loaded plugins, in the "remote" AppDomain.
|
||||
/// </summary>
|
||||
public sealed class PluginManager : MarshalByRefObject {
|
||||
/// <summary>
|
||||
/// Collection of instances of active plugins, keyed by script identifier. Other
|
||||
/// plugin assemblies may be present in the AppDomain, but have not been identified
|
||||
/// by the application as being of interest.
|
||||
/// </summary>
|
||||
private Dictionary<string, IPlugin> mActivePlugins = new Dictionary<string, IPlugin>();
|
||||
|
||||
/// <summary>
|
||||
/// Reference to file data.
|
||||
/// </summary>
|
||||
private byte[] mFileData;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Constructor, invoked from CreateInstanceAndUnwrap().
|
||||
/// </summary>
|
||||
public PluginManager() {
|
||||
Debug.WriteLine("PluginManager ctor (id=" + AppDomain.CurrentDomain.Id + ")");
|
||||
|
||||
// Seems to require [SecurityCritical]
|
||||
//Type lsc = Type.GetType("System.Runtime.Remoting.Lifetime.LifetimeServices");
|
||||
//PropertyInfo prop = lsc.GetProperty("LeaseTime");
|
||||
//prop.SetValue(null, TimeSpan.FromSeconds(30));
|
||||
}
|
||||
|
||||
~PluginManager() {
|
||||
Debug.WriteLine("~PluginManager (id=" + AppDomain.CurrentDomain.Id + ")");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the file data to use for all plugins.
|
||||
///
|
||||
/// The file data argument will be an AppDomain-local copy of the data, made by the
|
||||
/// argument marshalling code. So plugins can scribble all over it without trashing
|
||||
/// the original. We want to store it in PluginManager so we don't make a new copy
|
||||
/// for each individual plugin.
|
||||
/// </summary>
|
||||
/// <param name="fileData">65xx code and data.</param>
|
||||
public void SetFileData(byte[] fileData) {
|
||||
mFileData = fileData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests simple round-trip communication. This may be called from an arbitrary thread.
|
||||
/// </summary>
|
||||
public int Ping(int val) {
|
||||
Debug.WriteLine("PluginManager Ping tid=" + Thread.CurrentThread.ManagedThreadId +
|
||||
" (id=" + AppDomain.CurrentDomain.Id + "): " + val);
|
||||
return val + 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a plugin instance from a compiled assembly. Pass in the script identifier
|
||||
/// for future lookups. If the plugin has already been instantiated, that object
|
||||
/// will be returned.
|
||||
/// </summary>
|
||||
/// <param name="dllPath">Full path to compiled assembly.</param>
|
||||
/// <param name="scriptIdent">Identifier to use in e.g. GetPlugin().</param>
|
||||
/// <returns>Reference to plugin instance.</returns>
|
||||
public IPlugin LoadPlugin(string dllPath, string scriptIdent) {
|
||||
if (mActivePlugins.TryGetValue(dllPath, out IPlugin ip)) {
|
||||
Debug.WriteLine("PM: returning cached plugin for " + dllPath);
|
||||
return ip;
|
||||
}
|
||||
|
||||
Assembly asm = Assembly.LoadFile(dllPath);
|
||||
|
||||
foreach (Type type in asm.GetExportedTypes()) {
|
||||
// Using a System.Linq extension method.
|
||||
if (type.IsClass && !type.IsAbstract &&
|
||||
type.GetInterfaces().Contains(typeof(IPlugin))) {
|
||||
|
||||
ConstructorInfo ctor = type.GetConstructor(Type.EmptyTypes);
|
||||
IPlugin iplugin = (IPlugin)ctor.Invoke(null);
|
||||
Debug.WriteLine("PM created instance: " + iplugin);
|
||||
mActivePlugins.Add(scriptIdent, iplugin);
|
||||
return iplugin;
|
||||
}
|
||||
}
|
||||
throw new Exception("No IPlugin class found in " + dllPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an instance of a previously-loaded plugin.
|
||||
/// </summary>
|
||||
/// <param name="scriptIdent">Script identifier that was passed to LoadPlugin().</param>
|
||||
/// <returns>Reference to instance of plugin.</returns>
|
||||
public IPlugin GetPlugin(string scriptIdent) {
|
||||
if (mActivePlugins.TryGetValue(scriptIdent, out IPlugin plugin)) {
|
||||
return plugin;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a string with the assembly's location.
|
||||
/// </summary>
|
||||
public string GetPluginAssemblyLocation(IPlugin plugin) {
|
||||
return plugin.GetType().Assembly.Location;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a list of references to instances of active plugins.
|
||||
/// </summary>
|
||||
/// <returns>Newly-created list of plugin references.</returns>
|
||||
public List<IPlugin> GetActivePlugins() {
|
||||
List<IPlugin> list = new List<IPlugin>(mActivePlugins.Count);
|
||||
foreach (KeyValuePair<string, IPlugin> kvp in mActivePlugins) {
|
||||
list.Add(kvp.Value);
|
||||
}
|
||||
Debug.WriteLine("PluginManager: returning " + list.Count + " plugins (id=" +
|
||||
AppDomain.CurrentDomain.Id + ")");
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the list of loaded plugins. This does not unload the assemblies from
|
||||
/// the AppDomain.
|
||||
/// </summary>
|
||||
public void ClearPluginList() {
|
||||
mActivePlugins.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the Prepare() method on all active plugins.
|
||||
/// </summary>
|
||||
/// <param name="appRef">Reference to host object providing app services.</param>
|
||||
public void PreparePlugins(IApplication appRef, List<PlatSym> platSyms) {
|
||||
foreach (KeyValuePair<string, IPlugin> kvp in mActivePlugins) {
|
||||
kvp.Value.Prepare(appRef, mFileData, platSyms);
|
||||
}
|
||||
}
|
||||
|
||||
#if false
|
||||
/// <summary>
|
||||
/// DEBUG ONLY: establish a fast lease timeout. Normally the lease
|
||||
/// is five minutes; this reduces it to a few seconds. (The actual time is
|
||||
/// also affected by LifetimeServices.LeaseManagerPollTime, which defaults
|
||||
/// to 10 seconds.)
|
||||
///
|
||||
/// Unfortunately this must be tagged [SecurityCritical] to match the method being
|
||||
/// overridden, but in a partially-trusted sandbox that's not allowed. You have
|
||||
/// to relax security entirely for this to work.
|
||||
/// </summary>
|
||||
//[SecurityPermissionAttribute(SecurityAction.Demand,
|
||||
// Flags = SecurityPermissionFlag.Infrastructure)]
|
||||
[System.Security.SecurityCritical]
|
||||
public override object InitializeLifetimeService() {
|
||||
object lease = base.InitializeLifetimeService();
|
||||
|
||||
// netstandard2.0 doesn't have System.Runtime.Remoting.Lifetime, so use reflection
|
||||
PropertyInfo leaseState = lease.GetType().GetProperty("CurrentState");
|
||||
PropertyInfo initialLeaseTime = lease.GetType().GetProperty("InitialLeaseTime");
|
||||
PropertyInfo sponsorshipTimeout = lease.GetType().GetProperty("SponsorshipTimeout");
|
||||
PropertyInfo renewOnCallTime = lease.GetType().GetProperty("RenewOnCallTime");
|
||||
|
||||
Console.WriteLine("Default lease: ini=" +
|
||||
initialLeaseTime.GetValue(lease) + " spon=" +
|
||||
sponsorshipTimeout.GetValue(lease) + " renOC=" +
|
||||
renewOnCallTime.GetValue(lease));
|
||||
|
||||
if ((int)leaseState.GetValue(lease) == 1 /*LeaseState.Initial*/) {
|
||||
// Initial lease duration.
|
||||
initialLeaseTime.SetValue(lease, TimeSpan.FromSeconds(8));
|
||||
|
||||
// How long we will wait for the sponsor to respond
|
||||
// with a lease renewal time.
|
||||
sponsorshipTimeout.SetValue(lease, TimeSpan.FromSeconds(5));
|
||||
|
||||
// Each call to the remote object extends the lease so that
|
||||
// it has at least this much time left.
|
||||
renewOnCallTime.SetValue(lease, TimeSpan.FromSeconds(2));
|
||||
}
|
||||
return lease;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
50
PluginCommon/Util.cs
Normal file
50
PluginCommon/Util.cs
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
|
||||
using CommonUtil;
|
||||
|
||||
namespace PluginCommon {
|
||||
/// <summary>
|
||||
/// Utility functions available for plugins to use.
|
||||
///
|
||||
/// The idea is to make CommonUtil functions available to plugins while isolating
|
||||
/// them from changes to the library. Anything here is guaranteed to keep working,
|
||||
/// while other classes and functions in CommonUtil may change between releases.
|
||||
/// </summary>
|
||||
public static class Util {
|
||||
/// <summary>
|
||||
/// Extracts an integer from the data stream.
|
||||
/// </summary>
|
||||
/// <param name="data">Raw data stream.</param>
|
||||
/// <param name="offset">Start offset.</param>
|
||||
/// <param name="width">Word width, which may be 1-4 bytes.</param>
|
||||
/// <param name="isBigEndian">True if word is in big-endian order.</param>
|
||||
/// <returns>Value found.</returns>
|
||||
public static int GetWord(byte[] data, int offset, int width, bool isBigEndian) {
|
||||
return RawData.GetWord(data, offset, width, isBigEndian);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compute a standard CRC-32 (polynomial 0xedb88320) on a buffer of data.
|
||||
/// </summary>
|
||||
/// <param name="data">Buffer to process.</param>
|
||||
/// <returns>CRC value.</returns>
|
||||
public static uint ComputeBufferCRC(byte[] data) {
|
||||
return CRC32.OnBuffer(0, data, 0, data.Length);
|
||||
}
|
||||
}
|
||||
}
|
107
README.md
107
README.md
@ -1,2 +1,105 @@
|
||||
# 6502bench
|
||||
A workbench for developing 6502 code
|
||||
# 6502bench #
|
||||
|
||||
6502bench is a code development "workbench" for 6502, 65C02, and 65802/65816
|
||||
code. It currently features one tool, the SourceGen disassembler.
|
||||
|
||||
You can download the source code and build it yourself, or click the
|
||||
"Releases" tab near the top of the github page for pre-built downloads.
|
||||
|
||||
|
||||
## SourceGen ##
|
||||
|
||||
SourceGen converts machine-language programs to assembly-language source
|
||||
code. It has most of the features you will find in other 6502 disassemblers,
|
||||
as well as many less-common ones.
|
||||
|
||||
A demo video is available: https://youtu.be/dalISyBPQq8
|
||||
|
||||
#### Features ####
|
||||
|
||||
Analysis:
|
||||
- Support for 6502 (including undocumented opcodes), 65C02, and 65816.
|
||||
- Code flow analyzer traces execution to find all reachable
|
||||
instructions. Hinting mechanism allows manual specification of
|
||||
entry points.
|
||||
- Processor status flags are tracked, allowing automatic detection
|
||||
of branch-always and branch-never, as well as register widths on
|
||||
16-bit CPUs. The analyzer tracks these across subroutine calls and
|
||||
branches. Cycle counts factor these in automatically.
|
||||
- Editable labels are generated for every branch and data target.
|
||||
- Automatic detection and classification of ASCII strings and runs of
|
||||
identical bytes.
|
||||
- All target-platform-specific stuff is stored in plain text files
|
||||
loaded at runtime. This includes symbols for ROM entry points
|
||||
and standard zero-page locations. Additional symbols and overrides
|
||||
can be specified at the project level.
|
||||
- Extension scripts can be used to reformat code and identify inline
|
||||
data that follows JSR/JSL. Code is compiled at run time and
|
||||
executes in a sandbox.
|
||||
|
||||
UI:
|
||||
- Fully interactive point-and-click GUI. Add labels and multi-line
|
||||
comments, change addresses, and see the changes immediately.
|
||||
- Instruction operand formats (hex, decimal, etc) can be set for
|
||||
individual lines. Symbols that don't match the operands are automatically
|
||||
offset, allowing simple expressions like "address - 1".
|
||||
- Full-line comments are automatically word-wrapped, and can be
|
||||
"boxed" for an authentic retro feel.
|
||||
- Data areas can be formatted as bytes, words, addresses, and more.
|
||||
Several types of strings are recognized (null-terminated, length
|
||||
prefixed, etc).
|
||||
- "Infinite" undo/redo of all actions.
|
||||
- Notes can be added that aren't included in generated output. Very
|
||||
useful for marking up a work in progress.
|
||||
- Cross-reference tables are generated for every branch and data
|
||||
target address, as well as for external platform symbols.
|
||||
- Instruction summaries, including cpu cycles and flags modified, are
|
||||
shown along with a description of the opcode function.
|
||||
- Display is configurable for upper/lower case, choice of pseudo-op
|
||||
names, expression formats, and more.
|
||||
|
||||
Output:
|
||||
- Assembly source can be generated for multiple assemblers (currently
|
||||
cc65 and Merlin 32).
|
||||
- Cross-assemblers can be launched directly from the generation GUI to
|
||||
verify output correctness.
|
||||
- Optional automatic conversion of labels from global to local.
|
||||
- Symbols may be exported from one project and imported into another
|
||||
to facilitate multi-binary disassembly.
|
||||
|
||||
Misc:
|
||||
- Preset project attributes (CPU type, platform symbol file sets) are defined
|
||||
for a variety of platforms.
|
||||
- Project file is stored in a text format, and only holds metadata. None
|
||||
of the original file is included, allowing the project file to be shared
|
||||
without violating copyrights (note: may vary depending on local laws).
|
||||
|
||||
There are a couple of significant areas where support is currently lacking:
|
||||
- Poor support for multi-bank 65816 files (IIgs OMF, SNES).
|
||||
- No support for alternate character sets (e.g. PETSCII).
|
||||
|
||||
|
||||
## About the Code ##
|
||||
|
||||
All of the code is written in C# .NET, using the (free to download) Visual
|
||||
Studio Community 2017 IDE as the primary development environment. The user
|
||||
interface uses the WinForms API. Efforts have been made to avoid doing
|
||||
anything Windows-specific, in the hope that the applications will be
|
||||
straightforward to port to other platforms.
|
||||
|
||||
The solution is called "WorkBench.sln" rather than "6502bench.sln" because
|
||||
some things in Visual Studio got weird when it didn't start with a letter.
|
||||
|
||||
The code style is closer to what Android uses than "standard" C#. Lines
|
||||
are folded to fit 100 columns.
|
||||
|
||||
The source code is licensed under Apache 2.0
|
||||
(http://www.apache.org/licenses/LICENSE-2.0), which makes it free for use in
|
||||
both open-source programs and closed-source commercial software. The license
|
||||
terms are similar to BSD or MIT, but with some additional constraints on
|
||||
patent licensing. (This is the same license Google uses for the Android
|
||||
Open Source Project.)
|
||||
|
||||
Images are licensed under Creative Commons ShareAlike 4.0 International
|
||||
(https://creativecommons.org/licenses/by-sa/4.0/).
|
||||
|
||||
|
284
SourceGen/AddressMap.cs
Normal file
284
SourceGen/AddressMap.cs
Normal file
@ -0,0 +1,284 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace SourceGen {
|
||||
/// <summary>
|
||||
/// Map file offsets to 65xx addresses and vice-versa. Useful for sources with
|
||||
/// multiple ORG directives.
|
||||
///
|
||||
/// It's possible to generate code that would overlap once relocated at run time,
|
||||
/// which means a given address could map to multiple offsets. For this reason
|
||||
/// it's useful to know the offset of the referring code when evaluating a
|
||||
/// reference, so that a "local" match can take priority.
|
||||
/// </summary>
|
||||
public class AddressMap : IEnumerable<AddressMap.AddressMapEntry> {
|
||||
/// <summary>
|
||||
/// Code starting at the specified offset will have the specified address.
|
||||
///
|
||||
/// The entries are held in the list in order, sorted by offset, with no gaps.
|
||||
/// This makes the "length" field redundant, as it can be computed by
|
||||
/// (entry[N+1].mOffset - entry[N].mOffset), with a special case for the last
|
||||
/// entry in the list. It's convenient to maintain it explicitly however, as
|
||||
/// the list is read far more often than it is updated.
|
||||
///
|
||||
/// Entries are mutable, but must only be altered by AddressMap. Don't retain
|
||||
/// instances of this across other activity.
|
||||
/// </summary>
|
||||
public class AddressMapEntry {
|
||||
public int Offset { get; set; }
|
||||
public int Addr { get; set; }
|
||||
public int Length { get; set; }
|
||||
|
||||
public AddressMapEntry(int offset, int addr, int len) {
|
||||
Offset = offset;
|
||||
Addr = addr;
|
||||
Length = len;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Total length, in bytes, spanned by this map.
|
||||
/// </summary>
|
||||
private int mTotalLength;
|
||||
|
||||
/// <summary>
|
||||
/// List of definitions, in sorted order.
|
||||
/// </summary>
|
||||
private List<AddressMapEntry> mAddrList = new List<AddressMapEntry>();
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="length">Total length, in bytes, spanned by this map.</param>
|
||||
public AddressMap(int length) {
|
||||
/// There must always be at least one entry, defining the target address
|
||||
/// for file offset 0. This can be changed, but can't be removed.
|
||||
mTotalLength = length;
|
||||
mAddrList.Add(new AddressMapEntry(0, 0, length));
|
||||
}
|
||||
|
||||
// IEnumerable
|
||||
public IEnumerator<AddressMapEntry> GetEnumerator() {
|
||||
return ((IEnumerable<AddressMapEntry>)mAddrList).GetEnumerator();
|
||||
}
|
||||
|
||||
// IEnumerable
|
||||
IEnumerator IEnumerable.GetEnumerator() {
|
||||
return ((IEnumerable<AddressMapEntry>)mAddrList).GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the address map entry index associated with the specified offset, or -1
|
||||
/// if there is no address map entry there.
|
||||
/// </summary>
|
||||
public int Get(int offset) {
|
||||
foreach (AddressMapEntry ad in mAddrList) {
|
||||
if (ad.Offset == offset) {
|
||||
return ad.Addr;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds, updates, or removes a map entry.
|
||||
/// </summary>
|
||||
/// <param name="offset">File offset at which the address changes.</param>
|
||||
/// <param name="addr">24-bit address.</param>
|
||||
public void Set(int offset, int addr) {
|
||||
Debug.Assert(offset >= 0);
|
||||
if (addr == -1) {
|
||||
if (offset != 0) { // ignore attempts to remove entry at offset zero
|
||||
Remove(offset);
|
||||
}
|
||||
return;
|
||||
}
|
||||
Debug.Assert(addr >= 0 && addr < 0x01000000); // 24-bit address space
|
||||
|
||||
int i;
|
||||
for (i = 0; i < mAddrList.Count; i++) {
|
||||
AddressMapEntry ad = mAddrList[i];
|
||||
if (ad.Offset == offset) {
|
||||
// update existing
|
||||
ad.Addr = addr;
|
||||
mAddrList[i] = ad;
|
||||
return;
|
||||
} else if (ad.Offset > offset) {
|
||||
// The i'th entry is one past the interesting part.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Carve a chunk out of the previous entry.
|
||||
AddressMapEntry prev = mAddrList[i - 1];
|
||||
int prevOldLen = prev.Length;
|
||||
int prevNewLen = offset - prev.Offset;
|
||||
prev.Length = prevNewLen;
|
||||
mAddrList[i - 1] = prev;
|
||||
|
||||
mAddrList.Insert(i,
|
||||
new AddressMapEntry(offset, addr, prevOldLen - prevNewLen));
|
||||
|
||||
DebugValidate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes an entry from the set.
|
||||
/// </summary>
|
||||
/// <param name="offset">The initial offset of the mapping to remove. This
|
||||
/// must be the initial value, not a mid-range value.</param>
|
||||
/// <returns>True if something was removed.</returns>
|
||||
public bool Remove(int offset) {
|
||||
if (offset == 0) {
|
||||
throw new Exception("Not allowed to remove entry 0");
|
||||
}
|
||||
|
||||
for (int i = 1; i < mAddrList.Count; i++) {
|
||||
if (mAddrList[i].Offset == offset) {
|
||||
// Add the length to the previous entry.
|
||||
AddressMapEntry prev = mAddrList[i - 1];
|
||||
prev.Length += mAddrList[i].Length;
|
||||
mAddrList[i - 1] = prev;
|
||||
|
||||
mAddrList.RemoveAt(i);
|
||||
DebugValidate();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the index of the address map entry that contains the given offset.
|
||||
/// We assume the offset is valid.
|
||||
/// </summary>
|
||||
private int IndexForOffset(int offset) {
|
||||
for (int i = 1; i < mAddrList.Count; i++) {
|
||||
if (mAddrList[i].Offset > offset) {
|
||||
return i - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return mAddrList.Count - 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given address falls into the range spanned by the
|
||||
/// address map entry.
|
||||
/// </summary>
|
||||
/// <param name="index">Address map entry index.</param>
|
||||
/// <param name="addr">Address to check.</param>
|
||||
/// <returns></returns>
|
||||
private bool IndexContainsAddress(int index, int addr) {
|
||||
return addr >= mAddrList[index].Addr &&
|
||||
addr < mAddrList[index].Addr + mAddrList[index].Length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines the file offset that best contains the specified target address.
|
||||
/// </summary>
|
||||
/// <param name="srcOffset">Offset of the address reference.</param>
|
||||
/// <param name="targetAddr">Address to look up.</param>
|
||||
/// <returns>The file offset, or -1 if the address falls outside the file.</returns>
|
||||
public int AddressToOffset(int srcOffset, int targetAddr) {
|
||||
if (mAddrList.Count == 1) {
|
||||
// Trivial case.
|
||||
if (IndexContainsAddress(0, targetAddr)) {
|
||||
Debug.Assert(targetAddr >= mAddrList[0].Addr);
|
||||
return targetAddr - mAddrList[0].Addr;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// We have multiple, potentially overlapping address ranges. Start by
|
||||
// looking for a match in the srcOffset range; if that fails, scan
|
||||
// forward from the start.
|
||||
int srcOffIndex = IndexForOffset(srcOffset);
|
||||
if (IndexContainsAddress(srcOffIndex, targetAddr)) {
|
||||
Debug.Assert(targetAddr >= mAddrList[srcOffIndex].Addr);
|
||||
return (targetAddr - mAddrList[srcOffIndex].Addr) + mAddrList[srcOffIndex].Offset;
|
||||
}
|
||||
|
||||
for (int i = 0; i < mAddrList.Count; i++) {
|
||||
if (i == srcOffIndex) {
|
||||
// optimization -- we already checked this one
|
||||
continue;
|
||||
}
|
||||
if (IndexContainsAddress(i, targetAddr)) {
|
||||
Debug.Assert(targetAddr >= mAddrList[i].Addr);
|
||||
return (targetAddr - mAddrList[i].Addr) + mAddrList[i].Offset;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a file offset to an address.
|
||||
/// </summary>
|
||||
/// <param name="offset">File offset.</param>
|
||||
/// <returns>24-bit address.</returns>
|
||||
public int OffsetToAddress(int offset) {
|
||||
int srcOffIndex = IndexForOffset(offset);
|
||||
return mAddrList[srcOffIndex].Addr + (offset - mAddrList[srcOffIndex].Offset);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Internal consistency checks.
|
||||
/// </summary>
|
||||
private void DebugValidate() {
|
||||
if (mAddrList.Count < 1) {
|
||||
throw new Exception("AddressMap: empty");
|
||||
}
|
||||
if (mAddrList[0].Offset != 0) {
|
||||
throw new Exception("AddressMap: bad offset 0");
|
||||
}
|
||||
|
||||
if (mAddrList.Count == 1) {
|
||||
if (mAddrList[0].Length != mTotalLength) {
|
||||
throw new Exception("AddressMap: single entry len bad");
|
||||
}
|
||||
} else {
|
||||
int totalLen = 0;
|
||||
for (int i = 0; i < mAddrList.Count; i++) {
|
||||
AddressMapEntry ent = mAddrList[i];
|
||||
if (i != 0) {
|
||||
if (ent.Offset != mAddrList[i - 1].Offset + mAddrList[i - 1].Length) {
|
||||
throw new Exception("Bad offset step to " + i);
|
||||
}
|
||||
}
|
||||
|
||||
totalLen += ent.Length;
|
||||
}
|
||||
|
||||
if (totalLen != mTotalLength) {
|
||||
throw new Exception("AddressMap: bad length sum (" + totalLen + " vs " +
|
||||
mTotalLength + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return "[AddressMap: " + mAddrList.Count + " entries]";
|
||||
}
|
||||
}
|
||||
}
|
355
SourceGen/Anattrib.cs
Normal file
355
SourceGen/Anattrib.cs
Normal file
@ -0,0 +1,355 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
|
||||
using Asm65;
|
||||
|
||||
namespace SourceGen {
|
||||
/// <summary>
|
||||
/// Analyzer attribute holder. Contains the output of the instruction and data analyzers.
|
||||
/// Every byte in the input file has one of these associated with it.
|
||||
///
|
||||
/// (Yes, it's a mutable struct. Yes, that fact has bitten me a few times. The array
|
||||
/// of these may have millions of elements, so the reduction in overhead seems worthwhile.)
|
||||
/// </summary>
|
||||
public struct Anattrib {
|
||||
[FlagsAttribute]
|
||||
private enum AttribFlags {
|
||||
InstrStart = 1 << 0, // byte is first of an instruction
|
||||
Instruction = 1 << 1, // byte is part of an instruction or inline data
|
||||
InlineData = 1 << 2, // byte is inline data
|
||||
Data = 1 << 3, // byte is data
|
||||
|
||||
EntryPoint = 1 << 8, // external code branches here
|
||||
BranchTarget = 1 << 9, // internal code branches here
|
||||
ExternalBranch = 1 << 10, // this abs/rel branch lands outside input file
|
||||
|
||||
NoContinue = 1 << 12, // execution does not continue to following instruction
|
||||
|
||||
Visited = 1 << 16, // has the analyzer visited this byte?
|
||||
Changed = 1 << 17, // set/cleared as the analyzer works
|
||||
|
||||
Hinted = 1 << 18, // was this byte affected by a type hint?
|
||||
}
|
||||
|
||||
// Flags indicating what type of data is here. Use the following Is* properties
|
||||
// to set/clear.
|
||||
private AttribFlags mAttribFlags;
|
||||
|
||||
public bool IsInstructionStart {
|
||||
get {
|
||||
return (mAttribFlags & AttribFlags.InstrStart) != 0;
|
||||
}
|
||||
set {
|
||||
IsInstruction = value;
|
||||
if (value) {
|
||||
mAttribFlags |= AttribFlags.InstrStart;
|
||||
} else {
|
||||
mAttribFlags &= ~AttribFlags.InstrStart;
|
||||
}
|
||||
}
|
||||
}
|
||||
public bool IsInstruction {
|
||||
get {
|
||||
return (mAttribFlags & AttribFlags.Instruction) != 0;
|
||||
}
|
||||
set {
|
||||
Debug.Assert(value == false ||
|
||||
(mAttribFlags & (AttribFlags.InlineData | AttribFlags.Data)) == 0);
|
||||
if (value) {
|
||||
mAttribFlags |= AttribFlags.Instruction;
|
||||
} else {
|
||||
mAttribFlags &= ~AttribFlags.Instruction;
|
||||
}
|
||||
}
|
||||
}
|
||||
public bool IsInlineData {
|
||||
get {
|
||||
return (mAttribFlags & AttribFlags.InlineData) != 0;
|
||||
}
|
||||
set {
|
||||
Debug.Assert(value == false ||
|
||||
(mAttribFlags & (AttribFlags.Instruction | AttribFlags.Data)) == 0);
|
||||
if (value) {
|
||||
mAttribFlags |= AttribFlags.InlineData;
|
||||
} else {
|
||||
mAttribFlags &= ~AttribFlags.InlineData;
|
||||
}
|
||||
}
|
||||
}
|
||||
public bool IsData {
|
||||
get {
|
||||
return (mAttribFlags & AttribFlags.Data) != 0;
|
||||
}
|
||||
set {
|
||||
Debug.Assert(value == false ||
|
||||
(mAttribFlags & (AttribFlags.InlineData | AttribFlags.Instruction)) == 0);
|
||||
if (value) {
|
||||
mAttribFlags |= AttribFlags.Data;
|
||||
} else {
|
||||
mAttribFlags &= ~AttribFlags.Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
public bool IsStart {
|
||||
get {
|
||||
return IsInstructionStart || IsDataStart || IsInlineDataStart;
|
||||
}
|
||||
}
|
||||
public bool IsEntryPoint {
|
||||
get {
|
||||
return (mAttribFlags & AttribFlags.EntryPoint) != 0;
|
||||
}
|
||||
set {
|
||||
if (value) {
|
||||
mAttribFlags |= AttribFlags.EntryPoint;
|
||||
} else {
|
||||
mAttribFlags &= ~AttribFlags.EntryPoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
public bool IsBranchTarget {
|
||||
get {
|
||||
return (mAttribFlags & AttribFlags.BranchTarget) != 0;
|
||||
}
|
||||
set {
|
||||
if (value) {
|
||||
mAttribFlags |= AttribFlags.BranchTarget;
|
||||
} else {
|
||||
mAttribFlags &= ~AttribFlags.BranchTarget;
|
||||
}
|
||||
}
|
||||
}
|
||||
public bool IsExternalBranch {
|
||||
get {
|
||||
return (mAttribFlags & AttribFlags.ExternalBranch) != 0;
|
||||
}
|
||||
set {
|
||||
if (value) {
|
||||
mAttribFlags |= AttribFlags.ExternalBranch;
|
||||
} else {
|
||||
mAttribFlags &= ~AttribFlags.ExternalBranch;
|
||||
}
|
||||
}
|
||||
}
|
||||
public bool DoesNotContinue {
|
||||
get {
|
||||
return (mAttribFlags & AttribFlags.NoContinue) != 0;
|
||||
}
|
||||
set {
|
||||
if (value) {
|
||||
mAttribFlags |= AttribFlags.NoContinue;
|
||||
} else {
|
||||
mAttribFlags &= ~AttribFlags.NoContinue;
|
||||
}
|
||||
}
|
||||
}
|
||||
public bool DoesNotBranch {
|
||||
get {
|
||||
return (BranchTaken == OpDef.BranchTaken.Never);
|
||||
}
|
||||
}
|
||||
public bool IsVisited {
|
||||
get {
|
||||
return (mAttribFlags & AttribFlags.Visited) != 0;
|
||||
}
|
||||
set {
|
||||
if (value) {
|
||||
mAttribFlags |= AttribFlags.Visited;
|
||||
} else {
|
||||
mAttribFlags &= ~AttribFlags.Visited;
|
||||
}
|
||||
}
|
||||
}
|
||||
public bool IsChanged {
|
||||
get {
|
||||
return (mAttribFlags & AttribFlags.Changed) != 0;
|
||||
}
|
||||
set {
|
||||
if (value) {
|
||||
mAttribFlags |= AttribFlags.Changed;
|
||||
} else {
|
||||
mAttribFlags &= ~AttribFlags.Changed;
|
||||
}
|
||||
}
|
||||
}
|
||||
public bool IsHinted {
|
||||
get {
|
||||
return (mAttribFlags & AttribFlags.Hinted) != 0;
|
||||
}
|
||||
set {
|
||||
if (value) {
|
||||
mAttribFlags |= AttribFlags.Hinted;
|
||||
} else {
|
||||
mAttribFlags &= ~AttribFlags.Hinted;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsDataStart {
|
||||
get {
|
||||
return IsData && DataDescriptor != null;
|
||||
}
|
||||
}
|
||||
public bool IsInlineDataStart {
|
||||
get {
|
||||
return IsInlineData && DataDescriptor != null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the target memory address for this byte.
|
||||
/// </summary>
|
||||
public int Address { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Instructions: length of the instruction (for InstrStart). If a FormatDescriptor
|
||||
/// is assigned, the length must match.
|
||||
/// Inline data: FormatDescriptor length, or zero if no descriptor is defined.
|
||||
/// Data: FormatDescriptor length, or zero if no descriptor is defined.
|
||||
///
|
||||
/// This field should only be set by CodeAnalysis methods, although the "get" value
|
||||
/// can be changed for data/inline-data by setting the DataDescriptor field.
|
||||
/// </summary>
|
||||
public int Length {
|
||||
get {
|
||||
// For data we don't even use the field; this ensures that we're always
|
||||
// using the FormatDescriptor's length.
|
||||
if (IsData || IsInlineData) {
|
||||
Debug.Assert(mLength == 0);
|
||||
if (DataDescriptor != null) {
|
||||
return DataDescriptor.Length;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return mLength;
|
||||
}
|
||||
set {
|
||||
Debug.Assert(!IsData);
|
||||
mLength = value;
|
||||
}
|
||||
}
|
||||
private int mLength;
|
||||
|
||||
/// <summary>
|
||||
/// Instructions only: processor status flags.
|
||||
///
|
||||
/// Note this returns a copy of a struct, so modifications to the returned value
|
||||
/// (including calls to Merge and Apply) are not permanent.
|
||||
/// </summary>
|
||||
public StatusFlags StatusFlags {
|
||||
get { return mStatusFlags; }
|
||||
set { mStatusFlags = value; }
|
||||
}
|
||||
private StatusFlags mStatusFlags;
|
||||
|
||||
public void MergeStatusFlags(StatusFlags other) {
|
||||
mStatusFlags.Merge(other);
|
||||
}
|
||||
public void ApplyStatusFlags(StatusFlags other) {
|
||||
mStatusFlags.Apply(other);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Branch instructions only: outcome of branch.
|
||||
/// </summary>
|
||||
public OpDef.BranchTaken BranchTaken { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Instructions only: decoded operand address value. Will be -1 if not
|
||||
/// yet computed or not applicable. For a relative branch instruction,
|
||||
/// this will have the absolute branch target address. On the 65816, this
|
||||
/// will be a 24-bit address.
|
||||
/// </summary>
|
||||
public int OperandAddress {
|
||||
get { return mOperandAddressSet ? mOperandAddress : -1; }
|
||||
set {
|
||||
Debug.Assert(mOperandAddress >= -1);
|
||||
mOperandAddress = value;
|
||||
mOperandAddressSet = (value >= 0);
|
||||
}
|
||||
}
|
||||
private int mOperandAddress;
|
||||
private bool mOperandAddressSet;
|
||||
|
||||
/// <summary>
|
||||
/// Instructions only: offset referenced by OperandAddress. Will be -1 if not
|
||||
/// yet computed, not applicable, or if OperandAddress refers to a location
|
||||
/// outside the scope of the file.
|
||||
/// </summary>
|
||||
public int OperandOffset {
|
||||
get { return mOperandOffsetSet ? mOperandOffset : -1; }
|
||||
set {
|
||||
Debug.Assert(mOperandOffset >= -1);
|
||||
mOperandOffset = value;
|
||||
mOperandOffsetSet = (value >= 0);
|
||||
}
|
||||
}
|
||||
private int mOperandOffset;
|
||||
private bool mOperandOffsetSet;
|
||||
|
||||
/// <summary>
|
||||
/// Instructions only: is OperandOffset a direct target offset? (This is used when
|
||||
/// tracing jump instructions, to know if we should add the offset to the scan list.
|
||||
/// It's determined by the opcode, e.g. "JMP addr" -> true, "JMP (addr,X)" -> false.)
|
||||
/// </summary>
|
||||
public bool IsOperandOffsetDirect { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Symbol defined as the label for this offset. All offsets that are instruction
|
||||
/// or data target offsets will have one of these defined. Users can define additional
|
||||
/// symbols as well.
|
||||
///
|
||||
/// Will be null if no label is defined for this offset.
|
||||
/// </summary>
|
||||
public Symbol Symbol { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Format descriptor for operands and data items. Will be null if no descriptor
|
||||
/// is defined for this offset.
|
||||
/// </summary>
|
||||
public FormatDescriptor DataDescriptor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is this an instruction with an operand (i.e. not impl/acc)?
|
||||
/// </summary>
|
||||
public bool IsInstructionWithOperand {
|
||||
get {
|
||||
if (!IsInstructionStart) {
|
||||
return false;
|
||||
}
|
||||
return Length != 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a fixed-width string with indicators for items of interest.
|
||||
/// </summary>
|
||||
public string ToAttrString() {
|
||||
StringBuilder sb = new StringBuilder(5);
|
||||
char blank = '.';
|
||||
sb.Append(IsEntryPoint ? '@' : blank);
|
||||
sb.Append(IsHinted ? 'H' : blank);
|
||||
sb.Append(DoesNotBranch ? '!' : blank);
|
||||
sb.Append(DoesNotContinue ? '#' : blank);
|
||||
sb.Append(IsBranchTarget ? '>' : blank);
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
6
SourceGen/App.config
Normal file
6
SourceGen/App.config
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
|
||||
</startup>
|
||||
</configuration>
|
187
SourceGen/AppForms/AboutBox.Designer.cs
generated
Normal file
187
SourceGen/AppForms/AboutBox.Designer.cs
generated
Normal file
@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
namespace SourceGen.AppForms {
|
||||
partial class AboutBox {
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing) {
|
||||
if (disposing && (components != null)) {
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent() {
|
||||
this.boardPictureBox = new System.Windows.Forms.PictureBox();
|
||||
this.sourceGenLabel = new System.Windows.Forms.Label();
|
||||
this.versionLabel = new System.Windows.Forms.Label();
|
||||
this.createdLabel = new System.Windows.Forms.Label();
|
||||
this.okButton = new System.Windows.Forms.Button();
|
||||
this.legalStuffTextBox = new System.Windows.Forms.TextBox();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.osPlatformLabel = new System.Windows.Forms.Label();
|
||||
this.debugEnabledLabel = new System.Windows.Forms.Label();
|
||||
((System.ComponentModel.ISupportInitialize)(this.boardPictureBox)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// boardPictureBox
|
||||
//
|
||||
this.boardPictureBox.Location = new System.Drawing.Point(13, 13);
|
||||
this.boardPictureBox.Name = "boardPictureBox";
|
||||
this.boardPictureBox.Size = new System.Drawing.Size(320, 236);
|
||||
this.boardPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
|
||||
this.boardPictureBox.TabIndex = 0;
|
||||
this.boardPictureBox.TabStop = false;
|
||||
//
|
||||
// sourceGenLabel
|
||||
//
|
||||
this.sourceGenLabel.AutoSize = true;
|
||||
this.sourceGenLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 24F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.sourceGenLabel.Location = new System.Drawing.Point(340, 13);
|
||||
this.sourceGenLabel.Name = "sourceGenLabel";
|
||||
this.sourceGenLabel.Size = new System.Drawing.Size(349, 37);
|
||||
this.sourceGenLabel.TabIndex = 1;
|
||||
this.sourceGenLabel.Text = "6502bench SourceGen";
|
||||
//
|
||||
// versionLabel
|
||||
//
|
||||
this.versionLabel.AutoSize = true;
|
||||
this.versionLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 20.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.versionLabel.Location = new System.Drawing.Point(340, 60);
|
||||
this.versionLabel.Name = "versionLabel";
|
||||
this.versionLabel.Size = new System.Drawing.Size(273, 31);
|
||||
this.versionLabel.TabIndex = 2;
|
||||
this.versionLabel.Text = "Version X.Y.Z Alpha1";
|
||||
//
|
||||
// createdLabel
|
||||
//
|
||||
this.createdLabel.AutoSize = true;
|
||||
this.createdLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.createdLabel.Location = new System.Drawing.Point(407, 142);
|
||||
this.createdLabel.Name = "createdLabel";
|
||||
this.createdLabel.Size = new System.Drawing.Size(206, 40);
|
||||
this.createdLabel.TabIndex = 3;
|
||||
this.createdLabel.Text = "Copyright 2018 faddenSoft\r\nCreated by Andy McFadden\r\n";
|
||||
//
|
||||
// okButton
|
||||
//
|
||||
this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.okButton.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.okButton.Location = new System.Drawing.Point(617, 526);
|
||||
this.okButton.Name = "okButton";
|
||||
this.okButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.okButton.TabIndex = 0;
|
||||
this.okButton.Text = "OK";
|
||||
this.okButton.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// legalStuffTextBox
|
||||
//
|
||||
this.legalStuffTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.legalStuffTextBox.Location = new System.Drawing.Point(12, 305);
|
||||
this.legalStuffTextBox.MaxLength = 0;
|
||||
this.legalStuffTextBox.Multiline = true;
|
||||
this.legalStuffTextBox.Name = "legalStuffTextBox";
|
||||
this.legalStuffTextBox.ReadOnly = true;
|
||||
this.legalStuffTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
|
||||
this.legalStuffTextBox.Size = new System.Drawing.Size(680, 215);
|
||||
this.legalStuffTextBox.TabIndex = 4;
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(12, 289);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(59, 13);
|
||||
this.label1.TabIndex = 5;
|
||||
this.label1.Text = "Legal stuff:";
|
||||
//
|
||||
// osPlatformLabel
|
||||
//
|
||||
this.osPlatformLabel.AutoSize = true;
|
||||
this.osPlatformLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.osPlatformLabel.Location = new System.Drawing.Point(12, 263);
|
||||
this.osPlatformLabel.Name = "osPlatformLabel";
|
||||
this.osPlatformLabel.Size = new System.Drawing.Size(86, 16);
|
||||
this.osPlatformLabel.TabIndex = 6;
|
||||
this.osPlatformLabel.Text = "[OS platform]";
|
||||
//
|
||||
// debugEnabledLabel
|
||||
//
|
||||
this.debugEnabledLabel.AutoSize = true;
|
||||
this.debugEnabledLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.debugEnabledLabel.Location = new System.Drawing.Point(340, 233);
|
||||
this.debugEnabledLabel.Name = "debugEnabledLabel";
|
||||
this.debugEnabledLabel.Size = new System.Drawing.Size(293, 16);
|
||||
this.debugEnabledLabel.TabIndex = 7;
|
||||
this.debugEnabledLabel.Text = "Assertions and extended validation are enabled";
|
||||
this.debugEnabledLabel.Visible = false;
|
||||
//
|
||||
// AboutBox
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(704, 561);
|
||||
this.Controls.Add(this.debugEnabledLabel);
|
||||
this.Controls.Add(this.osPlatformLabel);
|
||||
this.Controls.Add(this.label1);
|
||||
this.Controls.Add(this.legalStuffTextBox);
|
||||
this.Controls.Add(this.okButton);
|
||||
this.Controls.Add(this.createdLabel);
|
||||
this.Controls.Add(this.versionLabel);
|
||||
this.Controls.Add(this.sourceGenLabel);
|
||||
this.Controls.Add(this.boardPictureBox);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "AboutBox";
|
||||
this.ShowInTaskbar = false;
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "AboutBox";
|
||||
this.Load += new System.EventHandler(this.AboutBox_Load);
|
||||
((System.ComponentModel.ISupportInitialize)(this.boardPictureBox)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.PictureBox boardPictureBox;
|
||||
private System.Windows.Forms.Label sourceGenLabel;
|
||||
private System.Windows.Forms.Label versionLabel;
|
||||
private System.Windows.Forms.Label createdLabel;
|
||||
private System.Windows.Forms.Button okButton;
|
||||
private System.Windows.Forms.TextBox legalStuffTextBox;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.Label osPlatformLabel;
|
||||
private System.Windows.Forms.Label debugEnabledLabel;
|
||||
}
|
||||
}
|
51
SourceGen/AppForms/AboutBox.cs
Normal file
51
SourceGen/AppForms/AboutBox.cs
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace SourceGen.AppForms {
|
||||
public partial class AboutBox : Form {
|
||||
private const string IMAGE_FILE_NAME = "AboutImage.png";
|
||||
private const string LEGAL_STUFF_FILE_NAME = "LegalStuff.txt";
|
||||
|
||||
public AboutBox() {
|
||||
InitializeComponent();
|
||||
|
||||
boardPictureBox.ImageLocation = RuntimeDataAccess.GetPathName(IMAGE_FILE_NAME);
|
||||
versionLabel.Text = string.Format(Properties.Resources.VERSION_FMT,
|
||||
Program.ProgramVersion);
|
||||
|
||||
osPlatformLabel.Text = "OS: " +
|
||||
System.Runtime.InteropServices.RuntimeInformation.OSDescription;
|
||||
#if DEBUG
|
||||
debugEnabledLabel.Visible = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
private void AboutBox_Load(object sender, EventArgs e) {
|
||||
string text;
|
||||
string pathName = RuntimeDataAccess.GetPathName(LEGAL_STUFF_FILE_NAME);
|
||||
try {
|
||||
text = File.ReadAllText(pathName);
|
||||
} catch (Exception ex) {
|
||||
text = ex.ToString();
|
||||
}
|
||||
|
||||
legalStuffTextBox.Text = text;
|
||||
}
|
||||
}
|
||||
}
|
120
SourceGen/AppForms/AboutBox.resx
Normal file
120
SourceGen/AppForms/AboutBox.resx
Normal file
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
143
SourceGen/AppForms/DataFileLoadIssue.Designer.cs
generated
Normal file
143
SourceGen/AppForms/DataFileLoadIssue.Designer.cs
generated
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
namespace SourceGen.AppForms {
|
||||
partial class DataFileLoadIssue {
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing) {
|
||||
if (disposing && (components != null)) {
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent() {
|
||||
this.problemWithFileLabel = new System.Windows.Forms.Label();
|
||||
this.pathNameTextBox = new System.Windows.Forms.TextBox();
|
||||
this.problemLabel = new System.Windows.Forms.Label();
|
||||
this.cancelButton = new System.Windows.Forms.Button();
|
||||
this.okButton = new System.Windows.Forms.Button();
|
||||
this.doYouWantLabel = new System.Windows.Forms.Label();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// problemWithFileLabel
|
||||
//
|
||||
this.problemWithFileLabel.AutoSize = true;
|
||||
this.problemWithFileLabel.Location = new System.Drawing.Point(13, 13);
|
||||
this.problemWithFileLabel.Name = "problemWithFileLabel";
|
||||
this.problemWithFileLabel.Size = new System.Drawing.Size(221, 13);
|
||||
this.problemWithFileLabel.TabIndex = 2;
|
||||
this.problemWithFileLabel.Text = "There was an error while loading the data file:";
|
||||
//
|
||||
// pathNameTextBox
|
||||
//
|
||||
this.pathNameTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.pathNameTextBox.Location = new System.Drawing.Point(13, 39);
|
||||
this.pathNameTextBox.Name = "pathNameTextBox";
|
||||
this.pathNameTextBox.ReadOnly = true;
|
||||
this.pathNameTextBox.Size = new System.Drawing.Size(488, 20);
|
||||
this.pathNameTextBox.TabIndex = 3;
|
||||
//
|
||||
// problemLabel
|
||||
//
|
||||
this.problemLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.problemLabel.Location = new System.Drawing.Point(13, 73);
|
||||
this.problemLabel.Name = "problemLabel";
|
||||
this.problemLabel.Size = new System.Drawing.Size(488, 31);
|
||||
this.problemLabel.TabIndex = 4;
|
||||
//
|
||||
// cancelButton
|
||||
//
|
||||
this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.cancelButton.Location = new System.Drawing.Point(428, 113);
|
||||
this.cancelButton.Name = "cancelButton";
|
||||
this.cancelButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.cancelButton.TabIndex = 1;
|
||||
this.cancelButton.Text = "Cancel";
|
||||
this.cancelButton.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// okButton
|
||||
//
|
||||
this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.okButton.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.okButton.Location = new System.Drawing.Point(347, 113);
|
||||
this.okButton.Name = "okButton";
|
||||
this.okButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.okButton.TabIndex = 0;
|
||||
this.okButton.Text = "OK";
|
||||
this.okButton.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// doYouWantLabel
|
||||
//
|
||||
this.doYouWantLabel.AutoSize = true;
|
||||
this.doYouWantLabel.Location = new System.Drawing.Point(13, 117);
|
||||
this.doYouWantLabel.Name = "doYouWantLabel";
|
||||
this.doYouWantLabel.Size = new System.Drawing.Size(175, 13);
|
||||
this.doYouWantLabel.TabIndex = 5;
|
||||
this.doYouWantLabel.Text = "Do you want to locate the data file?\r\n";
|
||||
//
|
||||
// DataFileLoadIssue
|
||||
//
|
||||
this.AcceptButton = this.okButton;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.CancelButton = this.cancelButton;
|
||||
this.ClientSize = new System.Drawing.Size(515, 148);
|
||||
this.Controls.Add(this.doYouWantLabel);
|
||||
this.Controls.Add(this.okButton);
|
||||
this.Controls.Add(this.cancelButton);
|
||||
this.Controls.Add(this.problemLabel);
|
||||
this.Controls.Add(this.pathNameTextBox);
|
||||
this.Controls.Add(this.problemWithFileLabel);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "DataFileLoadIssue";
|
||||
this.ShowInTaskbar = false;
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "Data File Load Issue";
|
||||
this.Load += new System.EventHandler(this.DataFileLoadIssue_Load);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Label problemWithFileLabel;
|
||||
private System.Windows.Forms.TextBox pathNameTextBox;
|
||||
private System.Windows.Forms.Label problemLabel;
|
||||
private System.Windows.Forms.Button cancelButton;
|
||||
private System.Windows.Forms.Button okButton;
|
||||
private System.Windows.Forms.Label doYouWantLabel;
|
||||
}
|
||||
}
|
40
SourceGen/AppForms/DataFileLoadIssue.cs
Normal file
40
SourceGen/AppForms/DataFileLoadIssue.cs
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace SourceGen.AppForms {
|
||||
public partial class DataFileLoadIssue : Form {
|
||||
/// <summary>
|
||||
/// Path name of problematic file.
|
||||
/// </summary>
|
||||
public string PathName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Message to show in the dialog.
|
||||
/// </summary>
|
||||
public string Message { get; set; }
|
||||
|
||||
public DataFileLoadIssue() {
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void DataFileLoadIssue_Load(object sender, EventArgs e) {
|
||||
pathNameTextBox.Text = PathName;
|
||||
problemLabel.Text = Message;
|
||||
}
|
||||
}
|
||||
}
|
120
SourceGen/AppForms/DataFileLoadIssue.resx
Normal file
120
SourceGen/AppForms/DataFileLoadIssue.resx
Normal file
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
140
SourceGen/AppForms/EditAddress.Designer.cs
generated
Normal file
140
SourceGen/AppForms/EditAddress.Designer.cs
generated
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
namespace SourceGen.AppForms {
|
||||
partial class EditAddress {
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing) {
|
||||
if (disposing && (components != null)) {
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent() {
|
||||
System.Windows.Forms.Label addressLabel;
|
||||
this.okButton = new System.Windows.Forms.Button();
|
||||
this.cancelButton = new System.Windows.Forms.Button();
|
||||
this.textBox1 = new System.Windows.Forms.TextBox();
|
||||
this.instructionLabel1 = new System.Windows.Forms.Label();
|
||||
this.instructionLabel2 = new System.Windows.Forms.Label();
|
||||
addressLabel = new System.Windows.Forms.Label();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// addressLabel
|
||||
//
|
||||
addressLabel.AutoSize = true;
|
||||
addressLabel.Location = new System.Drawing.Point(12, 16);
|
||||
addressLabel.Name = "addressLabel";
|
||||
addressLabel.Size = new System.Drawing.Size(48, 13);
|
||||
addressLabel.TabIndex = 1;
|
||||
addressLabel.Text = "Address:";
|
||||
//
|
||||
// okButton
|
||||
//
|
||||
this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.okButton.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.okButton.Location = new System.Drawing.Point(190, 91);
|
||||
this.okButton.Name = "okButton";
|
||||
this.okButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.okButton.TabIndex = 3;
|
||||
this.okButton.Text = "OK";
|
||||
this.okButton.UseVisualStyleBackColor = true;
|
||||
this.okButton.Click += new System.EventHandler(this.okButton_Click);
|
||||
//
|
||||
// cancelButton
|
||||
//
|
||||
this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.cancelButton.Location = new System.Drawing.Point(271, 91);
|
||||
this.cancelButton.Name = "cancelButton";
|
||||
this.cancelButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.cancelButton.TabIndex = 4;
|
||||
this.cancelButton.Text = "Cancel";
|
||||
this.cancelButton.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// textBox1
|
||||
//
|
||||
this.textBox1.Location = new System.Drawing.Point(68, 13);
|
||||
this.textBox1.Name = "textBox1";
|
||||
this.textBox1.Size = new System.Drawing.Size(275, 20);
|
||||
this.textBox1.TabIndex = 0;
|
||||
//
|
||||
// instructionLabel1
|
||||
//
|
||||
this.instructionLabel1.AutoSize = true;
|
||||
this.instructionLabel1.Location = new System.Drawing.Point(12, 36);
|
||||
this.instructionLabel1.Name = "instructionLabel1";
|
||||
this.instructionLabel1.Size = new System.Drawing.Size(331, 13);
|
||||
this.instructionLabel1.TabIndex = 2;
|
||||
this.instructionLabel1.Text = "Enter 16-bit or 24-bit address in hexadecimal, e.g. $1000 or 00/be00.\r\n";
|
||||
//
|
||||
// instructionLabel2
|
||||
//
|
||||
this.instructionLabel2.AutoSize = true;
|
||||
this.instructionLabel2.Location = new System.Drawing.Point(12, 58);
|
||||
this.instructionLabel2.Name = "instructionLabel2";
|
||||
this.instructionLabel2.Size = new System.Drawing.Size(258, 13);
|
||||
this.instructionLabel2.TabIndex = 5;
|
||||
this.instructionLabel2.Text = "Leave the field blank to remove the address override.";
|
||||
//
|
||||
// EditAddress
|
||||
//
|
||||
this.AcceptButton = this.okButton;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.CancelButton = this.cancelButton;
|
||||
this.ClientSize = new System.Drawing.Size(358, 126);
|
||||
this.Controls.Add(this.instructionLabel2);
|
||||
this.Controls.Add(this.instructionLabel1);
|
||||
this.Controls.Add(this.textBox1);
|
||||
this.Controls.Add(addressLabel);
|
||||
this.Controls.Add(this.cancelButton);
|
||||
this.Controls.Add(this.okButton);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "EditAddress";
|
||||
this.ShowInTaskbar = false;
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "Edit Address";
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Button okButton;
|
||||
private System.Windows.Forms.Button cancelButton;
|
||||
private System.Windows.Forms.TextBox textBox1;
|
||||
private System.Windows.Forms.Label instructionLabel1;
|
||||
private System.Windows.Forms.Label instructionLabel2;
|
||||
}
|
||||
}
|
124
SourceGen/AppForms/EditAddress.cs
Normal file
124
SourceGen/AppForms/EditAddress.cs
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace SourceGen.AppForms {
|
||||
public partial class EditAddress : Form {
|
||||
#if false
|
||||
private bool mAllowLastChar;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Maximum allowed address value.
|
||||
/// </summary>
|
||||
public int MaxAddressValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Address typed by user. Only valid after the dialog returns OK. Will be set to -1
|
||||
/// if the user is attempting to delete the address.
|
||||
/// </summary>
|
||||
public int Address { get; private set; }
|
||||
|
||||
public EditAddress() {
|
||||
InitializeComponent();
|
||||
Address = -2;
|
||||
MaxAddressValue = (1 << 24) - 1;
|
||||
|
||||
#if false
|
||||
// This is probably not all that useful. We're not preventing
|
||||
// invalid inputs, e.g. excessively large values or "$/$/$/", by restricting
|
||||
// the keys that can be typed.
|
||||
textBox1.KeyDown += textBox1_KeyDown;
|
||||
textBox1.KeyPress += textBox1_KeyPress;
|
||||
#endif
|
||||
|
||||
// Update the OK button based on current contents.
|
||||
textBox1.TextChanged += textBox1_TextChanged;
|
||||
}
|
||||
|
||||
public void SetInitialAddress(int addr) {
|
||||
textBox1.Text = Asm65.Address.AddressToString(addr, false);
|
||||
textBox1.SelectAll();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles a click on the OK button by setting the Address property to the
|
||||
/// decoded value from the text field.
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void okButton_Click(object sender, EventArgs e) {
|
||||
if (textBox1.Text.Length == 0) {
|
||||
Address = -1;
|
||||
} else {
|
||||
Asm65.Address.ParseAddress(textBox1.Text, MaxAddressValue, out int addr);
|
||||
Address = addr;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables or disables the OK button depending on whether the current input is
|
||||
/// valid. We allow valid addresses and an empty box.
|
||||
/// </summary>
|
||||
private void UpdateOkEnabled() {
|
||||
string text = textBox1.Text;
|
||||
okButton.Enabled = (text.Length == 0) ||
|
||||
Asm65.Address.ParseAddress(text, MaxAddressValue, out int unused);
|
||||
}
|
||||
|
||||
#if false
|
||||
/// <summary>
|
||||
/// Limits characters to [A-F][a-f][0-9][/].
|
||||
/// </summary>
|
||||
private void textBox1_KeyDown(object sender, KeyEventArgs e) {
|
||||
bool allow = false;
|
||||
if (e.KeyCode == Keys.D4 && e.Modifiers == Keys.Shift) {
|
||||
allow = true; // allow '$'; not sure this works on non-US keyboards?
|
||||
} else if (e.KeyCode >= Keys.A && e.KeyCode <= Keys.F) {
|
||||
allow = !(e.Alt || e.Control); // allow shift
|
||||
} else if ((e.KeyCode >= Keys.D0 && e.KeyCode <= Keys.D9) ||
|
||||
e.KeyCode == Keys.OemQuestion) {
|
||||
allow = (e.Modifiers == 0);
|
||||
} else if (e.KeyCode == Keys.Back || e.KeyCode == Keys.Delete) {
|
||||
allow = true;
|
||||
}
|
||||
|
||||
mAllowLastChar = allow;
|
||||
//Debug.WriteLine("DOWN " + e.KeyCode + " allow=" + allow);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rejects invalid characters.
|
||||
/// </summary>
|
||||
private void textBox1_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e) {
|
||||
//Debug.WriteLine("PRESS " + e.KeyChar + " : " + mAllowLastChar);
|
||||
if (!mAllowLastChar) {
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Updates the OK button whenever the text changes. This works for all change sources,
|
||||
/// including programmatic.
|
||||
/// </summary>
|
||||
private void textBox1_TextChanged(object sender, EventArgs e) {
|
||||
UpdateOkEnabled();
|
||||
}
|
||||
}
|
||||
}
|
123
SourceGen/AppForms/EditAddress.resx
Normal file
123
SourceGen/AppForms/EditAddress.resx
Normal file
@ -0,0 +1,123 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="addressLabel.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>False</value>
|
||||
</metadata>
|
||||
</root>
|
1583
SourceGen/AppForms/EditAppSettings.Designer.cs
generated
Normal file
1583
SourceGen/AppForms/EditAppSettings.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
617
SourceGen/AppForms/EditAppSettings.cs
Normal file
617
SourceGen/AppForms/EditAppSettings.cs
Normal file
@ -0,0 +1,617 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace SourceGen.AppForms {
|
||||
public partial class EditAppSettings : Form {
|
||||
/// <summary>
|
||||
/// Tab page enumeration. Numbers must match page indices in designer.
|
||||
/// </summary>
|
||||
public enum Tab {
|
||||
Unknown = -1,
|
||||
CodeList = 0,
|
||||
Assembler = 1,
|
||||
AsmFormat = 2,
|
||||
PseudoOp = 3
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ProjectView reference. When the user hits Apply, the object's ApplyAppSettings
|
||||
/// method will be invoked.
|
||||
/// </summary>
|
||||
private ProjectView mProjectView;
|
||||
|
||||
/// <summary>
|
||||
/// Copy of settings that we make changes to. On "Apply" or "OK", this is pushed
|
||||
/// into the global settings object, and applied to the ProjectView.
|
||||
/// </summary>
|
||||
private AppSettings mSettings;
|
||||
|
||||
/// <summary>
|
||||
/// Dirty flag, set when anything in mSettings changes. Don't modify this directly. Use
|
||||
/// the SetDirty() call so that the Apply button's enabled status gets updated.
|
||||
/// </summary>
|
||||
private bool mDirty;
|
||||
|
||||
/// <summary>
|
||||
/// Tab to show when dialog is first opened.
|
||||
/// </summary>
|
||||
private Tab mInitialTab;
|
||||
|
||||
// Map buttons to column show/hide buttons.
|
||||
private const int NUM_COLUMNS = ProjectView.CodeListColumnWidths.NUM_COLUMNS;
|
||||
private string[] mColumnFormats = new string[NUM_COLUMNS];
|
||||
private Button[] mColButtons;
|
||||
|
||||
// Map pseudo-op text entry fields to PseudoOpName properties.
|
||||
private struct TextBoxPropertyMap {
|
||||
public TextBox TextBox { get; private set; }
|
||||
public PropertyInfo PropInfo { get; private set; }
|
||||
|
||||
public TextBoxPropertyMap(TextBox textBox, string propName) {
|
||||
TextBox = textBox;
|
||||
PropInfo = typeof(PseudoOp.PseudoOpNames).GetProperty(propName);
|
||||
}
|
||||
}
|
||||
private TextBoxPropertyMap[] mPseudoNameMap;
|
||||
|
||||
|
||||
public EditAppSettings(ProjectView projectView, Tab initialTab) {
|
||||
InitializeComponent();
|
||||
|
||||
mProjectView = projectView;
|
||||
mInitialTab = initialTab;
|
||||
|
||||
// Make a work copy, so we can discard changes if the user cancels out of the dialog.
|
||||
projectView.SaveCodeListColumnWidths();
|
||||
mSettings = AppSettings.Global.GetCopy();
|
||||
|
||||
// Put buttons in an array.
|
||||
mColButtons = new Button[] {
|
||||
showCol0, showCol1, showCol2, showCol3, showCol4,
|
||||
showCol5, showCol6, showCol7, showCol8 };
|
||||
Debug.Assert(NUM_COLUMNS == 9);
|
||||
|
||||
// Extract formats from button labels.
|
||||
for (int i = 0; i < NUM_COLUMNS; i++) {
|
||||
mColButtons[i].Click += ColumnVisibilityButtonClick;
|
||||
mColumnFormats[i] = mColButtons[i].Text;
|
||||
}
|
||||
|
||||
// Map text boxes to PseudoOpName fields.
|
||||
mPseudoNameMap = new TextBoxPropertyMap[] {
|
||||
new TextBoxPropertyMap(equDirectiveTextBox, "EquDirective"),
|
||||
new TextBoxPropertyMap(orgDirectiveTextBox, "OrgDirective"),
|
||||
new TextBoxPropertyMap(regWidthDirectiveTextBox, "RegWidthDirective"),
|
||||
new TextBoxPropertyMap(defineData1TextBox, "DefineData1"),
|
||||
new TextBoxPropertyMap(defineData2TextBox, "DefineData2"),
|
||||
new TextBoxPropertyMap(defineData3TextBox, "DefineData3"),
|
||||
new TextBoxPropertyMap(defineData4TextBox, "DefineData4"),
|
||||
new TextBoxPropertyMap(defineBigData2TextBox, "DefineBigData2"),
|
||||
new TextBoxPropertyMap(fillTextBox, "Fill"),
|
||||
new TextBoxPropertyMap(denseTextBox, "Dense"),
|
||||
new TextBoxPropertyMap(strGenericTextBox, "StrGeneric"),
|
||||
new TextBoxPropertyMap(strGenericHiTextBox, "StrGenericHi"),
|
||||
new TextBoxPropertyMap(strReverseTextBox, "StrReverse"),
|
||||
new TextBoxPropertyMap(strReverseHiTextBox, "StrReverseHi"),
|
||||
new TextBoxPropertyMap(strLen8TextBox, "StrLen8"),
|
||||
new TextBoxPropertyMap(strLen8HiTextBox, "StrLen8Hi"),
|
||||
new TextBoxPropertyMap(strLen16TextBox, "StrLen16"),
|
||||
new TextBoxPropertyMap(strLen16HiTextBox, "StrLen16Hi"),
|
||||
new TextBoxPropertyMap(strNullTermTextBox, "StrNullTerm"),
|
||||
new TextBoxPropertyMap(strNullTermHiTextBox, "StrNullTermHi"),
|
||||
new TextBoxPropertyMap(strDciTextBox, "StrDci"),
|
||||
new TextBoxPropertyMap(strDciHiTextBox, "StrDciHi"),
|
||||
};
|
||||
}
|
||||
|
||||
private void EditAppSettings_Load(object sender, EventArgs e) {
|
||||
// Column widths. We called SaveCodeListColumnWidths() earlier, so this
|
||||
// should always be a valid serialized string.
|
||||
string widthStr = mSettings.GetString(AppSettings.CDLV_COL_WIDTHS, null);
|
||||
Debug.Assert(!string.IsNullOrEmpty(widthStr));
|
||||
ProjectView.CodeListColumnWidths widths =
|
||||
ProjectView.CodeListColumnWidths.Deserialize(widthStr);
|
||||
Debug.Assert(widths != null);
|
||||
for (int i = 0; i < NUM_COLUMNS; i++) {
|
||||
SetShowHideButton(i, widths.Width[i]);
|
||||
}
|
||||
|
||||
// Display localized font string.
|
||||
FontConverter cvt = new FontConverter();
|
||||
currentFontDisplayLabel.Text = cvt.ConvertToString(mProjectView.CodeListViewFont);
|
||||
|
||||
// Upper-case formatting.
|
||||
upperHexCheckBox.Checked = mSettings.GetBool(AppSettings.FMT_UPPER_HEX_DIGITS, false);
|
||||
upperOpcodeCheckBox.Checked = mSettings.GetBool(
|
||||
AppSettings.FMT_UPPER_OP_MNEMONIC, false);
|
||||
upperPseudoOpCheckBox.Checked = mSettings.GetBool(
|
||||
AppSettings.FMT_UPPER_PSEUDO_OP_MNEMONIC, false);
|
||||
upperACheckBox.Checked = mSettings.GetBool(AppSettings.FMT_UPPER_OPERAND_A, false);
|
||||
upperSCheckBox.Checked = mSettings.GetBool(AppSettings.FMT_UPPER_OPERAND_S, false);
|
||||
upperXYCheckBox.Checked = mSettings.GetBool(AppSettings.FMT_UPPER_OPERAND_XY, false);
|
||||
|
||||
int clipIndex = mSettings.GetInt(AppSettings.CLIP_LINE_FORMAT, 0);
|
||||
if (clipIndex >= 0 && clipIndex < clipboardFormatComboBox.Items.Count) {
|
||||
clipboardFormatComboBox.SelectedIndex = clipIndex;
|
||||
}
|
||||
|
||||
enableDebugCheckBox.Checked = mSettings.GetBool(AppSettings.DEBUG_MENU_ENABLED, false);
|
||||
|
||||
// Assemblers.
|
||||
cc65PathTextBox.Text =
|
||||
mSettings.GetString(AppSettings.ASM_CC65_EXECUTABLE, string.Empty);
|
||||
merlin32PathTextBox.Text =
|
||||
mSettings.GetString(AppSettings.ASM_MERLIN32_EXECUTABLE, string.Empty);
|
||||
showAsmIdentCheckBox.Checked =
|
||||
mSettings.GetBool(AppSettings.SRCGEN_ADD_IDENT_COMMENT, false);
|
||||
disableLabelLocalizationCheckBox.Checked =
|
||||
mSettings.GetBool(AppSettings.SRCGEN_DISABLE_LABEL_LOCALIZATION, false);
|
||||
longLabelNewLineCheckBox.Checked =
|
||||
mSettings.GetBool(AppSettings.SRCGEN_LONG_LABEL_NEW_LINE, false);
|
||||
showCycleCountsCheckBox.Checked =
|
||||
mSettings.GetBool(AppSettings.SRCGEN_SHOW_CYCLE_COUNTS, false);
|
||||
|
||||
// Pseudo ops.
|
||||
string opStrCereal = mSettings.GetString(AppSettings.FMT_PSEUDO_OP_NAMES, null);
|
||||
if (!string.IsNullOrEmpty(opStrCereal)) {
|
||||
PseudoOp.PseudoOpNames opNames = PseudoOp.PseudoOpNames.Deserialize(opStrCereal);
|
||||
ImportPseudoOpNames(opNames);
|
||||
} else {
|
||||
// no data available, populate with blanks
|
||||
//PseudoOp.PseudoOpNames opNames = PseudoOp.sDefaultPseudoOpNames;
|
||||
ImportPseudoOpNames(new PseudoOp.PseudoOpNames());
|
||||
}
|
||||
|
||||
PopulateWidthDisamSettings();
|
||||
|
||||
string exprMode = mSettings.GetString(AppSettings.FMT_EXPRESSION_MODE, string.Empty);
|
||||
useMerlinExpressions.Checked =
|
||||
(Asm65.Formatter.FormatConfig.ParseExpressionMode(exprMode) ==
|
||||
Asm65.Formatter.FormatConfig.ExpressionMode.Merlin);
|
||||
|
||||
if (mInitialTab != Tab.Unknown) {
|
||||
settingsTabControl.SelectTab((int)mInitialTab);
|
||||
}
|
||||
|
||||
mDirty = false;
|
||||
UpdateControls();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates controls.
|
||||
/// </summary>
|
||||
private void UpdateControls() {
|
||||
applyButton.Enabled = mDirty;
|
||||
|
||||
clearMerlin32Button.Enabled = !string.IsNullOrEmpty(merlin32PathTextBox.Text);
|
||||
clearCc65Button.Enabled = !string.IsNullOrEmpty(cc65PathTextBox.Text);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the dirty flag and updates the controls.
|
||||
/// </summary>
|
||||
/// <param name="dirty">New value for dirty flag.</param>
|
||||
private void SetDirty(bool dirty) {
|
||||
mDirty = dirty;
|
||||
UpdateControls();
|
||||
}
|
||||
|
||||
private void okButton_Click(object sender, EventArgs e) {
|
||||
ApplySettings();
|
||||
}
|
||||
|
||||
private void applyButton_Click(object sender, EventArgs e) {
|
||||
ApplySettings();
|
||||
}
|
||||
|
||||
private void ApplySettings() {
|
||||
PseudoOp.PseudoOpNames opNames = ExportPseudoOpNames();
|
||||
string pseudoCereal = opNames.Serialize();
|
||||
mSettings.SetString(AppSettings.FMT_PSEUDO_OP_NAMES, pseudoCereal);
|
||||
|
||||
mProjectView.SetAppSettings(mSettings);
|
||||
AsmGen.AssemblerVersionCache.QueryVersions();
|
||||
SetDirty(false);
|
||||
}
|
||||
|
||||
|
||||
#region Code View
|
||||
|
||||
/// <summary>
|
||||
/// Updates the text on a show/hide column button.
|
||||
/// </summary>
|
||||
/// <param name="index">Column index.</param>
|
||||
/// <param name="width">New width.</param>
|
||||
private void SetShowHideButton(int index, int width) {
|
||||
Button button = mColButtons[index];
|
||||
string fmt = mColumnFormats[index];
|
||||
string show = Properties.Resources.SHOW_COL;
|
||||
string hide = Properties.Resources.HIDE_COL;
|
||||
button.Text = string.Format(fmt, (width == 0) ? show : hide);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for all show/hide column buttons.
|
||||
/// </summary>
|
||||
/// <param name="sender">Identifies the button that was clicked.</param>
|
||||
/// <param name="e">Stuff.</param>
|
||||
private void ColumnVisibilityButtonClick(object sender, EventArgs e) {
|
||||
int index = -1;
|
||||
for (int i = 0; i < mColButtons.Length; i++) {
|
||||
if (sender == mColButtons[i]) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Debug.Assert(index != -1);
|
||||
|
||||
string widthStr = mSettings.GetString(AppSettings.CDLV_COL_WIDTHS, null);
|
||||
Debug.Assert(!string.IsNullOrEmpty(widthStr));
|
||||
ProjectView.CodeListColumnWidths widths =
|
||||
ProjectView.CodeListColumnWidths.Deserialize(widthStr);
|
||||
if (widths.Width[index] == 0) {
|
||||
// Expand to default width. The default width changes when the font
|
||||
// changes, so it's best to just reacquire the default width set as needed.
|
||||
ProjectView.CodeListColumnWidths defaultWidths =
|
||||
mProjectView.GetDefaultCodeListColumnWidths();
|
||||
widths.Width[index] = defaultWidths.Width[index];
|
||||
} else {
|
||||
widths.Width[index] = 0;
|
||||
}
|
||||
widthStr = widths.Serialize();
|
||||
mSettings.SetString(AppSettings.CDLV_COL_WIDTHS, widthStr);
|
||||
SetShowHideButton(index, widths.Width[index]);
|
||||
|
||||
SetDirty(true);
|
||||
}
|
||||
|
||||
private void selectFontButton_Click(object sender, EventArgs e) {
|
||||
FontDialog dlg = new FontDialog();
|
||||
dlg.Font = mProjectView.CodeListViewFont;
|
||||
dlg.ShowEffects = false;
|
||||
Debug.WriteLine("Showing font dialog...");
|
||||
if (dlg.ShowDialog() != DialogResult.Cancel) {
|
||||
FontConverter cvt = new FontConverter();
|
||||
// Store invariant string, display localized string.
|
||||
mSettings.SetString(AppSettings.CDLV_FONT, cvt.ConvertToInvariantString(dlg.Font));
|
||||
currentFontDisplayLabel.Text = cvt.ConvertToString(dlg.Font);
|
||||
SetDirty(true);
|
||||
}
|
||||
Debug.WriteLine("Font dialog done...");
|
||||
dlg.Dispose();
|
||||
}
|
||||
|
||||
private void upperHexCheckBox_CheckedChanged(object sender, EventArgs e) {
|
||||
mSettings.SetBool(AppSettings.FMT_UPPER_HEX_DIGITS, upperHexCheckBox.Checked);
|
||||
SetDirty(true);
|
||||
}
|
||||
private void upperOpcodeCheckBox_CheckedChanged(object sender, EventArgs e) {
|
||||
mSettings.SetBool(AppSettings.FMT_UPPER_OP_MNEMONIC, upperOpcodeCheckBox.Checked);
|
||||
SetDirty(true);
|
||||
}
|
||||
private void upperPseudoOpCheckBox_CheckedChanged(object sender, EventArgs e) {
|
||||
mSettings.SetBool(AppSettings.FMT_UPPER_PSEUDO_OP_MNEMONIC,
|
||||
upperPseudoOpCheckBox.Checked);
|
||||
SetDirty(true);
|
||||
}
|
||||
private void upperACheckBox_CheckedChanged(object sender, EventArgs e) {
|
||||
mSettings.SetBool(AppSettings.FMT_UPPER_OPERAND_A, upperACheckBox.Checked);
|
||||
SetDirty(true);
|
||||
}
|
||||
private void upperSCheckBox_CheckedChanged(object sender, EventArgs e) {
|
||||
mSettings.SetBool(AppSettings.FMT_UPPER_OPERAND_S, upperSCheckBox.Checked);
|
||||
SetDirty(true);
|
||||
}
|
||||
private void upperXYCheckBox_CheckedChanged(object sender, EventArgs e) {
|
||||
mSettings.SetBool(AppSettings.FMT_UPPER_OPERAND_XY, upperXYCheckBox.Checked);
|
||||
SetDirty(true);
|
||||
}
|
||||
private void upperAllLowerButton_Click(object sender, EventArgs e) {
|
||||
upperHexCheckBox.Checked =
|
||||
upperOpcodeCheckBox.Checked =
|
||||
upperPseudoOpCheckBox.Checked =
|
||||
upperACheckBox.Checked =
|
||||
upperSCheckBox.Checked =
|
||||
upperXYCheckBox.Checked = false;
|
||||
}
|
||||
private void upperAllUpperButton_Click(object sender, EventArgs e) {
|
||||
upperHexCheckBox.Checked =
|
||||
upperOpcodeCheckBox.Checked =
|
||||
upperPseudoOpCheckBox.Checked =
|
||||
upperACheckBox.Checked =
|
||||
upperSCheckBox.Checked =
|
||||
upperXYCheckBox.Checked = true;
|
||||
}
|
||||
|
||||
private void clipboardFormatComboBox_SelectedIndexChanged(object sender, EventArgs e) {
|
||||
mSettings.SetInt(AppSettings.CLIP_LINE_FORMAT, clipboardFormatComboBox.SelectedIndex);
|
||||
SetDirty(true);
|
||||
}
|
||||
|
||||
private void enableDebugCheckBox_CheckedChanged(object sender, EventArgs e) {
|
||||
mSettings.SetBool(AppSettings.DEBUG_MENU_ENABLED, enableDebugCheckBox.Checked);
|
||||
SetDirty(true);
|
||||
}
|
||||
|
||||
#endregion Code View
|
||||
|
||||
|
||||
#region Asm Config
|
||||
|
||||
private void browseCc65Button_Click(object sender, EventArgs e) {
|
||||
string pathName = BrowseForExecutable("cc65 CL", "cl65.exe");
|
||||
if (pathName != null) {
|
||||
cc65PathTextBox.Text = pathName;
|
||||
mSettings.SetString(AppSettings.ASM_CC65_EXECUTABLE, pathName);
|
||||
}
|
||||
}
|
||||
|
||||
private void cc65PathTextBox_TextChanged(object sender, EventArgs e) {
|
||||
mSettings.SetString(AppSettings.ASM_CC65_EXECUTABLE, cc65PathTextBox.Text);
|
||||
SetDirty(true);
|
||||
}
|
||||
|
||||
private void clearCc65Button_Click(object sender, EventArgs e) {
|
||||
cc65PathTextBox.Text = string.Empty;
|
||||
mSettings.SetString(AppSettings.ASM_CC65_EXECUTABLE, null);
|
||||
SetDirty(true);
|
||||
}
|
||||
|
||||
private void browseMerlin32Button_Click(object sender, EventArgs e) {
|
||||
string pathName = BrowseForExecutable("Merlin Assembler", "Merlin32.exe");
|
||||
if (pathName != null) {
|
||||
merlin32PathTextBox.Text = pathName;
|
||||
mSettings.SetString(AppSettings.ASM_MERLIN32_EXECUTABLE, pathName);
|
||||
}
|
||||
}
|
||||
|
||||
private void clearMerlin32Button_Click(object sender, EventArgs e) {
|
||||
merlin32PathTextBox.Text = string.Empty;
|
||||
mSettings.SetString(AppSettings.ASM_MERLIN32_EXECUTABLE, null);
|
||||
SetDirty(true);
|
||||
}
|
||||
|
||||
private void merlin32PathTextBox_TextChanged(object sender, EventArgs e) {
|
||||
mSettings.SetString(AppSettings.ASM_MERLIN32_EXECUTABLE, merlin32PathTextBox.Text);
|
||||
SetDirty(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a file dialog to search for a specific executable.
|
||||
/// </summary>
|
||||
/// <param name="prefix">Human-readable filter string for UI.</param>
|
||||
/// <param name="name">Filename of executable.</param>
|
||||
/// <returns>Path of executable, or null if dialog was canceled.</returns>
|
||||
private string BrowseForExecutable(string prefix, string name) {
|
||||
string pathName = null;
|
||||
|
||||
OpenFileDialog dlg = new OpenFileDialog();
|
||||
dlg.FileName = name;
|
||||
dlg.Filter = prefix + "|" + name;
|
||||
dlg.RestoreDirectory = true;
|
||||
if (dlg.ShowDialog() != DialogResult.Cancel) {
|
||||
pathName = dlg.FileName;
|
||||
SetDirty(true);
|
||||
}
|
||||
dlg.Dispose();
|
||||
|
||||
return pathName;
|
||||
}
|
||||
|
||||
private void showAsmIdentCheckBox_CheckedChanged(object sender, EventArgs e) {
|
||||
mSettings.SetBool(AppSettings.SRCGEN_ADD_IDENT_COMMENT, showAsmIdentCheckBox.Checked);
|
||||
SetDirty(true);
|
||||
}
|
||||
|
||||
private void disableLabelLocalizationCheckBox_CheckedChanged(object sender, EventArgs e) {
|
||||
mSettings.SetBool(AppSettings.SRCGEN_DISABLE_LABEL_LOCALIZATION,
|
||||
disableLabelLocalizationCheckBox.Checked);
|
||||
SetDirty(true);
|
||||
}
|
||||
|
||||
private void longLabelNewLineCheckBox_CheckedChanged(object sender, EventArgs e) {
|
||||
mSettings.SetBool(AppSettings.SRCGEN_LONG_LABEL_NEW_LINE,
|
||||
longLabelNewLineCheckBox.Checked);
|
||||
SetDirty(true);
|
||||
}
|
||||
|
||||
private void showCycleCountsCheckBox_CheckedChanged(object sender, EventArgs e) {
|
||||
mSettings.SetBool(AppSettings.SRCGEN_SHOW_CYCLE_COUNTS,
|
||||
showCycleCountsCheckBox.Checked);
|
||||
SetDirty(true);
|
||||
}
|
||||
|
||||
#endregion Asm Config
|
||||
|
||||
|
||||
#region Display Format
|
||||
|
||||
/// <summary>
|
||||
/// Populates the width disambiguation text boxes.
|
||||
/// </summary>
|
||||
private void PopulateWidthDisamSettings() {
|
||||
// Operand width disambiguation. This is a little tricky -- we have to query all
|
||||
// settings then set all controls, or the field-updated callback may interfere
|
||||
// with us by changing AppSettings.
|
||||
string opcSuffixAbs = mSettings.GetString(AppSettings.FMT_OPCODE_SUFFIX_ABS,
|
||||
string.Empty);
|
||||
string opcSuffixLong = mSettings.GetString(AppSettings.FMT_OPCODE_SUFFIX_LONG,
|
||||
string.Empty);
|
||||
string opPrefixAbs = mSettings.GetString(AppSettings.FMT_OPERAND_PREFIX_ABS,
|
||||
string.Empty);
|
||||
string opPrefixLong = mSettings.GetString(AppSettings.FMT_OPERAND_PREFIX_LONG,
|
||||
string.Empty);
|
||||
|
||||
disambSuffix16TextBox.Text = opcSuffixAbs;
|
||||
disambSuffix24TextBox.Text = opcSuffixLong;
|
||||
disambPrefix16TextBox.Text = opPrefixAbs;
|
||||
disambPrefix24TextBox.Text = opPrefixLong;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets all of the width disambiguation settings. Used for the quick-set buttons.
|
||||
/// </summary>
|
||||
private void SetWidthDisamSettings(string opcodeSuffixAbs, string opcodeSuffixLong,
|
||||
string operandPrefixAbs, string operandPrefixLong) {
|
||||
mSettings.SetString(AppSettings.FMT_OPCODE_SUFFIX_ABS, opcodeSuffixAbs);
|
||||
mSettings.SetString(AppSettings.FMT_OPCODE_SUFFIX_LONG, opcodeSuffixLong);
|
||||
mSettings.SetString(AppSettings.FMT_OPERAND_PREFIX_ABS, operandPrefixAbs);
|
||||
mSettings.SetString(AppSettings.FMT_OPERAND_PREFIX_LONG, operandPrefixLong);
|
||||
PopulateWidthDisamSettings();
|
||||
}
|
||||
|
||||
// Called when text is typed.
|
||||
private void WidthDisamControlChanged(object sender, EventArgs e) {
|
||||
ExportWidthDisamSettings();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exports the current state of the width controls to the settings object.
|
||||
/// </summary>
|
||||
private void ExportWidthDisamSettings() {
|
||||
mSettings.SetString(AppSettings.FMT_OPCODE_SUFFIX_ABS, disambSuffix16TextBox.Text);
|
||||
mSettings.SetString(AppSettings.FMT_OPCODE_SUFFIX_LONG, disambSuffix24TextBox.Text);
|
||||
mSettings.SetString(AppSettings.FMT_OPERAND_PREFIX_ABS, disambPrefix16TextBox.Text);
|
||||
mSettings.SetString(AppSettings.FMT_OPERAND_PREFIX_LONG, disambPrefix24TextBox.Text);
|
||||
SetDirty(true);
|
||||
|
||||
//Debug.WriteLine("disam: '" +
|
||||
// mSettings.GetString(AppSettings.FMT_OPCODE_SUFFIX_ABS, string.Empty) + "' '" +
|
||||
// mSettings.GetString(AppSettings.FMT_OPCODE_SUFFIX_LONG, string.Empty) + "' '" +
|
||||
// mSettings.GetString(AppSettings.FMT_OPERAND_PREFIX_ABS, string.Empty) + "' '" +
|
||||
// mSettings.GetString(AppSettings.FMT_OPERAND_PREFIX_LONG, string.Empty) + "'");
|
||||
}
|
||||
|
||||
private void shiftAfterAdjustCheckBox_CheckedChanged(object sender, EventArgs e) {
|
||||
string mode = useMerlinExpressions.Checked ?
|
||||
Asm65.Formatter.FormatConfig.ExpressionMode.Merlin.ToString() :
|
||||
Asm65.Formatter.FormatConfig.ExpressionMode.Simple.ToString();
|
||||
mSettings.SetString(AppSettings.FMT_EXPRESSION_MODE, mode);
|
||||
SetDirty(true);
|
||||
}
|
||||
|
||||
private void quickFmtDefaultButton_Click(object sender, EventArgs e) {
|
||||
SetWidthDisamSettings(null, "l", "a:", "f:");
|
||||
useMerlinExpressions.Checked = false;
|
||||
// dirty flag set by change callbacks
|
||||
}
|
||||
|
||||
private void quickFmtCc65Button_Click(object sender, EventArgs e) {
|
||||
SetWidthDisamSettings(null, null, "a:", "f:");
|
||||
useMerlinExpressions.Checked = false;
|
||||
// dirty flag set by change callbacks
|
||||
}
|
||||
|
||||
private void quickFmtMerlin32Button_Click(object sender, EventArgs e) {
|
||||
SetWidthDisamSettings(":", "l", null, null);
|
||||
useMerlinExpressions.Checked = true;
|
||||
// dirty flag set by change callbacks
|
||||
}
|
||||
|
||||
#endregion Display Format
|
||||
|
||||
|
||||
#region Pseudo-Op
|
||||
|
||||
/// <summary>
|
||||
/// Imports values from PseudoOpNames struct into text fields.
|
||||
/// </summary>
|
||||
private void ImportPseudoOpNames(PseudoOp.PseudoOpNames opNames) {
|
||||
for (int i = 0; i < mPseudoNameMap.Length; i++) {
|
||||
string str = (string)mPseudoNameMap[i].PropInfo.GetValue(opNames);
|
||||
mPseudoNameMap[i].TextBox.Text = (str == null) ? string.Empty : str;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exports values from text fields to a PseudoOpNames object.
|
||||
/// </summary>
|
||||
private PseudoOp.PseudoOpNames ExportPseudoOpNames() {
|
||||
PseudoOp.PseudoOpNames opNames = new PseudoOp.PseudoOpNames();
|
||||
for (int i = 0; i < mPseudoNameMap.Length; i++) {
|
||||
// NOTE: PseudoOpNames must be a class (not a struct) or this will fail.
|
||||
// SetValue() would be invoked on a boxed copy that is discarded afterward.
|
||||
mPseudoNameMap[i].PropInfo.SetValue(opNames, mPseudoNameMap[i].TextBox.Text);
|
||||
}
|
||||
return opNames;
|
||||
}
|
||||
|
||||
// Invoked when text is changed in any pseudo-op text box.
|
||||
private void PseudoOpTextChanged(object sender, EventArgs e) {
|
||||
// Just set the dirty flag. The (somewhat expensive) export will happen
|
||||
// on Apply/OK.
|
||||
SetDirty(true);
|
||||
}
|
||||
|
||||
private void quickPseudoDefaultButton_Click(object sender, EventArgs e) {
|
||||
ImportPseudoOpNames(new PseudoOp.PseudoOpNames());
|
||||
}
|
||||
|
||||
private void quickPseudoCc65Button_Click(object sender, EventArgs e) {
|
||||
ImportPseudoOpNames(new PseudoOp.PseudoOpNames() {
|
||||
EquDirective = "=",
|
||||
OrgDirective = ".org",
|
||||
DefineData1 = ".byte",
|
||||
DefineData2 = ".word",
|
||||
DefineData3 = ".faraddr",
|
||||
DefineData4 = ".dword",
|
||||
DefineBigData2 = ".dbyt",
|
||||
Fill = ".res",
|
||||
StrGeneric = ".byte",
|
||||
StrNullTerm = ".asciiz",
|
||||
});
|
||||
}
|
||||
|
||||
private void quickPseudoMerlin32_Click(object sender, EventArgs e) {
|
||||
// Note this doesn't quite match up with the Merlin generator, which uses
|
||||
// the same pseudo-op for low/high ASCII but different string delimiters. We
|
||||
// don't change the delimiters for the display list, so we want to tweak the
|
||||
// opcode slightly.
|
||||
//char hiAscii = '\u21e1';
|
||||
char hiAscii = '\u2191';
|
||||
ImportPseudoOpNames(new PseudoOp.PseudoOpNames() {
|
||||
EquDirective = "equ",
|
||||
OrgDirective = "org",
|
||||
DefineData1 = "dfb",
|
||||
DefineData2 = "dw",
|
||||
DefineData3 = "adr",
|
||||
DefineData4 = "adrl",
|
||||
DefineBigData2 = "ddb",
|
||||
Fill = "ds",
|
||||
Dense = "hex",
|
||||
StrGeneric = "asc",
|
||||
StrGenericHi = "asc" + hiAscii,
|
||||
StrReverse = "rev",
|
||||
StrReverseHi = "rev" + hiAscii,
|
||||
StrLen8 = "str",
|
||||
StrLen8Hi = "str" + hiAscii,
|
||||
StrLen16 = "strl",
|
||||
StrLen16Hi = "strl" + hiAscii,
|
||||
StrDci = "dci",
|
||||
StrDciHi = "dci" + hiAscii,
|
||||
});
|
||||
}
|
||||
|
||||
#endregion Pseudo-Op
|
||||
}
|
||||
}
|
120
SourceGen/AppForms/EditAppSettings.resx
Normal file
120
SourceGen/AppForms/EditAppSettings.resx
Normal file
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
153
SourceGen/AppForms/EditComment.Designer.cs
generated
Normal file
153
SourceGen/AppForms/EditComment.Designer.cs
generated
Normal file
@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
namespace SourceGen.AppForms {
|
||||
partial class EditComment {
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing) {
|
||||
if (disposing && (components != null)) {
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent() {
|
||||
this.cancelButton = new System.Windows.Forms.Button();
|
||||
this.okButton = new System.Windows.Forms.Button();
|
||||
this.instructionLabel = new System.Windows.Forms.Label();
|
||||
this.textBox1 = new System.Windows.Forms.TextBox();
|
||||
this.asciiOnlyLabel = new System.Windows.Forms.Label();
|
||||
this.maxLengthLabel = new System.Windows.Forms.Label();
|
||||
this.numCharsLabel = new System.Windows.Forms.Label();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// cancelButton
|
||||
//
|
||||
this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.cancelButton.Location = new System.Drawing.Point(426, 105);
|
||||
this.cancelButton.Name = "cancelButton";
|
||||
this.cancelButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.cancelButton.TabIndex = 6;
|
||||
this.cancelButton.Text = "Cancel";
|
||||
this.cancelButton.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// okButton
|
||||
//
|
||||
this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.okButton.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.okButton.Location = new System.Drawing.Point(345, 105);
|
||||
this.okButton.Name = "okButton";
|
||||
this.okButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.okButton.TabIndex = 5;
|
||||
this.okButton.Text = "OK";
|
||||
this.okButton.UseVisualStyleBackColor = true;
|
||||
this.okButton.Click += new System.EventHandler(this.okButton_Click);
|
||||
//
|
||||
// instructionLabel
|
||||
//
|
||||
this.instructionLabel.AutoSize = true;
|
||||
this.instructionLabel.Location = new System.Drawing.Point(13, 13);
|
||||
this.instructionLabel.Name = "instructionLabel";
|
||||
this.instructionLabel.Size = new System.Drawing.Size(81, 13);
|
||||
this.instructionLabel.TabIndex = 0;
|
||||
this.instructionLabel.Text = "Enter comment:";
|
||||
//
|
||||
// textBox1
|
||||
//
|
||||
this.textBox1.Location = new System.Drawing.Point(13, 30);
|
||||
this.textBox1.Name = "textBox1";
|
||||
this.textBox1.Size = new System.Drawing.Size(488, 20);
|
||||
this.textBox1.TabIndex = 1;
|
||||
this.textBox1.TextChanged += new System.EventHandler(this.textBox1_TextChanged);
|
||||
//
|
||||
// asciiOnlyLabel
|
||||
//
|
||||
this.asciiOnlyLabel.AutoSize = true;
|
||||
this.asciiOnlyLabel.Location = new System.Drawing.Point(13, 57);
|
||||
this.asciiOnlyLabel.Name = "asciiOnlyLabel";
|
||||
this.asciiOnlyLabel.Size = new System.Drawing.Size(145, 13);
|
||||
this.asciiOnlyLabel.TabIndex = 2;
|
||||
this.asciiOnlyLabel.Text = "• ASCII-only is recommended";
|
||||
//
|
||||
// maxLengthLabel
|
||||
//
|
||||
this.maxLengthLabel.AutoSize = true;
|
||||
this.maxLengthLabel.Location = new System.Drawing.Point(13, 74);
|
||||
this.maxLengthLabel.Name = "maxLengthLabel";
|
||||
this.maxLengthLabel.Size = new System.Drawing.Size(281, 13);
|
||||
this.maxLengthLabel.TabIndex = 3;
|
||||
this.maxLengthLabel.Text = "• Limit to 52 or fewer characters for nice 80-column output";
|
||||
//
|
||||
// numCharsLabel
|
||||
//
|
||||
this.numCharsLabel.Location = new System.Drawing.Point(386, 53);
|
||||
this.numCharsLabel.Name = "numCharsLabel";
|
||||
this.numCharsLabel.Size = new System.Drawing.Size(115, 23);
|
||||
this.numCharsLabel.TabIndex = 4;
|
||||
this.numCharsLabel.Text = "{0} characters";
|
||||
this.numCharsLabel.TextAlign = System.Drawing.ContentAlignment.TopRight;
|
||||
//
|
||||
// EditComment
|
||||
//
|
||||
this.AcceptButton = this.okButton;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.CancelButton = this.cancelButton;
|
||||
this.ClientSize = new System.Drawing.Size(513, 140);
|
||||
this.Controls.Add(this.numCharsLabel);
|
||||
this.Controls.Add(this.maxLengthLabel);
|
||||
this.Controls.Add(this.asciiOnlyLabel);
|
||||
this.Controls.Add(this.textBox1);
|
||||
this.Controls.Add(this.instructionLabel);
|
||||
this.Controls.Add(this.okButton);
|
||||
this.Controls.Add(this.cancelButton);
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "EditComment";
|
||||
this.ShowInTaskbar = false;
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "Edit Comment";
|
||||
this.Load += new System.EventHandler(this.EditComment_Load);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Button cancelButton;
|
||||
private System.Windows.Forms.Button okButton;
|
||||
private System.Windows.Forms.Label instructionLabel;
|
||||
private System.Windows.Forms.TextBox textBox1;
|
||||
private System.Windows.Forms.Label asciiOnlyLabel;
|
||||
private System.Windows.Forms.Label maxLengthLabel;
|
||||
private System.Windows.Forms.Label numCharsLabel;
|
||||
}
|
||||
}
|
72
SourceGen/AppForms/EditComment.cs
Normal file
72
SourceGen/AppForms/EditComment.cs
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace SourceGen.AppForms {
|
||||
public partial class EditComment : Form {
|
||||
/// <summary>
|
||||
/// Comment string being edited.
|
||||
/// </summary>
|
||||
public string Comment { get; set; }
|
||||
|
||||
private string mNumCharsFormat;
|
||||
|
||||
private Color mDefaultLabelColor;
|
||||
|
||||
private const int RECOMMENDED_MAX_LENGTH = 52;
|
||||
|
||||
|
||||
public EditComment() {
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void EditComment_Load(object sender, EventArgs e) {
|
||||
mDefaultLabelColor = asciiOnlyLabel.ForeColor;
|
||||
|
||||
// Extract the format string from the label.
|
||||
mNumCharsFormat = numCharsLabel.Text;
|
||||
|
||||
textBox1.Text = Comment;
|
||||
UpdateLengthLabel();
|
||||
}
|
||||
|
||||
private void UpdateLengthLabel() {
|
||||
numCharsLabel.Text = string.Format(mNumCharsFormat, textBox1.Text.Length);
|
||||
}
|
||||
|
||||
private void textBox1_TextChanged(object sender, EventArgs e) {
|
||||
UpdateLengthLabel();
|
||||
|
||||
if (!CommonUtil.TextUtil.IsPrintableAscii(textBox1.Text)) {
|
||||
asciiOnlyLabel.ForeColor = Color.Red;
|
||||
} else {
|
||||
asciiOnlyLabel.ForeColor = mDefaultLabelColor;
|
||||
}
|
||||
if (textBox1.Text.Length > RECOMMENDED_MAX_LENGTH) {
|
||||
maxLengthLabel.ForeColor = Color.Red;
|
||||
} else {
|
||||
maxLengthLabel.ForeColor = mDefaultLabelColor;
|
||||
}
|
||||
}
|
||||
|
||||
private void okButton_Click(object sender, EventArgs e) {
|
||||
Comment = textBox1.Text;
|
||||
}
|
||||
}
|
||||
}
|
120
SourceGen/AppForms/EditComment.resx
Normal file
120
SourceGen/AppForms/EditComment.resx
Normal file
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
559
SourceGen/AppForms/EditData.Designer.cs
generated
Normal file
559
SourceGen/AppForms/EditData.Designer.cs
generated
Normal file
@ -0,0 +1,559 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
namespace SourceGen.AppForms {
|
||||
partial class EditData {
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing) {
|
||||
if (disposing && (components != null)) {
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent() {
|
||||
this.cancelButton = new System.Windows.Forms.Button();
|
||||
this.okButton = new System.Windows.Forms.Button();
|
||||
this.selectFormatLabel = new System.Windows.Forms.Label();
|
||||
this.rawDataSectionLabel = new System.Windows.Forms.Label();
|
||||
this.radioSingleBytes = new System.Windows.Forms.RadioButton();
|
||||
this.radio16BitBig = new System.Windows.Forms.RadioButton();
|
||||
this.radio16BitLittle = new System.Windows.Forms.RadioButton();
|
||||
this.radio24BitLittle = new System.Windows.Forms.RadioButton();
|
||||
this.radio32BitLittle = new System.Windows.Forms.RadioButton();
|
||||
this.radioSimpleDataBinary = new System.Windows.Forms.RadioButton();
|
||||
this.radioSimpleDataDecimal = new System.Windows.Forms.RadioButton();
|
||||
this.radioSimpleDataHex = new System.Windows.Forms.RadioButton();
|
||||
this.radioDenseHex = new System.Windows.Forms.RadioButton();
|
||||
this.radioFill = new System.Windows.Forms.RadioButton();
|
||||
this.horizontalLine1 = new System.Windows.Forms.Label();
|
||||
this.horizontalLine2 = new System.Windows.Forms.Label();
|
||||
this.stringSectionLabel = new System.Windows.Forms.Label();
|
||||
this.horizontalLine3 = new System.Windows.Forms.Label();
|
||||
this.radioStringMixed = new System.Windows.Forms.RadioButton();
|
||||
this.radioStringMixedReverse = new System.Windows.Forms.RadioButton();
|
||||
this.radioStringNullTerm = new System.Windows.Forms.RadioButton();
|
||||
this.radioStringLen8 = new System.Windows.Forms.RadioButton();
|
||||
this.radioStringLen16 = new System.Windows.Forms.RadioButton();
|
||||
this.radioStringDci = new System.Windows.Forms.RadioButton();
|
||||
this.symbolEntryTextBox = new System.Windows.Forms.TextBox();
|
||||
this.symbolPartPanel = new System.Windows.Forms.Panel();
|
||||
this.radioSymbolPartBank = new System.Windows.Forms.RadioButton();
|
||||
this.radioSymbolPartHigh = new System.Windows.Forms.RadioButton();
|
||||
this.radioSymbolPartLow = new System.Windows.Forms.RadioButton();
|
||||
this.radioSimpleDataAscii = new System.Windows.Forms.RadioButton();
|
||||
this.radioDefaultFormat = new System.Windows.Forms.RadioButton();
|
||||
this.simpleDisplayAsGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.radioSimpleDataAddress = new System.Windows.Forms.RadioButton();
|
||||
this.radioSimpleDataSymbolic = new System.Windows.Forms.RadioButton();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.symbolPartPanel.SuspendLayout();
|
||||
this.simpleDisplayAsGroupBox.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// cancelButton
|
||||
//
|
||||
this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.cancelButton.Location = new System.Drawing.Point(438, 461);
|
||||
this.cancelButton.Name = "cancelButton";
|
||||
this.cancelButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.cancelButton.TabIndex = 23;
|
||||
this.cancelButton.Text = "Cancel";
|
||||
this.cancelButton.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// okButton
|
||||
//
|
||||
this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.okButton.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.okButton.Location = new System.Drawing.Point(357, 461);
|
||||
this.okButton.Name = "okButton";
|
||||
this.okButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.okButton.TabIndex = 22;
|
||||
this.okButton.Text = "OK";
|
||||
this.okButton.UseVisualStyleBackColor = true;
|
||||
this.okButton.Click += new System.EventHandler(this.okButton_Click);
|
||||
//
|
||||
// selectFormatLabel
|
||||
//
|
||||
this.selectFormatLabel.AutoSize = true;
|
||||
this.selectFormatLabel.Location = new System.Drawing.Point(12, 9);
|
||||
this.selectFormatLabel.Name = "selectFormatLabel";
|
||||
this.selectFormatLabel.Size = new System.Drawing.Size(253, 13);
|
||||
this.selectFormatLabel.TabIndex = 0;
|
||||
this.selectFormatLabel.Text = "Select data format ({0} bytes selected in {1} groups):";
|
||||
//
|
||||
// rawDataSectionLabel
|
||||
//
|
||||
this.rawDataSectionLabel.AutoSize = true;
|
||||
this.rawDataSectionLabel.Location = new System.Drawing.Point(12, 63);
|
||||
this.rawDataSectionLabel.Name = "rawDataSectionLabel";
|
||||
this.rawDataSectionLabel.Size = new System.Drawing.Size(64, 13);
|
||||
this.rawDataSectionLabel.TabIndex = 2;
|
||||
this.rawDataSectionLabel.Text = "Simple Data";
|
||||
//
|
||||
// radioSingleBytes
|
||||
//
|
||||
this.radioSingleBytes.AutoSize = true;
|
||||
this.radioSingleBytes.Location = new System.Drawing.Point(14, 89);
|
||||
this.radioSingleBytes.Name = "radioSingleBytes";
|
||||
this.radioSingleBytes.Size = new System.Drawing.Size(82, 17);
|
||||
this.radioSingleBytes.TabIndex = 4;
|
||||
this.radioSingleBytes.TabStop = true;
|
||||
this.radioSingleBytes.Text = "Single &bytes";
|
||||
this.radioSingleBytes.UseVisualStyleBackColor = true;
|
||||
this.radioSingleBytes.CheckedChanged += new System.EventHandler(this.MainGroup_CheckedChanged);
|
||||
//
|
||||
// radio16BitBig
|
||||
//
|
||||
this.radio16BitBig.AutoSize = true;
|
||||
this.radio16BitBig.Location = new System.Drawing.Point(14, 135);
|
||||
this.radio16BitBig.Name = "radio16BitBig";
|
||||
this.radio16BitBig.Size = new System.Drawing.Size(137, 17);
|
||||
this.radio16BitBig.TabIndex = 6;
|
||||
this.radio16BitBig.TabStop = true;
|
||||
this.radio16BitBig.Text = "16-bit words, big-endian";
|
||||
this.radio16BitBig.UseVisualStyleBackColor = true;
|
||||
this.radio16BitBig.CheckedChanged += new System.EventHandler(this.MainGroup_CheckedChanged);
|
||||
//
|
||||
// radio16BitLittle
|
||||
//
|
||||
this.radio16BitLittle.AutoSize = true;
|
||||
this.radio16BitLittle.Location = new System.Drawing.Point(14, 112);
|
||||
this.radio16BitLittle.Name = "radio16BitLittle";
|
||||
this.radio16BitLittle.Size = new System.Drawing.Size(141, 17);
|
||||
this.radio16BitLittle.TabIndex = 5;
|
||||
this.radio16BitLittle.TabStop = true;
|
||||
this.radio16BitLittle.Text = "16-bit words, little-endian";
|
||||
this.radio16BitLittle.UseVisualStyleBackColor = true;
|
||||
this.radio16BitLittle.CheckedChanged += new System.EventHandler(this.MainGroup_CheckedChanged);
|
||||
//
|
||||
// radio24BitLittle
|
||||
//
|
||||
this.radio24BitLittle.AutoSize = true;
|
||||
this.radio24BitLittle.Location = new System.Drawing.Point(14, 158);
|
||||
this.radio24BitLittle.Name = "radio24BitLittle";
|
||||
this.radio24BitLittle.Size = new System.Drawing.Size(141, 17);
|
||||
this.radio24BitLittle.TabIndex = 7;
|
||||
this.radio24BitLittle.TabStop = true;
|
||||
this.radio24BitLittle.Text = "24-bit words, little-endian";
|
||||
this.radio24BitLittle.UseVisualStyleBackColor = true;
|
||||
this.radio24BitLittle.CheckedChanged += new System.EventHandler(this.MainGroup_CheckedChanged);
|
||||
//
|
||||
// radio32BitLittle
|
||||
//
|
||||
this.radio32BitLittle.AutoSize = true;
|
||||
this.radio32BitLittle.Location = new System.Drawing.Point(14, 181);
|
||||
this.radio32BitLittle.Name = "radio32BitLittle";
|
||||
this.radio32BitLittle.Size = new System.Drawing.Size(141, 17);
|
||||
this.radio32BitLittle.TabIndex = 8;
|
||||
this.radio32BitLittle.TabStop = true;
|
||||
this.radio32BitLittle.Text = "32-bit words, little-endian";
|
||||
this.radio32BitLittle.UseVisualStyleBackColor = true;
|
||||
this.radio32BitLittle.CheckedChanged += new System.EventHandler(this.MainGroup_CheckedChanged);
|
||||
//
|
||||
// radioSimpleDataBinary
|
||||
//
|
||||
this.radioSimpleDataBinary.AutoSize = true;
|
||||
this.radioSimpleDataBinary.Location = new System.Drawing.Point(6, 64);
|
||||
this.radioSimpleDataBinary.Name = "radioSimpleDataBinary";
|
||||
this.radioSimpleDataBinary.Size = new System.Drawing.Size(54, 17);
|
||||
this.radioSimpleDataBinary.TabIndex = 4;
|
||||
this.radioSimpleDataBinary.TabStop = true;
|
||||
this.radioSimpleDataBinary.Text = "Binary";
|
||||
this.radioSimpleDataBinary.UseVisualStyleBackColor = true;
|
||||
this.radioSimpleDataBinary.CheckedChanged += new System.EventHandler(this.SimpleDisplay_CheckedChanged);
|
||||
//
|
||||
// radioSimpleDataDecimal
|
||||
//
|
||||
this.radioSimpleDataDecimal.AutoSize = true;
|
||||
this.radioSimpleDataDecimal.Location = new System.Drawing.Point(6, 41);
|
||||
this.radioSimpleDataDecimal.Name = "radioSimpleDataDecimal";
|
||||
this.radioSimpleDataDecimal.Size = new System.Drawing.Size(63, 17);
|
||||
this.radioSimpleDataDecimal.TabIndex = 3;
|
||||
this.radioSimpleDataDecimal.TabStop = true;
|
||||
this.radioSimpleDataDecimal.Text = "Decimal";
|
||||
this.radioSimpleDataDecimal.UseVisualStyleBackColor = true;
|
||||
this.radioSimpleDataDecimal.CheckedChanged += new System.EventHandler(this.SimpleDisplay_CheckedChanged);
|
||||
//
|
||||
// radioSimpleDataHex
|
||||
//
|
||||
this.radioSimpleDataHex.AutoSize = true;
|
||||
this.radioSimpleDataHex.Location = new System.Drawing.Point(6, 18);
|
||||
this.radioSimpleDataHex.Name = "radioSimpleDataHex";
|
||||
this.radioSimpleDataHex.Size = new System.Drawing.Size(44, 17);
|
||||
this.radioSimpleDataHex.TabIndex = 2;
|
||||
this.radioSimpleDataHex.TabStop = true;
|
||||
this.radioSimpleDataHex.Text = "Hex";
|
||||
this.radioSimpleDataHex.UseVisualStyleBackColor = true;
|
||||
this.radioSimpleDataHex.CheckedChanged += new System.EventHandler(this.SimpleDisplay_CheckedChanged);
|
||||
//
|
||||
// radioDenseHex
|
||||
//
|
||||
this.radioDenseHex.AutoSize = true;
|
||||
this.radioDenseHex.Location = new System.Drawing.Point(14, 247);
|
||||
this.radioDenseHex.Name = "radioDenseHex";
|
||||
this.radioDenseHex.Size = new System.Drawing.Size(130, 17);
|
||||
this.radioDenseHex.TabIndex = 11;
|
||||
this.radioDenseHex.TabStop = true;
|
||||
this.radioDenseHex.Text = "Densely-&packed bytes";
|
||||
this.radioDenseHex.UseVisualStyleBackColor = true;
|
||||
this.radioDenseHex.CheckedChanged += new System.EventHandler(this.MainGroup_CheckedChanged);
|
||||
//
|
||||
// radioFill
|
||||
//
|
||||
this.radioFill.AutoSize = true;
|
||||
this.radioFill.Location = new System.Drawing.Point(14, 270);
|
||||
this.radioFill.Name = "radioFill";
|
||||
this.radioFill.Size = new System.Drawing.Size(88, 17);
|
||||
this.radioFill.TabIndex = 12;
|
||||
this.radioFill.TabStop = true;
|
||||
this.radioFill.Text = "&Fill with value";
|
||||
this.radioFill.UseVisualStyleBackColor = true;
|
||||
this.radioFill.CheckedChanged += new System.EventHandler(this.MainGroup_CheckedChanged);
|
||||
//
|
||||
// horizontalLine1
|
||||
//
|
||||
this.horizontalLine1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
|
||||
this.horizontalLine1.Location = new System.Drawing.Point(12, 81);
|
||||
this.horizontalLine1.Name = "horizontalLine1";
|
||||
this.horizontalLine1.Size = new System.Drawing.Size(500, 2);
|
||||
this.horizontalLine1.TabIndex = 3;
|
||||
//
|
||||
// horizontalLine2
|
||||
//
|
||||
this.horizontalLine2.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
|
||||
this.horizontalLine2.Location = new System.Drawing.Point(12, 239);
|
||||
this.horizontalLine2.Name = "horizontalLine2";
|
||||
this.horizontalLine2.Size = new System.Drawing.Size(320, 2);
|
||||
this.horizontalLine2.TabIndex = 10;
|
||||
//
|
||||
// stringSectionLabel
|
||||
//
|
||||
this.stringSectionLabel.AutoSize = true;
|
||||
this.stringSectionLabel.Location = new System.Drawing.Point(12, 308);
|
||||
this.stringSectionLabel.Name = "stringSectionLabel";
|
||||
this.stringSectionLabel.Size = new System.Drawing.Size(34, 13);
|
||||
this.stringSectionLabel.TabIndex = 13;
|
||||
this.stringSectionLabel.Text = "String";
|
||||
//
|
||||
// horizontalLine3
|
||||
//
|
||||
this.horizontalLine3.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
|
||||
this.horizontalLine3.Location = new System.Drawing.Point(12, 326);
|
||||
this.horizontalLine3.Name = "horizontalLine3";
|
||||
this.horizontalLine3.Size = new System.Drawing.Size(320, 2);
|
||||
this.horizontalLine3.TabIndex = 14;
|
||||
//
|
||||
// radioStringMixed
|
||||
//
|
||||
this.radioStringMixed.AutoSize = true;
|
||||
this.radioStringMixed.Location = new System.Drawing.Point(14, 334);
|
||||
this.radioStringMixed.Name = "radioStringMixed";
|
||||
this.radioStringMixed.Size = new System.Drawing.Size(257, 17);
|
||||
this.radioStringMixed.TabIndex = 15;
|
||||
this.radioStringMixed.TabStop = true;
|
||||
this.radioStringMixed.Text = "Mixed ASCII ({0} bytes) and non-ASCII ({1} bytes)";
|
||||
this.radioStringMixed.UseVisualStyleBackColor = true;
|
||||
this.radioStringMixed.CheckedChanged += new System.EventHandler(this.MainGroup_CheckedChanged);
|
||||
//
|
||||
// radioStringMixedReverse
|
||||
//
|
||||
this.radioStringMixedReverse.AutoSize = true;
|
||||
this.radioStringMixedReverse.Location = new System.Drawing.Point(14, 357);
|
||||
this.radioStringMixedReverse.Name = "radioStringMixedReverse";
|
||||
this.radioStringMixedReverse.Size = new System.Drawing.Size(275, 17);
|
||||
this.radioStringMixedReverse.TabIndex = 16;
|
||||
this.radioStringMixedReverse.TabStop = true;
|
||||
this.radioStringMixedReverse.Text = "Reversed ASCII ({0} bytes) and non-ASCII ({1} bytes)";
|
||||
this.radioStringMixedReverse.UseVisualStyleBackColor = true;
|
||||
this.radioStringMixedReverse.CheckedChanged += new System.EventHandler(this.MainGroup_CheckedChanged);
|
||||
//
|
||||
// radioStringNullTerm
|
||||
//
|
||||
this.radioStringNullTerm.AutoSize = true;
|
||||
this.radioStringNullTerm.Location = new System.Drawing.Point(14, 381);
|
||||
this.radioStringNullTerm.Name = "radioStringNullTerm";
|
||||
this.radioStringNullTerm.Size = new System.Drawing.Size(151, 17);
|
||||
this.radioStringNullTerm.TabIndex = 17;
|
||||
this.radioStringNullTerm.TabStop = true;
|
||||
this.radioStringNullTerm.Text = "Null-terminated strings ({0})";
|
||||
this.radioStringNullTerm.UseVisualStyleBackColor = true;
|
||||
this.radioStringNullTerm.CheckedChanged += new System.EventHandler(this.MainGroup_CheckedChanged);
|
||||
//
|
||||
// radioStringLen8
|
||||
//
|
||||
this.radioStringLen8.AutoSize = true;
|
||||
this.radioStringLen8.Location = new System.Drawing.Point(14, 405);
|
||||
this.radioStringLen8.Name = "radioStringLen8";
|
||||
this.radioStringLen8.Size = new System.Drawing.Size(197, 17);
|
||||
this.radioStringLen8.TabIndex = 18;
|
||||
this.radioStringLen8.TabStop = true;
|
||||
this.radioStringLen8.Text = "Strings prefixed with 8-bit length ({0})";
|
||||
this.radioStringLen8.UseVisualStyleBackColor = true;
|
||||
this.radioStringLen8.CheckedChanged += new System.EventHandler(this.MainGroup_CheckedChanged);
|
||||
//
|
||||
// radioStringLen16
|
||||
//
|
||||
this.radioStringLen16.AutoSize = true;
|
||||
this.radioStringLen16.Location = new System.Drawing.Point(14, 429);
|
||||
this.radioStringLen16.Name = "radioStringLen16";
|
||||
this.radioStringLen16.Size = new System.Drawing.Size(203, 17);
|
||||
this.radioStringLen16.TabIndex = 19;
|
||||
this.radioStringLen16.TabStop = true;
|
||||
this.radioStringLen16.Text = "Strings prefixed with 16-bit length ({0})";
|
||||
this.radioStringLen16.UseVisualStyleBackColor = true;
|
||||
this.radioStringLen16.CheckedChanged += new System.EventHandler(this.MainGroup_CheckedChanged);
|
||||
//
|
||||
// radioStringDci
|
||||
//
|
||||
this.radioStringDci.AutoSize = true;
|
||||
this.radioStringDci.Location = new System.Drawing.Point(14, 453);
|
||||
this.radioStringDci.Name = "radioStringDci";
|
||||
this.radioStringDci.Size = new System.Drawing.Size(170, 17);
|
||||
this.radioStringDci.TabIndex = 20;
|
||||
this.radioStringDci.TabStop = true;
|
||||
this.radioStringDci.Text = "Dextral character inverted ({0})";
|
||||
this.radioStringDci.UseVisualStyleBackColor = true;
|
||||
this.radioStringDci.CheckedChanged += new System.EventHandler(this.MainGroup_CheckedChanged);
|
||||
//
|
||||
// symbolEntryTextBox
|
||||
//
|
||||
this.symbolEntryTextBox.Location = new System.Drawing.Point(108, 62);
|
||||
this.symbolEntryTextBox.Name = "symbolEntryTextBox";
|
||||
this.symbolEntryTextBox.Size = new System.Drawing.Size(200, 20);
|
||||
this.symbolEntryTextBox.TabIndex = 1;
|
||||
this.symbolEntryTextBox.TextChanged += new System.EventHandler(this.symbolEntryTextBox_TextChanged);
|
||||
//
|
||||
// symbolPartPanel
|
||||
//
|
||||
this.symbolPartPanel.Controls.Add(this.radioSymbolPartBank);
|
||||
this.symbolPartPanel.Controls.Add(this.radioSymbolPartHigh);
|
||||
this.symbolPartPanel.Controls.Add(this.radioSymbolPartLow);
|
||||
this.symbolPartPanel.Location = new System.Drawing.Point(108, 86);
|
||||
this.symbolPartPanel.Name = "symbolPartPanel";
|
||||
this.symbolPartPanel.Size = new System.Drawing.Size(200, 20);
|
||||
this.symbolPartPanel.TabIndex = 27;
|
||||
//
|
||||
// radioSymbolPartBank
|
||||
//
|
||||
this.radioSymbolPartBank.AutoSize = true;
|
||||
this.radioSymbolPartBank.Location = new System.Drawing.Point(103, 1);
|
||||
this.radioSymbolPartBank.Name = "radioSymbolPartBank";
|
||||
this.radioSymbolPartBank.Size = new System.Drawing.Size(50, 17);
|
||||
this.radioSymbolPartBank.TabIndex = 2;
|
||||
this.radioSymbolPartBank.TabStop = true;
|
||||
this.radioSymbolPartBank.Text = "Bank";
|
||||
this.radioSymbolPartBank.UseVisualStyleBackColor = true;
|
||||
this.radioSymbolPartBank.CheckedChanged += new System.EventHandler(this.PartGroup_CheckedChanged);
|
||||
//
|
||||
// radioSymbolPartHigh
|
||||
//
|
||||
this.radioSymbolPartHigh.AutoSize = true;
|
||||
this.radioSymbolPartHigh.Location = new System.Drawing.Point(52, 1);
|
||||
this.radioSymbolPartHigh.Name = "radioSymbolPartHigh";
|
||||
this.radioSymbolPartHigh.Size = new System.Drawing.Size(47, 17);
|
||||
this.radioSymbolPartHigh.TabIndex = 1;
|
||||
this.radioSymbolPartHigh.TabStop = true;
|
||||
this.radioSymbolPartHigh.Text = "High";
|
||||
this.radioSymbolPartHigh.UseVisualStyleBackColor = true;
|
||||
this.radioSymbolPartHigh.CheckedChanged += new System.EventHandler(this.PartGroup_CheckedChanged);
|
||||
//
|
||||
// radioSymbolPartLow
|
||||
//
|
||||
this.radioSymbolPartLow.AutoSize = true;
|
||||
this.radioSymbolPartLow.Location = new System.Drawing.Point(4, 1);
|
||||
this.radioSymbolPartLow.Name = "radioSymbolPartLow";
|
||||
this.radioSymbolPartLow.Size = new System.Drawing.Size(45, 17);
|
||||
this.radioSymbolPartLow.TabIndex = 0;
|
||||
this.radioSymbolPartLow.TabStop = true;
|
||||
this.radioSymbolPartLow.Text = "Low";
|
||||
this.radioSymbolPartLow.UseVisualStyleBackColor = true;
|
||||
this.radioSymbolPartLow.CheckedChanged += new System.EventHandler(this.PartGroup_CheckedChanged);
|
||||
//
|
||||
// radioSimpleDataAscii
|
||||
//
|
||||
this.radioSimpleDataAscii.AutoSize = true;
|
||||
this.radioSimpleDataAscii.Location = new System.Drawing.Point(6, 87);
|
||||
this.radioSimpleDataAscii.Name = "radioSimpleDataAscii";
|
||||
this.radioSimpleDataAscii.Size = new System.Drawing.Size(52, 17);
|
||||
this.radioSimpleDataAscii.TabIndex = 5;
|
||||
this.radioSimpleDataAscii.TabStop = true;
|
||||
this.radioSimpleDataAscii.Text = "ASCII";
|
||||
this.radioSimpleDataAscii.UseVisualStyleBackColor = true;
|
||||
this.radioSimpleDataAscii.CheckedChanged += new System.EventHandler(this.SimpleDisplay_CheckedChanged);
|
||||
//
|
||||
// radioDefaultFormat
|
||||
//
|
||||
this.radioDefaultFormat.AutoSize = true;
|
||||
this.radioDefaultFormat.Location = new System.Drawing.Point(14, 30);
|
||||
this.radioDefaultFormat.Name = "radioDefaultFormat";
|
||||
this.radioDefaultFormat.Size = new System.Drawing.Size(59, 17);
|
||||
this.radioDefaultFormat.TabIndex = 1;
|
||||
this.radioDefaultFormat.TabStop = true;
|
||||
this.radioDefaultFormat.Text = "&Default";
|
||||
this.radioDefaultFormat.UseVisualStyleBackColor = true;
|
||||
this.radioDefaultFormat.CheckedChanged += new System.EventHandler(this.MainGroup_CheckedChanged);
|
||||
//
|
||||
// simpleDisplayAsGroupBox
|
||||
//
|
||||
this.simpleDisplayAsGroupBox.Controls.Add(this.radioSimpleDataAddress);
|
||||
this.simpleDisplayAsGroupBox.Controls.Add(this.radioSimpleDataSymbolic);
|
||||
this.simpleDisplayAsGroupBox.Controls.Add(this.radioSimpleDataAscii);
|
||||
this.simpleDisplayAsGroupBox.Controls.Add(this.radioSimpleDataHex);
|
||||
this.simpleDisplayAsGroupBox.Controls.Add(this.symbolPartPanel);
|
||||
this.simpleDisplayAsGroupBox.Controls.Add(this.radioSimpleDataBinary);
|
||||
this.simpleDisplayAsGroupBox.Controls.Add(this.symbolEntryTextBox);
|
||||
this.simpleDisplayAsGroupBox.Controls.Add(this.radioSimpleDataDecimal);
|
||||
this.simpleDisplayAsGroupBox.Location = new System.Drawing.Point(190, 84);
|
||||
this.simpleDisplayAsGroupBox.Name = "simpleDisplayAsGroupBox";
|
||||
this.simpleDisplayAsGroupBox.Size = new System.Drawing.Size(320, 114);
|
||||
this.simpleDisplayAsGroupBox.TabIndex = 24;
|
||||
this.simpleDisplayAsGroupBox.TabStop = false;
|
||||
this.simpleDisplayAsGroupBox.Text = "Display As...";
|
||||
//
|
||||
// radioSimpleDataAddress
|
||||
//
|
||||
this.radioSimpleDataAddress.AutoSize = true;
|
||||
this.radioSimpleDataAddress.Location = new System.Drawing.Point(89, 18);
|
||||
this.radioSimpleDataAddress.Name = "radioSimpleDataAddress";
|
||||
this.radioSimpleDataAddress.Size = new System.Drawing.Size(63, 17);
|
||||
this.radioSimpleDataAddress.TabIndex = 6;
|
||||
this.radioSimpleDataAddress.TabStop = true;
|
||||
this.radioSimpleDataAddress.Text = "&Address";
|
||||
this.radioSimpleDataAddress.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// radioSimpleDataSymbolic
|
||||
//
|
||||
this.radioSimpleDataSymbolic.AutoSize = true;
|
||||
this.radioSimpleDataSymbolic.Location = new System.Drawing.Point(89, 41);
|
||||
this.radioSimpleDataSymbolic.Name = "radioSimpleDataSymbolic";
|
||||
this.radioSimpleDataSymbolic.Size = new System.Drawing.Size(115, 17);
|
||||
this.radioSimpleDataSymbolic.TabIndex = 7;
|
||||
this.radioSimpleDataSymbolic.TabStop = true;
|
||||
this.radioSimpleDataSymbolic.Text = "&Symbolic reference";
|
||||
this.radioSimpleDataSymbolic.UseVisualStyleBackColor = true;
|
||||
this.radioSimpleDataSymbolic.CheckedChanged += new System.EventHandler(this.SimpleDisplay_CheckedChanged);
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(12, 221);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(54, 13);
|
||||
this.label1.TabIndex = 9;
|
||||
this.label1.Text = "Bulk Data";
|
||||
//
|
||||
// EditData
|
||||
//
|
||||
this.AcceptButton = this.okButton;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.CancelButton = this.cancelButton;
|
||||
this.ClientSize = new System.Drawing.Size(525, 496);
|
||||
this.Controls.Add(this.label1);
|
||||
this.Controls.Add(this.simpleDisplayAsGroupBox);
|
||||
this.Controls.Add(this.radioDefaultFormat);
|
||||
this.Controls.Add(this.radioStringDci);
|
||||
this.Controls.Add(this.radioStringLen16);
|
||||
this.Controls.Add(this.radioStringLen8);
|
||||
this.Controls.Add(this.radioStringNullTerm);
|
||||
this.Controls.Add(this.radioStringMixedReverse);
|
||||
this.Controls.Add(this.radioStringMixed);
|
||||
this.Controls.Add(this.stringSectionLabel);
|
||||
this.Controls.Add(this.horizontalLine1);
|
||||
this.Controls.Add(this.horizontalLine2);
|
||||
this.Controls.Add(this.horizontalLine3);
|
||||
this.Controls.Add(this.radioFill);
|
||||
this.Controls.Add(this.radioDenseHex);
|
||||
this.Controls.Add(this.radio32BitLittle);
|
||||
this.Controls.Add(this.radio24BitLittle);
|
||||
this.Controls.Add(this.radio16BitLittle);
|
||||
this.Controls.Add(this.radio16BitBig);
|
||||
this.Controls.Add(this.radioSingleBytes);
|
||||
this.Controls.Add(this.rawDataSectionLabel);
|
||||
this.Controls.Add(this.selectFormatLabel);
|
||||
this.Controls.Add(this.okButton);
|
||||
this.Controls.Add(this.cancelButton);
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "EditData";
|
||||
this.ShowInTaskbar = false;
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "Edit Data";
|
||||
this.Load += new System.EventHandler(this.EditData_Load);
|
||||
this.Shown += new System.EventHandler(this.EditData_Shown);
|
||||
this.symbolPartPanel.ResumeLayout(false);
|
||||
this.symbolPartPanel.PerformLayout();
|
||||
this.simpleDisplayAsGroupBox.ResumeLayout(false);
|
||||
this.simpleDisplayAsGroupBox.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Button cancelButton;
|
||||
private System.Windows.Forms.Button okButton;
|
||||
private System.Windows.Forms.Label selectFormatLabel;
|
||||
private System.Windows.Forms.Label rawDataSectionLabel;
|
||||
private System.Windows.Forms.RadioButton radioSingleBytes;
|
||||
private System.Windows.Forms.RadioButton radio16BitBig;
|
||||
private System.Windows.Forms.RadioButton radio16BitLittle;
|
||||
private System.Windows.Forms.RadioButton radio24BitLittle;
|
||||
private System.Windows.Forms.RadioButton radio32BitLittle;
|
||||
private System.Windows.Forms.RadioButton radioSimpleDataBinary;
|
||||
private System.Windows.Forms.RadioButton radioSimpleDataDecimal;
|
||||
private System.Windows.Forms.RadioButton radioSimpleDataHex;
|
||||
private System.Windows.Forms.RadioButton radioDenseHex;
|
||||
private System.Windows.Forms.RadioButton radioFill;
|
||||
private System.Windows.Forms.Label horizontalLine1;
|
||||
private System.Windows.Forms.Label horizontalLine2;
|
||||
private System.Windows.Forms.Label stringSectionLabel;
|
||||
private System.Windows.Forms.Label horizontalLine3;
|
||||
private System.Windows.Forms.RadioButton radioStringMixed;
|
||||
private System.Windows.Forms.RadioButton radioStringMixedReverse;
|
||||
private System.Windows.Forms.RadioButton radioStringNullTerm;
|
||||
private System.Windows.Forms.RadioButton radioStringLen8;
|
||||
private System.Windows.Forms.RadioButton radioStringLen16;
|
||||
private System.Windows.Forms.RadioButton radioStringDci;
|
||||
private System.Windows.Forms.TextBox symbolEntryTextBox;
|
||||
private System.Windows.Forms.Panel symbolPartPanel;
|
||||
private System.Windows.Forms.RadioButton radioSymbolPartBank;
|
||||
private System.Windows.Forms.RadioButton radioSymbolPartHigh;
|
||||
private System.Windows.Forms.RadioButton radioSymbolPartLow;
|
||||
private System.Windows.Forms.RadioButton radioSimpleDataAscii;
|
||||
private System.Windows.Forms.RadioButton radioDefaultFormat;
|
||||
private System.Windows.Forms.GroupBox simpleDisplayAsGroupBox;
|
||||
private System.Windows.Forms.RadioButton radioSimpleDataSymbolic;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.RadioButton radioSimpleDataAddress;
|
||||
}
|
||||
}
|
953
SourceGen/AppForms/EditData.cs
Normal file
953
SourceGen/AppForms/EditData.cs
Normal file
@ -0,0 +1,953 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using CommonUtil;
|
||||
|
||||
namespace SourceGen.AppForms {
|
||||
public partial class EditData : Form {
|
||||
/// <summary>
|
||||
/// Result set that describes the formatting to perform. Not all regions will have
|
||||
/// the same format, e.g. the "mixed ASCII" mode will alternate strings and bytes
|
||||
/// (rather than a dedicated "mixed ASCII" format type).
|
||||
/// </summary>
|
||||
public SortedList<int, FormatDescriptor> Results { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Selected offsets. An otherwise contiguous range of offsets can be broken up
|
||||
/// by user-specified labels and address discontinuities, so this needs to be
|
||||
/// processed by range.
|
||||
/// </summary>
|
||||
public TypedRangeSet Selection { private get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// FormatDescriptor from the first offset. May be null if the offset doesn't
|
||||
/// have a format descriptor specified. This will be used to configure the
|
||||
/// dialog controls if the format is suited to the selection. The goal is to
|
||||
/// make single-item editing work as expected.
|
||||
/// </summary>
|
||||
public FormatDescriptor FirstFormatDescriptor { private get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Raw file data.
|
||||
/// </summary>
|
||||
private byte[] mFileData;
|
||||
|
||||
/// <summary>
|
||||
/// Symbol table to use when resolving symbolic values.
|
||||
/// </summary>
|
||||
private SymbolTable mSymbolTable;
|
||||
|
||||
/// <summary>
|
||||
/// Formatter to use when displaying addresses and hex values.
|
||||
/// </summary>
|
||||
private Asm65.Formatter mFormatter;
|
||||
|
||||
/// <summary>
|
||||
/// Set this during initial control configuration, so we know to ignore the CheckedChanged
|
||||
/// events.
|
||||
/// </summary>
|
||||
private bool mIsInitialSetup;
|
||||
|
||||
/// <summary>
|
||||
/// Set to true if, during the initial setup, the format defined by FirstFormatDescriptor
|
||||
/// was unavailable.
|
||||
/// </summary>
|
||||
private bool mPreferredFormatUnavailable;
|
||||
|
||||
|
||||
public EditData(byte[] fileData, SymbolTable symbolTable, Asm65.Formatter formatter) {
|
||||
InitializeComponent();
|
||||
|
||||
mFileData = fileData;
|
||||
mSymbolTable = symbolTable;
|
||||
mFormatter = formatter;
|
||||
|
||||
//Results = new List<Result>();
|
||||
}
|
||||
|
||||
private void EditData_Load(object sender, EventArgs e) {
|
||||
DateTime startWhen = DateTime.Now;
|
||||
|
||||
mIsInitialSetup = true;
|
||||
|
||||
// Determine which of the various options is suitable for the selected offsets.
|
||||
// Disable any radio buttons that won't work.
|
||||
AnalyzeRanges();
|
||||
|
||||
// Configure the dialog from the FormatDescriptor, if one is available.
|
||||
Debug.WriteLine("First FD: " + FirstFormatDescriptor);
|
||||
SetControlsFromDescriptor(FirstFormatDescriptor);
|
||||
|
||||
if (mPreferredFormatUnavailable) {
|
||||
// This can happen when e.g. a bunch of stuff is formatted as null-terminated
|
||||
// strings. We don't recognize a lone zero as a string, but we allow it if
|
||||
// it's next to a bunch of others. If you come back later and try to format
|
||||
// just that one byte, you end up here.
|
||||
// TODO(maybe): make it more obvious what's going on?
|
||||
Debug.WriteLine("NOTE: preferred format unavailable");
|
||||
}
|
||||
|
||||
mIsInitialSetup = false;
|
||||
UpdateControls();
|
||||
|
||||
Debug.WriteLine("EditData dialog load time: " +
|
||||
(DateTime.Now - startWhen).TotalMilliseconds + " ms");
|
||||
}
|
||||
|
||||
private void EditData_Shown(object sender, EventArgs e) {
|
||||
// Start with the focus in the text box if the initial format allows for a
|
||||
// symbolic reference. This way they can start typing immediately.
|
||||
if (simpleDisplayAsGroupBox.Enabled) {
|
||||
symbolEntryTextBox.Focus();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles CheckedChanged event for all radio buttons in main group. This will
|
||||
/// fire twice when a radio button is clicked (once to un-check the old, once
|
||||
/// to check the new).
|
||||
/// </summary>
|
||||
private void MainGroup_CheckedChanged(object sender, EventArgs e) {
|
||||
// Enable/disable the style group and the low/high/bank radio group.
|
||||
// Update preview window.
|
||||
UpdateControls();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles CheckedChanged event for radio buttons in the simple-data "display as"
|
||||
/// group box.
|
||||
/// </summary>
|
||||
private void SimpleDisplay_CheckedChanged(object sender, EventArgs e) {
|
||||
// Enable/disable the low/high/bank radio group.
|
||||
UpdateControls();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles CheckedChanged event for all radio buttons in symbol-part group.
|
||||
/// </summary>
|
||||
private void PartGroup_CheckedChanged(object sender, EventArgs e) {
|
||||
// not currently using a preview window; could add one for single items?
|
||||
}
|
||||
|
||||
private void symbolEntryTextBox_TextChanged(object sender, EventArgs e) {
|
||||
// Make sure Symbol is checked if they're typing text in.
|
||||
Debug.Assert(radioSimpleDataSymbolic.Enabled);
|
||||
radioSimpleDataSymbolic.Checked = true;
|
||||
// Update OK button based on symbol validity.
|
||||
UpdateControls();
|
||||
}
|
||||
|
||||
private void okButton_Click(object sender, EventArgs e) {
|
||||
CreateDescriptorListFromControls();
|
||||
FormatDescriptor.DebugDumpSortedList(Results);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates all of the controls to reflect the current internal state.
|
||||
/// </summary>
|
||||
private void UpdateControls() {
|
||||
if (mIsInitialSetup) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Configure the simple data "display as" style box.
|
||||
bool wantStyle = false;
|
||||
int simpleWidth = -1;
|
||||
bool isBigEndian = false;
|
||||
if (radioSingleBytes.Checked) {
|
||||
wantStyle = true;
|
||||
simpleWidth = 1;
|
||||
} else if (radio16BitLittle.Checked) {
|
||||
wantStyle = true;
|
||||
simpleWidth = 2;
|
||||
} else if (radio16BitBig.Checked) {
|
||||
wantStyle = true;
|
||||
simpleWidth = 2;
|
||||
isBigEndian = true;
|
||||
} else if (radio24BitLittle.Checked) {
|
||||
wantStyle = true;
|
||||
simpleWidth = 3;
|
||||
} else if (radio32BitLittle.Checked) {
|
||||
wantStyle = true;
|
||||
simpleWidth = 4;
|
||||
}
|
||||
bool focusOnSymbol = !simpleDisplayAsGroupBox.Enabled && wantStyle;
|
||||
simpleDisplayAsGroupBox.Enabled = wantStyle;
|
||||
if (wantStyle) {
|
||||
// TODO(soon): compute on first need and save results; this is getting called
|
||||
// 2x as radio buttons are hit, and might be slow on large data sets
|
||||
radioSimpleDataAscii.Enabled = IsRawAsciiCompatible(simpleWidth, isBigEndian);
|
||||
}
|
||||
|
||||
// Enable the symbolic reference entry box if the "display as" group is enabled.
|
||||
// That way instead of "click 16-bit", "click symbol", "enter symbol", the user
|
||||
// can skip the second step.
|
||||
symbolEntryTextBox.Enabled = simpleDisplayAsGroupBox.Enabled;
|
||||
symbolPartPanel.Enabled = radioSimpleDataSymbolic.Checked;
|
||||
|
||||
// If we just enabled the group box, set the focus on the symbol entry box. This
|
||||
// removes another click from the steps, though it's a bit aggressive if you're
|
||||
// trying to arrow your way through the items.
|
||||
if (focusOnSymbol) {
|
||||
symbolEntryTextBox.Focus();
|
||||
}
|
||||
|
||||
bool isOk = true;
|
||||
if (radioSimpleDataSymbolic.Checked) {
|
||||
// Just check for correct format. References to non-existent labels are allowed.
|
||||
isOk = Asm65.Label.ValidateLabel(symbolEntryTextBox.Text);
|
||||
|
||||
// Actually, let's discourage references to auto-labels.
|
||||
if (isOk && mSymbolTable.TryGetValue(symbolEntryTextBox.Text, out Symbol sym)) {
|
||||
isOk = sym.SymbolSource != Symbol.Source.Auto;
|
||||
}
|
||||
}
|
||||
okButton.Enabled = isOk;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Analyzes the selection to see which data formatting options are suitable.
|
||||
/// Disables radio buttons and updates labels.
|
||||
///
|
||||
/// Call this once, when the dialog is first loaded.
|
||||
/// </summary>
|
||||
private void AnalyzeRanges() {
|
||||
Debug.Assert(Selection.Count != 0);
|
||||
|
||||
string fmt = (Selection.RangeCount == 1) ?
|
||||
Properties.Resources.FMT_FORMAT_SINGLE_GROUP :
|
||||
Properties.Resources.FMT_FORMAT_MULTIPLE_GROUPS;
|
||||
selectFormatLabel.Text = string.Format(fmt, Selection.Count, Selection.RangeCount);
|
||||
|
||||
IEnumerator<TypedRangeSet.TypedRange> iter = Selection.RangeListIterator;
|
||||
|
||||
int mixedAsciiOkCount = 0;
|
||||
int mixedAsciiNotCount = 0;
|
||||
int nullTermStringCount = 0;
|
||||
int len8StringCount = 0;
|
||||
int len16StringCount = 0;
|
||||
int dciStringCount = 0;
|
||||
//int revDciStringCount = 0;
|
||||
|
||||
// For each range, check to see if the data within qualifies for the various
|
||||
// options. If any of them fail to meet the criteria, the option is disabled
|
||||
// for all ranges.
|
||||
while (iter.MoveNext()) {
|
||||
TypedRangeSet.TypedRange rng = iter.Current;
|
||||
Debug.WriteLine("Testing [" + rng.Low + ", " + rng.High + "]");
|
||||
|
||||
// Start with the easy ones. Single-byte and dense are always enabled.
|
||||
|
||||
int count = rng.High - rng.Low + 1;
|
||||
Debug.Assert(count > 0);
|
||||
if ((count & 0x01) != 0) {
|
||||
// not divisible by 2, disallow 16-bit entries
|
||||
radio16BitLittle.Enabled = false;
|
||||
radio16BitBig.Enabled = false;
|
||||
}
|
||||
if ((count & 0x03) != 0) {
|
||||
// not divisible by 4, disallow 32-bit entries
|
||||
radio32BitLittle.Enabled = false;
|
||||
}
|
||||
if ((count / 3) * 3 != count) {
|
||||
// not divisible by 3, disallow 24-bit entries
|
||||
radio24BitLittle.Enabled = false;
|
||||
}
|
||||
|
||||
|
||||
// Check for run of bytes (2 or more of the same thing). Remember that
|
||||
// we check this one region at a time, and each region could have different
|
||||
// bytes, but so long as the bytes are all the same within a region we're good.
|
||||
if (radioFill.Enabled && count > 1 &&
|
||||
DataAnalysis.RecognizeRun(mFileData, rng.Low, rng.High) == count) {
|
||||
// LGTM
|
||||
} else {
|
||||
radioFill.Enabled = false;
|
||||
}
|
||||
|
||||
// See if there's enough string data to make it worthwhile. We use an
|
||||
// arbitrary threshold of 2+ ASCII characters, and require twice as many
|
||||
// ASCII as non-ASCII. We arbitrarily require the strings to be either
|
||||
// high or low ASCII, and treat the other as non-ASCII. (We could relax
|
||||
// this -- we generate separate items for each string and non-ASCII chunk --
|
||||
// but I'm trying to hide the option when the buffer doesn't really seem
|
||||
// to be holding strings. Could replace with some sort of minimum string
|
||||
// length requirement?)
|
||||
if (radioStringMixed.Enabled) {
|
||||
int asciiCount;
|
||||
DataAnalysis.CountAsciiBytes(mFileData, rng.Low, rng.High,
|
||||
out int lowAscii, out int highAscii, out int nonAscii);
|
||||
if (highAscii > lowAscii) {
|
||||
asciiCount = highAscii;
|
||||
nonAscii += lowAscii;
|
||||
} else {
|
||||
asciiCount = lowAscii;
|
||||
nonAscii += highAscii;
|
||||
}
|
||||
|
||||
if (asciiCount >= 2 && asciiCount >= nonAscii * 2) {
|
||||
// Looks good
|
||||
mixedAsciiOkCount += asciiCount;
|
||||
mixedAsciiNotCount += nonAscii;
|
||||
} else {
|
||||
// Fail
|
||||
radioStringMixed.Enabled = false;
|
||||
radioStringMixedReverse.Enabled = false;
|
||||
mixedAsciiOkCount = mixedAsciiNotCount = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for null-terminated strings. Zero-length strings are allowed, but
|
||||
// not counted -- we want to have some actual character data. Individual
|
||||
// strings need to be entirely high-ASCII or low-ASCII, but not all strings
|
||||
// in a region have to be the same.
|
||||
if (radioStringNullTerm.Enabled) {
|
||||
int strCount = DataAnalysis.RecognizeNullTerminatedStrings(mFileData,
|
||||
rng.Low, rng.High);
|
||||
if (strCount > 0) {
|
||||
nullTermStringCount += strCount;
|
||||
} else {
|
||||
radioStringNullTerm.Enabled = false;
|
||||
nullTermStringCount = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for strings prefixed with an 8-bit length.
|
||||
if (radioStringLen8.Enabled) {
|
||||
int strCount = DataAnalysis.RecognizeLen8Strings(mFileData, rng.Low, rng.High);
|
||||
if (strCount > 0) {
|
||||
len8StringCount += strCount;
|
||||
} else {
|
||||
radioStringLen8.Enabled = false;
|
||||
len8StringCount = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for strings prefixed with a 16-bit length.
|
||||
if (radioStringLen16.Enabled) {
|
||||
int strCount = DataAnalysis.RecognizeLen16Strings(mFileData, rng.Low, rng.High);
|
||||
if (strCount > 0) {
|
||||
len16StringCount += strCount;
|
||||
} else {
|
||||
radioStringLen16.Enabled = false;
|
||||
len16StringCount = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for DCI strings. All strings within a single range must have the
|
||||
// same "polarity", e.g. low ASCII terminated by high ASCII.
|
||||
if (radioStringDci.Enabled) {
|
||||
int strCount = DataAnalysis.RecognizeDciStrings(mFileData, rng.Low, rng.High);
|
||||
if (strCount > 0) {
|
||||
dciStringCount += strCount;
|
||||
} else {
|
||||
radioStringDci.Enabled = false;
|
||||
dciStringCount = -1;
|
||||
}
|
||||
}
|
||||
|
||||
//// Check for reverse DCI strings. All strings within a single range must have the
|
||||
//// same "polarity", e.g. low ASCII terminated by high ASCII.
|
||||
//if (radioStringDciReverse.Enabled) {
|
||||
// int strCount = DataAnalysis.RecognizeReverseDciStrings(mFileData,
|
||||
// rng.Low, rng.High);
|
||||
// if (strCount > 0) {
|
||||
// revDciStringCount += strCount;
|
||||
// } else {
|
||||
// radioStringDciReverse.Enabled = false;
|
||||
// revDciStringCount = -1;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
// Update the dialog with string and character counts, summed across all regions.
|
||||
|
||||
if (mixedAsciiOkCount > 0) {
|
||||
Debug.Assert(radioStringMixed.Enabled);
|
||||
radioStringMixed.Text = string.Format(radioStringMixed.Text,
|
||||
mixedAsciiOkCount, mixedAsciiNotCount);
|
||||
radioStringMixedReverse.Text = string.Format(radioStringMixedReverse.Text,
|
||||
mixedAsciiOkCount, mixedAsciiNotCount);
|
||||
} else {
|
||||
Debug.Assert(!radioStringMixed.Enabled);
|
||||
radioStringMixed.Text = string.Format(radioStringMixed.Text, "xx", "xx");
|
||||
radioStringMixedReverse.Text = string.Format(radioStringMixedReverse.Text,
|
||||
"xx", "xx");
|
||||
}
|
||||
|
||||
if (nullTermStringCount > 0) {
|
||||
Debug.Assert(radioStringNullTerm.Enabled);
|
||||
radioStringNullTerm.Text = string.Format(radioStringNullTerm.Text, nullTermStringCount);
|
||||
} else {
|
||||
Debug.Assert(!radioStringNullTerm.Enabled);
|
||||
radioStringNullTerm.Text = string.Format(radioStringNullTerm.Text, "xx");
|
||||
}
|
||||
|
||||
if (len8StringCount > 0) {
|
||||
Debug.Assert(radioStringLen8.Enabled);
|
||||
radioStringLen8.Text = string.Format(radioStringLen8.Text, len8StringCount);
|
||||
} else {
|
||||
Debug.Assert(!radioStringLen8.Enabled);
|
||||
radioStringLen8.Text = string.Format(radioStringLen8.Text, "xx");
|
||||
}
|
||||
|
||||
if (len16StringCount > 0) {
|
||||
Debug.Assert(radioStringLen16.Enabled);
|
||||
radioStringLen16.Text = string.Format(radioStringLen16.Text, len16StringCount);
|
||||
} else {
|
||||
Debug.Assert(!radioStringLen16.Enabled);
|
||||
radioStringLen16.Text = string.Format(radioStringLen16.Text, "xx");
|
||||
}
|
||||
|
||||
if (dciStringCount > 0) {
|
||||
Debug.Assert(radioStringDci.Enabled);
|
||||
radioStringDci.Text = string.Format(radioStringDci.Text, dciStringCount);
|
||||
} else {
|
||||
Debug.Assert(!radioStringDci.Enabled);
|
||||
radioStringDci.Text = string.Format(radioStringDci.Text, "xx");
|
||||
}
|
||||
|
||||
//if (revDciStringCount > 0) {
|
||||
// Debug.Assert(radioStringDciReverse.Enabled);
|
||||
// radioStringDciReverse.Text =
|
||||
// string.Format(radioStringDciReverse.Text, revDciStringCount);
|
||||
//} else {
|
||||
// Debug.Assert(!radioStringDciReverse.Enabled);
|
||||
// radioStringDciReverse.Text = string.Format(radioStringDciReverse.Text, "xx");
|
||||
//}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the data in the buffer can be represented as ASCII values.
|
||||
/// Using ".DD1 'A'" for 0x41 is obvious, but we also allow ".DD2 'A'" for
|
||||
/// 0x41 0x00. 16-bit character constants are more likely as intermediate
|
||||
/// operands, but could be found in data areas.
|
||||
///
|
||||
/// High and low ASCII are allowed, and may be freely mixed.
|
||||
///
|
||||
/// Testing explicitly is probably excessive, and possibly counter-productive if
|
||||
/// the user is trying to flag an area that is a mix of ASCII and non-ASCII and
|
||||
/// just wants hex for the rest, but we'll give it a try.
|
||||
/// </summary>
|
||||
/// <param name="wordWidth">Number of bytes per character.</param>
|
||||
/// <param name="isBigEndian">Word endian-ness.</param>
|
||||
/// <returns>True if data in all regions can be represented as high or low ASCII.</returns>
|
||||
private bool IsRawAsciiCompatible(int wordWidth, bool isBigEndian) {
|
||||
IEnumerator<TypedRangeSet.TypedRange> iter = Selection.RangeListIterator;
|
||||
while (iter.MoveNext()) {
|
||||
TypedRangeSet.TypedRange rng = iter.Current;
|
||||
Debug.Assert(((rng.High - rng.Low + 1) / wordWidth) * wordWidth ==
|
||||
rng.High - rng.Low + 1);
|
||||
for (int i = rng.Low; i <= rng.High; i += wordWidth) {
|
||||
int val = RawData.GetWord(mFileData, rng.Low, wordWidth, isBigEndian);
|
||||
if (val < 0x20 || (val >= 0x7f && val < 0xa0) || val >= 0xff) {
|
||||
// bad value, fail
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configures the dialog controls based on the provided format descriptor. If
|
||||
/// the desired options are unavailable, a suitable default is selected instead.
|
||||
/// </summary>
|
||||
/// <param name="dfd">FormatDescriptor to use.</param>
|
||||
private void SetControlsFromDescriptor(FormatDescriptor dfd) {
|
||||
Debug.Assert(mIsInitialSetup);
|
||||
radioSimpleDataHex.Checked = true;
|
||||
radioSymbolPartLow.Checked = true;
|
||||
|
||||
if (dfd == null) {
|
||||
radioDefaultFormat.Checked = true;
|
||||
return;
|
||||
}
|
||||
|
||||
RadioButton preferredFormat;
|
||||
|
||||
switch (dfd.FormatType) {
|
||||
case FormatDescriptor.Type.NumericLE:
|
||||
case FormatDescriptor.Type.NumericBE:
|
||||
switch (dfd.Length) {
|
||||
case 1:
|
||||
preferredFormat = radioSingleBytes;
|
||||
break;
|
||||
case 2:
|
||||
preferredFormat =
|
||||
(dfd.FormatType == FormatDescriptor.Type.NumericLE ?
|
||||
radio16BitLittle : radio16BitBig);
|
||||
break;
|
||||
case 3:
|
||||
preferredFormat = radio24BitLittle;
|
||||
break;
|
||||
case 4:
|
||||
preferredFormat = radio32BitLittle;
|
||||
break;
|
||||
default:
|
||||
Debug.Assert(false);
|
||||
preferredFormat = radioDefaultFormat;
|
||||
break;
|
||||
}
|
||||
if (preferredFormat.Enabled) {
|
||||
switch (dfd.FormatSubType) {
|
||||
case FormatDescriptor.SubType.None:
|
||||
case FormatDescriptor.SubType.Hex:
|
||||
radioSimpleDataHex.Checked = true;
|
||||
break;
|
||||
case FormatDescriptor.SubType.Decimal:
|
||||
radioSimpleDataDecimal.Checked = true;
|
||||
break;
|
||||
case FormatDescriptor.SubType.Binary:
|
||||
radioSimpleDataBinary.Checked = true;
|
||||
break;
|
||||
case FormatDescriptor.SubType.Ascii:
|
||||
radioSimpleDataAscii.Checked = true;
|
||||
break;
|
||||
case FormatDescriptor.SubType.Address:
|
||||
radioSimpleDataAddress.Checked = true;
|
||||
break;
|
||||
case FormatDescriptor.SubType.Symbol:
|
||||
radioSimpleDataSymbolic.Checked = true;
|
||||
switch (dfd.SymbolRef.ValuePart) {
|
||||
case WeakSymbolRef.Part.Low:
|
||||
radioSymbolPartLow.Checked = true;
|
||||
break;
|
||||
case WeakSymbolRef.Part.High:
|
||||
radioSymbolPartHigh.Checked = true;
|
||||
break;
|
||||
case WeakSymbolRef.Part.Bank:
|
||||
radioSymbolPartBank.Checked = true;
|
||||
break;
|
||||
default:
|
||||
Debug.Assert(false);
|
||||
break;
|
||||
}
|
||||
Debug.Assert(dfd.HasSymbol);
|
||||
symbolEntryTextBox.Text = dfd.SymbolRef.Label;
|
||||
break;
|
||||
default:
|
||||
Debug.Assert(false);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// preferred format not enabled; leave Hex/Low checked
|
||||
}
|
||||
break;
|
||||
case FormatDescriptor.Type.String:
|
||||
switch (dfd.FormatSubType) {
|
||||
case FormatDescriptor.SubType.None:
|
||||
preferredFormat = radioStringMixed;
|
||||
break;
|
||||
case FormatDescriptor.SubType.Reverse:
|
||||
preferredFormat = radioStringMixedReverse;
|
||||
break;
|
||||
case FormatDescriptor.SubType.CString:
|
||||
preferredFormat = radioStringNullTerm;
|
||||
break;
|
||||
case FormatDescriptor.SubType.L8String:
|
||||
preferredFormat = radioStringLen8;
|
||||
break;
|
||||
case FormatDescriptor.SubType.L16String:
|
||||
preferredFormat = radioStringLen16;
|
||||
break;
|
||||
case FormatDescriptor.SubType.Dci:
|
||||
preferredFormat = radioStringDci;
|
||||
break;
|
||||
case FormatDescriptor.SubType.DciReverse:
|
||||
preferredFormat = radioDefaultFormat;
|
||||
break;
|
||||
default:
|
||||
Debug.Assert(false);
|
||||
preferredFormat = radioDefaultFormat;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case FormatDescriptor.Type.Dense:
|
||||
preferredFormat = radioDenseHex;
|
||||
break;
|
||||
case FormatDescriptor.Type.Fill:
|
||||
preferredFormat = radioFill;
|
||||
break;
|
||||
default:
|
||||
// Should not be here.
|
||||
Debug.Assert(false);
|
||||
preferredFormat = radioDefaultFormat;
|
||||
break;
|
||||
}
|
||||
|
||||
if (preferredFormat.Enabled) {
|
||||
preferredFormat.Checked = true;
|
||||
} else {
|
||||
mPreferredFormatUnavailable = true;
|
||||
radioDefaultFormat.Checked = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a list of FormatDescriptors, based on the current control configuration.
|
||||
///
|
||||
/// The entries in the list are guaranteed to be sorted by start address and not
|
||||
/// overlap.
|
||||
///
|
||||
/// We assume that whatever the control gives us is correct, e.g. it's not going
|
||||
/// to tell us to put a buffer full of zeroes into a DCI string.
|
||||
/// </summary>
|
||||
/// <returns>Result list.</returns>
|
||||
private void CreateDescriptorListFromControls() {
|
||||
FormatDescriptor.Type type = FormatDescriptor.Type.Default;
|
||||
FormatDescriptor.SubType subType = FormatDescriptor.SubType.None;
|
||||
WeakSymbolRef symbolRef = null;
|
||||
int chunkLength = -1;
|
||||
|
||||
// Decode the "display as" panel, if it's relevant.
|
||||
if (radioSimpleDataHex.Enabled) {
|
||||
if (radioSimpleDataHex.Checked) {
|
||||
subType = FormatDescriptor.SubType.Hex;
|
||||
} else if (radioSimpleDataDecimal.Checked) {
|
||||
subType = FormatDescriptor.SubType.Decimal;
|
||||
} else if (radioSimpleDataBinary.Checked) {
|
||||
subType = FormatDescriptor.SubType.Binary;
|
||||
} else if (radioSimpleDataAscii.Checked) {
|
||||
subType = FormatDescriptor.SubType.Ascii;
|
||||
} else if (radioSimpleDataAddress.Checked) {
|
||||
subType = FormatDescriptor.SubType.Address;
|
||||
} else if (radioSimpleDataSymbolic.Checked) {
|
||||
WeakSymbolRef.Part part;
|
||||
if (radioSymbolPartLow.Checked) {
|
||||
part = WeakSymbolRef.Part.Low;
|
||||
} else if (radioSymbolPartHigh.Checked) {
|
||||
part = WeakSymbolRef.Part.High;
|
||||
} else if (radioSymbolPartBank.Checked) {
|
||||
part = WeakSymbolRef.Part.Bank;
|
||||
} else {
|
||||
Debug.Assert(false);
|
||||
part = WeakSymbolRef.Part.Low;
|
||||
}
|
||||
subType = FormatDescriptor.SubType.Symbol;
|
||||
symbolRef = new WeakSymbolRef(symbolEntryTextBox.Text, part);
|
||||
} else {
|
||||
Debug.Assert(false);
|
||||
}
|
||||
} else {
|
||||
subType = 0; // set later, or doesn't matter
|
||||
}
|
||||
|
||||
// Decode the main format.
|
||||
if (radioDefaultFormat.Checked) {
|
||||
// Default/None; note this would create a multi-byte Default format, which isn't
|
||||
// really allowed. What we actually want to do is remove the explicit formatting
|
||||
// from all spanned offsets, so we use a dedicated type for that.
|
||||
type = FormatDescriptor.Type.REMOVE;
|
||||
} else if (radioSingleBytes.Checked) {
|
||||
type = FormatDescriptor.Type.NumericLE;
|
||||
chunkLength = 1;
|
||||
} else if (radio16BitLittle.Checked) {
|
||||
type = FormatDescriptor.Type.NumericLE;
|
||||
chunkLength = 2;
|
||||
} else if (radio16BitBig.Checked) {
|
||||
type = FormatDescriptor.Type.NumericBE;
|
||||
chunkLength = 2;
|
||||
} else if (radio24BitLittle.Checked) {
|
||||
type = FormatDescriptor.Type.NumericLE;
|
||||
chunkLength = 3;
|
||||
} else if (radio32BitLittle.Checked) {
|
||||
type = FormatDescriptor.Type.NumericLE;
|
||||
chunkLength = 4;
|
||||
} else if (radioDenseHex.Checked) {
|
||||
type = FormatDescriptor.Type.Dense;
|
||||
} else if (radioFill.Checked) {
|
||||
type = FormatDescriptor.Type.Fill;
|
||||
} else if (radioStringMixed.Checked) {
|
||||
type = FormatDescriptor.Type.String;
|
||||
} else if (radioStringMixedReverse.Checked) {
|
||||
type = FormatDescriptor.Type.String;
|
||||
subType = FormatDescriptor.SubType.Reverse;
|
||||
} else if (radioStringNullTerm.Checked) {
|
||||
type = FormatDescriptor.Type.String;
|
||||
subType = FormatDescriptor.SubType.CString;
|
||||
} else if (radioStringLen8.Checked) {
|
||||
type = FormatDescriptor.Type.String;
|
||||
subType = FormatDescriptor.SubType.L8String;
|
||||
} else if (radioStringLen16.Checked) {
|
||||
type = FormatDescriptor.Type.String;
|
||||
subType = FormatDescriptor.SubType.L16String;
|
||||
} else if (radioStringDci.Checked) {
|
||||
type = FormatDescriptor.Type.String;
|
||||
subType = FormatDescriptor.SubType.Dci;
|
||||
//} else if (radioStringDciReverse.Checked) {
|
||||
// type = FormatDescriptor.Type.String;
|
||||
// subType = FormatDescriptor.SubType.DciReverse;
|
||||
} else {
|
||||
Debug.Assert(false);
|
||||
// default/none
|
||||
}
|
||||
|
||||
|
||||
Results = new SortedList<int, FormatDescriptor>();
|
||||
|
||||
IEnumerator<TypedRangeSet.TypedRange> iter = Selection.RangeListIterator;
|
||||
while (iter.MoveNext()) {
|
||||
TypedRangeSet.TypedRange rng = iter.Current;
|
||||
|
||||
if (type == FormatDescriptor.Type.String) {
|
||||
// We want to create one FormatDescriptor object per string. That way
|
||||
// each string gets its own line.
|
||||
if ((subType == FormatDescriptor.SubType.None ||
|
||||
subType == FormatDescriptor.SubType.Reverse)) {
|
||||
CreateMixedStringEntries(rng.Low, rng.High, subType);
|
||||
} else if (subType == FormatDescriptor.SubType.CString) {
|
||||
CreateCStringEntries(rng.Low, rng.High, subType);
|
||||
} else if (subType == FormatDescriptor.SubType.L8String ||
|
||||
subType == FormatDescriptor.SubType.L16String) {
|
||||
CreateLengthStringEntries(rng.Low, rng.High, subType);
|
||||
} else if (subType == FormatDescriptor.SubType.Dci ||
|
||||
subType == FormatDescriptor.SubType.DciReverse) {
|
||||
CreateDciStringEntries(rng.Low, rng.High, subType);
|
||||
} else {
|
||||
Debug.Assert(false);
|
||||
CreateMixedStringEntries(rng.Low, rng.High, subType); // shrug
|
||||
}
|
||||
} else {
|
||||
CreateSimpleEntries(type, subType, chunkLength, symbolRef, rng.Low, rng.High);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates one or more FormatDescriptor entries for the specified range, adding them
|
||||
/// to the Results list.
|
||||
///
|
||||
/// This will either create one entry that spans the entire range (for e.g. strings
|
||||
/// and bulk data), or create equal-sized chunks.
|
||||
/// </summary>
|
||||
/// <param name="type">Region data type.</param>
|
||||
/// <param name="subType">Region data sub-type.</param>
|
||||
/// <param name="chunkLength">Length of a chunk, or -1 for full buffer.</param>
|
||||
/// <param name="symbolRef">Symbol reference, or null if not applicable.</param>
|
||||
/// <param name="low">Offset of first byte in range.</param>
|
||||
/// <param name="high">Offset of last byte in range.</param>
|
||||
private void CreateSimpleEntries(FormatDescriptor.Type type,
|
||||
FormatDescriptor.SubType subType, int chunkLength,
|
||||
WeakSymbolRef symbolRef, int low, int high) {
|
||||
|
||||
if (chunkLength == -1) {
|
||||
chunkLength = (high - low) + 1;
|
||||
}
|
||||
Debug.Assert(((high - low + 1) / chunkLength) * chunkLength == high - low + 1);
|
||||
|
||||
// Either we have one chunk, or we have multiple chunks with the same type and
|
||||
// length. Either way, we only need to create the descriptor once. (This is
|
||||
// safe because FormatDescriptor instances are immutable.)
|
||||
//
|
||||
// Because certain details, like the fill byte and high-vs-low ASCII, are pulled
|
||||
// out of the data stream at format time, we don't have to dig for them now.
|
||||
FormatDescriptor dfd;
|
||||
if (subType == FormatDescriptor.SubType.Symbol) {
|
||||
dfd = FormatDescriptor.Create(chunkLength, symbolRef,
|
||||
type == FormatDescriptor.Type.NumericBE);
|
||||
} else {
|
||||
dfd = FormatDescriptor.Create(chunkLength, type, subType);
|
||||
}
|
||||
|
||||
while (low <= high) {
|
||||
Results.Add(low, dfd);
|
||||
low += chunkLength;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates one or more FormatDescriptor entries for the specified range, adding them
|
||||
/// to the Results list.
|
||||
/// </summary>
|
||||
/// <param name="low">Offset of first byte in range.</param>
|
||||
/// <param name="high">Offset of last byte in range.</param>
|
||||
/// <param name="subType">String sub-type.</param>
|
||||
private void CreateMixedStringEntries(int low, int high,
|
||||
FormatDescriptor.SubType subType) {
|
||||
int stringStart = -1;
|
||||
int highBit = 0;
|
||||
int cur;
|
||||
for (cur = low; cur <= high; cur++) {
|
||||
byte val = mFileData[cur];
|
||||
if (CommonUtil.TextUtil.IsHiLoAscii(val)) {
|
||||
// is ASCII
|
||||
if (stringStart >= 0) {
|
||||
// was in a string
|
||||
if (highBit != (val & 0x80)) {
|
||||
// end of string due to high bit flip, output
|
||||
CreateStringOrByte(stringStart, cur - stringStart, subType);
|
||||
// start a new string
|
||||
stringStart = cur;
|
||||
} else {
|
||||
// still in string, keep going
|
||||
}
|
||||
} else {
|
||||
// wasn't in a string, start one
|
||||
stringStart = cur;
|
||||
}
|
||||
highBit = val & 0x80;
|
||||
} else {
|
||||
// not ASCII
|
||||
if (stringStart >= 0) {
|
||||
// was in a string, output it
|
||||
CreateStringOrByte(stringStart, cur - stringStart, subType);
|
||||
stringStart = -1;
|
||||
}
|
||||
// output as single byte
|
||||
CreateByteFD(cur, FormatDescriptor.SubType.Hex);
|
||||
}
|
||||
}
|
||||
if (stringStart >= 0) {
|
||||
// close out the string
|
||||
CreateStringOrByte(stringStart, cur - stringStart, subType);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a format descriptor for ASCII data. If the data is only one byte long,
|
||||
/// a single-byte ASCII char item is emitted instead.
|
||||
/// </summary>
|
||||
/// <param name="offset">Offset of first byte.</param>
|
||||
/// <param name="length">Length of string.</param>
|
||||
/// <param name="subType">String sub-type.</param>
|
||||
private void CreateStringOrByte(int offset, int length,
|
||||
FormatDescriptor.SubType subType) {
|
||||
Debug.Assert(length > 0);
|
||||
if (length == 1) {
|
||||
// single byte, output as single ASCII char rather than 1-byte string
|
||||
CreateByteFD(offset, FormatDescriptor.SubType.Ascii);
|
||||
} else {
|
||||
FormatDescriptor dfd;
|
||||
dfd = FormatDescriptor.Create(length,
|
||||
FormatDescriptor.Type.String, subType);
|
||||
Results.Add(offset, dfd);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a format descriptor for a single-byte numeric value.
|
||||
/// </summary>
|
||||
/// <param name="offset">File offset.</param>
|
||||
/// <param name="subType">How to format the item.</param>
|
||||
private void CreateByteFD(int offset, FormatDescriptor.SubType subType) {
|
||||
FormatDescriptor dfd = FormatDescriptor.Create(1,
|
||||
FormatDescriptor.Type.NumericLE, subType);
|
||||
Results.Add(offset, dfd);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates one or more FormatDescriptor entries for the specified range, adding them
|
||||
/// to the Results list.
|
||||
/// </summary>
|
||||
/// <param name="low">Offset of first byte in range.</param>
|
||||
/// <param name="high">Offset of last byte in range.</param>
|
||||
/// <param name="subType">String sub-type.</param>
|
||||
private void CreateCStringEntries(int low, int high,
|
||||
FormatDescriptor.SubType subType) {
|
||||
int startOffset = low;
|
||||
for (int i = low; i <= high; i++) {
|
||||
if (mFileData[i] == 0x00) {
|
||||
// End of string. Zero-length strings are allowed.
|
||||
FormatDescriptor dfd = FormatDescriptor.Create(
|
||||
i - startOffset + 1, FormatDescriptor.Type.String, subType);
|
||||
Results.Add(startOffset, dfd);
|
||||
startOffset = i + 1;
|
||||
} else {
|
||||
// keep going
|
||||
}
|
||||
}
|
||||
|
||||
// Earlier analysis guaranteed that the last byte in the buffer is 0x00.
|
||||
Debug.Assert(startOffset == high + 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates one or more FormatDescriptor entries for the specified range, adding them
|
||||
/// to the Results list.
|
||||
/// </summary>
|
||||
/// <param name="low">Offset of first byte in range.</param>
|
||||
/// <param name="high">Offset of last byte in range.</param>
|
||||
/// <param name="subType">String sub-type.</param>
|
||||
private void CreateLengthStringEntries(int low, int high,
|
||||
FormatDescriptor.SubType subType) {
|
||||
int i;
|
||||
for (i = low; i <= high;) {
|
||||
int length = mFileData[i];
|
||||
if (subType == FormatDescriptor.SubType.L16String) {
|
||||
length |= mFileData[i + 1] << 8;
|
||||
length += 2;
|
||||
} else {
|
||||
length++;
|
||||
}
|
||||
// Zero-length strings are allowed.
|
||||
FormatDescriptor dfd = FormatDescriptor.Create(length,
|
||||
FormatDescriptor.Type.String, subType);
|
||||
Results.Add(i, dfd);
|
||||
i += length;
|
||||
}
|
||||
|
||||
Debug.Assert(i == high + 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates one or more FormatDescriptor entries for the specified range, adding them
|
||||
/// to the Results list.
|
||||
/// </summary>
|
||||
/// <param name="low">Offset of first byte in range.</param>
|
||||
/// <param name="high">Offset of last byte in range.</param>
|
||||
/// <param name="subType">String sub-type.</param>
|
||||
private void CreateDciStringEntries(int low, int high,
|
||||
FormatDescriptor.SubType subType) {
|
||||
int start, end, adj, endMask;
|
||||
if (subType == FormatDescriptor.SubType.Dci) {
|
||||
start = low;
|
||||
end = high + 1;
|
||||
adj = 1;
|
||||
} else if (subType == FormatDescriptor.SubType.DciReverse) {
|
||||
start = high;
|
||||
end = low - 1;
|
||||
adj = -1;
|
||||
} else {
|
||||
Debug.Assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Zero-length strings aren't a thing for DCI. The analyzer requires that all
|
||||
// strings in a region have the same polarity, so just grab the last byte.
|
||||
endMask = mFileData[end - 1] & 0x80;
|
||||
|
||||
int stringStart = start;
|
||||
for (int i = start; i != end; i += adj) {
|
||||
byte val = mFileData[i];
|
||||
if ((val & 0x80) == endMask) {
|
||||
// found the end of a string
|
||||
int length = (i - stringStart) * adj + 1;
|
||||
FormatDescriptor dfd = FormatDescriptor.Create(length,
|
||||
FormatDescriptor.Type.String, subType);
|
||||
Results.Add(stringStart < i ? stringStart : i, dfd);
|
||||
stringStart = i + adj;
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Assert(stringStart == end);
|
||||
}
|
||||
}
|
||||
}
|
120
SourceGen/AppForms/EditData.resx
Normal file
120
SourceGen/AppForms/EditData.resx
Normal file
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
265
SourceGen/AppForms/EditDefSymbol.Designer.cs
generated
Normal file
265
SourceGen/AppForms/EditDefSymbol.Designer.cs
generated
Normal file
@ -0,0 +1,265 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
namespace SourceGen.AppForms {
|
||||
partial class EditDefSymbol {
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing) {
|
||||
if (disposing && (components != null)) {
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent() {
|
||||
this.cancelButton = new System.Windows.Forms.Button();
|
||||
this.okButton = new System.Windows.Forms.Button();
|
||||
this.labelLabel = new System.Windows.Forms.Label();
|
||||
this.labelTextBox = new System.Windows.Forms.TextBox();
|
||||
this.valueTextBox = new System.Windows.Forms.TextBox();
|
||||
this.labelNotesLabel = new System.Windows.Forms.Label();
|
||||
this.valueLabel = new System.Windows.Forms.Label();
|
||||
this.valueNotesLabel = new System.Windows.Forms.Label();
|
||||
this.commentLabel = new System.Windows.Forms.Label();
|
||||
this.commentTextBox = new System.Windows.Forms.TextBox();
|
||||
this.commentNotesLabel = new System.Windows.Forms.Label();
|
||||
this.symbolTypeGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.constantRadioButton = new System.Windows.Forms.RadioButton();
|
||||
this.addressRadioButton = new System.Windows.Forms.RadioButton();
|
||||
this.labelUniqueLabel = new System.Windows.Forms.Label();
|
||||
this.symbolTypeGroupBox.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// cancelButton
|
||||
//
|
||||
this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.cancelButton.Location = new System.Drawing.Point(203, 253);
|
||||
this.cancelButton.Name = "cancelButton";
|
||||
this.cancelButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.cancelButton.TabIndex = 5;
|
||||
this.cancelButton.Text = "Cancel";
|
||||
this.cancelButton.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// okButton
|
||||
//
|
||||
this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.okButton.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.okButton.Location = new System.Drawing.Point(122, 253);
|
||||
this.okButton.Name = "okButton";
|
||||
this.okButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.okButton.TabIndex = 4;
|
||||
this.okButton.Text = "OK";
|
||||
this.okButton.UseVisualStyleBackColor = true;
|
||||
this.okButton.Click += new System.EventHandler(this.okButton_Click);
|
||||
//
|
||||
// labelLabel
|
||||
//
|
||||
this.labelLabel.AutoSize = true;
|
||||
this.labelLabel.Location = new System.Drawing.Point(14, 16);
|
||||
this.labelLabel.Name = "labelLabel";
|
||||
this.labelLabel.Size = new System.Drawing.Size(36, 13);
|
||||
this.labelLabel.TabIndex = 6;
|
||||
this.labelLabel.Text = "Label:";
|
||||
//
|
||||
// labelTextBox
|
||||
//
|
||||
this.labelTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.labelTextBox.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.labelTextBox.Location = new System.Drawing.Point(77, 14);
|
||||
this.labelTextBox.Name = "labelTextBox";
|
||||
this.labelTextBox.Size = new System.Drawing.Size(200, 20);
|
||||
this.labelTextBox.TabIndex = 0;
|
||||
this.labelTextBox.TextChanged += new System.EventHandler(this.labelTextBox_TextChanged);
|
||||
//
|
||||
// valueTextBox
|
||||
//
|
||||
this.valueTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.valueTextBox.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.valueTextBox.Location = new System.Drawing.Point(77, 81);
|
||||
this.valueTextBox.Name = "valueTextBox";
|
||||
this.valueTextBox.Size = new System.Drawing.Size(200, 20);
|
||||
this.valueTextBox.TabIndex = 1;
|
||||
this.valueTextBox.TextChanged += new System.EventHandler(this.valueTextBox_TextChanged);
|
||||
//
|
||||
// labelNotesLabel
|
||||
//
|
||||
this.labelNotesLabel.AutoSize = true;
|
||||
this.labelNotesLabel.Location = new System.Drawing.Point(74, 37);
|
||||
this.labelNotesLabel.Name = "labelNotesLabel";
|
||||
this.labelNotesLabel.Size = new System.Drawing.Size(187, 13);
|
||||
this.labelNotesLabel.TabIndex = 9;
|
||||
this.labelNotesLabel.Text = "• 2+ alphanumerics, starting with letter";
|
||||
//
|
||||
// valueLabel
|
||||
//
|
||||
this.valueLabel.AutoSize = true;
|
||||
this.valueLabel.Location = new System.Drawing.Point(14, 83);
|
||||
this.valueLabel.Name = "valueLabel";
|
||||
this.valueLabel.Size = new System.Drawing.Size(37, 13);
|
||||
this.valueLabel.TabIndex = 7;
|
||||
this.valueLabel.Text = "Value:";
|
||||
//
|
||||
// valueNotesLabel
|
||||
//
|
||||
this.valueNotesLabel.AutoSize = true;
|
||||
this.valueNotesLabel.Location = new System.Drawing.Point(74, 104);
|
||||
this.valueNotesLabel.Name = "valueNotesLabel";
|
||||
this.valueNotesLabel.Size = new System.Drawing.Size(155, 13);
|
||||
this.valueNotesLabel.TabIndex = 11;
|
||||
this.valueNotesLabel.Text = "• Decimal, hex ($), or binary (%)";
|
||||
//
|
||||
// commentLabel
|
||||
//
|
||||
this.commentLabel.AutoSize = true;
|
||||
this.commentLabel.Location = new System.Drawing.Point(17, 137);
|
||||
this.commentLabel.Name = "commentLabel";
|
||||
this.commentLabel.Size = new System.Drawing.Size(54, 13);
|
||||
this.commentLabel.TabIndex = 8;
|
||||
this.commentLabel.Text = "Comment:";
|
||||
//
|
||||
// commentTextBox
|
||||
//
|
||||
this.commentTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.commentTextBox.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.commentTextBox.Location = new System.Drawing.Point(77, 134);
|
||||
this.commentTextBox.Name = "commentTextBox";
|
||||
this.commentTextBox.Size = new System.Drawing.Size(200, 20);
|
||||
this.commentTextBox.TabIndex = 2;
|
||||
//
|
||||
// commentNotesLabel
|
||||
//
|
||||
this.commentNotesLabel.AutoSize = true;
|
||||
this.commentNotesLabel.Location = new System.Drawing.Point(74, 157);
|
||||
this.commentNotesLabel.Name = "commentNotesLabel";
|
||||
this.commentNotesLabel.Size = new System.Drawing.Size(55, 13);
|
||||
this.commentNotesLabel.TabIndex = 12;
|
||||
this.commentNotesLabel.Text = "• Optional";
|
||||
//
|
||||
// symbolTypeGroupBox
|
||||
//
|
||||
this.symbolTypeGroupBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.symbolTypeGroupBox.Controls.Add(this.constantRadioButton);
|
||||
this.symbolTypeGroupBox.Controls.Add(this.addressRadioButton);
|
||||
this.symbolTypeGroupBox.Location = new System.Drawing.Point(13, 190);
|
||||
this.symbolTypeGroupBox.Name = "symbolTypeGroupBox";
|
||||
this.symbolTypeGroupBox.Size = new System.Drawing.Size(264, 48);
|
||||
this.symbolTypeGroupBox.TabIndex = 3;
|
||||
this.symbolTypeGroupBox.TabStop = false;
|
||||
this.symbolTypeGroupBox.Text = "Symbol Type";
|
||||
//
|
||||
// constantRadioButton
|
||||
//
|
||||
this.constantRadioButton.AutoSize = true;
|
||||
this.constantRadioButton.Location = new System.Drawing.Point(99, 20);
|
||||
this.constantRadioButton.Name = "constantRadioButton";
|
||||
this.constantRadioButton.Size = new System.Drawing.Size(67, 17);
|
||||
this.constantRadioButton.TabIndex = 1;
|
||||
this.constantRadioButton.TabStop = true;
|
||||
this.constantRadioButton.Text = "Constant";
|
||||
this.constantRadioButton.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// addressRadioButton
|
||||
//
|
||||
this.addressRadioButton.AutoSize = true;
|
||||
this.addressRadioButton.Location = new System.Drawing.Point(6, 20);
|
||||
this.addressRadioButton.Name = "addressRadioButton";
|
||||
this.addressRadioButton.Size = new System.Drawing.Size(63, 17);
|
||||
this.addressRadioButton.TabIndex = 0;
|
||||
this.addressRadioButton.TabStop = true;
|
||||
this.addressRadioButton.Text = "Address";
|
||||
this.addressRadioButton.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// labelUniqueLabel
|
||||
//
|
||||
this.labelUniqueLabel.AutoSize = true;
|
||||
this.labelUniqueLabel.Location = new System.Drawing.Point(74, 53);
|
||||
this.labelUniqueLabel.Name = "labelUniqueLabel";
|
||||
this.labelUniqueLabel.Size = new System.Drawing.Size(160, 13);
|
||||
this.labelUniqueLabel.TabIndex = 10;
|
||||
this.labelUniqueLabel.Text = "• Unique among project symbols";
|
||||
//
|
||||
// EditDefSymbol
|
||||
//
|
||||
this.AcceptButton = this.okButton;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.CancelButton = this.cancelButton;
|
||||
this.ClientSize = new System.Drawing.Size(290, 288);
|
||||
this.Controls.Add(this.labelUniqueLabel);
|
||||
this.Controls.Add(this.symbolTypeGroupBox);
|
||||
this.Controls.Add(this.commentNotesLabel);
|
||||
this.Controls.Add(this.commentTextBox);
|
||||
this.Controls.Add(this.commentLabel);
|
||||
this.Controls.Add(this.valueNotesLabel);
|
||||
this.Controls.Add(this.valueLabel);
|
||||
this.Controls.Add(this.labelNotesLabel);
|
||||
this.Controls.Add(this.valueTextBox);
|
||||
this.Controls.Add(this.labelTextBox);
|
||||
this.Controls.Add(this.labelLabel);
|
||||
this.Controls.Add(this.okButton);
|
||||
this.Controls.Add(this.cancelButton);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "EditDefSymbol";
|
||||
this.ShowInTaskbar = false;
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "Edit Symbol";
|
||||
this.Load += new System.EventHandler(this.EditDefSymbol_Load);
|
||||
this.symbolTypeGroupBox.ResumeLayout(false);
|
||||
this.symbolTypeGroupBox.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Button cancelButton;
|
||||
private System.Windows.Forms.Button okButton;
|
||||
private System.Windows.Forms.Label labelLabel;
|
||||
private System.Windows.Forms.TextBox labelTextBox;
|
||||
private System.Windows.Forms.TextBox valueTextBox;
|
||||
private System.Windows.Forms.Label labelNotesLabel;
|
||||
private System.Windows.Forms.Label valueLabel;
|
||||
private System.Windows.Forms.Label valueNotesLabel;
|
||||
private System.Windows.Forms.Label commentLabel;
|
||||
private System.Windows.Forms.TextBox commentTextBox;
|
||||
private System.Windows.Forms.Label commentNotesLabel;
|
||||
private System.Windows.Forms.GroupBox symbolTypeGroupBox;
|
||||
private System.Windows.Forms.RadioButton constantRadioButton;
|
||||
private System.Windows.Forms.RadioButton addressRadioButton;
|
||||
private System.Windows.Forms.Label labelUniqueLabel;
|
||||
}
|
||||
}
|
132
SourceGen/AppForms/EditDefSymbol.cs
Normal file
132
SourceGen/AppForms/EditDefSymbol.cs
Normal file
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using Asm65;
|
||||
|
||||
namespace SourceGen.AppForms {
|
||||
public partial class EditDefSymbol : Form {
|
||||
/// <summary>
|
||||
/// Set to previous value before calling; may be null if creating a new symbol.
|
||||
/// Will be set to new value on OK result.
|
||||
/// </summary>
|
||||
public DefSymbol DefSym { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Format object to use when formatting addresses and constants.
|
||||
/// </summary>
|
||||
private Formatter NumFormatter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of existing symbols, for uniqueness check. The list will not be modified.
|
||||
/// </summary>
|
||||
private SortedList<String, DefSymbol> DefSymbolList { get; set; }
|
||||
|
||||
// Saved off at dialog load time.
|
||||
private Color mDefaultLabelColor;
|
||||
|
||||
|
||||
public EditDefSymbol(Formatter formatter, SortedList<String, DefSymbol> defList) {
|
||||
InitializeComponent();
|
||||
|
||||
NumFormatter = formatter;
|
||||
DefSymbolList = defList;
|
||||
}
|
||||
|
||||
private void EditDefSymbol_Load(object sender, EventArgs e) {
|
||||
mDefaultLabelColor = labelNotesLabel.ForeColor;
|
||||
|
||||
if (DefSym != null) {
|
||||
labelTextBox.Text = DefSym.Label;
|
||||
valueTextBox.Text = NumFormatter.FormatValueInBase(DefSym.Value,
|
||||
DefSym.DataDescriptor.NumBase);
|
||||
commentTextBox.Text = DefSym.Comment;
|
||||
|
||||
if (DefSym.SymbolType == Symbol.Type.Constant) {
|
||||
constantRadioButton.Checked = true;
|
||||
} else {
|
||||
addressRadioButton.Checked = true;
|
||||
}
|
||||
} else {
|
||||
addressRadioButton.Checked = true;
|
||||
}
|
||||
|
||||
UpdateControls();
|
||||
}
|
||||
|
||||
private void UpdateControls() {
|
||||
bool labelValid, labelUnique, valueValid;
|
||||
|
||||
// Label must be valid and not already exist in project symbol list. (It's okay
|
||||
// if it exists elsewhere.)
|
||||
labelValid = Asm65.Label.ValidateLabel(labelTextBox.Text);
|
||||
|
||||
if (DefSymbolList.TryGetValue(labelTextBox.Text, out DefSymbol existing)) {
|
||||
// It's okay if it's the same object.
|
||||
labelUnique = (existing == DefSym);
|
||||
} else {
|
||||
labelUnique = true;
|
||||
}
|
||||
|
||||
// Value must be blank, meaning "erase any earlier definition", or valid value.
|
||||
// (Hmm... don't currently have a way to specify "no symbol" in DefSymbol.)
|
||||
//if (!string.IsNullOrEmpty(valueTextBox.Text)) {
|
||||
valueValid = ParseValue(out int unused1, out int unused2);
|
||||
//} else {
|
||||
// valueValid = true;
|
||||
//}
|
||||
|
||||
labelNotesLabel.ForeColor = labelValid ? mDefaultLabelColor : Color.Red;
|
||||
labelUniqueLabel.ForeColor = labelUnique ? mDefaultLabelColor : Color.Red;
|
||||
valueNotesLabel.ForeColor = valueValid ? mDefaultLabelColor : Color.Red;
|
||||
|
||||
okButton.Enabled = labelValid && labelUnique && valueValid;
|
||||
}
|
||||
|
||||
private bool ParseValue(out int value, out int numBase) {
|
||||
string str = valueTextBox.Text;
|
||||
if (str.IndexOf('/') >= 0) {
|
||||
// treat as address
|
||||
numBase = 16;
|
||||
return Asm65.Address.ParseAddress(str, (1 << 24) - 1, out value);
|
||||
} else {
|
||||
return Asm65.Number.TryParseInt(str, out value, out numBase);
|
||||
}
|
||||
}
|
||||
|
||||
private void okButton_Click(object sender, EventArgs e) {
|
||||
bool isConstant = constantRadioButton.Checked;
|
||||
|
||||
ParseValue(out int value, out int numBase);
|
||||
FormatDescriptor.SubType subType = FormatDescriptor.GetSubTypeForBase(numBase);
|
||||
DefSym = new DefSymbol(labelTextBox.Text, value, Symbol.Source.Project,
|
||||
isConstant ? Symbol.Type.Constant : Symbol.Type.ExternalAddr,
|
||||
subType, commentTextBox.Text, string.Empty);
|
||||
}
|
||||
|
||||
private void labelTextBox_TextChanged(object sender, EventArgs e) {
|
||||
UpdateControls();
|
||||
}
|
||||
|
||||
private void valueTextBox_TextChanged(object sender, EventArgs e) {
|
||||
UpdateControls();
|
||||
}
|
||||
}
|
||||
}
|
120
SourceGen/AppForms/EditDefSymbol.resx
Normal file
120
SourceGen/AppForms/EditDefSymbol.resx
Normal file
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
225
SourceGen/AppForms/EditLabel.Designer.cs
generated
Normal file
225
SourceGen/AppForms/EditLabel.Designer.cs
generated
Normal file
@ -0,0 +1,225 @@
|
||||
/*
|
||||
* Copyright 2018 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
namespace SourceGen.AppForms {
|
||||
partial class EditLabel {
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing) {
|
||||
if (disposing && (components != null)) {
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent() {
|
||||
this.cancelButton = new System.Windows.Forms.Button();
|
||||
this.okButton = new System.Windows.Forms.Button();
|
||||
this.instructionLabel = new System.Windows.Forms.Label();
|
||||
this.labelTextBox = new System.Windows.Forms.TextBox();
|
||||
this.maxLengthLabel = new System.Windows.Forms.Label();
|
||||
this.firstLetterLabel = new System.Windows.Forms.Label();
|
||||
this.validCharsLabel = new System.Windows.Forms.Label();
|
||||
this.notDuplicateLabel = new System.Windows.Forms.Label();
|
||||
this.labelTypeGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.radioButtonExport = new System.Windows.Forms.RadioButton();
|
||||
this.radioButtonGlobal = new System.Windows.Forms.RadioButton();
|
||||
this.radioButtonLocal = new System.Windows.Forms.RadioButton();
|
||||
this.labelTypeGroupBox.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// cancelButton
|
||||
//
|
||||
this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.cancelButton.Location = new System.Drawing.Point(267, 202);
|
||||
this.cancelButton.Name = "cancelButton";
|
||||
this.cancelButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.cancelButton.TabIndex = 8;
|
||||
this.cancelButton.Text = "Cancel";
|
||||
this.cancelButton.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// okButton
|
||||
//
|
||||
this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.okButton.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.okButton.Location = new System.Drawing.Point(186, 202);
|
||||
this.okButton.Name = "okButton";
|
||||
this.okButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.okButton.TabIndex = 7;
|
||||
this.okButton.Text = "OK";
|
||||
this.okButton.UseVisualStyleBackColor = true;
|
||||
this.okButton.Click += new System.EventHandler(this.okButton_Click);
|
||||
//
|
||||
// instructionLabel
|
||||
//
|
||||
this.instructionLabel.AutoSize = true;
|
||||
this.instructionLabel.Location = new System.Drawing.Point(13, 13);
|
||||
this.instructionLabel.Name = "instructionLabel";
|
||||
this.instructionLabel.Size = new System.Drawing.Size(60, 13);
|
||||
this.instructionLabel.TabIndex = 0;
|
||||
this.instructionLabel.Text = "Enter label:";
|
||||
//
|
||||
// labelTextBox
|
||||
//
|
||||
this.labelTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.labelTextBox.Location = new System.Drawing.Point(13, 30);
|
||||
this.labelTextBox.Name = "labelTextBox";
|
||||
this.labelTextBox.Size = new System.Drawing.Size(325, 20);
|
||||
this.labelTextBox.TabIndex = 1;
|
||||
this.labelTextBox.TextChanged += new System.EventHandler(this.labelTextBox_TextChanged);
|
||||
//
|
||||
// maxLengthLabel
|
||||
//
|
||||
this.maxLengthLabel.AutoSize = true;
|
||||
this.maxLengthLabel.Location = new System.Drawing.Point(13, 57);
|
||||
this.maxLengthLabel.Name = "maxLengthLabel";
|
||||
this.maxLengthLabel.Size = new System.Drawing.Size(251, 13);
|
||||
this.maxLengthLabel.TabIndex = 2;
|
||||
this.maxLengthLabel.Text = "• Must be 2-32 characters long (or blank to remove)";
|
||||
//
|
||||
// firstLetterLabel
|
||||
//
|
||||
this.firstLetterLabel.AutoSize = true;
|
||||
this.firstLetterLabel.Location = new System.Drawing.Point(12, 73);
|
||||
this.firstLetterLabel.Name = "firstLetterLabel";
|
||||
this.firstLetterLabel.Size = new System.Drawing.Size(187, 13);
|
||||
this.firstLetterLabel.TabIndex = 3;
|
||||
this.firstLetterLabel.Text = "• Must start with a letter or underscore";
|
||||
//
|
||||
// validCharsLabel
|
||||
//
|
||||
this.validCharsLabel.AutoSize = true;
|
||||
this.validCharsLabel.Location = new System.Drawing.Point(12, 89);
|
||||
this.validCharsLabel.Name = "validCharsLabel";
|
||||
this.validCharsLabel.Size = new System.Drawing.Size(297, 13);
|
||||
this.validCharsLabel.TabIndex = 4;
|
||||
this.validCharsLabel.Text = "• Valid characters are ASCII letters, numbers, and underscore";
|
||||
//
|
||||
// notDuplicateLabel
|
||||
//
|
||||
this.notDuplicateLabel.AutoSize = true;
|
||||
this.notDuplicateLabel.Location = new System.Drawing.Point(13, 105);
|
||||
this.notDuplicateLabel.Name = "notDuplicateLabel";
|
||||
this.notDuplicateLabel.Size = new System.Drawing.Size(217, 13);
|
||||
this.notDuplicateLabel.TabIndex = 5;
|
||||
this.notDuplicateLabel.Text = "• Must not be a duplicate of an existing label";
|
||||
//
|
||||
// labelTypeGroupBox
|
||||
//
|
||||
this.labelTypeGroupBox.Controls.Add(this.radioButtonExport);
|
||||
this.labelTypeGroupBox.Controls.Add(this.radioButtonGlobal);
|
||||
this.labelTypeGroupBox.Controls.Add(this.radioButtonLocal);
|
||||
this.labelTypeGroupBox.Location = new System.Drawing.Point(13, 132);
|
||||
this.labelTypeGroupBox.Name = "labelTypeGroupBox";
|
||||
this.labelTypeGroupBox.Size = new System.Drawing.Size(137, 93);
|
||||
this.labelTypeGroupBox.TabIndex = 6;
|
||||
this.labelTypeGroupBox.TabStop = false;
|
||||
this.labelTypeGroupBox.Text = "Label Type";
|
||||
//
|
||||
// radioButtonExport
|
||||
//
|
||||
this.radioButtonExport.AutoSize = true;
|
||||
this.radioButtonExport.Location = new System.Drawing.Point(7, 67);
|
||||
this.radioButtonExport.Name = "radioButtonExport";
|
||||
this.radioButtonExport.Size = new System.Drawing.Size(120, 17);
|
||||
this.radioButtonExport.TabIndex = 2;
|
||||
this.radioButtonExport.TabStop = true;
|
||||
this.radioButtonExport.Text = "Global and &exported";
|
||||
this.radioButtonExport.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// radioButtonGlobal
|
||||
//
|
||||
this.radioButtonGlobal.AutoSize = true;
|
||||
this.radioButtonGlobal.Location = new System.Drawing.Point(7, 43);
|
||||
this.radioButtonGlobal.Name = "radioButtonGlobal";
|
||||
this.radioButtonGlobal.Size = new System.Drawing.Size(55, 17);
|
||||
this.radioButtonGlobal.TabIndex = 1;
|
||||
this.radioButtonGlobal.TabStop = true;
|
||||
this.radioButtonGlobal.Text = "&Global";
|
||||
this.radioButtonGlobal.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// radioButtonLocal
|
||||
//
|
||||
this.radioButtonLocal.AutoSize = true;
|
||||
this.radioButtonLocal.Location = new System.Drawing.Point(7, 20);
|
||||
this.radioButtonLocal.Name = "radioButtonLocal";
|
||||
this.radioButtonLocal.Size = new System.Drawing.Size(106, 17);
|
||||
this.radioButtonLocal.TabIndex = 0;
|
||||
this.radioButtonLocal.TabStop = true;
|
||||
this.radioButtonLocal.Text = "&Local (if possible)";
|
||||
this.radioButtonLocal.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// EditLabel
|
||||
//
|
||||
this.AcceptButton = this.okButton;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.CancelButton = this.cancelButton;
|
||||
this.ClientSize = new System.Drawing.Size(354, 237);
|
||||
this.Controls.Add(this.labelTypeGroupBox);
|
||||
this.Controls.Add(this.notDuplicateLabel);
|
||||
this.Controls.Add(this.validCharsLabel);
|
||||
this.Controls.Add(this.firstLetterLabel);
|
||||
this.Controls.Add(this.maxLengthLabel);
|
||||
this.Controls.Add(this.labelTextBox);
|
||||
this.Controls.Add(this.instructionLabel);
|
||||
this.Controls.Add(this.okButton);
|
||||
this.Controls.Add(this.cancelButton);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "EditLabel";
|
||||
this.ShowInTaskbar = false;
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "Edit Label";
|
||||
this.Load += new System.EventHandler(this.EditLabel_Load);
|
||||
this.labelTypeGroupBox.ResumeLayout(false);
|
||||
this.labelTypeGroupBox.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Button cancelButton;
|
||||
private System.Windows.Forms.Button okButton;
|
||||
private System.Windows.Forms.Label instructionLabel;
|
||||
private System.Windows.Forms.TextBox labelTextBox;
|
||||
private System.Windows.Forms.Label maxLengthLabel;
|
||||
private System.Windows.Forms.Label firstLetterLabel;
|
||||
private System.Windows.Forms.Label validCharsLabel;
|
||||
private System.Windows.Forms.Label notDuplicateLabel;
|
||||
private System.Windows.Forms.GroupBox labelTypeGroupBox;
|
||||
private System.Windows.Forms.RadioButton radioButtonLocal;
|
||||
private System.Windows.Forms.RadioButton radioButtonGlobal;
|
||||
private System.Windows.Forms.RadioButton radioButtonExport;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user