Final preparations for open source roll-out
This commit is contained in:
parent
e96f0eecd9
commit
60669365f9
40 changed files with 2814 additions and 2639 deletions
53
README.md
53
README.md
|
|
@ -2,8 +2,8 @@ The Original IBM PC in Your Browser
|
|||
---
|
||||
|
||||
Welcome to [pcjs.org](http://www.pcjs.org/) and [PCjs](/docs/about/pcjs/), the first IBM PC simulation to run in your
|
||||
web browser without any plugins. It was added to the [JavaScript Machines](/docs/about/) project in Fall 2012.
|
||||
The project now includes:
|
||||
web browser without any plugins. It was added to the [JavaScript Machines](/docs/about/) project in Fall 2012, and is
|
||||
now part of the [PCjs Project](https://github.com/jeffpar/pcjs) on [GitHub](https://github.com/). The project now includes:
|
||||
|
||||
* [PCjs](/docs/about/pcjs/), a simulation of the original IBM PC (circa 1981)
|
||||
* [C1Pjs](/docs/c1pjs/), a simulation of the OSI Challenger 1P (circa 1978)
|
||||
|
|
@ -60,14 +60,21 @@ copy of the [PCjs web server](http://www.pcjs.org/) and run PCjs simulations:
|
|||
|
||||
+ A simple Node-based web server ([server.js](server.js))
|
||||
+ Custom Node modules used by the web server ([HTMLOut](my_modules/htmlout/), [MarkOut](my_modules/markout/), [DiskDump](my_modules/diskdump/), [FileDump](my_modules/filedump/))
|
||||
+ An assortment of IBM PC and C1P machine XML files (in [/apps](apps/), [/devices](devices/) and elsewhere)
|
||||
+ An assortment of IBM PC and C1P machine XML files (in [/apps](apps/), [/configs](configs/), [/disks](disks/) and elsewhere)
|
||||
+ The [PCjs](my_modules/pcjs-client/lib/) and [C1Pjs](my_modules/c1pjs-client/lib/) client applications, both "compiled" and uncompiled
|
||||
+ A smattering of [PCjs](docs/pcjs/) and [C1Pjs](docs/c1pjs/) documentation, along with [blog posts](blog/), related [publications](pubs/) and more
|
||||
|
||||
Aside from the [PCjs](my_modules/pcjs-client/lib/) and [C1Pjs](my_modules/c1pjs-client/lib/) applications,
|
||||
[DiskDump](my_modules/diskdump/) is another important module. Originally created to dump existing disk images as JSON,
|
||||
**DiskDump** has evolved into a full-featured disk image generator, capable of creating PC-compatible diskette *and*
|
||||
hard disk images from either lists *or* directories of files (including all subdirectories), and supports both
|
||||
command-line and web interfaces.
|
||||
|
||||
The PCjs web server is *not* required to run most PCjs simulations. Any web server (Node, Apache, Nginx, etc)
|
||||
that can serve the necessary JavaScript files to your browser will work. However, instructions for doing
|
||||
that are beyond the scope of this "Quick Start" document. And while it is possible to create simulations that
|
||||
require access to PCjs web server APIs, none of the simulations in the repository should require API access.
|
||||
that are beyond the scope of this document (see future document). The PCjs web server does provide disk and file
|
||||
APIs that simulations can take advantage of, but none of the simulations currently checked into the repository
|
||||
should require API access.
|
||||
|
||||
### Installing PCjs
|
||||
|
||||
|
|
@ -242,23 +249,24 @@ A complete list of command-line options can be found in [server.js](server.js).
|
|||
|
||||
### Client Components
|
||||
|
||||
A special parameter ("gort") can be appended to the URL to request uncompiled client source files, making PCjs and
|
||||
C1Pjs much easier to debug, albeit much slower:
|
||||
A special command parameter ("gort") can be appended to the URL to request uncompiled client source files, making PCjs
|
||||
and C1Pjs much easier to debug, albeit much slower:
|
||||
|
||||
http://localhost:8088/?gort=debug
|
||||
|
||||
The "gort=debug" command is unnecessary if the server is started with `--debug`; the server always serves uncompiled
|
||||
files when running in "debug mode".
|
||||
files when running in debug mode.
|
||||
|
||||
Conversely, if the server is running "debug mode" but you want to test a compiled version of PCjs, use:
|
||||
Conversely, if the server is running debug mode but you want to test a compiled version of PCjs, use:
|
||||
|
||||
http://localhost:8088/?gort=release
|
||||
|
||||
and the server will serve compiled JavaScript files, regardless whether the server is running in "debug mode" or
|
||||
"release mode".
|
||||
and the server will serve compiled JavaScript files, regardless whether the server is running in debug mode or
|
||||
release mode.
|
||||
|
||||
Another useful gort command is "gort=nodebug", which is like "debug" but also sets the client-side **DEBUG** variable
|
||||
to *false*, disabling all debug-only runtime checks in the client and allowing the simulation to run much faster:
|
||||
Another useful gort command is "gort=nodebug", which is like "gort=debug" but also sets the client-side **DEBUG**
|
||||
variable to *false*, disabling all debug-only runtime checks in the client and allowing the simulation to run much
|
||||
faster:
|
||||
|
||||
http://localhost:8088/?gort=nodebug
|
||||
|
||||
|
|
@ -285,7 +293,9 @@ To start developing features for a new version of PCjs, here are the recommended
|
|||
3. Make changes
|
||||
4. Run "grunt" to build new versions of the apps (eg, "/versions/pcjs/1.xx.yy/pc.js")
|
||||
|
||||
However, you may want to skip step #2 until you're ready to start testing the new version. Depending on the nature
|
||||
You might also want to check out the blog post on [PCjs Coding Conventions](/blog/2014/09/30/).
|
||||
|
||||
You may also want to skip step #2 until you're ready to start testing the new version. Depending on the nature
|
||||
of your changes, it may be better to manually edit the version number in only a few machine XML files for testing,
|
||||
leaving the rest of the XML files pointing to the previous version. Run "grunt promote" when the new version is much
|
||||
closer to being released.
|
||||
|
|
@ -309,9 +319,22 @@ manually or with the Grunt "clean" task:
|
|||
|
||||
<!--END:EXCLUDE-->
|
||||
|
||||
License
|
||||
---
|
||||
The [PCjs Project](https://github.com/jeffpar/pcjs) is now an open source project on [GitHub](http://github.com/).
|
||||
All published portions are free for redistribution and/or modification under the terms of the
|
||||
[GNU General Public License](/LICENSE) as published by the Free Software Foundation, either version 3 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
You are required to include the appropriate copyright notice (e.g., `PCjs v1.15.4 © 2012-2014 by @jeffpar`)
|
||||
in every source code file of every copy or modified version of this work, and to display that copyright notice
|
||||
on every screen that loads or runs any version of this software.
|
||||
|
||||
See [LICENSE](/LICENSE) for details.
|
||||
|
||||
More Information
|
||||
---
|
||||
Learn more about the [JavaScript Machines](/docs/about/) project and [PCjs](/docs/about/pcjs/). To
|
||||
Learn more about the [JavaScript Machines](/docs/about/) Project and [PCjs](/docs/about/pcjs/). To
|
||||
create your own PCjs machines, see the [Documentation](/docs/pcjs/) for details.
|
||||
|
||||
If you have questions or run into any problems, you're welcome to [tweet](http://twitter.com/jeffpar) or
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
PCjs Coding Conventions
|
||||
---
|
||||
|
||||
Some ramblings about the JavaScript coding conventions used for PCjs. This is not an attempt to convince anyone of
|
||||
anything, just an explanation of why things are the way they are.
|
||||
Here are a few highlights of the (evolving) JavaScript coding conventions used in PCjs.
|
||||
|
||||
### Tabs vs. Spaces
|
||||
|
||||
|
|
@ -79,6 +78,33 @@ uses the "long form." But again, since the Closure Compiler already does a good
|
|||
necessary to use the "long form", which is why you'll see newer code using more conventional Object notation to
|
||||
define class constants.
|
||||
|
||||
### DEBUG vs. RELEASE
|
||||
|
||||
While we're talking about constants, it's important to be aware of constants that are not scoped to
|
||||
any particular component.
|
||||
|
||||
In [/my_modules/shared/lib/defines.js](/my_modules/shared/lib/defines.js), **DEBUG** is set to **TRUE**,
|
||||
enabling all debug-only code by default. It is also declared as a *@define* so that the Closure Compiler can
|
||||
override it, setting it to **FALSE** and disabling debug-only code.
|
||||
|
||||
To ensure that debug-only code is not simply *disabled* but also *removed*, the code should be wrapped with:
|
||||
|
||||
if (DEBUG) {
|
||||
[code to be removed by the Closure Compiler]
|
||||
}
|
||||
|
||||
In many cases, the compiler is able to completely remove calls to debug-only class methods; eg:
|
||||
|
||||
Component.assert(off >= 0 && off < this.cb);
|
||||
|
||||
However, calls to debug-only instance methods seem to be more problematic, so all such calls are wrapped; eg:
|
||||
|
||||
if (DEBUG) this.log('load("' + sFileURL + '")');
|
||||
|
||||
There are a number of other important shared constants in [/my_modules/shared/lib/defines.js](/my_modules/shared/lib/defines.js)
|
||||
and PCjs-specific constants in [/my_modules/pcjs-client/lib/defines.js](/my_modules/pcjs-client/lib/defines.js); refer
|
||||
to those files for more information.
|
||||
|
||||
### Braces and Parentheses
|
||||
|
||||
Most opening braces appear at the end of the line containing the associated "if", "while", "for", "switch",
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
About JavaScript Machines
|
||||
---
|
||||
|
||||
The JavaScript Machines (**JSMachines**) project is a collection of computer simulations written in JavaScript,
|
||||
maintained on [GitHub](http://github.com/), and hosted at [pcjs.org](http://www.pcjs.org/) (formerly
|
||||
[jsmachines.net](http://jsmachines.net/)).
|
||||
The JavaScript Machines Project (originally at [jsmachines.net](http://jsmachines.net/)) is a collection of computer
|
||||
simulations written in JavaScript. It has now been released on [GitHub](https://github.com/) as the
|
||||
[PCjs Project](https://github.com/jeffpar/pcjs), a copy of which is hosted here at [pcjs.org](http://www.pcjs.org/).
|
||||
|
||||
The goals of the project are to create fast, full-featured simulations of classic computer
|
||||
hardware, help people understand how these early machines worked, make it easy to experiment with different machine
|
||||
|
|
@ -18,7 +18,7 @@ capabilities can be found in the [Documentation](/docs/).
|
|||
|
||||
### Emulating the Challenger 1P
|
||||
|
||||
The first **JSMachines** application was [C1Pjs](/docs/c1pjs/), a simulation of the
|
||||
The first **JSMachines** simulation was [C1Pjs](/docs/c1pjs/), a simulation of the
|
||||
Challenger 1P, which was a 6502-based microcomputer introduced by Ohio Scientific in 1978.
|
||||
|
||||
C1Pjs v1.0 was released in July 2012, first on ecpsim.org and cpusim.org, then on [jsmachines.net](http://jsmachines.net/c1pjs),
|
||||
|
|
@ -30,16 +30,17 @@ at [osiweb.org](http://osiweb.org/).
|
|||
|
||||
### Emulating the IBM PC
|
||||
|
||||
The next **JSMachines** application was [PCjs](/docs/about/pcjs/), which simulates the original IBM PC and IBM PC XT.
|
||||
The next **JSMachines** simulation was [PCjs](/docs/about/pcjs/), which simulates the original IBM PC, IBM PC XT,
|
||||
and IBM PC AT.
|
||||
|
||||
[PCjs](/docs/about/pcjs/) emulates the Intel 8088 CPU, as well as IBM Monochrome Display Adapter (MDA) and
|
||||
Color Display Adapter (CGA) video cards, along with assorted motherboard and expansion bus components. It also
|
||||
includes an optional debugger and a user-configurable control panel.
|
||||
[PCjs](/docs/about/pcjs/) emulates the Intel 8088 and 80286 CPUs, as well as IBM Monochrome Display Adapter (MDA),
|
||||
Color Graphics Adapter (CGA), and Enhanced Graphics Adapter (EGA) video cards, along with assorted motherboard and
|
||||
expansion bus components. It also includes an optional Debugger and a user-configurable Control Panel.
|
||||
|
||||
PCjs v1.0 was released on [jsmachines.net](http://jsmachines.net/) in late 2012, and the **JSMachines** project,
|
||||
with its second full-featured machine emulation, was launched.
|
||||
|
||||
See the PCjs [History](/docs/about/pcjs/) for information about more recent releases.
|
||||
Read [About PCjs](/docs/about/pcjs/) to learn more about its history, features, and upcoming improvements.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -61,22 +62,20 @@ including extensions to the link syntax that make it easy to embed C1Pjs and PCj
|
|||
|
||||
---
|
||||
|
||||
### License
|
||||
|
||||
The **JSMachines** project is maintained on [GitHub](http://github.com/) (public release date TBD). The portions
|
||||
of the project that have been published here are free for redistribution and/or modification under the terms
|
||||
of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License,
|
||||
License
|
||||
---
|
||||
The [PCjs Project](https://github.com/jeffpar/pcjs) is now an open source project on [GitHub](http://github.com/).
|
||||
All published portions are free for redistribution and/or modification under the terms of the
|
||||
[GNU General Public License](/LICENSE) as published by the Free Software Foundation, either version 3 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
You are required to include the appropriate copyright notice (e.g., `PCjs v1.15.3 © 2012-2014 by @jeffpar`)
|
||||
You are required to include the appropriate copyright notice (e.g., `PCjs v1.15.4 © 2012-2014 by @jeffpar`)
|
||||
in every source code file of every copy or modified version of this work, and to display that copyright notice
|
||||
on every screen that loads or runs any version of this software.
|
||||
|
||||
See [LICENSE](/LICENSE) for details.
|
||||
|
||||
More Information
|
||||
---
|
||||
|
||||
### More Information
|
||||
|
||||
If you have questions or run into any problems, you're welcome to [tweet](http://twitter.com/jeffpar) or
|
||||
[email](mailto:Jeff@pcjs.org).
|
||||
|
|
@ -2,7 +2,8 @@ About PCjs
|
|||
---
|
||||
|
||||
PCjs is a IBM PC and PC XT simulator written entirely in JavaScript. It's designed to load and run extremely
|
||||
fast, it works well in all modern web browsers (both desktop and mobile), and it's easy to customize.
|
||||
fast, it works well in all modern web browsers (both desktop and mobile), and it's easy to customize. It is part of
|
||||
the [PCjs Project](https://github.com/jeffpar/pcjs), an open source project on [GitHub](http://github.com/).
|
||||
|
||||
Check out the [Demos](/#demos) on the home page, and all the other PCjs [Application](/apps/pc/), [Boot Disk](/disks/pc/)
|
||||
and [Machine](/configs/pc/machines/) demos, including an IBM PC XT "[Server Array](/configs/pc/machines/5160/cga/256kb/array/)"
|
||||
|
|
@ -36,18 +37,19 @@ Chrome or Firefox for other platforms.
|
|||
|
||||
### Future
|
||||
|
||||
More hardware suport is targeted for version 1.20.0, including:
|
||||
More hardware support is targeted for version 1.15, including:
|
||||
|
||||
+ Complete EGA emulation
|
||||
+ 80286 CPU emulation
|
||||
+ PC AT hardware emulation
|
||||
|
||||
Limited EGA emulation is currently available as of version 1.14.0.
|
||||
Limited EGA emulation is currently available as of version 1.14.
|
||||
|
||||
### History
|
||||
|
||||
+ v1.14.0 introduced limited EGA emulation, as discussed on our [Blog](/blog/2014/07/30/).
|
||||
+ v1.13.0 introduced manifest files that describe software packages that can be used with PCjs.
|
||||
+ v1.15 introduced PC AT (Model 5170) emulation, as discussed on our [Blog](/blog/2014/09/13/).
|
||||
+ v1.14 introduced limited EGA emulation, as discussed on our [Blog](/blog/2014/07/30/).
|
||||
+ v1.13 introduced manifest files that describe software packages that can be used with PCjs.
|
||||
More information on software manifests is available [here](/apps/).
|
||||
+ v1.12.1 coincided with the first release of the new PCjs web server running on [Node.js](http://nodejs.org).
|
||||
The new server includes ROM and disk image conversion APIs, as well as a [Markdown](http://daringfireball.net/projects/markdown/syntax)
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
|
|
@ -270,6 +270,29 @@ C1PComputer.init = function()
|
|||
|
||||
var component;
|
||||
var modules = {};
|
||||
|
||||
/*
|
||||
* Let's see if the Control Panel is installed (NOTE: its ID must be "panel", and only one per machine is supported);
|
||||
* the Panel needs our setPower() notifications, and this relieves us from having an explicit <module> entry for type="panel".
|
||||
*/
|
||||
var panel = Component.getComponentByID('panel', parmsComputer['id']);
|
||||
if (panel) {
|
||||
modules['panel'] = [panel];
|
||||
/*
|
||||
* Iterate through all the other components and update their print methods if the Control Panel has provided overrides.
|
||||
*/
|
||||
if (panel.controlPrint) {
|
||||
var aComponents = Component.getComponents(parmsComputer['id']);
|
||||
for (var iComponent = 0; iComponent < aComponents.length; iComponent++) {
|
||||
component = aComponents[iComponent];
|
||||
if (component == panel) continue;
|
||||
component.notice = panel.notice;
|
||||
component.println = panel.println;
|
||||
component.controlPrint = panel.controlPrint;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var abMemory;
|
||||
var addrStart = 0, addrEnd = 0;
|
||||
|
||||
|
|
@ -326,15 +349,6 @@ C1PComputer.init = function()
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Let's see if the Control Panel is installed (NOTE: its ID must be "panel", and only one per machine is supported);
|
||||
* the Panel needs our setPower() notifications, and this relieves us from having an explicit <module> entry for type="panel".
|
||||
*/
|
||||
component = Component.getComponentByID('panel', parmsComputer['id']);
|
||||
if (component) {
|
||||
modules['panel'] = [component];
|
||||
}
|
||||
|
||||
var computer = new C1PComputer(parmsComputer, modules);
|
||||
/*
|
||||
* We may eventually add a "Power" button, but for now, all we have is a "Reset" button
|
||||
|
|
|
|||
|
|
@ -809,7 +809,7 @@ C1PDiskController.prototype.loadDisk = function(sDiskName, sDiskData, nErrorCode
|
|||
* to its trackNum index, but just in case that wasn't intended, we're going to mention it.
|
||||
*/
|
||||
if (iTrackNum != iTrack) {
|
||||
this.warning("track " + iTrackNum + " out of order (expected " + iTrack + ")");
|
||||
Component.warning("track " + iTrackNum + " out of order (expected " + iTrack + ")");
|
||||
}
|
||||
/*
|
||||
* For each track, we start with an empty trackData array and "push" (ie, append) all the
|
||||
|
|
|
|||
|
|
@ -56,19 +56,19 @@ Component.subclass(Component, C1PPanel);
|
|||
* component that doesn't recognize the specified binding should simply ignore it.
|
||||
*
|
||||
* @this {C1PPanel}
|
||||
* @param {string|null} c is the class of the HTML control (eg, "input", "output")
|
||||
* @param {string|null} t is the type of the HTML control (eg, "button", "list", "text", "submit", "textarea")
|
||||
* @param {string} s is the value of the 'binding' parameter stored in the HTML control's "data-value" attribute (eg, "reset")
|
||||
* @param {Object} e is the HTML control DOM object (eg, HTMLButtonElement)
|
||||
* @param {string|null} sHTMLClass is the class of the HTML control (eg, "input", "output")
|
||||
* @param {string|null} sHTMLType is the type of the HTML control (eg, "button", "list", "text", "submit", "textarea", "canvas")
|
||||
* @param {string} sBinding is the value of the 'binding' parameter stored in the HTML control's "data-value" attribute (eg, "reset")
|
||||
* @param {Object} control is the HTML control DOM object (eg, HTMLButtonElement)
|
||||
* @return {boolean} true if binding was successful, false if unrecognized binding request
|
||||
*/
|
||||
C1PPanel.prototype.setBinding = function(c, t, s, e)
|
||||
C1PPanel.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, control)
|
||||
{
|
||||
if (this.cmp && this.cmp.setBinding(c, t, s, e)) return true;
|
||||
if (this.cpu && this.cpu.setBinding(c, t, s, e)) return true;
|
||||
if (this.kbd && this.kbd.setBinding(c, t, s, e)) return true;
|
||||
if (DEBUGGER && this.dbg && this.dbg.setBinding(c, t, s, e)) return true;
|
||||
return Component.prototype.setBinding.call(this, c, t, s, e);
|
||||
if (this.cmp && this.cmp.setBinding(sHTMLClass, sHTMLType, sBinding, control)) return true;
|
||||
if (this.cpu && this.cpu.setBinding(sHTMLClass, sHTMLType, sBinding, control)) return true;
|
||||
if (this.kbd && this.kbd.setBinding(sHTMLClass, sHTMLType, sBinding, control)) return true;
|
||||
if (DEBUGGER && this.dbg && this.dbg.setBinding(sHTMLClass, sHTMLType, sBinding, control)) return true;
|
||||
return Component.prototype.setBinding.call(this, sHTMLClass, sHTMLType, sBinding, control);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -731,7 +731,8 @@ DiskDump.readFile = function(sPath, sEncoding, done)
|
|||
|
||||
/**
|
||||
* isExcluded(sName)
|
||||
*
|
||||
*
|
||||
* @this {DiskDump}
|
||||
* @param {string} sName is the basename of a file under consideration
|
||||
* @return {boolean} is true if the file should be excluded, false if not
|
||||
*/
|
||||
|
|
@ -752,6 +753,7 @@ DiskDump.prototype.isExcluded = function(sName)
|
|||
* object creation from any I/O that the object may perform, to ensure that a callback can never
|
||||
* be called before the caller has actually received the newly created object.
|
||||
*
|
||||
* @this {DiskDump}
|
||||
* @param {function(Error)} done
|
||||
*/
|
||||
DiskDump.prototype.loadFile = function(done)
|
||||
|
|
@ -774,6 +776,7 @@ DiskDump.prototype.loadFile = function(done)
|
|||
*
|
||||
* Records the loaded disk data buffer
|
||||
*
|
||||
* @this {DiskDump}
|
||||
* @param {Error} err
|
||||
* @param {Buffer|string} buf
|
||||
* @param {function(Error)} done
|
||||
|
|
@ -818,6 +821,7 @@ DiskDump.prototype.setData = function(err, buf, done)
|
|||
/**
|
||||
* dumpLine(nIndent, sLine, sComment)
|
||||
*
|
||||
* @this {DiskDump}
|
||||
* @param {number} [nIndent] is the relative number of characters to indent the given line (0 if none)
|
||||
* @param {string} [sLine] is the given line
|
||||
* @param {string} [sComment] is an optional comment to append to the line, if comment output is enabled
|
||||
|
|
@ -840,6 +844,7 @@ DiskDump.prototype.dumpLine = function(nIndent, sLine, sComment)
|
|||
/**
|
||||
* dumpProp(sKey, value, fLast)
|
||||
*
|
||||
* @this {DiskDump}
|
||||
* @param {string} sKey
|
||||
* @param {number|string|null} value
|
||||
* @param {boolean} [fLast]
|
||||
|
|
@ -857,6 +862,7 @@ DiskDump.prototype.dumpProp = function(sKey, value, fLast)
|
|||
/**
|
||||
* dumpBuffer(sKey, buf, len, cbItem, offData)
|
||||
*
|
||||
* @this {DiskDump}
|
||||
* @param {string|null} sKey is name of buffer data element
|
||||
* @param {Buffer} buf is a Buffer containing the bytes to dump
|
||||
* @param {number} len is the number of bytes to dump
|
||||
|
|
@ -908,6 +914,7 @@ DiskDump.prototype.dumpBuffer = function(sKey, buf, len, cbItem, offData)
|
|||
*
|
||||
* Dumps track data for an OSI disk track
|
||||
*
|
||||
* @this {DiskDump}
|
||||
* @param {string} sTrackSig
|
||||
* @param {number} nTrackNum
|
||||
* @param {number} nTrackType
|
||||
|
|
@ -932,6 +939,7 @@ DiskDump.prototype.dumpTrackOSI = function(sTrackSig, nTrackNum, nTrackType, nTr
|
|||
*
|
||||
* Dumps sector data for an OSI disk sector
|
||||
*
|
||||
* @this {DiskDump}
|
||||
* @param {number|null} nSectorSig
|
||||
* @param {number} nSectorNum
|
||||
* @param {number} nSectorPages
|
||||
|
|
@ -968,6 +976,7 @@ DiskDump.prototype.dumpSectorOSI = function(nSectorSig, nSectorNum, nSectorPages
|
|||
* NOTE: The C1Pjs Simulator doesn't support this feature (yet), which is why
|
||||
* trimSector() isn't used when dumping OSI disk images.
|
||||
*
|
||||
* @this {DiskDump}
|
||||
* @param {Buffer} buf
|
||||
* @param {number} len
|
||||
* @return {Array} containing [dwPattern, cbBuffer]
|
||||
|
|
@ -1018,7 +1027,8 @@ DiskDump.ATTR_ARCHIVE = 0x20;
|
|||
|
||||
/**
|
||||
* validateTime(dateTime)
|
||||
*
|
||||
*
|
||||
* @this {DiskDump}
|
||||
* @param {Date} dateTime
|
||||
* @return {boolean} true if date/time modified, false if not
|
||||
*/
|
||||
|
|
@ -1062,6 +1072,7 @@ DiskDump.prototype.validateTime = function(dateTime)
|
|||
/**
|
||||
* buildData(cb)
|
||||
*
|
||||
* @this {DiskDump}
|
||||
* @param {number} cb
|
||||
* @param {Array.<number>} [abInit]
|
||||
* @return {Array.<number>} of bytes zero-initialized
|
||||
|
|
@ -1078,6 +1089,7 @@ DiskDump.prototype.buildData = function(cb, abInit)
|
|||
/**
|
||||
* copyData(ab)
|
||||
*
|
||||
* @this {DiskDump}
|
||||
* @param {number} offDisk
|
||||
* @param {Array.<number>} ab
|
||||
* @return {number} number of bytes written
|
||||
|
|
@ -1091,7 +1103,8 @@ DiskDump.prototype.copyData = function(offDisk, ab)
|
|||
|
||||
/**
|
||||
* addManifestInfo(fileInfo)
|
||||
*
|
||||
*
|
||||
* @this {DiskDump}
|
||||
* @param {Object} fileInfo
|
||||
*/
|
||||
DiskDump.prototype.addManifestInfo = function(fileInfo)
|
||||
|
|
@ -1105,6 +1118,7 @@ DiskDump.prototype.addManifestInfo = function(fileInfo)
|
|||
* Returns an array (aFiles) via the done() callback, where each entry is a fileInfo object.
|
||||
* If fileInfo refers to a subdirectory, then FILE_SIZE is -1 and FILE_DATA entry is another aFiles array.
|
||||
*
|
||||
* @this {DiskDump}
|
||||
* @param {string} sDir is a fully-qualified directory name
|
||||
* @param {boolean} [fRoot] should be true for the first directory read
|
||||
* @param {function(Error,Array)} done
|
||||
|
|
@ -1234,6 +1248,7 @@ DiskDump.prototype.readDir = function(sDir, fRoot, done)
|
|||
* NOTE: sPath begins fully-qualified (see this.sDiskPath), but if any of the intermediate entries contains paths,
|
||||
* it's our responsibility to join them with sServerRoot.
|
||||
*
|
||||
* @this {DiskDump}
|
||||
* @param {string} sPath contains series of semi-colon-separated files (local or remote)
|
||||
* @param {function(Error,Array)} done
|
||||
*/
|
||||
|
|
@ -1356,6 +1371,7 @@ DiskDump.prototype.readPath = function(sPath, done)
|
|||
/**
|
||||
* buildName(sFile)
|
||||
*
|
||||
* @this {DiskDump}
|
||||
* @param {string} sFile is the basename of a file
|
||||
* @return {string} containing a corresponding FAT-compatible filename
|
||||
*/
|
||||
|
|
@ -1391,6 +1407,7 @@ DiskDump.prototype.buildName = function(sFile)
|
|||
* NOTE: When fileInfo is returned, there will be no FILE_PATH property, which means
|
||||
* don't go looking for a corresponding entry in the host file system, because there isn't one.
|
||||
*
|
||||
* @this {DiskDump}
|
||||
* @param {string} [sDir]
|
||||
* @return {Object|null} fileInfo (or null if no suitable volume label)
|
||||
*/
|
||||
|
|
@ -1433,6 +1450,7 @@ DiskDump.prototype.buildVolLabel = function(sDir)
|
|||
/**
|
||||
* buildFAT(abFAT, aFiles, iCluster, cbCluster)
|
||||
*
|
||||
* @this {DiskDump}
|
||||
* @param {Array.<number>} abFAT
|
||||
* @param {Array} aFiles
|
||||
* @param {number} iCluster
|
||||
|
|
@ -1476,6 +1494,7 @@ DiskDump.prototype.buildFAT = function(abFAT, aFiles, iCluster, cbCluster)
|
|||
/**
|
||||
* buildFATEntry(abFat, iFat, v)
|
||||
*
|
||||
* @this {DiskDump}
|
||||
* @param {Array.<number>} abFAT
|
||||
* @param {number} iFAT
|
||||
* @param {number} v
|
||||
|
|
@ -1501,6 +1520,7 @@ DiskDump.prototype.buildFATEntry = function(abFAT, iFAT, v)
|
|||
/**
|
||||
* buildDir(abDir, aFiles, dateMod, iCluster, iParentCluster)
|
||||
*
|
||||
* @this {DiskDump}
|
||||
* @param {Array.<number>} abDir
|
||||
* @param {Array} aFiles
|
||||
* @param {Date} [dateMod]
|
||||
|
|
@ -1537,6 +1557,7 @@ DiskDump.prototype.buildDir = function(abDir, aFiles, dateMod, iCluster, iParent
|
|||
*
|
||||
* TODO: Create constants that define the various directory entry fields, including the overall size (32 bytes).
|
||||
*
|
||||
* @this {DiskDump}
|
||||
* @param {Array.<number>} ab contains the bytes of a directory
|
||||
* @param {number} off is the offset within ab to build the next directory entry
|
||||
* @param {string} sFile is the file name
|
||||
|
|
@ -1621,6 +1642,7 @@ DiskDump.prototype.buildDirEntry = function(ab, off, sFile, cbFile, bAttr, dateM
|
|||
/**
|
||||
* buildClusters(aFiles, offDisk, cbCluster, iParentCluster, done)
|
||||
*
|
||||
* @this {DiskDump}
|
||||
* @param {Array} aFiles
|
||||
* @param {number} offDisk
|
||||
* @param {number} cbCluster
|
||||
|
|
@ -1706,6 +1728,7 @@ DiskDump.prototype.buildClusters = function(aFiles, offDisk, cbCluster, iParentC
|
|||
/**
|
||||
* buildImage()
|
||||
*
|
||||
* @this {DiskDump}
|
||||
* @param {boolean} fDir
|
||||
* @param {function(Error)} done
|
||||
*/
|
||||
|
|
@ -1740,6 +1763,7 @@ DiskDump.prototype.buildImage = function(fDir, done)
|
|||
* calculated total data and found a BPB we think will accommodate it. So, the code below
|
||||
* will still have to be prepared for running out of disk space. This is just a good estimate.
|
||||
*
|
||||
* @this {DiskDump}
|
||||
* @param {Array} aFiles
|
||||
* @return {number} of bytes required for all files, including all subdirectories
|
||||
*/
|
||||
|
|
@ -1765,6 +1789,7 @@ DiskDump.prototype.calcFileSizes = function(aFiles)
|
|||
/**
|
||||
* buildMBR(cHeads, cSectorsPerTrack, cbSector, cTotalSectors)
|
||||
*
|
||||
* @this {DiskDump}
|
||||
* @param {number} cHeads
|
||||
* @param {number} cSectorsPerTrack
|
||||
* @param {number} cbSector
|
||||
|
|
@ -1835,6 +1860,7 @@ DiskDump.prototype.buildMBR = function(cHeads, cSectorsPerTrack, cbSector, cTota
|
|||
* Note, however, that even if this function returns true, you won't receive the buffer until
|
||||
* all the writes to have it have finished.
|
||||
*
|
||||
* @this {DiskDump}
|
||||
* @param {Array} aFiles
|
||||
* @param {function(Error)} done
|
||||
* @return {boolean} true if disk allocation successful, false if not
|
||||
|
|
@ -1996,6 +2022,7 @@ DiskDump.prototype.buildImageFromFiles = function(aFiles, done)
|
|||
*
|
||||
* Converts the disk image data to JSON.
|
||||
*
|
||||
* @this {DiskDump}
|
||||
* @return {string|null} containing a JSON representation of the disk image, or null if unrecognized/malformed
|
||||
*/
|
||||
DiskDump.prototype.convertToJSON = function()
|
||||
|
|
@ -2288,6 +2315,7 @@ DiskDump.prototype.convertToJSON = function()
|
|||
* each containing an array of tracks. It's largely just a matter of reversing the meaning of the two outermost array
|
||||
* elements, here and in the C1Pjs disk module.
|
||||
*
|
||||
* @this {DiskDump}
|
||||
* @return {string|null} containing a JSON representation of the disk image, or null if unrecognized/malformed
|
||||
*/
|
||||
DiskDump.prototype.convertOSIDiskToJSON = function()
|
||||
|
|
@ -2406,6 +2434,7 @@ DiskDump.prototype.convertOSIDiskToJSON = function()
|
|||
* TODO: Consider creating a caching mechanism for these requests (ie, stash a limited number of these
|
||||
* disk images under /tmp, using a name based on a hash of the source path).
|
||||
*
|
||||
* @this {DiskDump}
|
||||
* @return {Buffer|null} containing the disk image's raw data, or null if no data available (or parse error)
|
||||
*/
|
||||
DiskDump.prototype.convertToIMG = function()
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ var DumpAPI = require("../../shared/lib/dumpapi");
|
|||
* or a "--map" command-line option), which in turn triggers a call to loadMap(). Note that loadMap() will need
|
||||
* to be a bit more general and use a worker function that calls either net.getFile() or fs.readFile(), similar
|
||||
* to what our loadFile() function already does.
|
||||
*
|
||||
*
|
||||
* @constructor
|
||||
* @param {string|undefined} sFormat should be one of "json"|"data"|"hex"|"bytes"|"rom" (see the FORMAT constants)
|
||||
* @param {boolean|string|undefined} fComments enables comments and other readability enhancements in the JSON output
|
||||
|
|
@ -67,7 +67,7 @@ function FileDump(sFormat, fComments, fDecimal, sServerRoot)
|
|||
this.buf = null;
|
||||
/*
|
||||
* TODO: Decide what to do with this usage info; we can't use it as a default, because setting this.json
|
||||
* causes outputFile() to ignore this.buf indiscriminately (ie, it breaks non-JSON output modes).
|
||||
* causes outputFile() to ignore this.buf indiscriminately (ie, it breaks non-JSON output modes).
|
||||
*/
|
||||
this.json = ""; // "[\n /**\n * " + FileDump.sAPIURL + " " + FileDump.sCopyright + "\n * " + FileDump.sUsage + "\n */\n]";
|
||||
}
|
||||
|
|
@ -101,24 +101,24 @@ FileDump.sUsage = "Usage: " + FileDump.sAPIURL + "?" + DumpAPI.QUERY.FILE + "=({
|
|||
* text format that consists entirely of 2-character hex values (deprecated), and "bytes" is a JSON-like format
|
||||
* that also uses hex values (but with "0x" prefixes) and is normally used only when comments are enabled (use
|
||||
* --decimal to force decimal byte output).
|
||||
*
|
||||
*
|
||||
* When a second file is "merged", the first file sets all even bytes and the second file sets all odd bytes.
|
||||
* In fact, any number of files can be merged: if there are N files, file #1 sets bytes at "offset mod N == 0",
|
||||
* file #2 sets all bytes at "offset mod N == 1", and file #N sets all bytes at "offset mod N == N - 1".
|
||||
*
|
||||
* Note that command-line arguments, if any, are not validated. For example, argv['comments'] may be any of
|
||||
* boolean, string, or undefined, since the user may have typed "--comments" or "--comments=foo" or nothing at all.
|
||||
*
|
||||
*
|
||||
* Examples
|
||||
* ---
|
||||
* filedump --file=devices/pc/video/ibm-ega.rom --format=bytes --decimal
|
||||
*
|
||||
*
|
||||
* Notes
|
||||
* ---
|
||||
* Originally, we had to specify `--format=bytes` because the onLoadROM() code in rom.js assumed the data was
|
||||
* always byte-sized, but it has since been updated to support dword arrays, so the default format ("json")
|
||||
* works fine as well. Also, `--decimal` reduces the size of the output file significantly.
|
||||
*
|
||||
*
|
||||
* If there's a ".map" file (eg, "ibm-ega.map"), it's automatically loaded and appended to the ROM data as a
|
||||
* "symbols" property; we may want to consider an option to disable the processing of map files, but for now, the
|
||||
* simple answer is: if you don't want one, don't create one.
|
||||
|
|
@ -131,29 +131,29 @@ FileDump.CLI = function()
|
|||
console.log("usage: filedump --file=({path}|{URL}) [--merge=({path}|{url})] [--format=(json|data|hex|bytes|rom)] [--comments] [--decimal] [--output={path}] [--overwrite]");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var argv = args.argv;
|
||||
var sFile = argv['file'];
|
||||
if (!sFile) {
|
||||
FileDump.logError(new Error("no filename specified"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var sOutputFile = argv['output'];
|
||||
if (typeof sOutputFile != "string") {
|
||||
FileDump.logError(new Error("bad or missing output filename"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (sOutputFile && sOutputFile.charAt(0) != '/') sOutputFile = path.join(process.cwd(), sOutputFile);
|
||||
var fOverwrite = argv['overwrite'];
|
||||
|
||||
|
||||
var sFormat = FileDump.validateFormat(argv['format']);
|
||||
if (sFormat === false) {
|
||||
FileDump.logError(new Error("unrecognized format"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var sMergeFile, asMergeFiles = [];
|
||||
var file = new FileDump(sFormat, argv['comments'], argv['decimal']);
|
||||
if (argv['merge']) {
|
||||
|
|
@ -227,6 +227,7 @@ FileDump.validateFormat = function(sFormat)
|
|||
* object creation from any I/O that the object may perform, to ensure that a callback can never
|
||||
* be called before the caller has actually received the newly created object.
|
||||
*
|
||||
* @this {FileDump}
|
||||
* @param {string} sFile
|
||||
* @param {number} iStart
|
||||
* @param {number} nSkip
|
||||
|
|
@ -241,10 +242,10 @@ FileDump.prototype.loadFile = function(sFile, iStart, nSkip, done)
|
|||
*/
|
||||
var obj = this;
|
||||
var sFilePath = net.isRemote(sFile)? sFile : path.join(this.sServerRoot, sFile);
|
||||
|
||||
|
||||
if (!this.sFilePath) this.sFilePath = sFilePath;
|
||||
if (this.fDebug) console.log("loadFile(" + sFilePath + "," + iStart + "," + nSkip + ")");
|
||||
|
||||
|
||||
if (net.isRemote(sFilePath)) {
|
||||
net.getFile(sFilePath, null, function(err, status, buf) {
|
||||
if (err) {
|
||||
|
|
@ -273,6 +274,7 @@ FileDump.prototype.loadFile = function(sFile, iStart, nSkip, done)
|
|||
*
|
||||
* Records the given file data in the FileDump's buffer
|
||||
*
|
||||
* @this {FileDump}
|
||||
* @param {Buffer} buf
|
||||
* @param {number} iStart
|
||||
* @param {number} nSkip
|
||||
|
|
@ -299,6 +301,7 @@ FileDump.prototype.setData = function(buf, iStart, nSkip)
|
|||
/**
|
||||
* dumpLine(nIndent, sLine, sComment)
|
||||
*
|
||||
* @this {FileDump}
|
||||
* @param {number} [nIndent] is the relative number of characters to indent the given line (0 if none)
|
||||
* @param {string} [sLine] is the given line
|
||||
* @param {string} [sComment] is an optional comment to append to the line, if comment output is enabled
|
||||
|
|
@ -322,6 +325,7 @@ FileDump.prototype.dumpLine = function(nIndent, sLine, sComment)
|
|||
/**
|
||||
* dumpBuffer(sKey, buf, len, cbItem, offData)
|
||||
*
|
||||
* @this {FileDump}
|
||||
* @param {string|null} sKey is name of buffer data element
|
||||
* @param {Buffer} buf is a Buffer containing the bytes to dump
|
||||
* @param {number} len is the number of bytes to dump
|
||||
|
|
@ -334,7 +338,7 @@ FileDump.prototype.dumpBuffer = function(sKey, buf, len, cbItem, offData)
|
|||
var chOpen = '', chClose = '', chSep = ' ', sHexPrefix = "";
|
||||
|
||||
this.sKey = sKey;
|
||||
|
||||
|
||||
if (this.sFormat != DumpAPI.FORMAT.HEX) {
|
||||
chOpen = '['; chClose = ']'; chSep = ','; sHexPrefix = "0x";
|
||||
}
|
||||
|
|
@ -385,6 +389,7 @@ FileDump.prototype.dumpBuffer = function(sKey, buf, len, cbItem, offData)
|
|||
*
|
||||
* NOTE: Since ".map" files are an internal construct, I support only local map files (for now)
|
||||
*
|
||||
* @this {FileDump}
|
||||
* @param {string} sFilePath
|
||||
* @param {function(Error,string)} done
|
||||
*/
|
||||
|
|
@ -413,13 +418,13 @@ FileDump.prototype.loadMap = function(sFilePath, done)
|
|||
}
|
||||
else {
|
||||
// console.log("add this to obj.json:\n" + str);
|
||||
|
||||
|
||||
/*
|
||||
* Parse MAP data into a set of properties; for example, if the .map file contains:
|
||||
*
|
||||
* 0320 = HF_PORT
|
||||
* 0320 = HF_PORT
|
||||
* 0000:0034 4 HDISK_INT
|
||||
* 0040:0042 1 CMD_BLOCK
|
||||
* 0040:0042 1 CMD_BLOCK
|
||||
* 0003 @ DISK_SETUP
|
||||
* 0000:004C 4 ORG_VECTOR
|
||||
* 0028 . MOV AX,WORD PTR ORG_VECTOR ;GET DISKETTE VECTOR
|
||||
|
|
@ -436,26 +441,26 @@ FileDump.prototype.loadMap = function(sFilePath, done)
|
|||
*
|
||||
* then we should produce the following corresponding JSON:
|
||||
*
|
||||
* {
|
||||
* "HF_PORT": {
|
||||
* "v":800
|
||||
* },
|
||||
* "HDISK_INT": {
|
||||
* "b":4, "s":0, "o":52
|
||||
* },
|
||||
* "ORG_VECTOR": {
|
||||
* "b":4, "s":0, "o":76
|
||||
* },
|
||||
* "CMD_BLOCK": {
|
||||
* "b":1, "s":64, "o":66
|
||||
* },
|
||||
* "DISK_SETUP": {
|
||||
* "o":3
|
||||
* },
|
||||
* ".40": {
|
||||
* "o":64, "a":"MOV AX,WORD PTR ORG_VECTOR ;GET DISKETTE VECTOR"
|
||||
* }
|
||||
* }
|
||||
* {
|
||||
* "HF_PORT": {
|
||||
* "v":800
|
||||
* },
|
||||
* "HDISK_INT": {
|
||||
* "b":4, "s":0, "o":52
|
||||
* },
|
||||
* "ORG_VECTOR": {
|
||||
* "b":4, "s":0, "o":76
|
||||
* },
|
||||
* "CMD_BLOCK": {
|
||||
* "b":1, "s":64, "o":66
|
||||
* },
|
||||
* "DISK_SETUP": {
|
||||
* "o":3
|
||||
* },
|
||||
* ".40": {
|
||||
* "o":64, "a":"MOV AX,WORD PTR ORG_VECTOR ;GET DISKETTE VECTOR"
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* where "v" is the value of an absolute (unsized) value; "b" is either 1, 2, 4 or undefined; "s" is either a hard-coded
|
||||
* segment or undefined; and "o" is the offset of an symbol. Also, if the symbol is not entirely upper-case, then we
|
||||
|
|
@ -562,8 +567,10 @@ FileDump.prototype.loadMap = function(sFilePath, done)
|
|||
|
||||
/**
|
||||
* buildJSON()
|
||||
*
|
||||
*
|
||||
* Common code between the API helper (convertToJSON()) and the command-line helper (convertToFile()).
|
||||
*
|
||||
* @this {FileDump}
|
||||
*/
|
||||
FileDump.prototype.buildJSON = function()
|
||||
{
|
||||
|
|
@ -586,6 +593,7 @@ FileDump.prototype.buildJSON = function()
|
|||
*
|
||||
* Converts the data buffer to JSON.
|
||||
*
|
||||
* @this {FileDump}
|
||||
* @param {function(Error,string)} done
|
||||
*/
|
||||
FileDump.prototype.convertToJSON = function(done)
|
||||
|
|
@ -599,6 +607,7 @@ FileDump.prototype.convertToJSON = function(done)
|
|||
*
|
||||
* Converts the data buffer to JSON, as appropriate.
|
||||
*
|
||||
* @this {FileDump}
|
||||
* @param {string} sOutputFile
|
||||
* @param {boolean} fOverwrite
|
||||
*/
|
||||
|
|
@ -621,16 +630,17 @@ FileDump.prototype.convertToFile = function(sOutputFile, fOverwrite)
|
|||
|
||||
/**
|
||||
* outputFile(sOutputFile, fOverwrite)
|
||||
*
|
||||
*
|
||||
* @this {FileDump}
|
||||
* @param {string} sOutputFile
|
||||
* @param {boolean} fOverwrite
|
||||
*/
|
||||
FileDump.prototype.outputFile = function(sOutputFile, fOverwrite)
|
||||
{
|
||||
var data = this.json || this.buf;
|
||||
|
||||
|
||||
var sFormat = this.sFormat.toUpperCase();
|
||||
|
||||
|
||||
if (sOutputFile) {
|
||||
try {
|
||||
if (fs.existsSync(sOutputFile) && !fOverwrite) {
|
||||
|
|
|
|||
|
|
@ -71,7 +71,10 @@ var fConsole = false;
|
|||
|
||||
/*
|
||||
* fServerDebug controls server-related debug features; it is false by default and can be enabled using the
|
||||
* setOptions() 'debug' property (or from the command-line interface using "--debug").
|
||||
* setOptions() 'debug' property (or from the server's command-line interface using "--debug").
|
||||
*
|
||||
* This used to be named fDebug, which was fine, but it has been renamed to make the distinction between the
|
||||
* server's debug state (fServerDebug) and the debug state of HTMLOut instances (this.fDebug) clearer.
|
||||
*/
|
||||
var fServerDebug = false;
|
||||
|
||||
|
|
@ -475,7 +478,7 @@ HTMLOut.filter = function(req, res, next)
|
|||
* and adding an Etag, unless we ALSO change the req.method from "GET" to something else.
|
||||
* Supposedly, we could also use app.disable('etag'), but I'm not sure that would prevent
|
||||
* Express from changing the status code, and I'm tired of testing work-arounds for this
|
||||
* irritating behavior in Safari.
|
||||
* irritating behavior.
|
||||
*/
|
||||
req.method = "NONE";
|
||||
res.set("Content-Type", "application/xml");
|
||||
|
|
@ -486,6 +489,10 @@ HTMLOut.filter = function(req, res, next)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (asNonDirectories.indexOf(sBaseName) >= 0) {
|
||||
res.set("Content-Type", "text/plain");
|
||||
}
|
||||
|
||||
/*
|
||||
* Next, check for API requests (eg, "/api/v1/dump?disk=/disks/pc/dos/ibm/2.00/PCDOS200-DISK1.json&format=img")
|
||||
|
|
@ -681,6 +688,7 @@ HTMLOut.setRoot = function(sRoot)
|
|||
/**
|
||||
* loadFile()
|
||||
*
|
||||
* @this {HTMLOut}
|
||||
* @param {string} sFile
|
||||
* @param {boolean} fTemplate
|
||||
*/
|
||||
|
|
@ -700,6 +708,7 @@ HTMLOut.prototype.loadFile = function(sFile, fTemplate)
|
|||
*
|
||||
* Records the given HTML template and immediately parses it.
|
||||
*
|
||||
* @this {HTMLOut}
|
||||
* @param {Error} err
|
||||
* @param {string} sData
|
||||
* @param {string} sFile
|
||||
|
|
@ -741,6 +750,7 @@ HTMLOut.prototype.setData = function(err, sData, sFile, fTemplate)
|
|||
/**
|
||||
* findTokens()
|
||||
*
|
||||
* @this {HTMLOut}
|
||||
* @param {RegExp} reTokens
|
||||
*/
|
||||
HTMLOut.prototype.findTokens = function(reTokens)
|
||||
|
|
@ -794,6 +804,8 @@ HTMLOut.prototype.findTokens = function(reTokens)
|
|||
|
||||
/**
|
||||
* replaceTokens()
|
||||
*
|
||||
* @this {HTMLOut}
|
||||
*/
|
||||
HTMLOut.prototype.replaceTokens = function()
|
||||
{
|
||||
|
|
@ -866,6 +878,7 @@ HTMLOut.prototype.replaceTokens = function()
|
|||
*
|
||||
* aParms[0], if present, is used as the preferred title for the home page
|
||||
*
|
||||
* @this {HTMLOut}
|
||||
* @param {string} sToken
|
||||
* @param {string} [sIndent]
|
||||
* @param {Array.<string>} [aParms]
|
||||
|
|
@ -880,6 +893,7 @@ HTMLOut.prototype.getTitle = function(sToken, sIndent, aParms)
|
|||
*
|
||||
* Returns the current version in "package.json".
|
||||
*
|
||||
* @this {HTMLOut}
|
||||
* @param {string} sToken
|
||||
* @param {string} [sIndent]
|
||||
* @param {Array.<string>} [aParms]
|
||||
|
|
@ -902,6 +916,7 @@ HTMLOut.prototype.getVersion = function(sToken, sIndent, aParms)
|
|||
/**
|
||||
* getPath(sToken, sIndent, aParms)
|
||||
*
|
||||
* @this {HTMLOut}
|
||||
* @param {string} sToken
|
||||
* @param {string} [sIndent]
|
||||
* @param {Array.<string>} [aParms]
|
||||
|
|
@ -914,6 +929,7 @@ HTMLOut.prototype.getPath = function(sToken, sIndent, aParms)
|
|||
/**
|
||||
* getPCPath(sToken, sIndent, aParms)
|
||||
*
|
||||
* @this {HTMLOut}
|
||||
* @param {string} sToken
|
||||
* @param {string} [sIndent]
|
||||
* @param {Array.<string>} [aParms]
|
||||
|
|
@ -941,6 +957,7 @@ HTMLOut.prototype.getPCPath = function(sToken, sIndent, aParms)
|
|||
* <a href="/apps/">[apps]</a>
|
||||
* </li>
|
||||
*
|
||||
* @this {HTMLOut}
|
||||
* @param {string} sToken
|
||||
* @param {string} [sIndent]
|
||||
* @param {Array.<string>} [aParms]
|
||||
|
|
@ -962,8 +979,8 @@ HTMLOut.prototype.getDirList = function(sToken, sIndent, aParms)
|
|||
asFiles.push("..");
|
||||
|
||||
/*
|
||||
* For sorting purposes, I want all folders ending in "kb" and beginning with one or two
|
||||
* digits to sort as if they all began with THREE digits (ie, with leading zeros as needed).
|
||||
* For sorting purposes, I want all folders ending in "kb" and beginning with one to three
|
||||
* digits to sort as if they all began with FOUR digits (ie, with leading zeros as needed).
|
||||
* But I don't want to change the folder names that are ultimately displayed. So instead,
|
||||
* I pad those names with slashes, since a leading slash will sort much like a leading zero
|
||||
* without being a valid filename character, meaning we can trim away those leading slashes
|
||||
|
|
@ -1002,7 +1019,7 @@ HTMLOut.prototype.getDirList = function(sToken, sIndent, aParms)
|
|||
if (asFilesNonListed.indexOf(sBaseName) >= 0) continue;
|
||||
} else {
|
||||
/*
|
||||
* Even when the server's in Debug mode, there are some files it makes no sense to list....
|
||||
* Even when the server's in Debug mode, there are some files it makes no sense to list.
|
||||
*/
|
||||
if (sBaseName == "index.html") continue;
|
||||
}
|
||||
|
|
@ -1073,6 +1090,7 @@ HTMLOut.prototype.getDirList = function(sToken, sIndent, aParms)
|
|||
*
|
||||
* Return the current year.
|
||||
*
|
||||
* @this {HTMLOut}
|
||||
* @param {string} sToken
|
||||
* @param {string} [sIndent]
|
||||
* @param {Array.<string>} [aParms]
|
||||
|
|
@ -1087,6 +1105,7 @@ HTMLOut.prototype.getYear = function(sToken, sIndent, aParms)
|
|||
*
|
||||
* If we're in the "blog" folder, then enumerate all available blog entries and create a rendering of blog excerpts.
|
||||
*
|
||||
* @this {HTMLOut}
|
||||
* @param {string} sToken
|
||||
* @param {string} [sIndent]
|
||||
* @param {Array.<string>} [aParms]
|
||||
|
|
@ -1189,7 +1208,7 @@ HTMLOut.prototype.getBlog = function(sToken, sIndent, aParms)
|
|||
for (var i = 0; i < aExcerpts.length; i++) {
|
||||
sExcerpts += aExcerpts[i].excerpt + "\n\n";
|
||||
}
|
||||
var mExcerpts = new MarkOut(sExcerpts, sIndent, obj.req, aParms, obj.fDebug, fServerDebug);
|
||||
var mExcerpts = new MarkOut(sExcerpts, sIndent, obj.req, aParms, obj.fDebug);
|
||||
obj.aTokens[sToken] = mExcerpts.convertMD(" ").trim();
|
||||
obj.replaceTokens();
|
||||
}
|
||||
|
|
@ -1222,7 +1241,8 @@ HTMLOut.prototype.getBlog = function(sToken, sIndent, aParms)
|
|||
* Some wrinkles have been added to the above: getManifestXML() can alternatively call getMachineXML()
|
||||
* with a specific machine XML file, which would have had the potential to bypass getReadMe() altogether, so
|
||||
* getMachineXML() may now call getReadMe() -- which must NOT call getMachineXML() back whenever that happens.
|
||||
*
|
||||
*
|
||||
* @this {HTMLOut}
|
||||
* @param {string} sToken
|
||||
* @param {string} [sIndent]
|
||||
* @param {Array.<string>} [aParms]
|
||||
|
|
@ -1240,6 +1260,7 @@ HTMLOut.prototype.getDefault = function(sToken, sIndent, aParms)
|
|||
*
|
||||
* If the HTML file specified by aParms[0] exists, insert its contents into the current HTML document.
|
||||
*
|
||||
* @this {HTMLOut}
|
||||
* @param {string} sToken
|
||||
* @param {string} [sIndent]
|
||||
* @param {Array.<string>} [aParms]
|
||||
|
|
@ -1280,6 +1301,7 @@ HTMLOut.prototype.getHTMLFile = function(sToken, sIndent, aParms)
|
|||
*
|
||||
* If "machine.xml" exists in the current directory, open it and determine if embedding it makes sense.
|
||||
*
|
||||
* @this {HTMLOut}
|
||||
* @param {string} sToken
|
||||
* @param {string} [sIndent]
|
||||
* @param {Array.<string>|null} [aParms]
|
||||
|
|
@ -1343,7 +1365,7 @@ HTMLOut.prototype.getMachineXML = function(sToken, sIndent, aParms, sXMLFile, sS
|
|||
sMachineDef += (sStateFile? ":" + sStateFile : "");
|
||||
|
||||
s = '[Embedded ' + sMachineClass + '](' + sXMLFile + ' "' + sMachineDef + '")';
|
||||
var m = new MarkOut(s, sIndent, obj.req, null, obj.fDebug, fServerDebug);
|
||||
var m = new MarkOut(s, sIndent, obj.req, null, obj.fDebug);
|
||||
s = m.convertMD(" ").trim();
|
||||
|
||||
obj.processMachines(m.getMachines(), function doneProcessXMLMachines() {
|
||||
|
|
@ -1388,6 +1410,7 @@ HTMLOut.prototype.getMachineXML = function(sToken, sIndent, aParms, sXMLFile, sS
|
|||
*
|
||||
* If "manifest.xml" exists in the current directory, open it and embed it.
|
||||
*
|
||||
* @this {HTMLOut}
|
||||
* @param {string} sToken
|
||||
* @param {string} [sIndent]
|
||||
* @param {Array.<string>} [aParms]
|
||||
|
|
@ -1574,7 +1597,8 @@ HTMLOut.prototype.getManifestXML = function(sToken, sIndent, aParms)
|
|||
* getReadMe(sToken, sIndent, aParms, sPrevious)
|
||||
*
|
||||
* If a "README.md" exists in the current directory, open it, convert it, and prepare for replacement.
|
||||
*
|
||||
*
|
||||
* @this {HTMLOut}
|
||||
* @param {string} sToken
|
||||
* @param {string} [sIndent]
|
||||
* @param {Array.<string>} [aParms]
|
||||
|
|
@ -1607,7 +1631,7 @@ HTMLOut.prototype.getReadMe = function(sToken, sIndent, aParms, sPrevious)
|
|||
obj.getMachineXML(sToken, sIndent); // we don't pass along aParms, because those are for Markdown files only
|
||||
}
|
||||
} else {
|
||||
var m = new MarkOut(s, sIndent, obj.req, aParms, obj.fDebug, fServerDebug);
|
||||
var m = new MarkOut(s, sIndent, obj.req, aParms, obj.fDebug);
|
||||
s = m.convertMD(" ").trim();
|
||||
/*
|
||||
* If the Markdown document begins with a heading, stuff that into the <title> tag;
|
||||
|
|
@ -1644,6 +1668,7 @@ HTMLOut.prototype.getReadMe = function(sToken, sIndent, aParms, sPrevious)
|
|||
/**
|
||||
* getSocketScripts(sToken, sIndent, aParms)
|
||||
*
|
||||
* @this {HTMLOut}
|
||||
* @param {string} sToken
|
||||
* @param {string} [sIndent]
|
||||
* @param {Array.<string>} [aParms]
|
||||
|
|
@ -1658,6 +1683,7 @@ HTMLOut.prototype.getSocketScripts = function(sToken, sIndent, aParms)
|
|||
*
|
||||
* Generate a random string of words, purely for entertainment purposes (eg, something in honor of "ADVENT").
|
||||
*
|
||||
* @this {HTMLOut}
|
||||
* @param {string} [sIndent]
|
||||
* @return {string}
|
||||
*/
|
||||
|
|
@ -1699,9 +1725,9 @@ HTMLOut.prototype.getRandomString = function(sIndent)
|
|||
*
|
||||
* Additional properties can include:
|
||||
*
|
||||
* 'compiled' (eg, true or false); if not defined, then we choose a value based on any Gort command,
|
||||
* or failing that, the internal fServerDebug setting
|
||||
* 'compiled' (eg, true or false); if not defined, we choose a value based on the module's fDebug setting
|
||||
*
|
||||
* @this {HTMLOut}
|
||||
* @param {Array} aMachines is an array of objects containing information about each machine on the current page
|
||||
* @param {function()} done
|
||||
*/
|
||||
|
|
@ -1785,6 +1811,7 @@ HTMLOut.prototype.processMachines = function(aMachines, done)
|
|||
/**
|
||||
* addFilesToHTML(asFiles)
|
||||
*
|
||||
* @this {HTMLOut}
|
||||
* @param {Array.<string>} asFiles is a list of CSS and/or JS files to include in the HTML
|
||||
* @param {string} [sScriptEmbed] is an optional script to embed in the <body> (after any JS files listed above)
|
||||
*/
|
||||
|
|
@ -1841,7 +1868,8 @@ HTMLOut.prototype.addFilesToHTML = function(asFiles, sScriptEmbed)
|
|||
|
||||
/**
|
||||
* genOnClick(sURL)
|
||||
*
|
||||
*
|
||||
* @this {HTMLOut}
|
||||
* @param {string} sURL
|
||||
* @param {string} [sFormat] (default is DumpAPI.FORMAT.IMG)
|
||||
* @return {string}
|
||||
|
|
|
|||
|
|
@ -93,10 +93,9 @@ var sDefaultFile = "./README.md";
|
|||
* @param {string|null} [sIndent] sets the overall indentation of the document
|
||||
* @param {Object} [req] is the web server's (ie, Express) request object, if any
|
||||
* @param {Array.<string>|null} [aParms] is an array of overrides to use (see below)
|
||||
* @param {boolean} [fDebug] turns on debugging features (eg, debug comments)
|
||||
* @param {boolean} [fServerDebug] turns on server debug features (eg, special URL encoding rules)
|
||||
* @param {boolean} [fDebug] turns on debugging features (eg, debug comments, special URL encodings, etc)
|
||||
*/
|
||||
function MarkOut(sMD, sIndent, req, aParms, fDebug, fServerDebug)
|
||||
function MarkOut(sMD, sIndent, req, aParms, fDebug)
|
||||
{
|
||||
this.sMD = sMD;
|
||||
this.sIndent = (sIndent || "");
|
||||
|
|
@ -109,7 +108,6 @@ function MarkOut(sMD, sIndent, req, aParms, fDebug, fServerDebug)
|
|||
this.sClassImageLabel = this.sClassImage + "-label";
|
||||
}
|
||||
this.fDebug = fDebug;
|
||||
this.fServerDebug = fServerDebug;
|
||||
this.sHTML = null;
|
||||
this.aIDs = []; // this keeps tracks of auto-generated ID attributes for page elements, to insure uniqueness
|
||||
this.aMachines = []; // this keeps tracks of embedded machines on the page
|
||||
|
|
@ -242,6 +240,7 @@ MarkOut.setOptions = function(options)
|
|||
* and make sure all the pre-requisites are in place (eg, CSS file and scripts in the HTML document's
|
||||
* header).
|
||||
*
|
||||
* @this {MarkOut}
|
||||
* @param {Object} infoMachine
|
||||
*/
|
||||
MarkOut.prototype.addMachine = function(infoMachine)
|
||||
|
|
@ -252,6 +251,7 @@ MarkOut.prototype.addMachine = function(infoMachine)
|
|||
/**
|
||||
* getMachines()
|
||||
*
|
||||
* @this {MarkOut}
|
||||
* @return {Array} of objects containing information about each machine defined by the document
|
||||
*/
|
||||
MarkOut.prototype.getMachines = function()
|
||||
|
|
@ -266,7 +266,8 @@ MarkOut.prototype.getMachines = function()
|
|||
* that's not a letter or a digit to a hyphen (-), and stripping all leading and trailing hyphens from
|
||||
* the result. Furthermore, if the generated ID is not unique (among the set of ALL generated IDs),
|
||||
* then no ID is produced.
|
||||
*
|
||||
*
|
||||
* @this {MarkOut}
|
||||
* @param {string} sText
|
||||
* @returns {string|null} converts the given text to a unique ID (or null if resulting ID was not unique)
|
||||
*/
|
||||
|
|
@ -301,6 +302,7 @@ MarkOut.aHTMLEntities = {
|
|||
/**
|
||||
* convertMD()
|
||||
*
|
||||
* @this {MarkOut}
|
||||
* @param {string} [sIndent] sets the indentation of HTML elements within the document
|
||||
*/
|
||||
MarkOut.prototype.convertMD = function(sIndent)
|
||||
|
|
@ -414,6 +416,7 @@ MarkOut.prototype.convertMD = function(sIndent)
|
|||
* If your text may contain some block markers (ie, double-linefeeds), or headers (either "Atx-style"
|
||||
* or "Setext-style) that require the insertion of double-linefeed block markers, then call this function.
|
||||
*
|
||||
* @this {MarkOut}
|
||||
* @param {string} sMD
|
||||
* @param {string} [sIndent]
|
||||
*/
|
||||
|
|
@ -478,6 +481,7 @@ MarkOut.prototype.convertMDBlocks = function(sMD, sIndent)
|
|||
/**
|
||||
* convertMDBlock(sBlock, sIndent)
|
||||
*
|
||||
* @this {MarkOut}
|
||||
* @param {string} sBlock
|
||||
* @param {string} [sIndent]
|
||||
*/
|
||||
|
|
@ -623,6 +627,7 @@ MarkOut.prototype.convertMDBlock = function(sBlock, sIndent)
|
|||
* Markdown apparently treats equivalently), I automatically use a list style that omits bullets.
|
||||
* So, if you REALLY want bullets, use "-" or "+".
|
||||
*
|
||||
* @this {MarkOut}
|
||||
* @param {string} sBlock
|
||||
* @param {string} sIndent
|
||||
* @return {string}
|
||||
|
|
@ -688,6 +693,7 @@ MarkOut.prototype.convertMDList = function(sBlock, sIndent)
|
|||
* galleries, which are nothing more than paragraphs containing a series of image links), so this
|
||||
* code is disabled for now.
|
||||
*
|
||||
* @this {MarkOut}
|
||||
* @param {string} s
|
||||
* @return {string}
|
||||
*/
|
||||
|
|
@ -720,6 +726,7 @@ MarkOut.prototype.convertMDLines = function(s)
|
|||
*
|
||||
* TODO: Consider adding support for "reference"-style Markdown links.
|
||||
*
|
||||
* @this {MarkOut}
|
||||
* @param {string} sBlock
|
||||
* @return {string}
|
||||
*/
|
||||
|
|
@ -748,7 +755,7 @@ MarkOut.prototype.convertMDLinks = function(sBlock)
|
|||
sType = "id"; // using the "name" attribute is deprecated as well
|
||||
sURL = sURL.substr(1);
|
||||
} else {
|
||||
sURL = net.encodeURL(sURL, this.req, this.fServerDebug);
|
||||
sURL = net.encodeURL(sURL, this.req, this.fDebug);
|
||||
}
|
||||
sBlock = str.replaceAll(aMatch[0], '<' + sTag + ' ' + sType + '="' + sURL + '"' + sTitle + '>' + sText + '</' + sTag + '>', sBlock);
|
||||
}
|
||||
|
|
@ -758,6 +765,7 @@ MarkOut.prototype.convertMDLinks = function(sBlock)
|
|||
/**
|
||||
* convertMDImageLinks(sBlock)
|
||||
*
|
||||
* @this {MarkOut}
|
||||
* @param {string} sBlock
|
||||
* @param {string} sIndent
|
||||
* @return {string}
|
||||
|
|
@ -778,7 +786,7 @@ MarkOut.prototype.convertMDImageLinks = function(sBlock, sIndent)
|
|||
var sBlockOrig = sBlock;
|
||||
var re = /!\[(.*?)\]\((.*?)(?:\s*"(.*?)"\)|\))/g;
|
||||
while ((aMatch = re.exec(sBlockOrig))) {
|
||||
var sImage = '<img src="' + net.encodeURL(aMatch[2], this.req, this.fServerDebug) + '" alt="' + aMatch[1] + '"';
|
||||
var sImage = '<img src="' + net.encodeURL(aMatch[2], this.req, this.fDebug) + '" alt="' + aMatch[1] + '"';
|
||||
if (aMatch[3]) {
|
||||
/*
|
||||
* The format of the special "link:" syntax is:
|
||||
|
|
@ -814,10 +822,10 @@ MarkOut.prototype.convertMDImageLinks = function(sBlock, sIndent)
|
|||
* The assumption here is that if we have "static" thumbs, then we should also have full "static"
|
||||
* copies as well.
|
||||
*/
|
||||
if (aMatch[2].indexOf("static/") >= 0 && sURL.indexOf("://") > 0 && (this.fServerDebug || net.hasParm(net.REVEAL_COMMAND, net.REVEAL_PDFS, this.req))) {
|
||||
if (aMatch[2].indexOf("static/") >= 0 && sURL.indexOf("://") > 0 && (this.fDebug || net.hasParm(net.REVEAL_COMMAND, net.REVEAL_PDFS, this.req))) {
|
||||
sURL = aMatch[2].replace("/thumbs/", "/").replace(" 1.jpeg", ".pdf").replace(".jpg", ".pdf");
|
||||
}
|
||||
sURL = net.encodeURL(sURL, this.req, this.fServerDebug);
|
||||
sURL = net.encodeURL(sURL, this.req, this.fDebug);
|
||||
if (asParts[iPart] == "nogallery") {
|
||||
fNoGallery = true;
|
||||
iPart++;
|
||||
|
|
@ -862,6 +870,7 @@ MarkOut.prototype.convertMDImageLinks = function(sBlock, sIndent)
|
|||
/**
|
||||
* convertMDMachineLinks(sBlock)
|
||||
*
|
||||
* @this {MarkOut}
|
||||
* @param {string} sBlock
|
||||
* @return {string}
|
||||
*/
|
||||
|
|
@ -992,6 +1001,7 @@ MarkOut.prototype.convertMDMachineLinks = function(sBlock)
|
|||
* Also, for reasons noted in the code below, we don't support emphasis in the middle
|
||||
* of words.
|
||||
*
|
||||
* @this {MarkOut}
|
||||
* @param {string} sBlock
|
||||
* @return {string}
|
||||
*/
|
||||
|
|
@ -1031,6 +1041,7 @@ MarkOut.prototype.convertMDEmphasis = function(sBlock)
|
|||
/**
|
||||
* addIndent(sIndent)
|
||||
*
|
||||
* @this {MarkOut}
|
||||
* @param {string|undefined} sIndent
|
||||
* @return {string} previous indent
|
||||
*/
|
||||
|
|
@ -1044,6 +1055,7 @@ MarkOut.prototype.addIndent = function(sIndent)
|
|||
/**
|
||||
* subIndent(sIndent)
|
||||
*
|
||||
* @this {MarkOut}
|
||||
* @param {string|undefined} sIndent
|
||||
*/
|
||||
MarkOut.prototype.subIndent = function(sIndent)
|
||||
|
|
@ -1064,6 +1076,7 @@ MarkOut.prototype.subIndent = function(sIndent)
|
|||
* This is used purely (at the moment) for debugging purposes, so that we can clearly see
|
||||
* what our simplistic Markdown parser is parsing at each stage.
|
||||
*
|
||||
* @this {MarkOut}
|
||||
* @param {string} sLabel
|
||||
* @param {string} sText
|
||||
* @return {string}
|
||||
|
|
@ -1080,6 +1093,7 @@ MarkOut.prototype.encodeComment = function(sLabel, sText)
|
|||
* This is used purely (at the moment) for debugging purposes, so that we can clearly see
|
||||
* what our simplistic Markdown parser is parsing at each stage.
|
||||
*
|
||||
* @this {MarkOut}
|
||||
* @param {string} sText
|
||||
* @return {string}
|
||||
*
|
||||
|
|
|
|||
|
|
@ -480,7 +480,7 @@ Bus.prototype.restoreMemory = function(a)
|
|||
* configuration since it was last saved (the most likely explanation) or there's some internal
|
||||
* inconsistency (eg, the block size is wrong).
|
||||
*/
|
||||
this.error("Unable to restore memory block " + iBlock);
|
||||
Component.error("Unable to restore memory block " + iBlock);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -554,7 +554,7 @@ Bus.prototype.addPortInputNotify = function(start, end, component, fn)
|
|||
if (fn !== undefined) {
|
||||
for (var port = start; port <= end; port++) {
|
||||
if (this.aPortInputNotify[port] !== undefined) {
|
||||
this.warning("Input port " + str.toHexWord(port) + " registered by " + this.aPortInputNotify[port][0].id + ", ignoring " + component.id);
|
||||
Component.warning("Input port " + str.toHexWord(port) + " registered by " + this.aPortInputNotify[port][0].id + ", ignoring " + component.id);
|
||||
continue;
|
||||
}
|
||||
this.aPortInputNotify[port] = [component, fn, false, false];
|
||||
|
|
@ -674,7 +674,7 @@ Bus.prototype.addPortOutputNotify = function(start, end, component, fn)
|
|||
if (fn !== undefined) {
|
||||
for (var port = start; port <= end; port++) {
|
||||
if (this.aPortOutputNotify[port] !== undefined) {
|
||||
this.warning("Output port " + str.toHexWord(port) + " registered by " + this.aPortOutputNotify[port][0].id + ", ignoring " + component.id);
|
||||
Component.warning("Output port " + str.toHexWord(port) + " registered by " + this.aPortOutputNotify[port][0].id + ", ignoring " + component.id);
|
||||
continue;
|
||||
}
|
||||
this.aPortOutputNotify[port] = [component, fn, false, false];
|
||||
|
|
@ -764,7 +764,7 @@ Bus.prototype.removePortOutputNotify = function(start, end, component, fn)
|
|||
*/
|
||||
Bus.prototype.reportError = function(op, addr, size)
|
||||
{
|
||||
this.error("Memory block error (" + op + "," + str.toHex(addr) + "," + str.toHex(size) + ")");
|
||||
Component.error("Memory block error (" + op + "," + str.toHex(addr) + "," + str.toHex(size) + ")");
|
||||
return false;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -157,12 +157,6 @@ function ChipSet(parmsChipSet)
|
|||
* and (on the MODEL_5160) whether or not a coprocessor is installed. If no SW1 settings are provided,
|
||||
* we look for individual 'fdrives' and 'monitor' settings and build a default SW1 value.
|
||||
*
|
||||
* TODO: Get rid of reliance on SW1 for MODEL_5170 and later; omitting it now results in a BIOS warning:
|
||||
*
|
||||
* ' 162-System Options Not Set-(Run SETUP)'
|
||||
*
|
||||
* ' (RESUME = "F1" KEY)'
|
||||
*
|
||||
* The defaults below select max memory, monochrome monitor (EGA monitor for MODEL_5170), and two floppies.
|
||||
* Don't get too excited about "max memory" either: on a MODEL_5150, the max was 64Kb, and on a MODEL_5160,
|
||||
* the max was 256Kb. However, the RAM component is free to install as much base memory as it likes,
|
||||
|
|
@ -2566,14 +2560,14 @@ ChipSet.prototype.updateDMA = function(channel)
|
|||
};
|
||||
|
||||
/**
|
||||
* inPICL(iPIC, addrFrom)
|
||||
* inPICLo(iPIC, addrFrom)
|
||||
*
|
||||
* @this {ChipSet}
|
||||
* @param {number} iPIC
|
||||
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
|
||||
* @return {number} simulated port value
|
||||
*/
|
||||
ChipSet.prototype.inPICL = function(iPIC, addrFrom)
|
||||
ChipSet.prototype.inPICLo = function(iPIC, addrFrom)
|
||||
{
|
||||
var b = 0;
|
||||
var pic = this.aPICs[iPIC];
|
||||
|
|
@ -2595,14 +2589,14 @@ ChipSet.prototype.inPICL = function(iPIC, addrFrom)
|
|||
};
|
||||
|
||||
/**
|
||||
* outPICL(iPIC, bOut, addrFrom)
|
||||
* outPICLo(iPIC, bOut, addrFrom)
|
||||
*
|
||||
* @this {ChipSet}
|
||||
* @param {number} iPIC
|
||||
* @param {number} bOut
|
||||
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
|
||||
*/
|
||||
ChipSet.prototype.outPICL = function(iPIC, bOut, addrFrom)
|
||||
ChipSet.prototype.outPICLo = function(iPIC, bOut, addrFrom)
|
||||
{
|
||||
var pic = this.aPICs[iPIC];
|
||||
this.messagePort(pic.port, bOut, addrFrom, "PIC" + iPIC, ChipSet.MESSAGE_PIC);
|
||||
|
|
@ -2613,7 +2607,7 @@ ChipSet.prototype.outPICL = function(iPIC, bOut, addrFrom)
|
|||
pic.nICW = 0;
|
||||
pic.aICW[pic.nICW++] = bOut;
|
||||
/*
|
||||
* I used to do the rest of this initialization in outPICH(), once all the ICW commands had been received,
|
||||
* I used to do the rest of this initialization in outPICHi(), once all the ICW commands had been received,
|
||||
* but a closer reading of the 8259A spec indicates that that should happen now, on receipt on ICW1.
|
||||
*
|
||||
* Also, on p.10 of that spec, it says "The Interrupt Mask Register is cleared". I originally took that to
|
||||
|
|
@ -2711,7 +2705,7 @@ ChipSet.prototype.outPICL = function(iPIC, bOut, addrFrom)
|
|||
}
|
||||
} else {
|
||||
/*
|
||||
* This must be an OCW3 request. If it's a "Read Register" command (PIC_LO.OCW3_READ_CMD), inPICL() will take care it.
|
||||
* This must be an OCW3 request. If it's a "Read Register" command (PIC_LO.OCW3_READ_CMD), inPICLo() will take care it.
|
||||
*
|
||||
* TODO: If OCW3 specified a "Poll" command (PIC_LO.OCW3_POLL_CMD) or a "Special Mask Mode" command (PIC_LO.OCW3_SMM_CMD),
|
||||
* that's unfortunate, because I don't support them yet.
|
||||
|
|
@ -2724,14 +2718,14 @@ ChipSet.prototype.outPICL = function(iPIC, bOut, addrFrom)
|
|||
};
|
||||
|
||||
/**
|
||||
* inPICH(iPIC, addrFrom)
|
||||
* inPICHi(iPIC, addrFrom)
|
||||
*
|
||||
* @this {ChipSet}
|
||||
* @param {number} iPIC
|
||||
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
|
||||
* @return {number} simulated port value
|
||||
*/
|
||||
ChipSet.prototype.inPICH = function(iPIC, addrFrom)
|
||||
ChipSet.prototype.inPICHi = function(iPIC, addrFrom)
|
||||
{
|
||||
var pic = this.aPICs[iPIC];
|
||||
var b = pic.bIMR;
|
||||
|
|
@ -2740,14 +2734,14 @@ ChipSet.prototype.inPICH = function(iPIC, addrFrom)
|
|||
};
|
||||
|
||||
/**
|
||||
* outPICH(iPIC, bOut, addrFrom)
|
||||
* outPICHi(iPIC, bOut, addrFrom)
|
||||
*
|
||||
* @this {ChipSet}
|
||||
* @param {number} iPIC
|
||||
* @param {number} bOut
|
||||
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
|
||||
*/
|
||||
ChipSet.prototype.outPICH = function(iPIC, bOut, addrFrom)
|
||||
ChipSet.prototype.outPICHi = function(iPIC, bOut, addrFrom)
|
||||
{
|
||||
var pic = this.aPICs[iPIC];
|
||||
this.messagePort(pic.port+1, bOut, addrFrom, "PIC" + iPIC, ChipSet.MESSAGE_PIC);
|
||||
|
|
@ -4230,8 +4224,8 @@ ChipSet.aPortInput = {
|
|||
0x06: /** @this {ChipSet} */ function(port, addrFrom) { return this.inDMAChannelAddr(ChipSet.DMA0.INDEX, 3, port, addrFrom); },
|
||||
0x07: /** @this {ChipSet} */ function(port, addrFrom) { return this.inDMAChannelCount(ChipSet.DMA0.INDEX, 3, port, addrFrom); },
|
||||
0x08: /** @this {ChipSet} */ function(port, addrFrom) { return this.inDMAStatus(ChipSet.DMA0.INDEX, port, addrFrom); },
|
||||
0x20: /** @this {ChipSet} */ function(port, addrFrom) { return this.inPICL(ChipSet.PIC0.INDEX, addrFrom); },
|
||||
0x21: /** @this {ChipSet} */ function(port, addrFrom) { return this.inPICH(ChipSet.PIC0.INDEX, addrFrom); },
|
||||
0x20: /** @this {ChipSet} */ function(port, addrFrom) { return this.inPICLo(ChipSet.PIC0.INDEX, addrFrom); },
|
||||
0x21: /** @this {ChipSet} */ function(port, addrFrom) { return this.inPICHi(ChipSet.PIC0.INDEX, addrFrom); },
|
||||
0x40: /** @this {ChipSet} */ function(port, addrFrom) { return this.inTimer(ChipSet.TIMER0.INDEX, addrFrom); },
|
||||
0x41: /** @this {ChipSet} */ function(port, addrFrom) { return this.inTimer(ChipSet.TIMER1.INDEX, addrFrom); },
|
||||
0x42: /** @this {ChipSet} */ function(port, addrFrom) { return this.inTimer(ChipSet.TIMER2.INDEX, addrFrom); },
|
||||
|
|
@ -4267,8 +4261,8 @@ ChipSet.aPortInput5170 = {
|
|||
0x8D: /** @this {ChipSet} */ function(port, addrFrom) { return this.inDMAPageSpare(5, port, addrFrom); },
|
||||
0x8E: /** @this {ChipSet} */ function(port, addrFrom) { return this.inDMAPageSpare(6, port, addrFrom); },
|
||||
0x8F: /** @this {ChipSet} */ function(port, addrFrom) { return this.inDMAPageReg(ChipSet.DMA1.INDEX, 0, port, addrFrom); },
|
||||
0xA0: /** @this {ChipSet} */ function(port, addrFrom) { return this.inPICL(ChipSet.PIC1.INDEX, addrFrom); },
|
||||
0xA1: /** @this {ChipSet} */ function(port, addrFrom) { return this.inPICH(ChipSet.PIC1.INDEX, addrFrom); },
|
||||
0xA0: /** @this {ChipSet} */ function(port, addrFrom) { return this.inPICLo(ChipSet.PIC1.INDEX, addrFrom); },
|
||||
0xA1: /** @this {ChipSet} */ function(port, addrFrom) { return this.inPICHi(ChipSet.PIC1.INDEX, addrFrom); },
|
||||
0xC0: /** @this {ChipSet} */ function(port, addrFrom) { return this.inDMAChannelAddr(ChipSet.DMA1.INDEX, 0, port, addrFrom); },
|
||||
0xC2: /** @this {ChipSet} */ function(port, addrFrom) { return this.inDMAChannelCount(ChipSet.DMA1.INDEX, 0, port, addrFrom); },
|
||||
0xC4: /** @this {ChipSet} */ function(port, addrFrom) { return this.inDMAChannelAddr(ChipSet.DMA1.INDEX, 1, port, addrFrom); },
|
||||
|
|
@ -4298,8 +4292,8 @@ ChipSet.aPortOutput = {
|
|||
0x0B: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAMode(ChipSet.DMA0.INDEX, port, bOut, addrFrom); },
|
||||
0x0C: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAIndex(ChipSet.DMA0.INDEX, port, bOut, addrFrom); },
|
||||
0x0D: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAClear(ChipSet.DMA0.INDEX, port, bOut, addrFrom); },
|
||||
0x20: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outPICL(ChipSet.PIC0.INDEX, bOut, addrFrom); },
|
||||
0x21: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outPICH(ChipSet.PIC0.INDEX, bOut, addrFrom); },
|
||||
0x20: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outPICLo(ChipSet.PIC0.INDEX, bOut, addrFrom); },
|
||||
0x21: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outPICHi(ChipSet.PIC0.INDEX, bOut, addrFrom); },
|
||||
0x40: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outTimer(ChipSet.TIMER0.INDEX, bOut, addrFrom); },
|
||||
0x41: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outTimer(ChipSet.TIMER1.INDEX, bOut, addrFrom); },
|
||||
0x42: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outTimer(ChipSet.TIMER2.INDEX, bOut, addrFrom); },
|
||||
|
|
@ -4336,8 +4330,8 @@ ChipSet.aPortOutput5170 = {
|
|||
0x8D: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAPageSpare(5, port, bOut, addrFrom); },
|
||||
0x8E: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAPageSpare(6, port, bOut, addrFrom); },
|
||||
0x8F: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAPageReg(ChipSet.DMA1.INDEX, 0, port, bOut, addrFrom); },
|
||||
0xA0: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outPICL(ChipSet.PIC1.INDEX, bOut, addrFrom); },
|
||||
0xA1: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outPICH(ChipSet.PIC1.INDEX, bOut, addrFrom); },
|
||||
0xA0: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outPICLo(ChipSet.PIC1.INDEX, bOut, addrFrom); },
|
||||
0xA1: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outPICHi(ChipSet.PIC1.INDEX, bOut, addrFrom); },
|
||||
0xC0: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAChannelAddr(ChipSet.DMA1.INDEX, 0, port, bOut, addrFrom); },
|
||||
0xC2: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAChannelCount(ChipSet.DMA1.INDEX, 0, port, bOut, addrFrom); },
|
||||
0xC4: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAChannelAddr(ChipSet.DMA1.INDEX, 1, port, bOut, addrFrom); },
|
||||
|
|
|
|||
|
|
@ -139,15 +139,15 @@ function Computer(parmsComputer, parmsMachine, fSuspended) {
|
|||
this.sUserID = this.queryUserID();
|
||||
|
||||
/*
|
||||
* Find the appropriate CPU (and the Debugger, if any)
|
||||
* Find the appropriate CPU (and Debugger and Control Panel, if any)
|
||||
*/
|
||||
this.cpu = Component.getComponentByType("CPU", this.id);
|
||||
if (!this.cpu) {
|
||||
Component.error("Unable to find CPU component");
|
||||
return;
|
||||
}
|
||||
|
||||
this.dbg = Component.getComponentByType("Debugger", this.id);
|
||||
this.panel = Component.getComponentByType("Panel", this.id);
|
||||
|
||||
/*
|
||||
* Initialize the Bus component
|
||||
|
|
@ -160,6 +160,20 @@ function Computer(parmsComputer, parmsMachine, fSuspended) {
|
|||
var aComponents = Component.getComponents(this.id);
|
||||
for (var iComponent = 0; iComponent < aComponents.length; iComponent++) {
|
||||
var component = aComponents[iComponent];
|
||||
/*
|
||||
* I can think of many "cleaner" ways for the Control Panel component to pass its
|
||||
* notice(), println(), etc, overrides on to all the other components, but it's just
|
||||
* too darn convenient to slam those overrides into the components directly.
|
||||
*
|
||||
* Adding more initBus() parameters was another option, but that function is already
|
||||
* looking a bit unwieldy, and Control Panel functionality is a little far afield
|
||||
* from Bus initialization.
|
||||
*/
|
||||
if (this.panel && this.panel.controlPrint) {
|
||||
component.notice = this.panel.notice;
|
||||
component.println = this.panel.println;
|
||||
component.controlPrint = this.panel.controlPrint;
|
||||
}
|
||||
if (component.initBus) component.initBus(this, this.bus, this.cpu, this.dbg);
|
||||
}
|
||||
|
||||
|
|
@ -557,7 +571,7 @@ Computer.prototype.powerRestore = function(component, stateComputer, fRepower, f
|
|||
*/
|
||||
if (!component.powerUp(data, fRepower)) {
|
||||
if (data) {
|
||||
this.error("Unable to restore state for " + component.type);
|
||||
Component.error("Unable to restore state for " + component.type);
|
||||
/*
|
||||
* If this is a resume error for a machine that also has a predefined state
|
||||
* AND we're not restoring from that state, then throw away the current state,
|
||||
|
|
@ -1179,6 +1193,7 @@ Computer.init = function()
|
|||
|
||||
var eComputer = aeComputers[iComputer];
|
||||
var parmsComputer = Component.getComponentParms(eComputer);
|
||||
|
||||
/*
|
||||
* We set fSuspended in the Computer constructor because we want to "power up" the
|
||||
* computer ourselves, after any/all bindings are in place.
|
||||
|
|
|
|||
|
|
@ -254,11 +254,15 @@ CPU.prototype.powerUp = function(data, fRepower)
|
|||
this.dbg.init();
|
||||
} else {
|
||||
/*
|
||||
* TODO: Once we get rid of those nasty Component method overrides, this test will have to be revised as well
|
||||
* The Computer (this.cmp) knows if there's a Control Panel (this.cmp.panel), and the Control Panel
|
||||
* knows if there's a "print" control (this.cmp.panel.controlPrint), and if there IS a "print" control
|
||||
* but no debugger, the machine is probably misconfigured (most likely, the page simply neglected to
|
||||
* load the Debugger component).
|
||||
*
|
||||
* However, we don't actually need to check all that; it's always safe use println(), regardless whether
|
||||
* a Control Panel with a "print" control is present or not.
|
||||
*/
|
||||
if (Component.controlPrint) {
|
||||
this.warning("No debugger detected");
|
||||
}
|
||||
this.println("No debugger detected");
|
||||
}
|
||||
}
|
||||
this.fPowered = true;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* @fileoverview Implements the PCjs Debugger component.
|
||||
* @fileoverview Implements the PCjs Debugger component.
|
||||
* @author <a href="mailto:Jeff@pcjs.org">Jeff Parsons</a>
|
||||
* @version 1.0
|
||||
* @suppress {missingProperties}
|
||||
|
|
@ -1562,7 +1562,7 @@ if (DEBUGGER) {
|
|||
*/
|
||||
if (fUpdateCPU !== false) this.cpu.updateCPU();
|
||||
|
||||
this.updateStatus(fRegs, false);
|
||||
this.updateStatus(fRegs || false, false);
|
||||
return (this.nCycles > 0);
|
||||
};
|
||||
|
||||
|
|
@ -2846,8 +2846,8 @@ if (DEBUGGER) {
|
|||
value = this.cpu.segSS.sel;
|
||||
break;
|
||||
/*
|
||||
* I used to alias "PC" to "IP", until I discovered that early (perhaps even ALL?) versions of DEBUG
|
||||
* treat "PC" as an alias for the 16-bit flags register. TODO: Add support for "PC" that matches DEBUG.
|
||||
* I used to alias "PC" to "IP", until I discovered that early (perhaps even ALL?) versions of DEBUG.COM
|
||||
* treat "PC" as an alias for the 16-bit flags register. TODO: Add support for "PC".
|
||||
*/
|
||||
case "IP":
|
||||
value = this.cpu.regIP;
|
||||
|
|
@ -3283,9 +3283,10 @@ if (DEBUGGER) {
|
|||
*/
|
||||
Debugger.prototype.doClear = function(sCmd)
|
||||
{
|
||||
if (Component.controlPrint) {
|
||||
Component.controlPrint.value = "";
|
||||
}
|
||||
/*
|
||||
* TODO: There should be a clear() component method that the Control Panel overrides to perform this function.
|
||||
*/
|
||||
if (this.controlPrint) this.controlPrint.value = "";
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -4275,7 +4276,7 @@ if (DEBUGGER) {
|
|||
/*
|
||||
* Limiting the amount of disassembled code to 256 bytes in non-DEBUG builds is partly to
|
||||
* prevent the user from wedging the browser by dumping too many lines, but also a recognition
|
||||
* that, in non-DEBUG builds, Component.println() keeps print output buffer truncated to 8Kb anyway.
|
||||
* that, in non-DEBUG builds, this.println() keeps print output buffer truncated to 8Kb anyway.
|
||||
*/
|
||||
this.println("range too large");
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -613,10 +613,10 @@ Disk.prototype.onLoadDisk = function(sDiskFile, sDiskData, nErrorCode, sDiskPath
|
|||
}
|
||||
|
||||
if (!aDiskData.length) {
|
||||
this.error("Empty disk image: " + this.sDiskName);
|
||||
Component.error("Empty disk image: " + this.sDiskName);
|
||||
}
|
||||
else if (aDiskData.length == 1) {
|
||||
this.error(aDiskData[0]);
|
||||
Component.error(aDiskData[0]);
|
||||
}
|
||||
/*
|
||||
* aDiskData is an array of cylinders, each of which is an array of heads, each of which
|
||||
|
|
@ -731,7 +731,7 @@ Disk.prototype.onLoadDisk = function(sDiskFile, sDiskData, nErrorCode, sDiskPath
|
|||
disk = this;
|
||||
}
|
||||
} catch (e) {
|
||||
this.error("Disk image error: " + e.message);
|
||||
Component.error("Disk image error: " + e.message);
|
||||
}
|
||||
}
|
||||
if (this.fnNotify) {
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ function FDC(parmsFDC) {
|
|||
*/
|
||||
this.pAutoMount = eval("(" + parmsFDC['autoMount'] + ")");
|
||||
} catch (e) {
|
||||
this.error("FDC auto-mount error: " + e.message + " (" + parmsFDC['autoMount'] + ")");
|
||||
Component.error("FDC auto-mount error: " + e.message + " (" + parmsFDC['autoMount'] + ")");
|
||||
this.pAutoMount = null;
|
||||
}
|
||||
}
|
||||
|
|
@ -395,7 +395,7 @@ FDC.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, control)
|
|||
try {
|
||||
dataValue = eval("({" + sValue + "})");
|
||||
} catch (e) {
|
||||
fdc.error("FDC option error: " + (e.message || e));
|
||||
Component.error("FDC option error: " + (e.message || e));
|
||||
}
|
||||
}
|
||||
var sDesc = dataValue['desc'];
|
||||
|
|
@ -744,6 +744,10 @@ FDC.prototype.saveController = function()
|
|||
|
||||
/**
|
||||
* initDrive(drive, iDrive, data)
|
||||
*
|
||||
* TODO: Consider a separate Drive class that both FDC and HDC can use, since there's a lot of commonality
|
||||
* between the drive objects created by both controllers. This will clean up overall drive management and allow
|
||||
* us to factor out some common Drive methods (eg, advanceSector()).
|
||||
*
|
||||
* @this {FDC}
|
||||
* @param {Object} drive
|
||||
|
|
@ -1933,8 +1937,7 @@ FDC.prototype.doFormat = function(drive)
|
|||
* NOTE: Since the FDC isn't aware of the extent of the transfer, all readByte() can do is return bytes
|
||||
* until the current track (or, in the case of a multi-track request, the current cylinder) has been exhausted.
|
||||
*
|
||||
* TODO: Research the requirements, if any, for multi-track I/O and determine what if anything needs to be
|
||||
* done. At the very least, if it must be supported, there would need to be some head-incrementing somewhere.
|
||||
* TODO: Research the requirements, if any, for multi-track I/O and determine what else needs to be done.
|
||||
*
|
||||
* @this {FDC}
|
||||
* @param {Object} drive
|
||||
|
|
@ -1958,7 +1961,11 @@ FDC.prototype.readByte = function(drive, done)
|
|||
break;
|
||||
}
|
||||
drive.ibSector = 0;
|
||||
drive.bSector++;
|
||||
/*
|
||||
* We "pre-advance" bSector et al now, instead of waiting to advance it right before the seek().
|
||||
* This allows the initial call to readByte() to perform a seek without triggering an unwanted advance.
|
||||
*/
|
||||
this.advanceSector(drive);
|
||||
} while (true);
|
||||
}
|
||||
done(b, false);
|
||||
|
|
@ -1981,8 +1988,7 @@ FDC.prototype.readByte = function(drive, done)
|
|||
* NOTE: Since the FDC isn't aware of the extent of the transfer, all writeByte() can do is accept bytes
|
||||
* until the current track (or, in the case of a multi-track request, the current cylinder) has been exhausted.
|
||||
*
|
||||
* TODO: Research the requirements, if any, for multi-track I/O and determine what if anything needs to be
|
||||
* done. At the very least, if it must be supported, there would need to be some head-incrementing somewhere.
|
||||
* TODO: Research the requirements, if any, for multi-track I/O and determine what else needs to be done.
|
||||
*
|
||||
* @this {FDC}
|
||||
* @param {Object} drive
|
||||
|
|
@ -2010,11 +2016,40 @@ FDC.prototype.writeByte = function(drive, b)
|
|||
break;
|
||||
}
|
||||
drive.ibSector = 0;
|
||||
drive.bSector++;
|
||||
/*
|
||||
* We "pre-advance" bSector et al now, instead of waiting to advance it right before the seek().
|
||||
* This allows the initial call to writeByte() to perform a seek without triggering an unwanted advance.
|
||||
*/
|
||||
this.advanceSector(drive);
|
||||
} while (true);
|
||||
return b;
|
||||
};
|
||||
|
||||
/**
|
||||
* advanceSector(drive)
|
||||
*
|
||||
* This increments the sector number; when the sector number reaches drive.nSectors on the current track, we
|
||||
* increment drive.bHead and reset drive.bSector, and when drive.bHead reaches drive.nHeads, we reset drive.bHead
|
||||
* and increment drive.bCylinder.
|
||||
*
|
||||
* @this {FDC}
|
||||
* @param {Object} drive
|
||||
*/
|
||||
FDC.prototype.advanceSector = function(drive)
|
||||
{
|
||||
Component.assert(drive.bCylinder < drive.nCylinders);
|
||||
drive.bSector++;
|
||||
var bSectorStart = 1;
|
||||
if (drive.bSector >= drive.nSectors + bSectorStart) {
|
||||
drive.bSector = bSectorStart;
|
||||
drive.bHead++;
|
||||
if (drive.bHead >= drive.nHeads) {
|
||||
drive.bHead = 0;
|
||||
drive.bCylinder++;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* writeFormat(drive, b)
|
||||
*
|
||||
|
|
@ -2085,9 +2120,9 @@ FDC.prototype.intBIOSDiskette = function(addr)
|
|||
var DL = this.cpu.regDX & 0xff;
|
||||
var DH = this.cpu.regDX >> 8;
|
||||
if (this.dbg && this.dbg.messageEnabled(this.dbg.MESSAGE_FDC) && DL < 0x80) {
|
||||
this.dbg.message("FDC.intBIOS(AH=" + str.toHexByte(AH) + ",D=" + str.toHexByte(DL) + ",C=" + str.toHexByte(CH) + ",H=" + str.toHexByte(DH) + ",S=" + str.toHexByte(CL) + ",N=" + str.toHexByte(AL) + ") at " + str.toHexAddr(addr - this.cpu.segCS.base, this.cpu.segCS.sel));
|
||||
this.dbg.message("\nFDC.intBIOS(AH=" + str.toHexByte(AH) + ",D=" + str.toHexByte(DL) + ",C=" + str.toHexByte(CH) + ",H=" + str.toHexByte(DH) + ",S=" + str.toHexByte(CL) + ",N=" + str.toHexByte(AL) + ") at " + str.toHexAddr(addr - this.cpu.segCS.base, this.cpu.segCS.sel));
|
||||
// this.cpu.haltCPU();
|
||||
this.cpu.addInterruptReturn(addr, function (fdc, nCycles) {
|
||||
this.cpu.addInterruptReturn(addr, function(fdc, nCycles) {
|
||||
return function onBIOSDisketteReturn(nLevel) {
|
||||
nCycles = fdc.cpu.getCycles() - nCycles;
|
||||
fdc.messageDebugger("FDC.intBIOS(" + nLevel + "): C=" + (fdc.cpu.getCF()? 1 : 0) + " (cycles=" + nCycles + ")");
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -74,8 +74,8 @@ if (typeof module !== 'undefined') {
|
|||
* supported in theory, but in practice, they're not.
|
||||
*
|
||||
* NOTE: Since Memory blocks are low-level objects that have no UI requirements, they do not
|
||||
* inherit from the Component class; so, if you want to use print(), for example, you must
|
||||
* rely on class methods like Component.println() rather than object methods like this.println().
|
||||
* inherit from the Component class; so, if you want to use println(), for example, you must
|
||||
* use the methods in the Debugger class.
|
||||
*
|
||||
* Because Memory blocks now allow us to have a "sparse" address space, we could choose to
|
||||
* take the memory hit of allocating 4K arrays per block, where each element stores only one byte,
|
||||
|
|
@ -160,10 +160,6 @@ Memory.prototype = {
|
|||
* @return {number}
|
||||
*/
|
||||
readNone: function(off) {
|
||||
/*
|
||||
* This can happen so frequently that the browser can't come up for air, so it's best to do this only under special circumstances...
|
||||
*/
|
||||
// if (DEBUG) Component.println("readNone(" + str.toHexWord(this.addr + off) + ")");
|
||||
return 0;
|
||||
},
|
||||
/**
|
||||
|
|
@ -174,10 +170,6 @@ Memory.prototype = {
|
|||
* @param {number} v (could be either a byte or word value, since we use the same handler for both kinds of accesses)
|
||||
*/
|
||||
writeNone: function(off, v) {
|
||||
/*
|
||||
* This can happen so frequently that the browser can't come up for air, so it's best to do this only under special circumstances...
|
||||
*/
|
||||
// if (DEBUG) Component.println("writeNone(" + str.toHexWord(this.addr + off) + "): " + str.toHexWord(v));
|
||||
},
|
||||
/**
|
||||
* readByteTArray(off)
|
||||
|
|
@ -537,13 +529,13 @@ Memory.prototype = {
|
|||
if (this.cReadBreakpoints++ === 0) {
|
||||
this.setReadAccess(Memory.afnVerify);
|
||||
}
|
||||
if (DEBUG) Component.println("read breakpoint added to memory block " + str.toHex(this.addr));
|
||||
if (DEBUG) this.dbg.println("read breakpoint added to memory block " + str.toHex(this.addr));
|
||||
}
|
||||
else {
|
||||
if (this.cWriteBreakpoints++ === 0) {
|
||||
this.setWriteAccess(Memory.afnVerify);
|
||||
}
|
||||
if (DEBUG) Component.println("write breakpoint added to memory block " + str.toHex(this.addr));
|
||||
if (DEBUG) this.dbg.println("write breakpoint added to memory block " + str.toHex(this.addr));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -559,14 +551,14 @@ Memory.prototype = {
|
|||
if (!fWrite) {
|
||||
if (--this.cReadBreakpoints === 0) {
|
||||
this.resetReadAccess();
|
||||
if (DEBUG) Component.println("all read breakpoints removed from memory block " + str.toHex(this.addr));
|
||||
if (DEBUG) this.dbg.println("all read breakpoints removed from memory block " + str.toHex(this.addr));
|
||||
}
|
||||
Component.assert(this.cReadBreakpoints >= 0);
|
||||
}
|
||||
else {
|
||||
if (--this.cWriteBreakpoints === 0) {
|
||||
this.resetWriteAccess();
|
||||
if (DEBUG) Component.println("all write breakpoints removed from memory block " + str.toHex(this.addr));
|
||||
if (DEBUG) this.dbg.println("all write breakpoints removed from memory block " + str.toHex(this.addr));
|
||||
}
|
||||
Component.assert(this.cWriteBreakpoints >= 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -228,7 +228,7 @@ Mouse.prototype.powerUp = function(data, fRepower) {
|
|||
var componentScreen = this.cmp.getComponentByType("Video");
|
||||
if (componentScreen) this.canvasScreen = componentScreen.getCanvas();
|
||||
} else {
|
||||
this.warning(this.id + ": " + this.sAdapterType + " " + this.idAdapter + " unavailable");
|
||||
Component.warning(this.id + ": " + this.sAdapterType + " " + this.idAdapter + " unavailable");
|
||||
}
|
||||
}
|
||||
if (this.fActive) {
|
||||
|
|
|
|||
|
|
@ -67,7 +67,8 @@ Component.subclass(Component, Panel);
|
|||
* @param {Object} control is the HTML control DOM object (eg, HTMLButtonElement)
|
||||
* @return {boolean} true if binding was successful, false if unrecognized binding request
|
||||
*/
|
||||
Panel.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, control) {
|
||||
Panel.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, control)
|
||||
{
|
||||
if (this.cmp && this.cmp.setBinding(sHTMLClass, sHTMLType, sBinding, control)) return true;
|
||||
if (this.cpu && this.cpu.setBinding(sHTMLClass, sHTMLType, sBinding, control)) return true;
|
||||
if (this.kbd && this.kbd.setBinding(sHTMLClass, sHTMLType, sBinding, control)) return true;
|
||||
|
|
@ -84,7 +85,8 @@ Panel.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, control)
|
|||
* @param {X86CPU} cpu
|
||||
* @param {Debugger} dbg
|
||||
*/
|
||||
Panel.prototype.initBus = function(cmp, bus, cpu, dbg) {
|
||||
Panel.prototype.initBus = function(cmp, bus, cpu, dbg)
|
||||
{
|
||||
this.cmp = cmp;
|
||||
this.cpu = cpu;
|
||||
this.dbg = dbg;
|
||||
|
|
@ -99,7 +101,8 @@ Panel.prototype.initBus = function(cmp, bus, cpu, dbg) {
|
|||
* @param {boolean} [fRepower]
|
||||
* @return {boolean} true if successful, false if failure
|
||||
*/
|
||||
Panel.prototype.powerUp = function(data, fRepower) {
|
||||
Panel.prototype.powerUp = function(data, fRepower)
|
||||
{
|
||||
if (!fRepower) {
|
||||
Panel.init();
|
||||
}
|
||||
|
|
@ -113,7 +116,8 @@ Panel.prototype.powerUp = function(data, fRepower) {
|
|||
* @param {boolean} fSave
|
||||
* @return {Object|boolean}
|
||||
*/
|
||||
Panel.prototype.powerDown = function(fSave) {
|
||||
Panel.prototype.powerDown = function(fSave)
|
||||
{
|
||||
return true;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ RAM.prototype.reset = function() {
|
|||
}
|
||||
if (this.chipset) this.chipset.addCMOSMemory(this.addrRAM, this.sizeRAM);
|
||||
} else {
|
||||
this.error("No RAM allocated");
|
||||
Component.error("No RAM allocated");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -221,11 +221,11 @@ ROM.prototype.onLoadROM = function(sROMFile, sROMData, nErrorCode)
|
|||
this.aSymbols = rom['symbols'];
|
||||
|
||||
if (!this.abROM.length) {
|
||||
this.error("Empty ROM: " + sROMFile);
|
||||
Component.error("Empty ROM: " + sROMFile);
|
||||
return;
|
||||
}
|
||||
else if (this.abROM.length == 1) {
|
||||
this.error(this.abROM[0]);
|
||||
Component.error(this.abROM[0]);
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
|
|
|
|||
|
|
@ -2478,11 +2478,11 @@ Video.prototype.onLoadSetFonts = function(sFontFile, sFontData, nErrorCode)
|
|||
var abFontData = eval("(" + sFontData + ")");
|
||||
|
||||
if (!abFontData.length) {
|
||||
this.error("Empty font ROM image: " + sFontFile);
|
||||
Component.error("Empty font ROM image: " + sFontFile);
|
||||
return;
|
||||
}
|
||||
else if (abFontData.length == 1) {
|
||||
this.error(abFontData[0]);
|
||||
Component.error(abFontData[0]);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -37,15 +37,15 @@ var X86 = {
|
|||
/*
|
||||
* CPU model numbers
|
||||
*/
|
||||
MODEL_8086: 8086,
|
||||
MODEL_8088: 8088,
|
||||
MODEL_80186: 80186,
|
||||
MODEL_80188: 80188,
|
||||
MODEL_80286: 80286,
|
||||
MODEL_8086: 8086,
|
||||
MODEL_8088: 8088,
|
||||
MODEL_80186: 80186,
|
||||
MODEL_80188: 80188,
|
||||
MODEL_80286: 80286,
|
||||
/*
|
||||
* Processor Status flag definitions (stored in regPS)
|
||||
*/
|
||||
PS: {
|
||||
PS: {
|
||||
CF: 0x0001, // bit 0: Carry flag
|
||||
BIT1: 0x0002, // bit 1: reserved, always set
|
||||
PF: 0x0004, // bit 2: Parity flag
|
||||
|
|
@ -124,23 +124,23 @@ var X86 = {
|
|||
},
|
||||
/*
|
||||
* Processor Exception Interrupts
|
||||
*
|
||||
*
|
||||
* Of the following exceptions, all are designed to be restartable, except for 0x08 and 0x09 (and 0x0D
|
||||
* after an attempt to write to a read-only segment).
|
||||
*
|
||||
*
|
||||
* Error codes are pushed onto the stack for 0x08 (always 0) and 0x0A through 0x0D.
|
||||
*
|
||||
*
|
||||
* Priority: Instruction exception, TRAP, NMI, Processor Extension Segment Overrun, and finally INTR.
|
||||
*
|
||||
*
|
||||
* All exceptions can also occur in real-mode, except where noted. A GP_FAULT in real-mode can be triggered
|
||||
* by "any memory reference instruction that attempts to reference [a] 16-bit word at offset 0FFFFH".
|
||||
*
|
||||
* Interrupts beyond 0x10 (up through 0x1F) are reserved for future exceptions.
|
||||
*
|
||||
*
|
||||
* Implementation Detail: For any opcode we know must generate a UD_FAULT interrupt, we invoke opInvalid().
|
||||
* We reserve the term "undefined" for opcodes that require further investigation, and we invoke opUndefined()
|
||||
* in those cases until an opcode's behavior has been defined; at that point, it's either valid or invalid.
|
||||
*
|
||||
*
|
||||
* As for "illegal", that's a silly (and redundant) term in this context, so we don't use it. Similarly,
|
||||
* the term "undocumented" should be limited to operations that are valid but that Intel did not document.
|
||||
*/
|
||||
|
|
@ -195,7 +195,7 @@ var X86 = {
|
|||
/*
|
||||
* Bit values for opFlags, which are all reset to zero prior to each instruction
|
||||
*/
|
||||
OPFLAG: {
|
||||
OPFLAG: {
|
||||
NOREAD: 0x0001,
|
||||
NOWRITE: 0x0002,
|
||||
NOINTR: 0x0004, // indicates a segreg has been set, or a prefix, or an STI (delay INTR acknowledgement)
|
||||
|
|
@ -221,9 +221,9 @@ var X86 = {
|
|||
*/
|
||||
OPCODE: {
|
||||
ES: 0x26, // opES()
|
||||
CS: 0x2E, // opCS()
|
||||
SS: 0x36, // opSS()
|
||||
DS: 0x3E, // opDS()
|
||||
CS: 0x2E, // opCS()
|
||||
SS: 0x36, // opSS()
|
||||
DS: 0x3E, // opDS()
|
||||
PUSHSP: 0x54,
|
||||
PUSHA: 0x60,
|
||||
POPA: 0x61,
|
||||
|
|
@ -239,31 +239,31 @@ var X86 = {
|
|||
OUTSW: 0x6F,
|
||||
ENTER: 0xC8,
|
||||
LEAVE: 0xC9,
|
||||
CALLF: 0x9A, // opCALLf()
|
||||
MOVSB: 0xA4, // opMOVSb()
|
||||
MOVSW: 0xA5, // opMOVSw()
|
||||
CMPSB: 0xA6,
|
||||
CMPSW: 0xA7,
|
||||
STOSB: 0xAA,
|
||||
STOSW: 0xAB,
|
||||
LODSB: 0xAC,
|
||||
LODSW: 0xAD,
|
||||
SCASB: 0xAE,
|
||||
SCASW: 0xAF,
|
||||
INT3: 0xCC,
|
||||
INTn: 0xCD,
|
||||
INTO: 0xCE,
|
||||
CALLF: 0x9A, // opCALLf()
|
||||
MOVSB: 0xA4, // opMOVSb()
|
||||
MOVSW: 0xA5, // opMOVSw()
|
||||
CMPSB: 0xA6,
|
||||
CMPSW: 0xA7,
|
||||
STOSB: 0xAA,
|
||||
STOSW: 0xAB,
|
||||
LODSB: 0xAC,
|
||||
LODSW: 0xAD,
|
||||
SCASB: 0xAE,
|
||||
SCASW: 0xAF,
|
||||
INT3: 0xCC,
|
||||
INTn: 0xCD,
|
||||
INTO: 0xCE,
|
||||
LOOPNZ: 0xE0,
|
||||
LOOPZ: 0xE1,
|
||||
LOOP: 0xE2,
|
||||
CALL: 0xE8,
|
||||
CALL: 0xE8,
|
||||
JMP: 0xE9, // JMP opcode (2-byte displacement)
|
||||
JMPS: 0xEB, // JMP opcode (1-byte displacement)
|
||||
LOCK: 0xF0,
|
||||
REPNZ: 0xF2,
|
||||
REPZ: 0xF3,
|
||||
CALLW: 0x10FF,
|
||||
CALLDW: 0x18FF,
|
||||
LOCK: 0xF0,
|
||||
REPNZ: 0xF2,
|
||||
REPZ: 0xF3,
|
||||
CALLW: 0x10FF,
|
||||
CALLDW: 0x18FF,
|
||||
UD2: 0x0B0F // UD2 (invalid opcode guaranteed to generate UD_FAULT on all post-8086 processors)
|
||||
}
|
||||
};
|
||||
|
|
@ -288,9 +288,9 @@ X86.PS.SET = (X86.PS.BIT1 | X86.PS.IOPL | X86.PS.NT | X86.PS.BIT15);
|
|||
/*
|
||||
* getPS() brings all the direct and indirect flags together, and setPS() performs the
|
||||
* reverse, setting all the corresponding "result registers" to match the indirect flags.
|
||||
*
|
||||
*
|
||||
* These "result registers" are created/reset by an initial call to setPS(0); they include:
|
||||
*
|
||||
*
|
||||
* this.resultSize (must be set to one of: SIZE_BYTE or SIZE_WORD)
|
||||
* this.resultValue
|
||||
* this.resultParitySign
|
||||
|
|
|
|||
|
|
@ -122,21 +122,20 @@ function X86CPU(parmsCPU) {
|
|||
* "INT 0x00" generated by a divide-by-zero or any other kind of interrupt (nor any interrupt simulated
|
||||
* with "PUSHF/CALLF").
|
||||
*
|
||||
* aInterruptReturn is a stack of return address notifications set up by software interrupt notification
|
||||
* aInterruptReturn is a hash of return address notifications set up by software interrupt notification
|
||||
* functions that want to receive return notifications. A software interrupt function must call
|
||||
* cpu.addInterruptReturn(fn).
|
||||
*
|
||||
* WARNING: There's no specific mechanism in place to insure that software interrupt return notifications
|
||||
* don't get "orphaned" and stack up if an interrupt handler bypasses the normal return path (INT 0x24 is
|
||||
* one example of an "evil" software interrupt). So use this feature sparingly, avoid "evil" software
|
||||
* interrupts, and/or add a mechanism to detect and clean up orphans.
|
||||
* WARNING: There's no mechanism in place to insure that software interrupt return notifications don't
|
||||
* get "orphaned" if an interrupt handler bypasses the normal return path (INT 0x24 is one example of an
|
||||
* "evil" software interrupt).
|
||||
*/
|
||||
this.aInterruptNotify = [];
|
||||
this.aInterruptReturn = [];
|
||||
|
||||
/*
|
||||
* Since aReturnNotify is a "sparse array", this global count gives the CPU a quick way of knowing whether
|
||||
* or not RETF or IRET instructions need to bother checking the array.
|
||||
* or not RETF or IRET instructions need to bother calling checkInterruptReturn().
|
||||
*/
|
||||
this.cInterruptReturn = 0;
|
||||
|
||||
|
|
@ -931,27 +930,27 @@ X86CPU.prototype.checkInterruptNotify = function(nInt)
|
|||
X86CPU.prototype.addInterruptReturn = function(addr, fn)
|
||||
{
|
||||
if (fn !== undefined) {
|
||||
if (this.aInterruptReturn[addr] === undefined)
|
||||
this.aInterruptReturn[addr] = [];
|
||||
this.aInterruptReturn[addr].push(fn);
|
||||
this.cInterruptReturn++;
|
||||
if (this.aInterruptReturn[addr] == null) {
|
||||
this.cInterruptReturn++;
|
||||
}
|
||||
this.aInterruptReturn[addr] = fn;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* checkInterruptReturn(addr)
|
||||
*
|
||||
* It is expected (though not required) that callers will check cInterruptReturn and avoid calling
|
||||
* this function if the count is zero.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} addr is a physical (non-segmented) address
|
||||
*/
|
||||
X86CPU.prototype.checkInterruptReturn = function(addr)
|
||||
{
|
||||
var aNotify = this.aInterruptReturn[addr];
|
||||
if (aNotify !== undefined) {
|
||||
while (aNotify.length > 0) {
|
||||
var fn = aNotify.pop();
|
||||
fn(--this.cInterruptReturn);
|
||||
}
|
||||
var fn = this.aInterruptReturn[addr];
|
||||
if (fn != null) {
|
||||
fn(--this.cInterruptReturn);
|
||||
delete this.aInterruptReturn[addr];
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2329,8 +2329,8 @@ var X86OpXX = {
|
|||
}
|
||||
if (nReps--) {
|
||||
/*
|
||||
* NOTE: Storing a word imposes another 4-cycle penalty on the 8088, so consider that if you think the
|
||||
* cycle times here are too high.
|
||||
* NOTE: Storing a word imposes another 4-cycle penalty on the 8088, so consider that
|
||||
* if you think the cycle times here are too high.
|
||||
*/
|
||||
this.setSOWord(this.segES, this.regDI, this.regAX);
|
||||
this.regDI = (this.regDI + ((this.regPS & X86.PS.DF)? -2 : 2)) & 0xffff;
|
||||
|
|
|
|||
|
|
@ -118,8 +118,8 @@ X86Seg.loadProt = function loadProt(sel, fSuppress)
|
|||
|
||||
/*
|
||||
* TODO: This is only the first of many steps toward accurately counting cycles in protected mode;
|
||||
* I simply noticed that "POP segreg" takes 5 cycles in real mode and 20 in protected mode, so I'm
|
||||
* starting with a 15-cycle penalty. Obviously the penalty will be much greater when the load fails.
|
||||
* I simply noted that "POP segreg" takes 5 cycles in real mode and 20 in protected mode, so I'm
|
||||
* starting with a 15-cycle difference. Obviously the difference will be much greater when the load fails.
|
||||
*/
|
||||
this.cpu.nStepCycles -= 15;
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ global *Buffer* object, as indicated by:
|
|||
/* global Buffer: false */
|
||||
|
||||
And [weblib.js](weblib.js) is appropriate only for client modules, because it contains code that relies on the
|
||||
brower's global *window* object, as indicated by:
|
||||
browser's global *window* object, as indicated by:
|
||||
|
||||
/* global window: true */
|
||||
|
||||
|
|
@ -25,4 +25,4 @@ when running within Node, allowing any other code to test the existence of *wind
|
|||
|
||||
instead of:
|
||||
|
||||
if (typeof window !== 'undefined') {...}
|
||||
if (typeof window !== "undefined") {...}
|
||||
|
|
|
|||
|
|
@ -114,6 +114,7 @@ function Component(type, parms, constructor)
|
|||
*
|
||||
if (this.initStep) this.initStep(parms);
|
||||
*/
|
||||
|
||||
this.fnReady = null;
|
||||
this.fReady = false;
|
||||
this.fBusy = this.fBusyCancel = false;
|
||||
|
|
@ -244,12 +245,14 @@ Component.add = function(component)
|
|||
Component.log = function(s, type)
|
||||
{
|
||||
if (DEBUG) {
|
||||
var msElapsed, sMsg = (type? (type + ": ") : "") + (s || "");
|
||||
if (Component.msStart === undefined) {
|
||||
Component.msStart = usr.getTime();
|
||||
if (s) {
|
||||
var msElapsed, sMsg = (type? (type + ": ") : "") + s;
|
||||
if (Component.msStart === undefined) {
|
||||
Component.msStart = usr.getTime();
|
||||
}
|
||||
msElapsed = usr.getTime() - Component.msStart;
|
||||
console.log(msElapsed + "ms: " + sMsg.replace(/\n/g, " "));
|
||||
}
|
||||
msElapsed = usr.getTime() - Component.msStart;
|
||||
console.log(sMsg? (msElapsed + "ms: " + sMsg.replace(/\n/g, " ")) : "");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -266,13 +269,10 @@ Component.assert = function(f, s)
|
|||
{
|
||||
if (DEBUG) {
|
||||
if (!f) {
|
||||
if (!s) {
|
||||
/*
|
||||
* TODO: An accompanying source file/line number/function call would be nice, if there was a browser-independent way....
|
||||
*/
|
||||
s = "assertion failure";
|
||||
}
|
||||
Component.log(s);
|
||||
/*
|
||||
* TODO: An accompanying source file/line number/function call would be nice, if there was a browser-independent way....
|
||||
*/
|
||||
Component.log(s || "assertion failure");
|
||||
throw new Error(s);
|
||||
}
|
||||
}
|
||||
|
|
@ -363,7 +363,7 @@ Component.getComponents = function(idRelated)
|
|||
if ((i = idRelated.indexOf('.')) > 0)
|
||||
idRelated = idRelated.substr(0, i + 1);
|
||||
else
|
||||
idRelated = undefined;
|
||||
idRelated = "";
|
||||
}
|
||||
for (i = 0; i < Component.all.length; i++) {
|
||||
var component = Component.all[i];
|
||||
|
|
@ -427,7 +427,7 @@ Component.getComponentByType = function(sType, idRelated, componentPrev)
|
|||
if ((i = idRelated.indexOf('.')) > 0) {
|
||||
idRelated = idRelated.substr(0, i + 1);
|
||||
} else {
|
||||
idRelated = undefined;
|
||||
idRelated = "";
|
||||
}
|
||||
}
|
||||
for (i = 0; i < Component.all.length; i++) {
|
||||
|
|
@ -605,10 +605,7 @@ Component.prototype = {
|
|||
/**
|
||||
* setBinding(sHTMLClass, sHTMLType, sBinding, control)
|
||||
*
|
||||
* Component's setBinding() method is intended to be overridden by subclasses. The only
|
||||
* exception is the Panel component, which passes two special bindings ("clear" and "print")
|
||||
* back to us if no one else accepted them, so that we can redirect all println() requests
|
||||
* to those controls.
|
||||
* Component's setBinding() method is intended to be overridden by subclasses.
|
||||
*
|
||||
* @this {Component}
|
||||
* @param {string|null} sHTMLClass is the class of the HTML control (eg, "input", "output")
|
||||
|
|
@ -619,67 +616,63 @@ Component.prototype = {
|
|||
*/
|
||||
setBinding: function(sHTMLClass, sHTMLType, sBinding, control) {
|
||||
switch (sBinding) {
|
||||
case "clear":
|
||||
if (!this.bindings[sBinding]) {
|
||||
this.bindings[sBinding] = control;
|
||||
control.onclick = (function(component) {
|
||||
return function() {
|
||||
if (component.bindings['print']) {
|
||||
component.bindings['print'].value = "";
|
||||
}
|
||||
};
|
||||
}(this));
|
||||
}
|
||||
return true;
|
||||
case "print":
|
||||
if (!this.bindings[sBinding]) {
|
||||
this.bindings[sBinding] = control;
|
||||
control.value = ""; // this was added for Firefox (Safari automatically clears the <textarea> on a page reload, but Firefox does not)
|
||||
/*
|
||||
* TODO: Get rid of these Component method overrides, because they're going to cause issues
|
||||
* if the day ever comes (and it WILL) that we want multiple machines on a single page with their
|
||||
* own Control Panels.
|
||||
*/
|
||||
Component.println = (function(control) {
|
||||
return function printControl(s, type) {
|
||||
s = (type !== undefined? (type + ": ") : "") + (s || "");
|
||||
if (!DEBUG) { // in non-DEBUG builds, prevent the <textarea> from getting too large, otherwise printing becomes slower and slower
|
||||
if (control.value.length > 8192) {
|
||||
control.value = control.value.substr(control.value.length - 4096);
|
||||
}
|
||||
}
|
||||
control.value += s + "\n";
|
||||
control.scrollTop = control.scrollHeight;
|
||||
if (DEBUG) console.log(s);
|
||||
};
|
||||
}(control));
|
||||
/*
|
||||
* Override Component.notice() with a replacement function that eliminates the web.alertUser() call
|
||||
*/
|
||||
Component.notice = function(s, fPrintOnly, id) {
|
||||
Component.println(s, "notice", id);
|
||||
case "clear":
|
||||
if (!this.bindings[sBinding]) {
|
||||
this.bindings[sBinding] = control;
|
||||
control.onclick = (function(component) {
|
||||
return function clearPanel() {
|
||||
if (component.bindings['print']) {
|
||||
component.bindings['print'].value = "";
|
||||
}
|
||||
};
|
||||
/*
|
||||
* HACK: Save this particular HTML element so that the Debugger can access it, too
|
||||
*/
|
||||
Component.controlPrint = control;
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
}(this));
|
||||
}
|
||||
return true;
|
||||
case "print":
|
||||
if (!this.bindings[sBinding]) {
|
||||
this.bindings[sBinding] = control;
|
||||
/*
|
||||
* Now that we're giving the Panel component multiple shots at binding its controls,
|
||||
* to relax initialization dependencies, we need to chill when unrecognized requests come in.
|
||||
*
|
||||
if (sHTMLClass == "input") {
|
||||
control.onclick = function() {
|
||||
Component.println("unsupported " + sHTMLType + ": " + sBinding);
|
||||
};
|
||||
}
|
||||
this.log("setBinding(\"" + sHTMLClass + "\",\"" + sHTMLType + "\",\"" + sBinding + "\"): unrecognized binding");
|
||||
* HACK: Save this particular HTML element so that the Debugger can access it, too
|
||||
*/
|
||||
break;
|
||||
this.controlPrint = control;
|
||||
/*
|
||||
* This was added for Firefox (Safari automatically clears the <textarea> on a page reload,
|
||||
* but Firefox does not).
|
||||
*/
|
||||
control.value = "";
|
||||
this.println = (function(control) {
|
||||
return function printPanel(s, type) {
|
||||
s = (type !== undefined? (type + ": ") : "") + (s || "");
|
||||
/*
|
||||
* In non-DEBUG builds, prevent the <textarea> from getting too large;
|
||||
* otherwise, printing becomes slower and slower.
|
||||
*/
|
||||
if (!DEBUG) {
|
||||
if (control.value.length > 8192) {
|
||||
control.value = control.value.substr(control.value.length - 4096);
|
||||
}
|
||||
}
|
||||
control.value += s + "\n";
|
||||
control.scrollTop = control.scrollHeight;
|
||||
if (DEBUG) console.log(s);
|
||||
};
|
||||
}(control));
|
||||
/**
|
||||
* Override this.notice() with a replacement function that eliminates the web.alertUser() call
|
||||
*
|
||||
* @this {Component}
|
||||
* @param {string} s
|
||||
* @param {boolean} [fPrintOnly]
|
||||
* @param {string} [id]
|
||||
*/
|
||||
this.notice = function noticePanel(s, fPrintOnly, id) {
|
||||
this.println(s, "notice", id);
|
||||
};
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
/**
|
||||
* log(s, type)
|
||||
|
|
@ -695,7 +688,9 @@ Component.prototype = {
|
|||
* @param {string} [type] is the message type
|
||||
*/
|
||||
log: function(s, type) {
|
||||
if (DEBUG) Component.log(s, type || this.id || this.type);
|
||||
if (DEBUG) {
|
||||
Component.log(s, type || this.id || this.type);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* println(s, type)
|
||||
|
|
@ -724,9 +719,9 @@ Component.prototype = {
|
|||
/**
|
||||
* notice(s, fPrintOnly)
|
||||
*
|
||||
* notice() is like println() but implies a need for user notification, which means calling log() isn't good enough, so we alert() as well;
|
||||
* however, if Component.println() is overridden, Component.notice will be replaced with the same override, on the assumption that the override
|
||||
* is taking care of user notification.
|
||||
* notice() is like println() but implies a need for user notification, which means calling log() isn't good enough,
|
||||
* so we alert() as well; however, if Component.println() is overridden, Component.notice will be replaced with the
|
||||
* same override, on the assumption that the override is taking care of alerting the user.
|
||||
*
|
||||
* @this {Component}
|
||||
* @param {string} s is the message text
|
||||
|
|
@ -736,24 +731,6 @@ Component.prototype = {
|
|||
notice: function(s, fPrintOnly, id) {
|
||||
Component.notice(s, fPrintOnly, id || this.id);
|
||||
},
|
||||
/**
|
||||
* warning(s)
|
||||
*
|
||||
* @this {Component}
|
||||
* @param {string} s describes the warning
|
||||
*/
|
||||
warning: function(s) {
|
||||
Component.warning(s);
|
||||
},
|
||||
/**
|
||||
* error(s)
|
||||
*
|
||||
* @this {Component}
|
||||
* @param {string} s describes the error; an alert() is displayed as well
|
||||
*/
|
||||
error: function(s) {
|
||||
Component.error(s);
|
||||
},
|
||||
/**
|
||||
* setError(s)
|
||||
*
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ usr.binarySearch = function(a, v, fnCompare) {
|
|||
|
||||
/**
|
||||
* binaryInsert(a, v, fnCompare)
|
||||
*
|
||||
*
|
||||
* If element v already exists in array a, the array is unchanged (we don't allow duplicates); otherwise, the
|
||||
* element is inserted into the array at the appropriate index.
|
||||
*
|
||||
|
|
@ -151,7 +151,7 @@ usr.aMonthDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|||
* i: minutes, with leading zeros (00,...,59)
|
||||
* j: day of the month, without leading zeros (1,...,31)
|
||||
* l: day of the week ("Sunday",...,"Saturday")
|
||||
* m: month, with leading zeros (01,...,12)
|
||||
* m: month, with leading zeros (01,...,12)
|
||||
* s: seconds, with leading zeros (00,...,59)
|
||||
* F: month ("January",...,"December")
|
||||
* H: hour in 24-hour format, with leading zeros (00,...,23)
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@
|
|||
* decodeURI() Decodes a URI
|
||||
* decodeURIComponent() Decodes a URI component
|
||||
* encodeURI() Encodes a URI
|
||||
* encodeURIComponent() Encodes a URI component
|
||||
* encodeURIComponent() Encodes a URI component
|
||||
* escape() Deprecated in version 1.5. Use encodeURI() or encodeURIComponent() instead
|
||||
* eval() Evaluates a string and executes it as if it was script code
|
||||
* isFinite() Determines whether a value is a finite, legal number
|
||||
|
|
@ -55,7 +55,7 @@
|
|||
* parseInt() Parses a string and returns an integer
|
||||
* String() Converts an object's value to a string
|
||||
* unescape() Deprecated in version 1.5. Use decodeURI() or decodeURIComponent() instead
|
||||
*
|
||||
*
|
||||
* And according to http://www.w3schools.com/jsref/obj_window.asp, these are the properties and functions
|
||||
* of the *window* object.
|
||||
*
|
||||
|
|
@ -86,7 +86,7 @@
|
|||
* self Returns the current window
|
||||
* status Sets or returns the text in the statusbar of a window
|
||||
* top Returns the topmost browser window
|
||||
*
|
||||
*
|
||||
* Method Description
|
||||
* ---
|
||||
* alert() Displays an alert box with a message and an OK button
|
||||
|
|
@ -122,7 +122,7 @@
|
|||
* We must defer loading the Component module until the function(s) requiring it are
|
||||
* called; otherwise, we create an initialization cycle in which Component requires weblib
|
||||
* and weblib requires Component.
|
||||
*
|
||||
*
|
||||
* In an ideal world, weblib would not be dependent on Component, but we really want to use
|
||||
* its logging functions.
|
||||
*/
|
||||
|
|
@ -155,16 +155,16 @@ var web = {};
|
|||
*/
|
||||
web.loadResource = function(sURL, fAsync, data, componentNotify, fnNotify, pNotify)
|
||||
{
|
||||
fAsync = !!fAsync; // ensure that fAsync is a valid boolean (Internet Explorer xmlHTTP functions insist on it)
|
||||
fAsync = !!fAsync; // ensure that fAsync is a valid boolean (Internet Explorer xmlHTTP functions insist on it)
|
||||
if (typeof module !== 'undefined') {
|
||||
/*
|
||||
* We don't even need to load Component, because we can't use any of the code below
|
||||
* within Node anyway. Instead, we must hand this request off to our network library.
|
||||
*
|
||||
*
|
||||
* if (!Component) Component = require("./component");
|
||||
*/
|
||||
var net = require("./netlib");
|
||||
return net.loadResource(sURL, fAsync, data, componentNotify, fnNotify, pNotify);
|
||||
return net.loadResource(sURL, fAsync, data, componentNotify, fnNotify, pNotify);
|
||||
}
|
||||
var nErrorCode = 0;
|
||||
var sURLData = null;
|
||||
|
|
@ -312,7 +312,7 @@ web.confirmUser = function(sPrompt)
|
|||
|
||||
/**
|
||||
* promptUser()
|
||||
*
|
||||
*
|
||||
* @param {string} sPrompt
|
||||
* @param {string} [sDefault]
|
||||
* @returns {string|null}
|
||||
|
|
@ -330,7 +330,7 @@ web.promptUser = function(sPrompt, sDefault)
|
|||
* getLocalStorageItem(sKey)
|
||||
*
|
||||
* Returns the requested key value, or null if the key does not exist, or undefined if localStorage is not available
|
||||
*
|
||||
*
|
||||
* @param {string} sKey
|
||||
* @return {string|null|undefined} sValue
|
||||
*/
|
||||
|
|
@ -345,7 +345,7 @@ web.getLocalStorageItem = function(sKey)
|
|||
|
||||
/**
|
||||
* setLocalStorageItem(sKey, sValue)
|
||||
*
|
||||
*
|
||||
* @param {string} sKey
|
||||
* @param {string} sValue
|
||||
* return {boolean} true if localStorage is available, false if not
|
||||
|
|
@ -427,13 +427,13 @@ web.getURLParameters = function(sParms)
|
|||
* Note that window.location.href returns the entire URL, whereas window.location.search
|
||||
* returns only the parameters, if any (starting with the '?', which we skip over with a substr() call).
|
||||
*/
|
||||
sParms = window.location.search.substr(1);
|
||||
sParms = window.location.search.substr(1);
|
||||
}
|
||||
var match;
|
||||
var pl = /\+/g; // RegExp for replacing addition symbol with a space
|
||||
var search = /([^&=]+)=?([^&]*)/g;
|
||||
var decode = function(s) { return decodeURIComponent(s.replace(pl, " ")); };
|
||||
|
||||
|
||||
while ((match = search.exec(sParms))) {
|
||||
aParms[decode(match[1])] = decode(match[2]);
|
||||
}
|
||||
|
|
@ -482,7 +482,7 @@ web.onCountRepeat = function(n, fn, fnComplete, msDelay)
|
|||
web.onClickRepeat = function(e, msDelay, msRepeat, fn)
|
||||
{
|
||||
var ms = 0, timer = null, fIgnoreMouseEvents = false;
|
||||
|
||||
|
||||
var fnRepeat = function doClickRepeat() {
|
||||
if (fn(ms === msRepeat)) {
|
||||
timer = setTimeout(fnRepeat, ms);
|
||||
|
|
@ -628,7 +628,7 @@ web.enablePageEvents = function(fEnable)
|
|||
|
||||
/**
|
||||
* sendPageEvent(sEvent)
|
||||
*
|
||||
*
|
||||
* This allows us to manually trigger page events.
|
||||
*
|
||||
* @param {string} sEvent (one of 'init', 'show' or 'exit')
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue