From 1ca377fb68392f9663b1629b68be605a98400be4 Mon Sep 17 00:00:00 2001 From: Jeff Parsons Date: Tue, 19 Jan 2016 11:49:30 -0800 Subject: [PATCH] Updated MarkOut and HTMLOut components to use embedPC() with the new 'parms' parameter instead of the old 'state' parameter. This allows us to continue using the Node web server to debug machines that are launched using new YAML-based Markdown machines settings, the most important being 'automount' (otherwise those machines might not be loaded with the correct disks) --- _includes/machine-engines.html | 2 +- disks/pc/os2/misc/1.0/debugger/README.md | 6 +- disks/pc/os2/misc/football/debugger/README.md | 6 +- docs/pcjs/demos/pc-dbg.js | 2 +- docs/pcjs/demos/pc.js | 2 +- modules/htmlout/lib/htmlout.js | 5 +- modules/markout/lib/markout.js | 101 +++++++++++++----- modules/shared/lib/embed.js | 13 ++- versions/pcjs/1.20.4/pc-dbg.js | 2 +- 9 files changed, 97 insertions(+), 42 deletions(-) diff --git a/_includes/machine-engines.html b/_includes/machine-engines.html index c55626f5b..a299df49c 100644 --- a/_includes/machine-engines.html +++ b/_includes/machine-engines.html @@ -34,5 +34,5 @@ {% capture machine_template %}{{ site.baseurl }}/modules/{{ machine.type | remove:'-dbg' }}js/templates/components.xsl{% endcapture %} {% endif %} {% endif %} - + {% endfor %} diff --git a/disks/pc/os2/misc/1.0/debugger/README.md b/disks/pc/os2/misc/1.0/debugger/README.md index 815f02d8b..9d4bb0e13 100644 --- a/disks/pc/os2/misc/1.0/debugger/README.md +++ b/disks/pc/os2/misc/1.0/debugger/README.md @@ -7,9 +7,9 @@ machines: type: pc-dbg config: /devices/pc/machine/5170/ega/1152kb/rev3/machine.xml automount: - A: - name: OS/2 1.0 Debugger Boot Disk - path: /disks/pc/os2/misc/1.0/debugger/OS210-BOOT.json + A: + name: OS/2 1.0 Debugger Boot Disk + path: /disks/pc/os2/misc/1.0/debugger/OS210-BOOT.json --- OS/2 1.0 Debugger Boot Disk diff --git a/disks/pc/os2/misc/football/debugger/README.md b/disks/pc/os2/misc/football/debugger/README.md index ac90ebd66..8d8eb20de 100644 --- a/disks/pc/os2/misc/football/debugger/README.md +++ b/disks/pc/os2/misc/football/debugger/README.md @@ -7,9 +7,9 @@ machines: type: pc-dbg config: /devices/pc/machine/compaq/deskpro386/ega/2048kb/machine.xml automount: - A: - name: OS/2 FOOTBALL Boot Disk (v7.68.17) - path: /disks/pc/os2/misc/football/debugger/FOOTBALL-7.68.17.json + A: + name: OS/2 FOOTBALL Boot Disk (v7.68.17) + path: /disks/pc/os2/misc/football/debugger/FOOTBALL-7.68.17.json --- OS/2 FOOTBALL Boot Disk (v7.68.17) diff --git a/docs/pcjs/demos/pc-dbg.js b/docs/pcjs/demos/pc-dbg.js index 7282a30f3..a5bc3284b 100644 --- a/docs/pcjs/demos/pc-dbg.js +++ b/docs/pcjs/demos/pc-dbg.js @@ -1210,7 +1210,7 @@ function kr(a,b){a.A=null;var c=za(Aa()+"/api/v1/user?req=verify&user="+b),d=c[1 function jr(a,b,c){if(c){var d={req:"store"};d.user=b;d.state=Xq(a,er);d.data=c;b=za(Aa()+"/api/v1/user",!1,d);d=b[1];if(b[0]){if(d){var e=d.indexOf("\n");0k.indexOf("/")&&(k=window.location.pathname+k);d?"{"==d.substr(0,1)?(d=d.slice(0,-1),1]*\sid=)(['"]).*?\2/,"$1$2"+c+"$2"+(d?" parms='"+d+"'":"")+(k?' url="'+k+'"':""))}k=null;if("<"==a.charAt(0))try{e||(a=a.replace(/\s*/g,"")),window.ActiveXObject||"ActiveXObject"in window?(k=new window.ActiveXObject("Microsoft.XMLDOM"), +function nr(a,b,c,d,e,f,g){function k(a,f){if(f)g(f,null);else{if(c){var k=b;k&&0>k.indexOf("/")&&(k=window.location.pathname+k);d?"}"==d.slice(-1)?(d=d.slice(0,-1),1]*\sid=)(['"]).*?\2/,"$1$2"+c+"$2"+(d?" parms='"+d+"'":"")+(k?' url="'+k+'"':""))}k=null;if("<"==a.charAt(0))try{e||(a=a.replace(/\s*/g,"")),window.ActiveXObject||"ActiveXObject"in window?(k=new window.ActiveXObject("Microsoft.XMLDOM"), k.async=!1,k.loadXML(a)):k=(new window.DOMParser).parseFromString(a,"text/xml")}catch(B){k=null,a=B.message}else a="unrecognized XML: "+(255/g.exec(a)){var e=d[2];b("Loading "+e+"...");za(e,!0,null,null,function(f,g,k){if(k||!g)c(a,"unable to resolve XML reference: "+d[0]+" ("+k+")");else{if(f=d[3])if(k=g.match(new RegExp("<"+d[1]+"[^>]*>"))){for(var q=k[0],r,x=/( [a-z]+=)(['"])(.*?)\2/g;r=x.exec(f);)q=0>q.indexOf(r[1])?q.replace(">",r[0]+">"):q.replace(new RegExp(r[1]+"(['\"])(.*?)\\1"),r[0]);k[0]!=q&&(g=g.replace(k[0],q))}else{c(a,"missing <"+d[1]+"> in "+e);return}g=g.replace(/<\?xml[^>]*>[\r\n]*/, "");a=a.replace(d[0],g);yr(a,b,c)}})}else c(a,null)} diff --git a/docs/pcjs/demos/pc.js b/docs/pcjs/demos/pc.js index 4611562bc..eab14bf5b 100644 --- a/docs/pcjs/demos/pc.js +++ b/docs/pcjs/demos/pc.js @@ -1033,7 +1033,7 @@ function Om(a,b){a.B=null;var c=pa(qa()+"/api/v1/user?req=verify&user="+b),d=c[1 function Nm(a,b,c){if(c){var d={req:"store"};d.user=b;d.state=zm(a,Hm);d.data=c;b=pa(qa()+"/api/v1/user",!1,d);d=b[1];if(b[0]){if(d){var e=d.indexOf("\n");0p.indexOf("/")&&(p=window.location.pathname+p);d?"{"==d.substr(0,1)?(d=d.slice(0,-1),1]*\sid=)(['"]).*?\2/,"$1$2"+c+"$2"+(d?" parms='"+d+"'":"")+(p?' url="'+p+'"':""))}p=null;if("<"==a.charAt(0))try{e||(a=a.replace(/\s*/g,"")),window.ActiveXObject||"ActiveXObject"in window?(p=new window.ActiveXObject("Microsoft.XMLDOM"), +function Rm(a,b,c,d,e,k,l){function p(a,k){if(k)l(k,null);else{if(c){var p=b;p&&0>p.indexOf("/")&&(p=window.location.pathname+p);d?"}"==d.slice(-1)?(d=d.slice(0,-1),1]*\sid=)(['"]).*?\2/,"$1$2"+c+"$2"+(d?" parms='"+d+"'":"")+(p?' url="'+p+'"':""))}p=null;if("<"==a.charAt(0))try{e||(a=a.replace(/\s*/g,"")),window.ActiveXObject||"ActiveXObject"in window?(p=new window.ActiveXObject("Microsoft.XMLDOM"), p.async=!1,p.loadXML(a)):p=(new window.DOMParser).parseFromString(a,"text/xml")}catch(G){p=null,a=G.message}else a="unrecognized XML: "+(255/g.exec(a)){var e=d[2];b("Loading "+e+"...");pa(e,!0,null,null,function(k,l,p){if(p||!l)c(a,"unable to resolve XML reference: "+d[0]+" ("+p+")");else{if(k=d[3])if(p=l.match(new RegExp("<"+d[1]+"[^>]*>"))){for(var q=p[0],w,B=/( [a-z]+=)(['"])(.*?)\2/g;w=B.exec(k);)q=0>q.indexOf(w[1])?q.replace(">",w[0]+">"):q.replace(new RegExp(w[1]+"(['\"])(.*?)\\1"),w[0]);p[0]!=q&&(l=l.replace(p[0],q))}else{c(a,"missing <"+d[1]+"> in "+e);return}l=l.replace(/<\?xml[^>]*>[\r\n]*/, "");a=a.replace(d[0],l);Sm(a,b,c)}})}else c(a,null)} diff --git a/modules/htmlout/lib/htmlout.js b/modules/htmlout/lib/htmlout.js index 18a8aea4d..c2c5cfbc6 100644 --- a/modules/htmlout/lib/htmlout.js +++ b/modules/htmlout/lib/htmlout.js @@ -1850,7 +1850,10 @@ HTMLOut.prototype.processMachines = function(aMachines, done) var sScriptEmbed = ""; if (infoMachine['func']) { - sScriptEmbed = ''; + sScriptEmbed = ''; } var asFiles = []; diff --git a/modules/markout/lib/markout.js b/modules/markout/lib/markout.js index 446a9685e..bb8a851b7 100644 --- a/modules/markout/lib/markout.js +++ b/modules/markout/lib/markout.js @@ -231,14 +231,14 @@ MarkOut.setOptions = function(options) * The infoMachine object should contain, at a minimum: * * { - * 'class': sMachineClass, // eg, "pc" - * 'func': sMachineFunc, - * 'id': sMachineID, - * 'xml': sMachineXMLFile, - * 'xsl': sMachineXSLFile, - * 'version': sMachineVersion, // eg, "1.13.0" + * 'class': sMachineClass, // eg, "pc" + * 'func': sMachineFunc, + * 'id': sMachineID, + * 'xml': sMachineXMLFile, + * 'xsl': sMachineXSLFile, + * 'version': sMachineVersion,// eg, "1.13.0" * 'debugger': fDebugger, // eg, false - * 'state': sMachineState + * 'parms': sMachineParms * } * * This is an internal function, used by convertMDMachineLinks() to record all the machines defined @@ -375,16 +375,54 @@ MarkOut.prototype.convertMD = function(sIndent) for (var iMachine = 0; iMachine < asMachines.length; iMachine++) { if (!asMachines[iMachine]) continue; var id = null; - var aOptions, machine = {}; - var reOption = /([^\s]+):\s*([^\n]*)/g; + var aOptions, aaOptions = [], machine = {}; + var reOption = /([ \t]*)([^\s]+):[ \t]*([^\n]*)/g; while (aOptions = reOption.exec(asMachines[iMachine])) { - if (!id && aOptions[1] == "id") { - id = aOptions[2]; - } - else { - machine[aOptions[1]] = aOptions[2]; - } + aaOptions.push(aOptions); } + for (var iOption = 0; iOption < aaOptions.length; iOption++) { + var aOptions = aaOptions[iOption]; + var sSpace = aOptions[1], sName = aOptions[2], sValue = aOptions[3]; + if (!id && sName == 'id') { + id = sValue; + } else if (sName == 'automount') { + /* + * I take a simplistic approach to parsing the object definition associated with "automount", + * because I know it only consist of 1 or more drive letters, each of which may be followed by + * 1 or 2 additional properties (eg, "name" and "path"). If we need to support other JSON + * object definitions in the future, this will have to be generalized. + * + * Here's an example of "automount" output: + * + * {"A":{"name":"OS/2 FOOTBALL Boot Disk (v7.68.17)","path":"/disks/pc/os2/misc/football/debugger/FOOTBALL-7.68.17.json"}} + */ + sValue = '{'; + var cDrives = 0, cProps = 0, iProp; + for (iProp = iOption + 1; iProp < aaOptions.length; iProp++) { + var sPropSpace = aaOptions[iProp][1]; + if (sPropSpace.length <= sSpace.length) break; + var sPropName = aaOptions[iProp][2]; + var sPropValue = aaOptions[iProp][3]; + if (!sPropValue) { + if (cProps) sValue += '}'; + if (cDrives++) sValue += ','; + sValue += '"' + sPropName + '":{'; + cProps = 0; + } else { + if (cProps++) sValue += ','; + sValue += '"' + sPropName + '":"' + sPropValue + '"'; + } + } + if (cProps++) sValue += '}'; + sValue += '}'; + iOption = iProp - 1; + } + machine[sName] = sValue; + } + /* + * Any 'state' and 'automount' properties must now be merged into a 'parms' property. + */ + machine['parms'] = '{state:"' + (machine['state'] || "") + '",autoMount:' + machine['automount'] + '}'; if (id) this.aMachineDefs[id] = machine; } } @@ -952,7 +990,7 @@ MarkOut.prototype.convertMDImageLinks = function(sBlock, sIndent) * Before we call convertMDLinks() to process any normal Markdown-style links, we first look for our own * special flavor of "machine" Markdown links; ie: * - * [IBM PC](/devices/pc/machine/5150/mda/64kb/ "PCjs:demoPC:stylesheet:version:options:state") + * [IBM PC](/devices/pc/machine/5150/mda/64kb/ "PCjs:demoPC:stylesheet:version:options:parms") * * where a special title attribute triggers generation of an embedded machine rather than a link. * @@ -965,6 +1003,11 @@ MarkOut.prototype.convertMDImageLinks = function(sBlock, sIndent) * * If the link ends with a slash, then it's an implied reference to a "machine.xml". * + * UPDATE: Since parms containing JSON may also contain colons, machine Markdown links may now use '|' + * instead of ':' as separators; eg: + * + * [IBM PC](/devices/pc/machine/5150/mda/64kb/ "PCjs|demoPC|stylesheet|version|options|parms") + * * Granted, there are a number of things we could be smarter about. First, you probably don't care about the * ID for the
; it's purely a mechanism for telling the script where to embed the machine, so we could * auto-generate an ID for you, but on the other hand, there might actually be situations where you want to style @@ -989,7 +1032,7 @@ MarkOut.prototype.convertMDImageLinks = function(sBlock, sIndent) MarkOut.prototype.convertMDMachineLinks = function(sBlock) { var aMatch, sReplacement; - var sMachine, sMachineID, sMachineXMLFile, sMachineXSLFile, sMachineVersion, sMachineOptions, sMachineState; + var sMachine, sMachineID, sMachineXMLFile, sMachineXSLFile, sMachineVersion, sMachineOptions, sMachineParms; /* * Before we start looking for Markdown-style machine links, see if there are any Liquid-style machines, @@ -1008,8 +1051,8 @@ MarkOut.prototype.convertMDMachineLinks = function(sBlock) sMachineXMLFile = machine['config'] || "machine.xml"; sMachineXSLFile = machine['template'] || ""; sMachineVersion = (machine['uncompiled'] && machine['uncompiled'] == "true"? "uncompiled" : ""); - sMachineState = machine['state'] || ""; - sReplacement = "[Embedded PC](" + sMachineXMLFile + ' "' + sMachine + 'js:' + sMachineID + ':' + sMachineXSLFile + '::' + sMachineOptions + ':' + sMachineState + '")'; + sMachineParms = machine['parms'] || ""; + sReplacement = "[Embedded PC](" + sMachineXMLFile + ' "' + sMachine + 'js|' + sMachineID + '|' + sMachineXSLFile + '||' + sMachineOptions + '|' + sMachineParms + '")'; } sBlock = sBlock.replace(aMatch[0], sReplacement); reIncludes.lastIndex = 0; // reset lastIndex, since we just modified the string that reIncludes is iterating over @@ -1019,7 +1062,7 @@ MarkOut.prototype.convertMDMachineLinks = function(sBlock) * Start looking for Markdown-style machine links now... */ var cMatches = 0; - var reMachines = /\[(.*?)]\((.*?)\s*"(PC|C1P)js:(.*?)"\)/gi; + var reMachines = /\[(.*?)]\((.*?)\s*"(PC|C1P)js[:|](.*?)"\)/gi; while ((aMatch = reMachines.exec(sBlock))) { @@ -1029,14 +1072,14 @@ MarkOut.prototype.convertMDMachineLinks = function(sBlock) sMachine = aMatch[3].toUpperCase(); var sMachineFunc = "embed" + sMachine; var sMachineClass = sMachine.toLowerCase(); - var aMachineParms = aMatch[4].split(':'); + var aMachineParms = aMatch[4].split(aMatch[4].indexOf('|') > 0? '|' : ':'); var sMachineMessage = "Waiting for " + sMachine + "js to load"; sMachineID = aMachineParms[0]; sMachineXSLFile = aMachineParms[1] || ""; sMachineVersion = aMachineParms[2] || this.sMachineVersion; sMachineOptions = aMachineParms[3] || ""; - sMachineState = aMachineParms[4] || ""; + sMachineParms = aMachineParms[4] || ""; var aMachineOptions = sMachineOptions.split(','); var fDebugger = (aMachineOptions.indexOf("debugger") >= 0); @@ -1071,14 +1114,14 @@ MarkOut.prototype.convertMDMachineLinks = function(sBlock) cMatches++; this.addMachine({ - 'class': sMachineClass, // eg, a machine class, such as "pc" or "c1p" - 'func': sMachineFunc, - 'id': sMachineID, - 'xml': sMachineXMLFile, - 'xsl': sMachineXSLFile, - 'version': sMachineVersion, // eg, "1.10", "*" to select the current version, or "uncompiled"; "*" is the default + 'class': sMachineClass, // eg, a machine class, such as "pc" or "c1p" + 'func': sMachineFunc, + 'id': sMachineID, + 'xml': sMachineXMLFile, + 'xsl': sMachineXSLFile, + 'version': sMachineVersion,// eg, "1.10", "*" to select the current version, or "uncompiled"; "*" is the default 'debugger': fDebugger, // eg, true or false; false is the default - 'state': sMachineState} + 'parms': sMachineParms} ); } diff --git a/modules/shared/lib/embed.js b/modules/shared/lib/embed.js index df2694487..0a4b6c866 100644 --- a/modules/shared/lib/embed.js +++ b/modules/shared/lib/embed.js @@ -131,13 +131,22 @@ function parseXML(sXML, sXMLFile, idMachine, sParms, fResolve, display, done) */ if (!sParms) { sParms = '{'; - } else if (sParms.substr(0, 1) == '{') { + } else if (sParms.slice(-1) == '}') { sParms = sParms.slice(0, -1); if (sParms.length > 1) sParms += ','; - } else { // backward compatibility: sParms is actually sStateFile + } else { // sParms must just be a "state" file, so encode it as a "state" property sParms = '{state:"' + sParms + '",'; } sParms += 'url:"' + sURL + '"}'; + /* + * Note that while we no longer generate a machine XML file with a "state" attribute (because it's + * encoded inside the "parms" attribute), the XSL file must still cope with "state" attributes inside + * other XML files; for example, manifest XML files like /apps/pc/1981/visicalc/manifest.xml contain + * machine elements with "state" attributes that must still be passed down to the computer element + * "the old fashioned way". + * + * Until/unless that changes, components.xsl cannot be simplified as much as I might have hoped. + */ sXML = sXML.replace(/(]*\sid=)(['"]).*?\2/, "$1$2" + idMachine + "$2" + (sParms? " parms='" + sParms + "'" : "") + (sURL? ' url="' + sURL + '"' : '')); } /* diff --git a/versions/pcjs/1.20.4/pc-dbg.js b/versions/pcjs/1.20.4/pc-dbg.js index 7282a30f3..a5bc3284b 100644 --- a/versions/pcjs/1.20.4/pc-dbg.js +++ b/versions/pcjs/1.20.4/pc-dbg.js @@ -1210,7 +1210,7 @@ function kr(a,b){a.A=null;var c=za(Aa()+"/api/v1/user?req=verify&user="+b),d=c[1 function jr(a,b,c){if(c){var d={req:"store"};d.user=b;d.state=Xq(a,er);d.data=c;b=za(Aa()+"/api/v1/user",!1,d);d=b[1];if(b[0]){if(d){var e=d.indexOf("\n");0k.indexOf("/")&&(k=window.location.pathname+k);d?"{"==d.substr(0,1)?(d=d.slice(0,-1),1]*\sid=)(['"]).*?\2/,"$1$2"+c+"$2"+(d?" parms='"+d+"'":"")+(k?' url="'+k+'"':""))}k=null;if("<"==a.charAt(0))try{e||(a=a.replace(/\s*/g,"")),window.ActiveXObject||"ActiveXObject"in window?(k=new window.ActiveXObject("Microsoft.XMLDOM"), +function nr(a,b,c,d,e,f,g){function k(a,f){if(f)g(f,null);else{if(c){var k=b;k&&0>k.indexOf("/")&&(k=window.location.pathname+k);d?"}"==d.slice(-1)?(d=d.slice(0,-1),1]*\sid=)(['"]).*?\2/,"$1$2"+c+"$2"+(d?" parms='"+d+"'":"")+(k?' url="'+k+'"':""))}k=null;if("<"==a.charAt(0))try{e||(a=a.replace(/\s*/g,"")),window.ActiveXObject||"ActiveXObject"in window?(k=new window.ActiveXObject("Microsoft.XMLDOM"), k.async=!1,k.loadXML(a)):k=(new window.DOMParser).parseFromString(a,"text/xml")}catch(B){k=null,a=B.message}else a="unrecognized XML: "+(255/g.exec(a)){var e=d[2];b("Loading "+e+"...");za(e,!0,null,null,function(f,g,k){if(k||!g)c(a,"unable to resolve XML reference: "+d[0]+" ("+k+")");else{if(f=d[3])if(k=g.match(new RegExp("<"+d[1]+"[^>]*>"))){for(var q=k[0],r,x=/( [a-z]+=)(['"])(.*?)\2/g;r=x.exec(f);)q=0>q.indexOf(r[1])?q.replace(">",r[0]+">"):q.replace(new RegExp(r[1]+"(['\"])(.*?)\\1"),r[0]);k[0]!=q&&(g=g.replace(k[0],q))}else{c(a,"missing <"+d[1]+"> in "+e);return}g=g.replace(/<\?xml[^>]*>[\r\n]*/, "");a=a.replace(d[0],g);yr(a,b,c)}})}else c(a,null)}