2007年12月31日 星期一

Javascript的IE和Firefox兼容性

以下以 IE 代替 Internet Explorer,以 MF 代替 Mozzila Firefox

1. document.form.item 问题
(1)现有问题:
现有代码中存在许多 document.formName.item("itemName") 这样的语句,不能在 MF 下运行
(2)解决方法:
改用 document.formName.elements["elementName"]
(3)其它
参见 2

2. 集合类对象问题
(1)现有问题:
现有代码中许多集合类对象取用时使用 (),IE 能接受,MF 不能。
(2)解决方法:
改用 [] 作为下标运算。如:document.forms("formName") 改为 document.forms["formName"]。
又如:document.getElementsByName("inputName")(1) 改为 document.getElementsByName("inputName")[1]
(3)其它

3. window.event
(1)现有问题:
使用 window.event 无法在 MF 上运行
(2)解决方法:
MF 的 event 只能在事件发生的现场使用,此问题暂无法解决。可以这样变通:
原代码(可在IE中运行):
<input type="button" name="someButton" value="提交" onclick="javascript:gotoSubmit()"/>
...
<script language="javascript">
function gotoSubmit() {
...
alert(window.event); // use window.event
...
}
</script>

新代码(可在IE和MF中运行):
<input type="button" name="someButton" value="提交" onclick="javascript:gotoSubmit(event)"/>
...
<script language="javascript">
function gotoSubmit(evt) {
evt = evt ? evt : (window.event ? window.event : null);
...
alert(evt); // use evt
...
}
</script>
此外,如果新代码中第一行不改,与老代码一样的话(即 gotoSubmit 调用没有给参数),则仍然只能在IE中运行,但不会出错。所以,这种方案 tpl 部分仍与老代码兼容。

4. HTML 对象的 id 作为对象名的问题
(1)现有问题
在 IE 中,HTML 对象的 ID 可以作为 document 的下属对象变量名直接使用。在 MF 中不能。
(2)解决方法
用 getElementById("idName") 代替 idName 作为对象变量使用。

5. 用idName字符串取得对象的问题
(1)现有问题
在IE中,利用 eval(idName) 可以取得 id 为 idName 的 HTML 对象,在MF 中不能。
(2)解决方法
用 getElementById(idName) 代替 eval(idName)。

6. 变量名与某 HTML 对象 id 相同的问题
(1)现有问题
在 MF 中,因为对象 id 不作为 HTML 对象的名称,所以可以使用与 HTML 对象 id 相同的变量名,IE 中不能。
(2)解决方法
在声明变量时,一律加上 var ,以避免歧义,这样在 IE 中亦可正常运行。
此外,最好不要取与 HTML 对象 id 相同的变量名,以减少错误。
(3)其它
参见 问题4

7. event.x 与 event.y 问题
(1)现有问题
在IE 中,event 对象有 x, y 属性,MF中没有。
(2)解决方法
在MF中,与event.x 等效的是 event.pageX。但event.pageX IE中没有。
故采用 event.clientX 代替 event.x。在IE 中也有这个变量。
event.clientX 与 event.pageX 有微妙的差别(当整个页面有滚动条的时候),不过大多数时候是等效的。

如果要完全一样,可以稍麻烦些:
mX = event.x ? event.x : event.pageX;
然后用 mX 代替 event.x
(3)其它
event.layerX 在 IE 与 MF 中都有,具体意义有无差别尚未试验。


8. 关于frame
(1)现有问题
在 IE中 可以用window.testFrame取得该frame,mf中不行
(2)解决方法
在frame的使用方面mf和ie的最主要的区别是:
如果在frame标签中书写了以下属性:
<frame src="xx.htm" id="frameId" name="frameName" />
那么ie可以通过id或者name访问这个frame对应的window对象
而mf只可以通过name来访问这个frame对应的window对象
例如如果上述frame标签写在最上层的window里面的htm里面,那么可以这样访问
ie: window.top.frameId或者window.top.frameName来访问这个window对象
mf: 只能这样window.top.frameName来访问这个window对象

另外,在mf和ie中都可以使用window.top.document.getElementById("frameId")来访问frame标签
并且可以通过window.top.document.getElementById("testFrame").src = 'xx.htm'来切换frame的内容
也都可以通过window.top.frameName.location = 'xx.htm'来切换frame的内容


9. 在mf中,自己定义的属性必须getAttribute()取得
10.在mf中没有 parentElement parement.children 而用
parentNode parentNode.childNodes
childNodes的下标的含义在IE和MF中不同,MF使用DOM规范,childNodes中会插入空白文本节点。
一般可以通过node.getElementsByTagName()来回避这个问题。
当html中节点缺失时,IE和MF对parentNode的解释不同,例如
<form>
<table>
<input/>
</table>
</form>
MF中input.parentNode的值为form, 而IE中input.parentNode的值为空节点

MF中节点没有removeNode方法,必须使用如下方法 node.parentNode.removeChild(node)

11.const 问题
(1)现有问题:
在 IE 中不能使用 const 关键字。如 const constVar = 32; 在IE中这是语法错误。
(2)解决方法:
不使用 const ,以 var 代替。

12. body 对象
MF的body在body标签没有被浏览器完全读入之前就存在,而IE则必须在body完全被读入之后才存在

13. url encoding
在js中如果书写url就直接写&不要写&例如var url = 'xx.jsp?objectName=xx&objectEvent=xxx';
frm.action = url那么很有可能url不会被正常显示以至于参数没有正确的传到服务器
一般会服务器报错参数没有找到
当然如果是在tpl中例外,因为tpl中符合xml规范,要求&书写为&
一般MF无法识别js中的&


14. nodeName 和 tagName 问题
(1)现有问题:
在MF中,所有节点均有 nodeName 值,但 textNode 没有 tagName 值。在 IE 中,nodeName 的使用好象
有问题(具体情况没有测试,但我的IE已经死了好几次)。
(2)解决方法:
使用 tagName,但应检测其是否为空。

15. 元素属性
IE下 input.type属性为只读,但是MF下可以修改


16. document.getElementsByName() 和 document.all[name] 的问题
(1)现有问题:
在 IE 中,getElementsByName()、document.all[name] 均不能用来取得 div 元素(是否还有其它不能取的元素还不知道)。

由 beat 发表于 下午01点59分 | 回复 (0) | 顶端

2007年02月03日 星期六

Latex moresize字体对应表

字体尺寸选择命令 10pt
默认值
11pt
默认值
12pt
默认值
moresize.png
由 beat 发表于 下午08点14分 | 回复 (0) | 顶端

2006年11月09日 星期四

PHP SOAP终于测验成功

PHP5已经支持soap了。可是不知怎么回事,网上的例子在我机器上总是通过不了。今天终于调通了,高兴!

PHP的SOAP很简单,首先建立一个函数文件soapfunc.php,这个文件包含了我们想通过SOAP协议暴露给Web services的函数:reverse,add2numbers和gettime,没有什么不同,就是普通的php函数,前两个就是网上到处都可以看到的,我自己又加了一个。这里,一定要注意规范php代码的格式,我的问题就是出在格式上了。




<?php
function reverse($str){
$retval = '';
if(strlen($str) < 1) {
return new SoapFault('Client','','Invalid string');
}
for ($i = 1; $i <= strlen($str); $i++) {
$retval .= $str[(strlen($str) - $i)];
}
return $retval;
}
function add2numbers($num1, $num2) {
if (trim($num1) != intval($num1)) {
return new SoapFault('Client','','The first number is invalid');
}
if (trim($num2) != intval($num2)) {
return new SoapFault('Client','','The second number is invalid');
}
return ($num1 + $num2);
}
function gettime(){
$time=strftime("%Y-%m-%d %H:%M:%S");
return $time;
}
?>


然后,编写soapserver.php,这个文件首先创建一个SoapServer对象实例,然后将我们要暴露的函数注册,最后的handle()用来处理接受到的SOAP请求。网上好多代码里面都没有这一行。



include_once('soapfunc.php');
$soap = new SoapServer(null,array('uri'=>"http://test-uri/"));
$soap->addFunction('reverse');
$soap->addFunction('add2numbers');
$soap->addFunction('gettime');
$soap->addFunction(SOAP_FUNCTIONS_ALL);
$soap->handle();
?>


最后,我们需要一个测试页面,来测一下我们的Web Service是否好用,soapclient.php




try {
$client = new SoapClient(null, array('location' =>
"[Your Website]/soapserver.php",'uri' => "http://test-uri/"));
$str = "This string will be reversed";
$reversed = $client->reverse($str);
echo "If you reverse '",$str,"', you get '",$reversed,"'
";
$n1=20;
$n2=33;
$sum = $client->add2numbers($n1,$n2);
echo "If you try ",$n1,"+",$n2,", you will get ",$sum,"
";
echo "The system time is: ",$client->gettime();
} catch (SoapFault $fault){
echo "Fault! code:",$fault->faultcode,", string: ",$fault->faultstring;
}
?>



测试页面首先创建一个SoapClient的实例,指定了该服务的URL和URI,SoapClient的构造函数第一个参数本应是指定WSDL(描述Web服务的公共接口)描述文件的,本来我也没看过WSDL的写法,所以就不采用wsdl方式定义了。
创建完SoapClient以后,就可以像本地函数一样调用Web Services了。

由 beat 发表于 上午03点29分 | 回复 (0) | 顶端

2006年09月03日 星期日

PHP parse_url函数

parse_url
(PHP 3, PHP 4, PHP 5)

parse_url -- 解析 URL,返回其组成部分
描述
array parse_url ( string url )


此函数返回一个关联数组,包含现有 URL 的各种组成部分。如果缺少了其中的某一个,则不会为这个组成部分创建数组项。组成部分为:


scheme - 如 http

host

port

user

pass

path

query - 在问号 ? 之后

fragment - 在散列符号 # 之后


此函数并 不 意味着给定的 URL 是合法的,它只是将上方列表中的各部分分开。parse_url() 可接受不完整的 URL,并尽量将其解析正确。

注: 此函数对相对路径的 URL 不起作用。

例子 1. parse_url() 示例

$ php -r 'print_r(parse_url("http://username:password@hostname/path?arg=value#anchor"));'
Array
(
[scheme] => http
[host] => hostname
[user] => username
[pass] => password
[path] => /path
[query] => arg=value
[fragment] => anchor
)

$ php -r 'print_r(parse_url("http://invalid_host..name/"));'
Array
(
[scheme] => http
[host] => invalid_host..name
[path] => /
)

参见 pathinfo()、parse_str()、dirname() 与 basename()。

由 beat 发表于 上午01点01分 | 回复 (0) | 顶端

2006年09月02日 星期六

彻底隐藏你HTML网页的源代码

<html>

<head><title>Test IFrame</title>
<script>
function clear() {
Source=document.body.firstChild.data;
document.open();
document.close();
document.body.innerHTML=Source;
}
</script>
</head>
<body onload=clear()>
<!--
<Iframe name=tag align=center width="100%" src="http://www.nkstars.org/beat/" scrolling="no" frameborder="0" onload="this.height=tag.document.body.scrollHeight"></iframe>
-->
</body>
</html>

由 beat 发表于 上午05点14分 | 回复 (0) | 顶端

iframe自适应高度解决方法

<html>

<head><title>Test IFrame</title>
</head>
<body>
<Iframe name=tag align=center width="100%" src="http://www.nkstars.org/beat/" scrolling="no" frameborder="0" onload="this.height=tag.document.body.scrollHeight"></iframe>
</body>
</html>

由 beat 发表于 上午05点05分 | 回复 (0) | 顶端

使用minidom来处理XML的示例

一.XML的读取.

在 NewEdit 中有代码片段的功能,代码片段分为片段的分类和片段的内容。在缺省情况下都是用XML格式保存的。下面我讲述一下,如何使用minidom来读取和保存XML文件。

下面是片段分类的一个示例文件--catalog.xml

<?xml version="1.0" encoding="utf-8"?>
<catalog>
<maxid>4</maxid>
<item id="1">
<caption>Python</caption>
<item id="4">
<caption>测试</caption>
</item>
</item>
<item id="2">
<caption>Zope</caption>
</item>
</catalog>

分类是树状结构,显示出来可能为:

Python
测试
Zope

先简单介绍一下XML的知识,如果你已经知道了可以跳过去。

1. XML文档的编码

此XML文档的编码为utf-8,因此你看到的“测试”其实是UTF-8编码。在XML文档的处理中都是使用UTF-8编码进行的,因此,如果你不写明encoding的话,都是认为文件是UTF-8编码的。在Python中,好象只支持几种编码,象我们常用的GB2312码就不支持,因此建议大家在处理XML时使用UTF-8编码。

2. XML文档的结构

XML文档有XML头信息和XML信息体。头信息如:

<?xml version="1.0" encoding="utf-8"?>

它表明了此XML文档所用的版本,编码方式。有些复杂的还有一些文档类型的定义(DOCTYPE),用于定义此XML文档所用的DTD或Schema和一些实体的定义。这里并没有用到,而且我也不是专家,就不再细说了。

XML信息体是由树状元素组成。每个XML文档都有一个文档元素,也就是树的根元素,所有其它的元素和内容都包含在根元素中。

3. DOM

DOM是Document Object Model的简称,它是以对象树来表示一个XML文档的方法,使用它的好处就是你可以非常灵活的在对象中进行遍历。

4. 元素和结点

元素就是标记,它是成对出现的。XML文档就是由元素组成的,但元素与元素之间可以有文本,元素的内容也是文本。在minidom中有许多的结点,元素也属于结点的一种,它不是叶子结点,即它存在子结点;还存在一些叶子结点,如文本结点,它下面不再有子结点。

象catalog.xml中,文档元素是catalog,它下面有两种元素:maxid和item。maxid用来表示当前最大的item的id值。每一个item都有一个id属性,id属性是唯一的,在 NewEdit 中用来生成每个分类所对应的代码片段的XML文档名,因此不能重复,而且它是一个递增的值。item元素有一个caption子元素,用来表示此分类项的名称,它还可以包含item元素。这样,就定义了一个树状XML结构,下面让我们看一看如果把它们读出来。


一、得到dom对象

>>> import xml.dom.minidom
>>> dom = xml.dom.minidom.parse('d:/catalog.xml')

这样我们得到了一个dom对象,它的第一个元素应该是catalog。

二、得到文档元素对象

>>> root = dom.documentElement

这样我们得到了根元素(catalog)。

三、结点属性

每一个结点都有它的nodeName,nodeValue,nodeType属性。nodeName为结点名字。

>>> root.nodeName
u'catalog'

nodeValue是结点的值,只对文本结点有效。nodeType是结点的类型,现在有以下几种:

'ATTRIBUTE_NODE'
'CDATA_SECTION_NODE'
'COMMENT_NODE'
'DOCUMENT_FRAGMENT_NODE'
'DOCUMENT_NODE'
'DOCUMENT_TYPE_NODE'
'ELEMENT_NODE'
'ENTITY_NODE'
'ENTITY_REFERENCE_NODE'
'NOTATION_NODE'
'PROCESSING_INSTRUCTION_NODE'
'TEXT_NODE'

这些结点通过名字很好理解。catalog是ELEMENT_NODE类型。

>>> root.nodeType
1
>>> root.ELEMENT_NODE
1

四、子元素、子结点的访问

访问子元素、子结点的方法很多,对于知道元素名字的子元素,可以使用getElementsByTagName方法,如读取maxid子元素:

>>> root.getElementsByTagName('maxid')
[<DOM Element: maxid at 0xb6d0a8>]

这样返回一个列表,由于我们的例子中maxid只有一项,因此列表也只有一项。

如果想得到某个元素下的所有子结点(包括元素),可以使用childNodes属性:

>>> root.childNodes
[<DOM Text node "\n ">, <DOM Element: maxid at 0xb6d0a8>, <DOM Text node "\n ">, <DOM Element: item at 0xb6d918>, <DOM Text node "\n ">, <DOM Element: item at 0xb6de40>, <DOM Text node "\n ">, <DOM Element: item at 0xb6dfa8>, <DOM Text node "\n">]

可以看出所有两个标记间的内容都被视为文本结点。象每行后面的回车,都被看到文本结点。从上面的结果我们可以看出每个结点的类型,本例中有文本结点和元素结点;结点的名字(元素结点);结点的值(文本结点)。每个结点都是一个对象,不同的结点对象有不同的属性和方法,更详细的要参见文档。由于本例比较简单,只涉及文本结点和元素结点。

getElementsByTagName可以搜索当前元素的所有子元素,包括所有层次的子元素。childNodes只保存了当前元素的第一层子结点。

这样我们可以遍历childNodes来访问每一个结点,判断它的nodeType来得到不同的内容。如,打印出所有元素的名字:

>>> for node in root.childNodes:
if node.nodeType == node.ELEMENT_NODE:
print node.nodeName

maxid
item
item

对于文本结点,想得到它的文本内容可以使用: .data属性。

对于简单的元素,如:<caption>Python</caption>,我们可以编写这样一个函数来得到它的内容(这里为Python)。

def getTagText(root, tag):
node = root.getElementsByTagName(tag)[0]
rc = ""
for node in node.childNodes:
if node.nodeType in ( node.TEXT_NODE, node.CDATA_SECTION_NODE):
rc = rc + node.data
return rc

这个函数只处理找到的第一个符合的子元素。它会将符合的第一个子元素中的所有文本结点拼在一起。当nodeType为文本类结点时,node.data为文本的内容。如果我们考查一下元素caption,我们可能看到:

[<DOM Text node "Python">]

说明caption元素只有一个文本结点。

如果一个元素有属性,那么可以使用getAttribute方法,如:

>>> itemlist = root.getElementsByTagName('item')
>>> item = itemlist[0]
>>> item.getAttribute('id')
u'1'

这样就得到了第一个item元素的属性值。

下面让我们简单地小结一下如何使用minidom来读取XML中的信息

1. 导入xml.dom.minidom模块,生成dom对象
2. 得到文档对象(根对象)
3. 通过getElementsByTagName()方法和childNodes属性(还有其它一些方法和属性)找到要处理的元素
4. 取得元素下文本结点的内容


二.写入.


下面我来演示一下如何从无到有生成象catalog.xml一样的XML文件。

一、生成dom对象

>>> import xml.dom.minidom
>>> impl = xml.dom.minidom.getDOMImplementation()
>>> dom = impl.createDocument(None, 'catalog', None)

这样就生成了一个空的dom对象。其中catalog为文档元素名,即根元素名。

二、显示生成的XML内容

每一个dom结点对象(包括dom对象本身)都有输出XML内容的方法,如:toxml(), toprettyxml()

toxml()输出紧凑格式的XML文本,如:

<catalog><item>test</item><item>test</item></catalog>

toprettyxml()输出美化后的XML文本,如:

<catalog>
<item>
test
</item>
<item>
test
</item>
</catalog>

可以看出,它是将每个结点后面都加入了回车符,并且自动处理缩近。但对于每一个元素,如果元素只有文本内容,则我希望元素的tag与文本是在一起的,如:

<item>test</item>

而不想是分开的格式,但minidom本身是不支持这样的处理。关于如何实现形如:

<catalog>
<item>test</item>
<item>test</item>
</catalog>

这样的XML格式,后面我们再说。

三、生成各种结点对象

dom对象拥有各种生成结点的方法,下面列出文本结点,CDATA结点和元素结点的生成过程。

1. 文本结点的生成

>>> text=dom.createTextNode('test')
test

要注意的是,在生成结点时,minidom并不对文本字符进行检查,象文本中如果出现了'<','&'之类的字符,应该转换为相应的实体符号'<','&'才可以,这里没有做这个处理。

2. CDATA结点的生成

>>> data = dom.createCDATASection('aaaaaa\nbbbbbb')
>>> data.toxml()
'<![CDATA[aaaaaa\nbbbbbb]]>'

CDATA是用于包括大块文本,同时可以不用转换'<','&'字符的标记,它是用<![CDATA[文本]]>来包括的。但文本中不可以有"]]>"这样的串存在。生成结点时minidom不作这些检查,只有当你输出时才有可能发现有错。

3. 元素结点的生成

>>> item = dom.createElement('caption')
>>> item.toxml()
'<caption/>'

对于象元素这样的结点,生成的元素结点其实是一个空元素,即不包含任何文本,如果要包含文本或其它的元素,我们需要使用appendChild()或insertBefore()之类的方法将子结点加就到元素结点中。如将上面生成的text结点加入到caption元素结点中:

>>> item.appendChild(text)
<DOM Text node "test">
>>> item.toxml()
'<caption>test</caption>'

使用元素对象的setAttribute()方法可以向元素中加入属性,如:

>>> item.setAttribute('id', 'idvalue')
>>> item.toxml()
'<caption id="idvalue">test</caption>'

四、生成dom对象树

我们有了dom对象,又知道了如何生成各种结点,包括叶子结点(不包含其它结点的结点,如文本结点)和非叶子结点(包含其它结点的结点,如元素结点)的生成,然后就需要利用结点对象本身的appendChild()或insertBefore()方法将各个结点根据在树中的位置连起来,串成一棵树。最后要串到文档结点上,即根结点上。如一个完整的示例为:

>>> import xml.dom.minidom
>>> impl = xml.dom.minidom.getDOMImplementation()
>>> dom = impl.createDocument(None, 'catalog', None)
>>> root = dom.documentElement
>>> item = dom.createElement('item')
>>> text = dom.createTextNode('test')
>>> item.appendChild(text)
<DOM Text node "test">
>>> root.appendChild(item)
<DOM Element: item at 0xb9cf80>
>>> print root.toxml()
<catalog><item>test</item></catalog>

五、简单生成元素结点的函数

下面是我写的一个小函数,用于简单的生成类似于:

<caption>test</caption>

或形如:

<item><![CDATA[test]]></item>

的元素结点

1 def makeEasyTag(dom, tagname, value, type='text'):
2 tag = dom.createElement(tagname)
3 if value.find(']]>') > -1:
4 type = 'text'
5 if type == 'text':
6 value = value.replace('&', '&')
7 value = value.replace('<', '& lt;')
8 text = dom.createTextNode(value)
9 elif type == 'cdata':
10 text = dom.createCDATASection(value)
11 tag.appendChild(text)
12 return tag

参数说明:

dom为dom对象
tagname为要生成元素的名字,如'item'
value为其文本内容,可以为多行
type为文本结点的格式,'text'为一般Text结点,'cdata'为CDATA结点
函数处理说明:

首先创建元素结点
查找文本内容是否有']]>',如果找到,则此文本结点只可以是Text结点
如果结点类型为'text',则对文本内容中的'<'替换为'<','&'替换为'&',再生成文本结点
如果结点类型为'cdata',则生成CDATA结点
将生成的文本结点追加到元素结点上
因此这个小函数可以自动地处理字符转化及避免CDATA结点中出现']]>'串。

上面生成'item'结点的语句可以改为:

>>> item = makeEasyTag(dom, 'item', 'test')
>>> item.toxml()
'<item>test</item>'

六、写入到XML文件中

dom对象树已经生成好了,我们可以调用dom的writexml()方法来将内容写入文件中。writexml()方法语法格式为:

writexml(writer, indent, addindent, newl, encoding)

writer是文件对象
indent是每个tag前填充的字符,如:' ',则表示每个tag前有两个空格
addindent是每个子结点的缩近字符
newl是每个tag后填充的字符,如:'\n',则表示每个tag后面有一个回车
encoding是生成的XML信息头中的encoding属性值,在输出时minidom并不真正进行编码的处理,如果你保存的文本内容中有汉字,则需要自已进行编码转换。
writexml方法是除了writer参数必须要有外,其余可以省略。下面给出一个文本内容有汉字的示例:

1 >>> import xml.dom.minidom
2 >>> impl = xml.dom.minidom.getDOMImplementation()
3 >>> dom = impl.createDocument(None, 'catalog', None)
4 >>> root = dom.documentElement
5 >>> text = unicode('汉字示例', 'cp936')
6 >>> item = makeEasyTag(dom, 'item', text)
7 >>> root.appendChild(item)
8 <DOM Element: item at 0xb9ceb8>
9 >>> root.toxml()
10 u'<catalog><item>\u6c49\u5b57\u793a\u4f8b</item></catalog>'
11 >>> f=file('d:/test.xml', 'w')
12 >>> import codecs
13 >>> writer = codecs.lookup('utf-8')[3](f)
14 >>> dom.writexml(writer, encoding='utf-8')
15 >>> writer.close()

5行 因为XML处理时内部使用Unicode编码,因此象汉字首先要转成Unicode,如果你不做这一步minicode并不检查,并且保存时可能不会出错。但读取时可能会出错。
12-13行 生成UTF-8编码的写入流对象,这样在保存时会自动将Unicode转换成UTF-8编码。

这样写XML文件就完成了。

三.美化.

对于dom对象的writexml()方法,虽然可以控制一些格式上的输出,但结果并不让人满意。比如我想实现:

<catalog>
<item>test</item>
<item>test</item>
</catalog>

而不是:

<catalog>
<item>
test
</item>
<item>
test
</item>
</catalog>

如果是象下面的输出结果我无法区分原来文本中是否带有空白,而上一种结果则不存在这一问题。好在我在wxPython自带的XML资源编辑器(xred)发现了美化的代码。代码如下:

1 def Indent(dom, node, indent = 0):
2 # Copy child list because it will change soon
3 children = node.childNodes[:]
4 # Main node doesn't need to be indented
5 if indent:
6 text = dom.createTextNode('\n' + '\t' * indent)
7 node.parentNode.insertBefore(text, node)
8 if children:
9 # Append newline after last child, except for text nodes
10 if children[-1].nodeType == node.ELEMENT_NODE:
11 text = dom.createTextNode('\n' + '\t' * indent)
12 node.appendChild(text)
13 # Indent children which are elements
14 for n in children:
15 if n.nodeType == node.ELEMENT_NODE:
16 Indent(dom, n, indent + 1)

参数说明:

dom为dom对象
node为要处理的元素结点
indent指明缩近的层数

函数说明:

Indent是一个递归函数,当一个结点有子元素时进行递归处理。主要是解决子元素的换行和缩近的处理。这里缩近是写死的,每一级缩近使用一个制表符。如果你愿意可以改为你想要的内容。就是把函数中的'\t'换替一下。或干脆写成一个全局变量,或参数以后改起来可能要容易的多。不过在 NewEdit 中,这样的处理足够了,就没有做这些工作。

Indent基本的想法就是递归遍历所有子结点,在所有需要加入回车和缩近的地方插入相应的文本结点。这样再使用writexml()输出时就是缩近好了的。具体程序不再细说,直接用就行了。

但这里要注意的是:

Indent()要修改原dom对象,因此在调用它之前最好先复制一个临时dom对象,使用完毕后再清除这个临时dom对象即可。下面是详细的调用过程:

1 domcopy = dom.cloneNode(True)
2 Indent(domcopy, domcopy.documentElement)
3 f = file(xmlfile, 'wb')
4 writer = codecs.lookup('utf-8')[3](f)
5 domcopy.writexml(writer, encoding = 'utf-8')
6 domcopy.unlink()

1行 克隆一个dom对象
2行 进行缩近处理
3-4行 进行UTF-8编码处理
5行 生成XML文件
6行 清除dom对象的内容

经过这番处理之后,你的XML文档应该好看多了。

由 beat 发表于 上午03点04分 | 回复 (0) | 顶端

2006年09月01日 星期五

基本的xml解析在Python的流程

我准备解析下面这个文档(关于xml的知识可以到http://www.w3.org上查看相关的Recommendations):
代码

<catalog>;
  <book isbn="1-56592-724-9">;
    <title>;The Cathedral & the Bazaar</title>;
    <author>;Eric S. Raymond</author>;
  </book>;
  <book isbn="1-56592-051-1">;
    <title>;Making TeX Work</title>;
    <author>;Norman Walsh</author>;
  </book>;
  <!-- imagine more entries here... -->;
</catalog>;

Python的标准模块里包含了xml 处理的module。我们这次用的是xml.dom.minidom,一个迷你版的DOM API
代码:

#! /usr/bin/python

import xml.dom.minidom
from xml.dom.minidom import Node

doc = xml.dom.minidom.parse("books.xml")

mapping = {}
for node in doc.getElementsByTagName("book"):
    isbn = node.getAttribute("isbn")
    L = node.getElementsByTagName("title")
    for node2 in L:
        title = ""
        for node3 in node2.childNodes:
            if node3.nodeType == Node.TEXT_NODE:
                title += node3.data
                mapping[isbn] = title
                # mapping now has the same value as in the SAX example:
                print(mapping)

通过这个程序,可以看到解析xml的文件的过程, minidom.parse返回的就是一个xml.dom.Document类型的实例。其实就是DOM中定义的Document了。通常的DOM的操作都是通过这个类来完成,比如例子中的建立ISBN和书名的对应关系表。对DOM的API,大家可以查看相关的文档。

同时,这次引入了一个新的控制结构,就是for-loop。这个和C和Java的for循环有些区别(Java在5.0中也引入了这种循环)。这个循环是for-each-in格式的。而不是传统的以初始值,步进值和中止条件控制循环过程的。

由 beat 发表于 下午11点12分 | 回复 (0) | 顶端

重温 Python 的 XML 工具

转载自:http://www.uplinux.com/www/dev/01/11.shtml

David Mertz 博士(mertz@gnosis.cx)
Phenomenological unifier,Gnosis Software, Inc.


David Mertz 创作的可爱的 Python 的第一、第二部分概述了在 Python 中使用 XML。然而,在那些最初的文章出现后,Python 中的 XML 工具有了很大的发展。不幸的是,这些改进中的大多数并不向后兼容。在这个特别部分中,重温了作者先前对 XML 工具的讨论,并提供最新的代码示例。


在许多情况下,Python 是使用 XML 文档的理想语言。像 Perl、REBOL、REXX 和 TCL 一样,它是一种灵活的脚本语言,并且有强大的文本操作能力。而且,除了对多数类型的文本文件(或流文件)编码外,XML 文档还编码大量复杂的数据结构。


继续在 Python 2.0 中对 XML 的支持
文本处理中常见的“读取几行,并将它们与一些规则表达式比较”样式通常不能很好地适合对 XML 进行彻底语法分析和处理。幸好,Python(与大多数其它语言相比)不仅有处理复杂数据结构的直接方法(通常使用类和属性),还有一系列 XML 相关的模块可以帮助语法分析、处理和生成 XML。


XML-SIG (专门兴趣组)的成员为维护 Python 一系列 XML 工具做了许多工作。与其它 Python 专门兴趣组一样,XML-SIG 要维护邮件发送列表、列表档案、有用的参考大全、文档、标准包和其它资源(请参阅本文后的参考资料)。


从 Python 2.0 开始,Python 在其标准发行版中包括大多数 XML-SIG 项目。最新的 XML-SIG 包可能包含一些 Python 标准发行版中没有的“极端先进”特性,但出于面向绝大多数人的目的 -- 包括本文中的讨论 -- Python 2.0 的 XML 支持将是您感兴趣的。幸运的是,早期 Python 版本对 xmllib 的基本支持在 Python 2.0+ 下有了很大进步。目前,Python 用户能正常的选择 DOMSAXexpat 技术来处理 XML (使用其他编程语言的 XML 开发人员将会意识到这些)。


模块:xmllib
xmllib 是一个非验证的低级语法分析器。应用程序员使用的 xmllib 可以覆盖 XMLParser 类,并提供处理文档元素(如特定或类属标记,或字符实体)的方法。从 Python 1.5x 到 Python 2.0+ 以来,xmllib 的使用方法并没变化;在绝大多数情况下更好的选择是使用 SAX 技术,它也是种面向流的技术,对语言和开发者来说更为标准。


本文中的示例与原来专栏中的相同:包括一个叫做 quotations.dtd 的 DTD 以及这个 DTD 的文档 sample.xml (请参阅参考资料,以获取本文中提到的文件的档案)。以下的代码显示了 sample.xml 中每段引言的前几行,并生成了非常简单的未知标记和实体的 ASCII 指示符。经过分析的文本作为连续流来处理,所使用的任何累加器都由程序员负责(如标记中的字符串 (#PCDATA),或所遇到的标记的列表或词典)。


清单 1: try_xmllib.py





import xmllib, string

classQuotationParser(xmllib.XMLParser):
"""Crude xmllib extractor for quotations.dtd document"""
def__init__(self):
xmllib.XMLParser.__init__(self)
self.thisquote = '' # quotation accumulator
defhandle_data(self, data):
self.thisquote = self.thisquote + data
defsyntax_error(self, message):
pass
defstart_quotations(self, attrs): # top level tag
print '--- Begin Document ---'
defstart_quotation(self, attrs):
print 'QUOTATION:'
defend_quotation(self):
print string.join(string.split(self.thisquote[:230]))+'...',
print '('+str(len(self.thisquote))+' bytes)'
self.thisquote = ''
defunknown_starttag(self, tag, attrs):
self.thisquote = self.thisquote + '{'
defunknown_endtag(self, tag):
self.thisquote = self.thisquote + '}'
defunknown_charref(self, ref):
self.thisquote = self.thisquote + '?'
defunknown_entityref(self, ref):
self.thisquote = self.thisquote + '#'

if __name__ == '__main__':
parser = QuotationParser()
for c in open("sample.xml").read():
parser.feed(c)
parser.close()




验证
您可能需要展望标准 XML 支持的未来的原因是,在进行语法分析的同时需要进行验证。不幸的是,标准 Python 2.0 XML 包并不包括验证型语法分析器。


xmlproc 是 python 原有的语法分析器,它执行几乎完整的验证。如果需要验证型语法分析器, xmlproc 是 Python 当前唯一的选择。而且,xmlproc 提供其它语法分析器所不具备的各种高级和测试接口。


选择一种语法分析器
如果决定使用 XML 的简单 API (SAX) -- 它应该用于复杂的事物,因为其它大部分工具都是在它的基础上建立的 -- 将为您完成许多语法分析器的分类工作。xml.sax 模块包含一个自动选择“最佳”语法分析器的设施。在标准 Python 2.0 安装中,唯一能选择的语法分析器是 expat,它是种 C 语言编写的快速扩展。然而,也可以在 $PYTHONLIB/xml/parsers 下安装另一个语法分析器,以备选择。设置语法分析器很简单:


清单 2: Python 选择最佳语法分析器的语句





import xml.sax
parser = xml.sax.make_parser()




您还可以通过传递参数来选择特定的语法分析器;但考虑到可移植性 -- 也为了对今后更好的语法分析器的向上兼容性 -- 最佳方法是使用 make_parser() 来完成工作。


您可以直接导入 xml.parsers.expat。如果这样做,您就能获得 SAX 界面并不提供的一些特殊技巧。这样,xml.parsers.expat 与 SAX 相比有些“低级”。但 SAX 技术非常标准,对面向流的处理也非常好;大多数情况下 SAX 的级别正合适。通常情况下,由于 make_parser() 函数已经能获得 expat 提供的性能,因此纯速度的差异很小。


什么是 SAX
考虑到背景因素,回答什么是 SAX 的较好答案是:


SAX (XML 的简单 API)是 XML 语法分析器的公用语法分析器接口。它允许应用程序作者编写使用 XML 语法分析器的应用程序,但是它却独立于所使用的语法分析器。(将它看作 XML 的 JDBC。)(Lars Marius Garshol,SAX for Python)

SAX -- 如同它提供的语法分析器模块的 API -- 基本上是一个 XML 文档的顺序处理器。使用它的方法与 xmllib 示例极其相似,但更加抽象。应用程序员将定义一个 handler 类,而不是语法分析器类,该 handler 类能注册到任何所使用的语法分析器中。必须定义 4 个 SAX 接口(每个接口都有几个方法):DocumentHandler、DTDHandler、EntityResolver 和 ErrorHandler。创建语法分析器除非被覆盖,否则它还连接默认接口。这些代码执行与 xmllib 示例相同的任务:


清单 3: try_sax.py





"Simple SAX example, updated for Python 2.0+"
import string
import xml.sax
from xml.sax.handler import *

classQuotationHandler(ContentHandler):
"""Crude extractor for quotations.dtd compliant XML document"""
def__init__(self):
self.in_quote = 0
self.thisquote = ''
defstartDocument(self):
print '--- Begin Document ---'
defstartElement(self, name, attrs):
if name == 'quotation':
print 'QUOTATION:'
self.in_quote = 1
else:
self.thisquote = self.thisquote + '{'
defendElement(self, name):
if name == 'quotation':
print string.join(string.split(self.thisquote[:230]))+'...',
print '('+str(len(self.thisquote))+' bytes)'
self.thisquote = ''
self.in_quote = 0
else:
self.thisquote = self.thisquote + '}'
defcharacters(self, ch):
if self.in_quote:
self.thisquote = self.thisquote + ch

if __name__ == '__main__':
parser = xml.sax.make_parser()
handler = QuotationHandler()
parser.setContentHandler(handler)
parser.parse("sample.xml")




xmllib 相比,上述示例中要注意两件小事:.parse() 方法处理整个流或字符串,所以不必为语法分析器创建循环;.parse() 同样能灵活地接收一个文件名、一个文件对象,或是众多的类文件对象(一些具有 .read() 方式)。


包:DOM
DOM 是一种 XML 文档的高级树型表示。该模型并非只针对 Python,而是一种普通 XML 模型(请参阅参考资料以获取进一步信息)。Python 的 DOM 包是基于 SAX 构建的,并且包括在 Python 2.0 的标准 XML 支持里。由于篇幅所限,没有将代码示例加到本文中,但在 XML-SIG 的 "Python/XML HOWTO" 中给出了一个极好的总体描述:


文档对象模型为 XML 文档指定了树型表示。顶级文档实例是树的根,它只有一个子代,即顶级元素实例;这个元素有表示内容和子元素的子节点,他们也可以有子代,以此类推。定义的函数允许随意遍历结果树,访问元素和属性值,插入和删除节点,以及将树转换回 XML。



DOM 可以用于修改 XML 文档,因为可以创建一棵 DOM 树,通过添加新节点和来回移动子树来修改这棵树,然后生成一个新的 XML 文档作为输出。您也可以自己构造一棵 DOM 树,然后将它转换成 XML;用这种方法生成 XML 输出比仅将 <tag1>...</tag1> 写入文件的方法更灵活。



使用 xml.dom 模块的语法与早期的文章相比有了一些变动。Python 2.0 中自带的 DOM 实现被称为 xml.dom.minidom,并提供轻量级和小型版本的 DOM。显然,完整的 XML-SIG 的 DOM 中有些试验性的特性并未被放入 xml.dom.minidom 中,但大家并不会注意到这一点。


生成 DOM 对象很简单;只需:


清单 4: 在 XML 文件中创建 Python DOM 对象





from xml.dom.minidom import parse, parseString
dom1 = parse('mydata.xml') # parse an XML file by name




使用 DOM 对象是种非常直接的 OOP 模式的工作。然而,经常在无法立刻简单区分的层级(除了循环列举)中碰到许多类似清单的属性。例如,以下是一段普通的 DOM Python 代码片断:


清单 5: 通过 Python DOM 节点对象的迭代





for node in dom_node.childNodes:
if node.nodeName == '#text': # PCDATA is a kind of node,
PCDATA = node.nodeValue # but not a new subtag
elif node.nodeName == 'spam':
spam_node_list.append(node) # Create list of <spam> nodes




Python 标准说明文档中有一些更详细的 DOM 示例。我的早期文章中有关使用 DOM 对象的示例(请参阅参考资料)指出的方向仍然是正确的,但是文章发布后至今,一些方法和属性名称以更改,因此请查阅一下 Python 的说明文档。


模块: pyxie
pyxie 模块是在 Python 标准 XML 支持之上构建的,它为 XML 文档提供了附加的高级接口。pyxie 将完成两项基本操作:它将 XML 文档转换成一种更易于进行语法分析的基于行的格式;并且它提供了将 XML 文档当作可操作树处理的方法。pyxie 所使用的基于行的 PYX 格式是不受语言限制的,其工具适用于几种语言。总之,文档的 PYX 表示与其 XML 表示相比,更易于使用常见的基于行的文本处理工具进行处理,如 grep、sed、awk、bash、perl,或标准 python 模块,如 stringre。根据结果,从 XML 转换到 PYX 可能节省许多工作。


pyxie 将 XML 文档当作树处理的概念与 DOM 中的思路相似。由于 DOM 标准得到许多编程语言的广泛支持,那么如果 XML 文档的树型表示是必需的,大多数程序员会使用 DOM 标准而非 pyxie


更多模块:xml_picklexml_objectify
我自行开发了处理 XML 的高级模块,称为 xml_picklexml_objectify。我还在其它地方写过许多类似模块(请参阅参考资料),在此不必做过多的介绍。当你“用 Python 思考”而不是“用 XML 思考”时,这些模块非常有用。特别是 xml_objectify 自身对程序员隐藏了几乎所有的 XML 线索,使您在程序中充分使用 Python “原始”对象。实际的 XML 数据格式几乎被抽象得不可见。同样,xml_pickle 使 Python 程序员以“原始” Python 对象开始,该对象的数据可以来源于任何源代码,然后把它们(连续地)放入其他用户以后可能需要的 XML 格式。


参考资料





由 beat 发表于 下午09点36分 | 回复 (0) | 顶端

2006年08月07日 星期一

2006年06月16日 星期五

关于Portal

这里所说的Portal是指JCP-JSR168规范所描述的:Portal是一个基于Web的应用,通常它提供个性化、单点登录、内容集成和显示等功能。Portal技术包括三个方面:

1) Portal服务器(Portal Server);

2) Portlet容器;(Portlet Container)

3) Portlet。

1) Portal Server 的定义是

一个 Portal(门户网站)就是指一个 Web-based 的系统,通常都会提供个人化设置、单一登陆、以及由各种不同来源或不同网站取得各式各样的信息,并且将这些信息放在网页之中组合而成的呈现平台,门户网站会有精巧的个人化设置去提供定制的网页,当不同等级的使用者来浏览该页面将获得不同的信息内容。

负责接收HTTP请求,调用portlet,并将portlet产生的内容聚集到portal page返回给客户。

2) Portlet Container 的定义是

portlet container 是提供 portlets 执行的环境,包含了许多 portlets 并且管理他们的生命周期,他也会永远保存着 portlets 的喜好设置,一个 portlet container 接收到来自 portal 的请求后,接着将这个请求传递给存在 container 的 portlet 执行。portlet container 没有义务去组合 portlets 产生的信息內容,这个工作必须由 portal 来处理。portal 和 portlet container 可以放在一起视为同一个系统的组件,或者分开成为两个独立的组件。

负责提供portlet的运行时环境,管理portlet的生命周期,还负责提供portlet持久化能力。

3) Portlet 的定义是

一个 Portlet 是以 Java 技术为技术的 Web 组件,由 Portlet Container 所管理,专门处理客户的 request 以及产生各种动态的信息内容。Portlets 为可插式 ( pluggable ) 的客户界面组件,提供呈现层成为一个信息系统。这些由 portlet 产生的内容也被称为片段 (fragment),而片段是具有一些规则的Markup( HTML、XHTML、WML ),而且可以和其他的片段组合而成一个复杂的文件。而 Portlet 中的内容正常来说是与其他 Portlet 的内容聚合而成为一个 Portal 网页。而 Portlet 的生命周期是被 Portlet Container 所管理控制的。客户端和 portlets 的互动是由 portal 通过典型的 request/response 方式实现,正常来说,客户会和 portlets 所产生的内容互动,举例来说,根据下一步的连接或者是确认送出的表单,结果 portal 将会接收到 portlet 的动作,将这个处理状况转向到目标 portlet。这些 portlet 内容的产生可能会因为不同的使用者而有不同的变化,完全是根据客户对于这个 portlet 的设置。

Portal主要是解决企业信息和应用的前端集成问题,它负责连结企业后台EAI,集成企业的结构和非结构化信息,并提供统一的访问企业信息和应用的入口。

(摘自JSR168规范文档)

portlet 与 servlet 的关系
Portlet 和 Servlet 算是兄弟有那么一点点相似却又有那么一点点不同,因为 Servlet 和 Portlet 不尽然相同,所以研究小組決定将 portlets 定义成为一个新的组件,因此定义了 portlets 一个新的并且明确的界面与行为。为了尽可能与现有的 servlet 结合达到重复使用的目的,portlet 的规范利用了 servlet 的规范,许多观念都很相似的,结合 portlets、servlets 及 jsp 在同一个网站系统中,我们称为 portlet application 。在同一个 portlet application 中,他们将分享同一个 classloader,context 及 session。

1) Portlet 和 Servlet 的相似之处

@ portlets 也是 Java 技术的 web 组件
@ portlets 也是有特定的 container 在管理
@ portlets 可以动态产生各种内容
@ portlets 的生命周期由 container 所管理
@ portlets 和客户端的互动是通过 request/response 的机制

2) Portlet 和 Servlet 也有一些不同

@ portlets 只产生 markup 信息片段,不是完整的网页文件。而 Portal 会将所有的 Portlet markup 信息片 段放到一个完整的 Portal 网页。
@ portlets 不会和 URL 有直接的关系
@ 客户端必须通过 portal 系统才能和 portlets 互动
@ portlets 有一些定义好的 request 处理,action request 以及 render request。
@ portlets 默认定义 portlet modes 及窗口状态可以指出在网页中该 portlet 的哪个功能正在执行及现在的 状态。
@ portlets 可以在同一个 portal 网页之中存在多个。

3) Portlet 有一些附加的功能是 Servlet 所没有的

@ Portlets 能够存取及储存永久配置文件及定制资料。
@ portlets 可以存取使用者数据
@ portlets 具有 URL 的重写功能在文件中去动态建立连结,允许 portal server 不用去知道如何在网页的片 段之中建立连结及动作。
@ portlets 可以储存临时性的数据在 portlet session 之中,拥有两个不同的范围:
application-wide scope 及 portlet private scope 。

4) Portlet 不具有一些功能, 但是 Servlet 却有提供

@ servlet 具有设置輸出的文字编码( character set encoding)方式
@ servlet 可以设置 HTTP 输出的 header
@ servlet 才能夠接收客户对于 portal 发出的 URL 请求

基于Portal开发项目的优势
1、可以与以后新开发的或已集成到Portal中的企业应用实现无缝集成。

2、可以分享Portal服务器和Portlet容器提供的种种功能。这要视Portal服务器提供商而定。

3、由于Portlet已规范化(JSR168),所以应用中开发的Portlet可以部署在不同的Portal服务器上。

由 beat 发表于 上午04点29分 | 回复 (0) | 顶端

2006年04月27日 星期四

DEBUG命令详解(zz)

Debug:A(汇编)


直接将 8086/8087/8088 记忆码合并到内存。

该命令从汇编语言语句创建可执行的机器码。所有数值都是十六进制格式,必须按一到四个字符输入这些数值。在引用的操作代码(操作码)前指定前缀记忆码。


a [address]


参数

address

指定键入汇编语言指令的位置。对 address 使用十六进制值,并键入不以“h”字符结尾的每个值。如果不指定地址,a 将在它上次停止处开始汇编。

有关将数据输入到指定字节中的信息,请单击“相关主题”列表中的 Debug E(键入)。

有关反汇编字节的信息,请单击“相关主题”列表中的 Debug U(反汇编)。


说明

使用记忆码

段的替代记忆码为 cs:、ds:、es: 和 ss:。远程返回的记忆码是 retf。字符串处理的记忆码必须明确声明字符串大小。例如,使用 movsw 可以移动 16 位的字串,使用 movsb 可以移动 8 位字节串。


汇编跳转和调用

汇编程序根据字节替换自动将短、近和远的跳转及调用汇编到目标地址。通过使用 near 或 far 前缀可以替代这样的跳转或调用,如下例所示:

-a0100:0500
0100:0500 jmp 502 ; a 2-byte short jump
0100:0502 jmp near 505 ; a 3-byte near jump
0100:0505 jmp far 50a ; a 5-byte far jump

可以将 near 前缀缩写为 ne。


区分字和字节内存位置

当某个操作数可以引用某个字内存位置或者字节内存位置时,必须用前缀 word ptr 或者前缀 byte ptr 指定数据类型。可接受的缩写分别是 wo 和 by。以下范例显示两种格式:

dec wo [si]
neg byte ptr [128]


指定操作数

Debug 使用包括在中括号 ([ ]) 的操作数引用内存地址的习惯用法。这是因为另一方面 Debug 不能区分立即操作数和内存地址的操作数。以下范例显示两种格式:

mov ax,21 ; load AX with 21h
mov ax,[21] ; load AX with the
; contents of
; memory location 21h


使用伪指令

使用 a 命令提供两个常用的伪指令:db 操作码,将字节值直接汇编到内存,dw 操作码,将字值直接汇编到内存。以下是两个伪指令的范例:

db 1,2,3,4,"THIS IS AN EXAMPLE"
db 'THIS IS A QUOTATION MARK:"'
db "THIS IS A QUOTATION MARK:'"
dw 1000,2000,3000,"BACH"


范例

a 命令支持所有形式的间接注册命令,如下例所示:

add bx,34[bp+2].[si-1]
pop [bp+di]
push [si] )

还支持所有操作码同义词,如下例所示:

loopz 100
loope 100
ja 200
jnbe 200

对于 8087 操作码,必须指定 wait 或 fwait 前缀,如下例所示:

fwait fadd st,st(3) ; this line assembles
; an fwait prefix


Debug:C(比较)


比较内存的两个部分。


c range address


参数

range

指定要比较的内存第一个区域的起始和结束地址,或起始地址和长度。有关有效的 range 值的信息,请单击“相关主题”列表中的“Debug 说明”。

address

指定要比较的第二个内存区域的起始地址。有关有效 address 值的信息,请单击“相关主题”列表中的“Debug 说明”。


说明

如果 range 和 address 内存区域相同,Debug 将不显示任何内容而直接返回到 Debug 提示符。如果有差异,Debug 将按如下格式显示:
address1 byte1 byte2 addess2

范例

以下命令具有相同效果:

c100,10f 300
c100l10 300

每个命令都对 100h 到 10Fh 的内存数据块与 300h 到 30Fh 的内存数据块进行比较。

Debug 响应前面的命令并显示如下信息(假定 DS = 197F):

197F:0100 4D E4 197F:0300
197F:0101 67 99 197F:0301
197F:0102 A3 27 197F:0302
197F:0103 35 F3 197F:0303
197F:0104 97 BD 197F:0304
197F:0105 04 35 197F:0305
197F:0107 76 71 197F:0307
197F:0108 E6 11 197F:0308
197F:0109 19 2C 197F:0309
197F:010A 80 0A 197F:030A
197F:010B 36 7F 197F:030B
197F:010C BE 22 197F:030C
197F:010D 83 93 197F:030D
197F:010E 49 77 197F:030E
197F:010F 4F 8A 197F:030F

注意列表中缺少地址 197F:0106 和 197F:0306。这表明那些地址中的值是相同的。


Debug:D(转储)


显示一定范围内存地址的内容。


d [range]


参数

range

指定要显示其内容的内存区域的起始和结束地址,或起始地址和长度。有关有效的 range 值的信息,请单击“相关主题”列表中的“Debug 说明”。如果不指定 range,Debug 程序将从以前 d 命令中所指定的地址范围的末尾开始显示 128 个字节的内容。

有关显示寄存器内容的信息,请单击“相关主题”列表中的 Debug R(寄存器)。


说明
当使用 d 命令时,Debug 以两个部分显示内存内容:十六进制部分(每个字节的值都用十六进制格式表示)和 ASCII 码部分(每个字节的值都用 ASCII 码字符表示)。每个非打印字符在显示的 ASCII 部分由句号 (.) 表示。每个显示行显示 16 字节的内容,第 8 字节和第 9 字节之间有一个连字符。每个显示行从 16 字节的边界上开始。

范例
假定键入以下命令:
dcs:100 10f
Debug 按以下格式显示范围中的内容:
04BA:0100 54 4F 4D 00 53 41 57 59-45 52 00 00 00 00 00 00 TOM.SAWYER......
如果在没有参数的情况下键入 d 命令,Debug 按以前范例中所描述的内容来编排显示格式。显示的每行以比前一行的地址大 16 个字节(如果是显示 40 列的屏幕,则为 8 个字节)的地址开头。
对于后面键入的每个不带参数的 d 命令,Debug 将紧接在最后显示的命令后立即显示字节内容。
如果键入以下命令,Debug 将从 CS:100 开始显示 20h 个字节的内容:
dcs:100 l 20
如果键入以下命令,Debug 将显示范围从 CS 段的 100h 到 115h 中所有字节的内容:
dcs:100 115

Debug:E(键入)

将数据输入到内存中指定的地址。
可以按十六进制或 ASCII 格式键入数据。以前存储在指定位置的任何数据全部丢失。

e address [list]

参数
address
指定输入数据的第一个内存位置。
list
指定要输入到内存的连续字节中的数据。
有关集成记忆码的信息,请单击“相关主题”列表中的 Debug A(汇编)。
有关显示内存部分内容的信息,请单击“相关主题”列表中的 Debug D (转储)。

说明

使用 address 参数

如果在没有指定可选的 list 参数的值情况下指定 address 的值,Debug 将显示地址和内容,在下一行重复地址,并等待您的输入。此时,您可以执行下列操作之一:

替换字节值。为此,请在当前值后键入新值。如果您键入的值不是有效的十六进制值,或该值包含两个以上的数字,则 Debug 不会回显无效或额外的字符。
进入下一个字节。为此,请按 SPACEBAR(空格键)。要更改该字节中的值,请在当前值后键入新值。如果按 SPACEBAR(空格键)时,移动超过了 8 位界限,Debug 程序将显示新的一行并在行首显示新地址。
返回到前一个字节。为此,请按 HYPHEN 键 (-)。可以反复按 HYPHEN 键 (-) 向后移动超过多个字节。在按 HYPHEN 时,Debug 开始新行并显示当前地址和字节值。
停止执行 e 命令。为此,请按 ENTER 键。在任何字节位置都可以按 ENTER。
使用 list 参数

如果指定 list 参数的值,随后的 e 命令将使用列表中的值替换现有的字节值。如果发生错误,将不更改任何字节值。

List 值可以是十六进制字节或字符串。使用空格、逗号或制表符来分隔值。必须将字符串包括在单或双引号中。

范例

假定键入以下命令:

ecs:100

Debug 按下面的格式显示第一个字节的内容:

04BA:0100 EB.

要将该值更改为 41,请在插入点键入 41,如下所示:

04BA:0100 EB.41_

可以用一个 e 命令键入连续的字节值。在键入新值后按 SPACEBAR(空格键),而不是按 ENTER 键。Debug 显示下一个值。在此范例中,如果按三次 SPACEBAR(空格键),Debug 将显示下面的值:

04BA:0100 EB.41 10. 00. BC._

要将十六进制值 BC 更改为 42,请在插入点键入 42,如下所示:

04BA:0100 EB.41 10. 00. BC.42_

假定决定值 10 应该是 6F。要纠正该值,请按 HYPHEN 键两次以返回到地址 0101(值 10)。Debug 显示以下内容:

04BA:0100 EB.41 10. 00. BC.42-
04BA:0102 00.-
04BA:0101 10._

在插入点键入 6f 更改值,如下所示:

04BA:0101 10.6f_

按 ENTER 停止 e 命令并返回到 Debug 提示符下。

以下是字符串项的范例:

eds:100 "This is the text example"

该字符串将从 DS:100 开始填充 24 个字节

Debug:F(填充)

使用指定的值填充指定内存区域中的地址。

可以指定十六进制或 ASCII 格式表示的数据。任何以前存储在指定位置的数据将会丢失。


f range list


参数

range

指定要填充内存区域的起始和结束地址,或起始地址和长度。关于有效的 range 值的信息,请单击“相关主题”列表中的“Debug 说明”。

list

指定要输入的数据。List 可以由十六进制数或引号包括起来的字符串组成。


说明

使用 range 参数

如果 range 包含的字节数比 list 中的数值大,Debug 将在 list 中反复指派值,直到 range 中的所有字节全部填充。

如果在 range 中的任何内存损坏或不存在,Debug 将显示错误消息并停止 f 命令。


使用 list 参数

如果 list 包含的数值多于 range 中的字节数,Debug 将忽略 list 中额外的值。


范例

假定键入以下命令:

f04ba:100l100 42 45 52 54 41

作为响应,Debug 使用指定的值填充从 04BA:100 到 04BA:1FF 的内存位置。Debug 重复这五个值直到 100h 个字节全部填满为止。


Debug:G(转向)


运行当前在内存中的程序。


g [=address] [breakpoints]


参数

=address

指定当前在内存中要开始执行的程序地址。如果不指定 address,Windows 2000 将从 CS:IP 寄存器中的当前地址开始执行程序。

breakpoints

指定可以设置为 g 命令的部分的 1 到 10 个临时断点。

有关执行循环、重复的字符串指令、软件中断或子程序的信息,请单击“相关主题”列表中的 Debug P(执行)。

有关执行指令的信息,请单击“相关主题”列表中的 Debug T(跟踪)。

Debug:H(十六进制)

对指定的两个参数执行十六进制运算。


h value1 value2


参数

value1

代表从 0 到 FFFFh 范围内的任何十六进制数字。

value2

代表从 0 到 FFFFh 范围内第二个十六进制数字。


说明

Debug 首先将指定的两个参数相加,然后从第一个参数中减去第二个参数。这些计算的结果显示在一行中:先计算和,然后计算差。


范例

假定键入以下命令:

h19f 10a

Debug 执行运算并显示以下结果。
02A9 0095

Debug:I(输入)


从指定的端口读取并显示一个字节值。

i port

参数

port

按地址指定输入端口。地址可以是 16 位的值。

有关将字节值发送到输出端口的信息,请单击“相关主题”列表中的 Debug O(输出)。


范例

假定键入以下命令:

i2f8

同时假定端口的字节值是 42h。Debug 读取该字节,并将其值显示如下:
42


Debug:L(加载)

将某个文件或特定磁盘扇区的内容加载到内存。

要从磁盘文件加载 BX:CX 寄存器中指定的字节数内容,请使用以下语法:

l [address]

要略过 Windows 2000 文件系统并直接加载特定的扇区,请使用以下语法:

l address drive start number


参数

address

指定要在其中加载文件或扇区内容的内存位置。如果不指定 address,Debug 将使用 CS 寄存器中的当前地址。

drive

指定包含读取指定扇区的磁盘的驱动器。该值是数值型:0 = A, 1 = B, 2 = C 等。

start

指定要加载其内容的第一个扇区的十六进制数。

number

指定要加载其内容的连续扇区的十六进制数。只有要加载特定扇区的内容而不是加载 debug 命令行或最近的 Debug n(名称)命令中指定的文件时,才能使用 drive、start 和 number 参数。

有关指定用于 l 命令的文件的信息,请单击“相关主题”列表中的 Debug n(名称)。

有关写入调试到磁盘的文件的信息,请单击“相关主题”列表中的 Debug w(写入)。


注意

使用不带参数的 l 命令

当使用不带参数的 l 命令时,在 debug 命令行上指定的文件将加载到内存中,从地址 CS:100 开始。Debug 同时将 BX 和 CX 寄存器设置为加载的字节数。如果不在 debug 命令行指定文件,所装入的文件将是最近使用 n 命令经常指定的文件。


使用具有 address 参数的 1 命令

如果使用带 address 参数的 l 命令,Debug 将从内存位置 address 开始加载文件或指定扇区的内容。


使用带全部参数的 l 命令

如果使用带所有参数的 l 命令,Debug 将加载指定磁盘扇区的内容而不是加载文件。


加载特定扇区的内容

指定范围内的每个扇区均从 drive 读取。Debug 从 start 开始加载,直到在 number 中指定的扇区数中的内容全部被加载。


加载 .exe 文件

Debug 忽略 .exe 文件的地址 address 参数。如果指定 .exe 文件,Debug 将文件重新定位到 .exe 文件的标题中指定的加载地址。在 .exe 文件被加载到内存前,标题自身从 .exe 文件脱离,因此磁盘上的 .exe 文件大小与内存中的不同。如果要检查整个 .exe 文件,请使用不同的扩展名重命名文件。


打开十六进制文件

Debug 将具有 .hex 扩展名的文件认为十六进制格式文件。键入不带参数的 l 命令,可以加载从十六进制文件中指定的地址处开始的十六进制文件。如果键入的 l 命令包含 address 参数,Debug 将把指定的地址加到在十六进制文件中找到的地址上,以确定起始地址。


范例

假定启动 Debug 并键入以下命令:

nfile.com

现在可以键入 l 命令以加载 File.com。Debug 将加载文件并显示 Debug 提示符。

假定需要从驱动器 C 将起始逻辑扇区为 15 (0Fh) 的 109 (6Dh) 个扇区的内容加载到起始地址为 04BA:0100 的内存中。为此,请键入以下命令:
l04ba:100 2 0f 6d


Debug:M(移动)

将一个内存块中的内容复制到另一个内存块中。

m range address


参数

range

指定要复制内容的内存区域的起始和结束地址,或起始地址和长度。

address

指定要将 range 内容复制到该位置的起始地址。

说明

复制操作对现有数据的影响

如果新数据没有写入正在被复制的数据块中的地址,则源数据将保持不变。但是,如果目标块已经包含数据(就象它在覆盖副本操作中一样),则将改写该数据。(覆盖复制操作是指那些目标数据块部分内容覆盖原数据块部分内容的操作。)


执行覆盖复制操作

m 命令执行目标地址的覆盖复制操作,而不丢失数据。将改写的地址内容首先复制。因此,如果将较高位地址的数据复制到较低位地址,则复制操作从原块的最低位地址开始并向最高位地址进行。反之,如果要将数据从低地址复制到高地址,复制操作从原块的最高地址开始,向最低地址进行。


范例

假定键入以下命令:

mcs:100 110 cs:500
Debug 首先将 CS:110 地址中的内容复制到地址 CS:510 中,然后将 CS:10F 地址中的内容复制到 CS:50F 中,如此操作直至将 CS:100 地址中的内容复制到地址 CS:500 中。要查看结果,请使用 Debug d(转储)命令,并使用 m 命令指定目标地址

Debug:N(名称)

指定 Debug l(加载)或 w(写入)命令的可执行文件的名称,或者指定正在调试的可执行文件的参数。


n [drive:][path] filename


要指定测试的可执行文件的参数,请使用以下语法:

n file-parameters


参数

如果在没有参数的情况下使用,则 n 命令清除当前规范。
[drive:][path] filename

指定要测试的可执行文件的位置和名称。

file-parameters

为正在测试的可执行文件指定参数和开关。

有关将文件或指定磁盘扇区的内容加载到内存中的信息,请单击“相关主题”列表中的 Debug L(加载)。

有关写入调试到磁盘的文件的信息,请单击“相关主题”列表中的 Debug W(写入)。


说明

n 命令的两个用途

可以按两种方式使用 n 命令。首先,您可以使用它以指定后面的 l(加载)或 w(写入)命令所使用的文件。如果在没有命名所调试文件的情况下启动 Debug,必须在使用 l 命令加载文件之前使用命令 nfilename。在 CS:5C 为文件控制块 (FCB) 正确编排文件名的格式。其次,可以使用 n 命令指定被调试文件的命令行参数和开关。


内存区域

以下四个内存区域都会受到 n 命令的影响:

内存位置
内容

CS:5C
文件 1 的文件控制数据块 (FCB)

CS:6C
文件 2 的文件控制数据块 (FCB)

CS:80
n 命令行的长度(以字符表示)

CS:81
n 命令行字符的开头


为 n 命令指定的第一个文件名被放在 CS:5C 的 FCB 中。如果指定第二个文件名,此名称将放置到 CS:6C 的 FCB 中。n 命令行上键入的字符数(除第一个字符之外,n)存储在位置 CS:80。n 命令行上的实际字符(再次,除了字母 n 之外)存储在以 CS:81 开头的位置。注意这些字符可以是在 Windows 2000 命令提示符下键入的命令中有效的任何开关和分隔符。

范例

假定已经启动 Debug,并加载了正在调试的程序 Prog.com。接着您决定为 Prog.com 指定两个参数并运行此程序。以下是此范例的命令序列:

debug prog.com
nparam1 param2
g

在这种情况下,Debug g(转向)命令会运行该程序,就好像您已在 Windows 2000 命令提示符后键入了如下命令:

prog param1 param2

所以,测试和调试反映 Prog.com 通常的运行时间环境。

在下面的命令序列中,第一个 n 命令将 File1.exe 指定为后接的 l(加载)命令的文件,该命令将 File1.exe 加载到内存。第二个 n 命令指定 File1.exe 将使用的参数。最后,g 命令将运行 File1.exe 文件,就好像您在 Windows 2000 命令行中键入了 File1 File2.dat File2.dat 一样。

nfile1.exe
l
nfile2.dat file3.dat
g

注意
不要在 n 命令的第二种形式后使用 l 命令。还要注意,如果现在使用 w(写入)命令,Windows 2000 将使用名称 File2.dat 保存正在调试的文件 File1.exe。为避免出现此结果,应该总是在 l 或 w 命令之前立即使用 n 命令的第一种形式。

Debug:O(输出)

将字节值发送到输出端口。


o port byte-value


参数

port

通过地址指定输出端口。端口地址可以是 16 位值。

byte-value

指定要指向 port 的字节值。

有关从输入端口读取字节值的信息,请单击“相关主题”列表中的 Debug I(输入)。

范例

要将字节值 4Fh 发送到地址为 2F8h 的输出端口,请键入以下命令:
o2f8 4f

Debug:P(执行)

执行循环、重复的字符串指令、软件中断或子例程;或通过任何其他指令跟踪。


p [= address] [number]


参数

=address

指定第一个要执行指令的位置。如果不指定地址,则默认地址是在 CS:IP 寄存器中指定的当前地址。

number

指定在将控制返回给 Debug 之前要执行的指令数。默认值为 1。

有关运行当前在内存中程序的信息,请单击“相关主题”列表中的 Debug G(转向)。

有关执行指令的信息,请单击“相关主题”列表中的 Debug T(跟踪)。


说明
控制传送到要测试的程序

当 p 命令将控制从 Debug 传送到要测试的程序时,该程序不间断运行,直到循环、重复字符串指令、软件中断或者完成了指定地址的子例程为止,或者直到执行了指定数量的机器指令为止。控制返回到 Debug。

地址参数的限制

如果 address 参数没有指定段,Debug 将使用被测试程序的 CS 寄存器。如果省略 address,程序将从 CS:IP 寄存器所指定的地址开始执行。必须在 address 参数之前使用等号 (=) 以便将它与 number 参数区分。如果在指定地址处的指令不是循环、重复的字符串指令、软件中断或子例程,则 p 命令与 Debug t(跟踪)命令的作用相同。

使用 p 命令显示的邮件

当 p 执行完一段说明后,Debug 显示出程序的寄存器内容、标志的状态以及下一段将要被执行的指令的解码形式。


警告

不能使用 p 命令跟踪只读内存 (ROM)。

范例

假定正在测试的程序在地址 CS:143F 处包含一个 call 指令。要运行 call 目标位置的子程序然后将控制返回到 Debug,请键入以下命令:

p=143f

Debug 按以下格式显示结果:
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=2246 ES=2246 SS=2246 CS=2246 IP=1443 NV UP EI PL NZ AC PO NC
2246:1442 7505 JNZ 144A

Debug:Q(退出)

停止 Debug 会话,不保存当前测试的文件。

当您键入 q 以后,控制返回到 Windows 2000 的命令提示符。


q


参数

该命令不带参数。
有关保存文件的信息,请单击“相关主题”列表中的 Debug W(写入)。

Debug:R(寄存器)


显示或改变一个或多个 CPU 寄存器的内容。


r [register-name]


参数

如果在没有参数的情况下使用,则 r 命令显示所有寄存器的内容以及寄存器存储区域中的标志。

register-name

指定要显示其内容的寄存器名。

有关显示内存部分内容的信息,请单击“相关主题”列表中的 Debug D(转储)。

有关反汇编字节的信息,请单击“相关主题”列表中的 Debug U(反汇编)。


说明

使用 r 命令

如果指定了寄存器名称,Windows 2000 将显示以十六进制标记表示的寄存器的 16 位值,并将冒号显示为提示符。如果要更改包含在寄存器中的值,除非键入新值并按 ENTER 键;否则,请按 ENTER 键返回 Debug 提示符。

有效寄存器名

以下是 register-name 的有效值:ax、bx、cx、dx、sp、bp、si、di、ds、es、ss、cs、ip、pc 及 f。ip 和 pc 都引用指令指针。

如果指定寄存器名称,而不是从前面的列表中指定,Windows 2000 将显示以下消息:

br error

使用 f 字符而不是寄存器名

如果键入 f 字符代替寄存器名,Debug 将每个标记的当前设置显示为两字母代码,然后显示 Debug 提示符。要更改标志的设置,请从下表中键入适当的两字母代码:

标志名
设置
清除

溢出
ov
nv

方向
dn(减)
up(增)

中断
ei(启用)
di(禁用)

正负
ng(负)
pl(正)


zr
nz

辅助进位
ac
na

奇偶校验
pe(偶校验)
po(奇校验)

进位
cy
nc


可以按任何顺序键入新的标志值。不需要在这些值之间留出空格。要停止 r 命令,请按 ENTER 键。任何没有指定新值的标志保持不变。

用 r 命令显示的邮件

如果为标记指定了多个值,Debug 将显示以下消息:

df error

如果指定没有在前面的表中列出的标志代码,Debug 将显示以下消息:

bf error

在这两种情况下,Debug 将忽略所有在无效项目之后指定的设置。

Debug 的默认设置

在启动 Debug 时,会将段寄存器设置到空闲内存的低端,指令指针设置为 0100h,清除所有标志,并且将其余寄存器设置为零,除了被设置为 FFEEh 的 sp 之外。

Debug:R


范例

要查看所有寄存器的内容、所有标记的状态和当前位置的指令解码表,请键入以下命令:

r

如果当前位置是 CS:11A,显示外观将类似于以下内容:

AX=0E00 BX=00FF CX=0007 DX=01FF SP=039D BP=0000 SI=005C DI=0000
DS=04BA ES=04BA SS=04BA CS=O4BA IP=011A NV UP DI NG NZ AC PE NC
04BA:011A CD21 INT 21

要只查看标志的状态,请键入以下命令:

rf

Debug 按以下格式显示信息:

NV UP DI NG NZ AC PE NC - _

现在,您可以按任意顺序键入一个或多个有效的标志值,其中可以有或没有空格,如下所示:

nv up di ng nz ac pe nc - pleicy

Debug 结束 r 命令并显示 Debug 提示符。要查看更改,请键入 r 或 rf 命令。Debug 将显示以下内容:

NV UP EI PL NZ AC PE CY - _
按 ENTER 返回到 Debug 提示符。

Debug:S(搜索)

在某个地址范围搜索一个或多个字节值的模式。


s range list


参数

range

指定要搜索范围的开始和结束地址。有关 range 参数有效值的信息,请单击“相关主题”列表中的 Debug。

list

指定一个或多个字节值的模式,或要搜索的字符串。用空格或逗号分隔每个字节值和下一个字节值。将字符串值包括在引号中。


说明

如果 list 参数包含多个字节值,Debug 将只显示出现字节值的第一个地址。如果 list 只包含一个字节值,Debug 将显示指定范围内出现该值的所有地址。


范例

假定需要查找包含值 41 并且范围从 CS:100 到 CS:110 的所有地址。为此,请键入以下命令:

scs:100 110 41

Debug 按以下格式显示结果:

04BA:0104
04BA:010D
-

以下命令在 CS:100 到 CS:1A0 的范围内搜索字符串“Ph”。
scs:100 1a0 "Ph"

Debug:U(反汇编)


反汇编字节并显示相应的原语句,其中包括地址和字节值。反汇编代码看起来象已汇编文件的列表。


u [range]


参数

如果在没有参数的情况下使用,则 u 命令分解 20h 字节(默认值),从前面 u 命令所显示地址后的第一个地址开始。

range

指定要反汇编代码的起始地址和结束地址,或起始地址和长度。有关 range 参数有效值的信息,请单击“相关主题”列表中的 Debug。

有关集成记忆码的信息,请单击“相关主题”列表中的 Debug A(汇编)。

有关显示内存部分内容的信息,请单击“相关主题”列表中的 Debug D(转储)。

范例

要反汇编 16 (10h) 字节,从地址 04BA:0100 开始,请键入以下命令:

u04ba:100l10

Debug 按以下格式显示结果:

04BA:0100 206472 AND [SI+72],AH
04BA:0103 69 DB 69
04BA:0104 7665 JBE 016B
04BA:0106 207370 AND [BP+DI+70],DH
04BA:0109 65 DB 65
04BA:010A 63 DB 63
04BA:010B 69 DB 69
04BA:010C 66 DB 66
04BA:010D 69 DB 69
04BA:010E 63 DB 63
04BA:010F 61 DB 61

如果只显示从 04BA:0100 到 04BA:0108 特定地址的信息,请键入以下命令:

u04ba:0100 0108

Debug 显示以下内容:

04BA:0100 206472 AND [SI+72],AH
04BA:0103 69 DB 69
04BA:0104 7665 JBE 016B
04BA:0106 207370 AND [BP+DI+70],DH

Debug:W(写入)

将文件或特定分区写入磁盘。

要将在 BX:CX 寄存器中指定字节数的内容写入磁盘文件,请使用以下语法:


w [address]


要略过 Windows 2000 文件系统并直接写入特定的扇区,请使用以下语法:

w address drive start number


参数

address

指定要写到磁盘文件的文件或部分文件的起始内存地址。如果不指定 address,Debug 程序将从 CS:100 开始。关于 address 参数有效值的信息,请在“相关主题”列表中单击 Debug。

drive

指定包含目标盘的驱动器。该值是数值型:0 = A, 1 = B, 2 = C,等等。

start

指定要写入第一个扇区的十六进制数。

number

指定要写入的扇区数。

有关指定用于 w 命令的文件的信息,请单击“相关主题”列表中的 Debug N(名称)。

有关将文件或文件扇区内容加载到内存中的信息,请单击“相关主题”列表中的 Debug L(加载)。

说明

必须在启动 Debug 时或者在最近的 Debug n(名称)命令中指定磁盘文件的名字。这两种方法都可以将地址 CS:5C 处文件控制块的文件名正确地编排格式。


在使用不带参数的 w 命令之前重新设置 BX:CX

如果使用了 Debug g(转向)、t(跟踪)、p(执行)或 r(寄存器)命令,必须在使用无参数的 w 命令之前,将 BX:CX 寄存器复位。

将修改后的文件写入磁盘

如果修改文件但不更改文件名、长度或起始地址,Debug 仍然可以正确地将文件写入源磁盘位置。

w 命令的限制

不能用该命令写入 .exe 或 .hex 文件。

警告

因为略过 Windows 2000 文件句柄,所以写入特定的分区非常危险。如果键入错误的值,则磁盘文件结构很容易被损坏。

范例

假定要将起始地址为 CS:100 的内存内容写入到驱动器 B 的磁盘中。需要将数据从磁盘的逻辑扇区号 37h 开始并持续 2Bh 个扇区。为此,键入以下命令:

wcs:100 1 37 2b

当写操作完成时,Debug 再次显示 Debug 提示符。

Debug:XA(分配扩展内存)

分配扩展内存的指定页面数。

要使用扩展内存,必须安装符合 4.0 版的 Lotus/Intel/Microsoft 扩展内存规范 (LIM EMS) 的扩展内存设备驱动程序。


xa [count]


参数

count

指定要分配的扩展内存的 16KB 页数。

有关使用扩展内存的其他 Debug 命令的信息,请单击“相关主题”列表中的 XD(释放扩展内存)、XM(映射扩展内存页)或 XS(显示扩展内存状态)。

说明

如果指定的页面数可用,则 Debug 将显示消息,此消息表明所创建的句柄的十六进制数;否则,Debug 将显示错误消息。

Debug:XA

范例

要分配扩展内存的 8 个页面,请键入以下命令:

xa8

如果命令成功,Debug 将显示类似的以下消息:
Handle created=0003

Debug:XD(释放扩展内存)


释放指向扩展内存的句柄。

要使用扩展内存,必须安装符合 4.0 版的 Lotus/Intel/Microsoft 扩展内存规范 (LIM EMS) 的扩展内存设备驱动程序。


xd [handle]


参数

handle

指定要释放的句柄。

有关使用扩展内存的其他 Debug 命令的信息,请单击“相关主题”列表中 XA(分配扩展内存)、XM(映射扩展内存页) 或 XS(显示扩展内存状态)。

范例

要释放句柄 0003,请键入以下命令:

xd 0003

如果命令成功,Debug 将显示下列消息:
Hdle 0003 deallocated

Debug:XM(映射扩展内存页)


将属于指定句柄的扩展内存逻辑页映射到扩展内存的物理页。

要使用扩展内存,必须安装符合 4.0 版的 Lotus/Intel/Microsoft 扩展内存规范 (LIM EMS) 的扩展内存设备驱动程序。


xm [lpage] [ppage] [handle]


参数

lpage

指定要映射到物理页 ppage 的扩展内存的逻辑页面号。

ppage

指定将 lpage 映射到的物理页面号。

handle

指定句柄。

有关使用扩展内存的其他 Debug 命令的信息,请单击“相关主题”列表中的 XA(分配扩展内存)、XD(释放扩展内存)或 XS(显示扩展内存)。


范例

要将句柄 0003 的逻辑页 5 映射到物理页 2,请键入以下命令:

xm 5 2 0003

如果命令成功,Debug 将显示下列消息:

Logical page 05 mapped to physical page 02

Debug:XS(显示扩展内存状态)


显示有关扩展内存状态的信息。

要使用扩展内存,必须安装符合 4.0 版的 Lotus/Intel/Microsoft 扩展内存规范 (LIM EMS) 的扩展内存设备驱动程序。


xs


参数

该命令不带参数。

有关使用扩展内存的其他 Debug 命令的信息,请单击“相关主题”列表中的 XA(分配扩展内存)、XD(释放扩展内存)或 XM(映射扩展内存页)。


说明

Debug 显示的信息有如下格式:

Handle xx has xx pages allocated
Physical page xx = Frame segment xx
xx of a total xx EMS pages have been allocated
xx of a total xx EMS handles have been allocated


范例

要显示扩展内存信息,请键入以下命令:

xs

Debug 显示与以下类似的信息:

Handle 0000 has 0000 pages allocated
Handle 0001 has 0002 pages allocated
Physical page 00 = Frame segment C000
Physical page 01 = Frame segment C400
Physical page 02 = Frame segment C800
Physical page 03 = Frame segment CC00
2 of a total 80 EMS pages have been allocated
2 of a total FF EMS handles have been allocated
(全文完)

由 beat 发表于 下午01点30分 | 回复 (0) | 顶端

Debug应用实例秀(zz)

豪华绚丽的Windows让人们把DOS抛到遥远的记忆角落。然而,真正有价值的东西不会轻易退出历史的舞台,Debug就是这样的经典作品之一。从古老的DOS到现今的Windows XP,Debug一直紧紧跟随着微软的操作系统,静静躺在系统文件夹里。也许你平时对它不闻不问,但要想成为人人羡慕的系统高手,我们就得唤醒这个沉睡已久的命令行工具了,通过阅读本文对它的研究,相信你会同笔者一样的感觉到:姜,还是老的辣!

一、寻根溯源:世界第一只计算机BUG和Debug

  霍德华·艾肯在哈佛大学攻读物理学博士学位时,开始梦想制作一台计算机帮他解决数学难题,工作后,他找到IBM公司为其投资100万美元研制计算机,第一台成品艾肯把它取名为:马克Ⅰ号,又叫“自动序列受控计算机”,从这时起IBM公司由生产制表机、肉铺磅秤、咖啡碾磨机等乱七八糟玩意的行业,正式跨进了计算机“领地”。

  1945年9月9日,为马克II号编制计算程序的女数学家格雷斯·霍波在调试程序时出现了故障,拆开继电器后,发现有只飞蛾被夹扁在触点中间,从而“卡”住了机器的运行。于是霍波把这只飞蛾粘在了计算机的工作日志中,并恢谐地把程序故障统称为“臭虫”(bug),自此以后,只要这台计算机一停止运转(那时候是经常的事),同事们就会开玩笑地对霍德华·艾肯说,我们正在“Debug”(除虫)呢!后来“bug”成为计算机领域的专业行话,如DOS系统中的调试程序,程序名称就叫Debug。

  目前那只飞蛾还保存在美国史密森尼博物院的美国历史国家博物馆中呢。

  1981年,第一个PC DOS(即DOS 1.00)面世时就已经带上了Debug.com。不过,到目前为止,Debug一直没有大的变动——当然,这是指Debug提供给用户的功能,Debug本身代码、内部运行机制必然随着操作系统的变化而不断改变。然而,无论是Windows 98、2000还是XP,Debug的操作方式与纯DOS环境下基本一样。

debug.jpg

二、初学乍练:短短几行命令学用Debug

  Debug.exe文件位于Windows\system32目录(Windows XP)或Windows\command目录(Windows 9x)下。基本使用方法如下:

Step 1:点击“开始→运行”,输入“CMD”(Windows 2000/XP)或“Command”(Windows 9x)打开命令提示符窗口。

  Step 2:输入“Debug”并回车,出现提示符“-”,现在你已经开启了神秘的Debug世界了。

  小提示

  执行“?”命令可以参看Debug主要命令及参数。

  Step 3:输入“D FE00:0”,回车后可以看到结果(见图1),这个就是主板BIOS的厂商信息。接着再输入“D FFFF:5 L 8”,回车后,主板的BIOS版本日期也出来了。

debug2.jpg

Step 4:现在再输入“Q”命令,回车后就退出了Debug程序。

三、继续深入:Debug经典实例秀

  在操作以下实例之前,提醒您要注意操作安全,因为Debug命令有一定风险,如果输入错误,有可能对系统造成一定破坏,这点请您一定注意。

  实例1:查看你的显卡信息

  输入“D C000:0090”命令并回车,这时右侧部分可以看到系统中显卡的显存、生产厂商等信息。

实例2:制作BIOS密码破解器

  忘记BIOS密码,一般都采用放电法来清空密码,但这对普通用户有一定难度,并且还得开机箱。其实利用Debug的0命令则简单得多!请在“-”后输入以下命令:

  o 70 19
  o 71 15
  q

  重启电脑,系统提示CMOS校验和出错,并要求重新进入BIOS设置CMOS。

  小提示:70和71是CMOS的两个端口,我们可以在它们的后面随意写入一些错误数据(如19、16、17等),就会清空CMOS里所有设置,如果不见效不妨多用几个数据试试。

  如果觉得每次输入Debug命令太麻烦,可以用下面的方法把命令存成一个COM文件,需要解除密码时只要运行一下就行了。请在Debug中命令提示符“-”后输入以下命令:

  A 100
  MOV DX,70
  MOV AL,10
  OUT DX,AL
  MOV DX,71
  MOV AL,01
  OUT DX,AL(这里要两次回车,接着会出现“-”提示符,然后再输入下面的命令)
  R CX(回车后会出现“CX 0000”,然后再次按回车)
  0C
  N pass.COM
  W
  Q

  这样就会在Debug当前目录下生成pass.com,是一个清除BIOS口令设置的程序,只要在DOS提示符下键入“pass”,然后按回车即可。经我们测试,其实在Windows下面运行也可以成功。知识不太稳定,有时会重新启动计算机。

实例3:检测LCD显示器的坏点

  购买LCD显示器最忌有亮点或暗点,我们可以借助相关的检测软件来辅助查看,但在配电脑时,老板常常不让我们装软件,其实利用Debug中的F命令就可以看得清清楚楚!

  为了检测LCD屏幕是否存在坏点,可以将整个屏幕填充为红、绿、蓝、白等纯色,以便检查。下面给出几个常用的显示屏检测F命令(Debug窗口一般较小,按Alt+Enter将它放大到整个屏幕):


  F B800:00 F9F 20 70 全屏白色
  F B800:00 F9F 20 40 全屏红色
  F B800:00 F9F 20 20 全屏绿色
  F B800:00 F9F 20 10 全屏蓝色
  F B800:00 F9F C5 07 C4 07 全屏白色十字网格
  F B800:00 F9F C5 04 C4 04 全屏红色十字网格
  F B800:00 F9F C5 02 C4 02 全屏绿色十字网格
  F B800:00 F9F C5 01 C4 01 全屏蓝色十字网格

实例4:用Debug恢复Windows 98启动

  在同时装有Windows 98和Windows 2000的电脑上,有时在Windows 98下整理C盘的磁盘碎片后(假设Windows 98装在C盘),下次很有可能启动不了Windows 98。这时必须重新生成BOOTSECT.DOS(此文件是用来引导Windows 98的),Windows 98才可以重新引导。可以用Debug生成BOOTSECT.DOS文件,先用软盘启动到DOS状态:

  C:>Debug
  L 100 2 0 1
  N BOOTSECT(BOOTSECT表示Windows 98引导记录的文件名)
  RCX
  CX 0000
  200
  W
  Q

  现在将C:\BOOTSECT改名为BOOTSECT.DOS,覆盖原来的BOOTSECT.DOS即可。

  做个死循环炸弹玩玩

  所谓死循环,实际上是编程上一种失误,造成的程序反复执行同样指令,造成软件死锁。利用Debug,我们可以做一个小小的死循环。在Debug的命令提示符“-”后输入以下命令:

  a100
  mov dl,1
  mov ah,2
  int 21
  inc dl
  jmp 102(按两次回车)
  nboot.com
  rbx(接着按两次回车,可能会出现出错信息,不要管它,再输入一遍即可)
  rcx
  a
  -w

  好了,现在可以在DOS下面执行生成的boot.com试试效果吧,同时按ctrl+break或ctrl+c可以强制停止。如果是在windows下,强制退出即可,不过PC喇叭的声音可能得过段时间才能停下来。

三、硬盘救命稻草:用Debug玩转磁盘

  特别提醒:由于以下操作非常危险,所以建议你三思而行,并且最好在电脑中只挂接要操作的硬盘,以免误操作了其他硬盘。

  实例1:清除硬盘驱动器的所有信息

  本来清除硬盘信息用Fdisk便可以轻松搞定,可如果当你碰上用FDISK命令无法删除分区信息的情况,甚至是一运行FDISK就死机,那么就不得不求助于Debug了。通过下面的命令,可以清除硬盘上所有分区信息。

  小提示:危险操作!请慎重执行!

C:\ >Debug
  F 200 L1000 0
  A CS:100
  xxxx:0100 MOV AX,301
  xxxx:0103 MOV BX,200
  xxxx:0106 MOV CX,1
  xxxx:0109 MOV DX,80 (注意:80代表主盘,81代表从盘)
  xxxx:010C INT 13
  xxxx:010E INT 20
  xxxx:0110
  g
  Program terminated normally
  q

  以上程序执行完毕后,重启电脑,此时硬盘的分区信息都已经被清除,我们便可以使用Fdisk为硬盘进行重新分区,然后格式化即可正常使用了。

  小提示:删除所有分区

  如果想快速删除所有分区,那么可将以下命令保存到一个文本文件中(比如:Delpart.txt ):

  a 100 int13rax
  0301
  rbx
  0200
  f 200 l 200 0
  rcx
  0001
  rdx
  0080
  p
  q

  然后在纯DOS(比如用启动软盘启动系统)中执行Debug

实例2:拯救软盘数据

  一分钟前还打得开的软盘,一分钟后就说“该软盘没有格式化,要格式化么?”但这里面却偏偏保存着重要数据,其实出现这种情况往往是软盘的0面0道1扇区逻辑损坏的原因,这时可以试试以下方法:

  Step 1:将一张好的软盘插入软驱。

  Step 2:执行Debug,并在提示符“-”后输入以下命令:
  
  -L 100 0 0 1

  Step 3:将好的软盘取出,插入需要恢复的软盘,再输入以下命令:

  -W 100 0 0 1

  不过,如果0面0道1扇是物理损坏,DEBUG会告诉我们不能写盘,这时,你只能再尝试HD-COPY等工具软件了。

实例3:清除硬盘的主引导记录

  如果你遇到了FDISK不能识别硬盘,或在电脑启动时出现没有硬盘的错误提示,比如:“Fixed disk 0 Failure”,那么可以试试下面的方法,但是要注意的是,这样会删除所有硬盘分区(包括非DOS分区),当然数据也会全部丢失。

  Step 1:制作一张启动软盘,其中包括:DEBUG、FDISK、FORMAT等程序。用它启动电脑,输入“Debug”并回车。

  Step 2:在Debug的命令提示符“-”后输入以下命令:

  FCS:200 400 0
  RAX
  0301
  RBX
  0600
  RCX
  0001
  RDX
  0080
  E 100 CD 13
  P
  Q

  Step 3:完成后分别运行FDISK和Format进行分区和格式化即可。

  实例4:低格硬盘

  方法一:完全低格

  -a 100
  mov ax,0703
  mov cx,0001
  mov dx,0080
  int 13
  int 3
  010D
  G 100

  小提示:有些主板的BIOS中已经存放着低格程序,因此可以直接用Debug来调用,命令为“g c800:0005”。

  方法二:快速低格

  -a 100
  mov ax,0500
  mov bx,0180
  mov cx,0001
  mov dx,0080
  int 13
  int 3
  E 0180 0 0 0002
  G 100

  你知道吗?

  Windows 2000/XP的Debug模式

  打开启动分区的“boot.ini”文件,接着在“multi(0)disk(0)rdisk(0)partition(1)\WINNT="Microsoft Windows 2000 Professional" /fastdetect”语句后面加一个空格,然后再输入“/DEBUG”,在启动Windows 2000/XP时调入系统中的除错程序,它可以在任何时间激活,这个参数可以用来解决有规律发生的错误。

  如果换为“/CRASHDEBUG”,那么在系统核心没有发生错误之前不会生效,如果遇到随机的内核错误,它就会帮你除错了。

由 beat 发表于 下午01点14分 | 回复 (0) | 顶端

2006年04月08日 星期六

使用ASCIIMathML.js使网页支持latex

ASCIIMathML主页:http://www1.chapman.edu/~jipsen/mathml/asciimath.html

浏览器:Netscape7.1/Mozilla/Firefox或 Internet Explorer 6 + MathPlayer

示例:


$e^{i\pi}=\cos\pi+i\sin\pi=1$
源码:
<script type="text/javascript" src="http://www1.chapman.edu/~jipsen/mathml/ASCIIMathML.js"></script>
\$e^{i\pi}=\cos\pi+i\sin\pi=1\$

由 beat 发表于 下午11点32分 | 回复 (0) | 顶端

2006年03月31日 星期五

SuSE 10 apache2 启用用户网站目录

SuSE 10默认安装apache2时没有将mod_userdir.conf模块添加到配置文件中,只需要修改/etc/apache2/httpd.conf,
添加一行

Include /etc/apache2/mod_userdir.conf

重新加载配置即可。

由 beat 发表于 下午07点58分 | 回复 (0) | 顶端

2006年03月30日 星期四

2005年10月24日 星期一

BSD Sockets

Here is something I picked up on the Net.
This file contains exaples of client and servers using several protocols, might be very usefull.


BSD Sockets
Sockets are a generalized networking capability first introduced in 4.1cBSD and subsequently refined into their current form with 4.2BSD. The sockets feature is available with most current UNIX system releases. (Transport Layer Interface (TLI) is the System V alternative). Sockets allow communication between two different processes on the same or different machines. Internet protocols are used by default for communication between machines; other protocols such as DECnet can be used if they are available.
To a programmer a socket looks and behaves much like a low level file descriptor. This is because commands such as read() and write() work with sockets in the same way they do with files and pipes. The differences between sockets and normal file descriptors occurs in the creation of a socket and through a variety of special operations to control a socket. These operations are different between sockets and normal file descriptors because of the additional complexity in establishing network connections when compared with normal disk access.

For most operations using sockets, the roles of client and server must be assigned. A server is a process which does some function on request from a client. As will be seen in this discussion, the roles are not symmetric and cannot be reversed without some effort.

This description of the use of sockets progresses in three stages:

The use of sockets in a connectionless or datagram mode between client and server processes on the same host. In this situation, the