在用Linux时不止一次被各种控制字符困扰,今天决定清算一下,以下便是成果。

ASCII控制字符

ASCII控制字符(ASCII字符集中的0~37)一般显示为^X,其中X是相应控制字符代码值加64(8进制100)所构成的字符。比如BS(退格)显示为^H,因为BS + 64 = 8 + 64 = 72 = H。在终端里输入这些控制字符的方法是ctrl + X,这里的X不需要区分大小写。

这样就能解释为什么vim有时会显示诸如^M、^J这样的让人眼花的东西。先说一下文本文件的格式:MAC/UNIX/PC。MAC格式的文本文件用ASCII CR(回车,'\r')分隔行;UNIX格式用ASCII LF(换行,'\n');PC格式则用ASCII CR + LF("\r\n")。vim可以正确、利索地显示任一格式,不像Windows记事本那样不能对UNIX和MAC格式分行,但是如果文件中混合着这三种分隔符,vim似乎是以非常民主的方式(少数服从多数)选择其中一种作为行分隔符,落选的则显示为^X。比如,假如vim认为文件是MAC格式的,那么CR就是分隔符,LF则显示为^J;假如是UNIX格式,则CR被显示为^M。

UNIX终端特殊输入字符

有些ASCII控制字符在UNIX终端里是有特殊含义的,比如ASCII DC3(^S)表示STOP(从终端的观点看,STOP是一个字符的名称),意为停止输出,按下这个键后,无论再键入什么,终端也不会有任何回显,但实际上仍然是可以接受、执行命令行的,据说这项功能是为了在网络条件不好时减少掉线的情况。与之相对应的是ASCII DC1(^Q)表示START,意为恢复输出。所以,如果不小心按了ctrl + S,再按ctrl + Q就可以了。

然而我也碰过ctrl + Q死活不作为的情形,非常郁闷,不得不放弃那个会话,损失自是相当惨重。现在估计,那是因为终端的START字符被更改了,不再关联到^Q上。

是的,终端特殊字符到ASCII控制字符的映射几乎全部可以更改,除了CR(回车)和NL(换行)。《UNIX环境高级编程》表18-6是一个关于这些字符的详细清单。

^S <=> STOP 和 ^Q <=> START 只是典型情况,却非唯一。此外再比如^H <=> ERASE(删除字符),我曾经遇到过这种情况:进入sftp后,每次按BS键都蹦出来^H(也有时候是^?),急得一败涂地。

要更改终端特殊字符,在命令行中用stty命令可以很方便地做到,stty print or change terminal characteristics。针对刚才说的BS键回显成^H不起作用的情况,这样就可以了:

stty erase ^H

意思是,^H will erase the last character typed。

用stty -a可以print all current settings in human-readable form。

P.S. 并非只有ASCII控制字符才可以作为UNIX终端特殊字符,普通的可打印字符也可以,只不过这样做没有实际意义而已,如果执行stty erase b,那你每敲一个b就会吃掉上一个字符,自然也就没法上b这个字母上屏了。

2009-03-03

CRANK OR SMASH

自从看过冯小刚的《非诚勿扰》后,电视上葛优拍的所有广告我看着都烦。我对葛优的那一套手段本来是几乎百看不厌的,可是被这个电影弄得彻底疲劳了。

08年下半年的党费还没交,可能是故意的。

 

~~~~~~~~~

 

婚纱照按计划拍了,看起来没完没了的雨居然在这个周末很知趣地歇了两天,我也不抱怨啥了。

这些天偶尔会玩会儿大波萝,这回用野蛮人,一丝不苟地打怪、拣垃圾。名字就叫CRANK,符合我每天等红灯时的暴躁情绪。


2009-02-26

tonight

雨声,计算机文档,抒情摇滚,哑铃,牛奶,红枣,白开水。


正在虚拟机上安装企业版的linux,同是在开着电影《地球停转之日》。

个人版的几个月没碰了:没有显示驱动,连看RMVB电影都卡;ppp拔号上网曾经行过的,后来怎么也找不到modem。装企业版纯粹是为了方便学习。

前些天尝试在虚拟机上安装SUSE 10 SP2,几乎抓狂,总是说找不到CD,换了几个别的发行版的镜像才确定是镜像文件的问题,奇怪的是在真实机器上能够安装的。

--

这些天一直在下雨,上午尤其大。鞋子几乎湿透了,这让我有些窝火,因为我本来要穿那双好一点的户外品牌的鞋子的,可安非让我穿另一双破的。下次,只要下雨我就穿它,多花点钱换来的防水性能不是只为了精神安慰。

如果周末还这样下就扯了,计划(yep,计划)那时拍婚纱照的。

--

装好了。电影看起来还不错,看《黑客帝国》时就觉得这小伙有些不同寻常的气质。

!!! CSS规范中可能不包括任何意义上的变量,这里只是一个直观的说法。

今天写了一个jscript脚本,它扫瞄一个文本文件,遇到 $name=value 就记录一个变量定义,遇到右边没有等号的 $name 就替换成先前定义的值或包含警告内容的注释(/*WARNING: undefined ...*/)文本。

写这个脚本的主要动机是在CSS中使用变量(实际是具有C/C++宏效果的常量)。我可以在CSS文件的前部的注释中定义颜色变量,然后在后面引用它,写好后,用这个脚本把包含了这种变量的CSS文件转换成符合CSS规范的文件。

次要动机是这几天对脚本程序手痒,写程序的愿望临时超过了打游戏的。这个程序主要使用了正则表达式来完成任务,以前用C#写一个代码高亮程序时,大量使用了正则表达式,这回虽然在内容上没有超越,不过毕竟是在新环境中使用,边查手册边写,有些东西暂时还不透彻,所以显得很有技巧性。比如在string.replace()方法中,替换文本中可以包含捕获的表达式,但是如果要把这个表达式直接用作字典对象的关键字,貌似不行。不过它可以用作函数的参数,于是我在代码中就地创建了一个函数来访问字典对象。而作为函数参数的话,捕获表达式的索引也有变化。

这个脚本的用法是这样的,比如我把它保存为CSS-preprocessor.js,在一个名为current.src.css的文件中写如下CSS代码:

/*current.src.css

...

DEFINE COLORS
-------------

$pageForeColor=#FFF
$pageBgColor=#CCC

$pageHeadBgColor=#214552
$pageHeadForeColor=#FFF
$pageHeadForeColor_a=#FFF
$pageHeadDescColor=#FFF

$pageFooterBgColor=#FFF

$boxBgColor=#FFF
$contentForeColor=#FFF
$contentBgColor=#214552

$moduleBgColor=#CFDFBF
$moduleForeColor=#564b47

$unimportantColor=#999 // minor description text
$headlineColor=#FF9900 // h1,h2,h3...

$textBlockBorderColor=#FFF // pre, quote, etc.
$textBlockBgColor=#315562;

$postbodyForeColor=#FFF
$postbodyForeColor_a=#8FDFFF
$postDateColor=#446677
$postTitleColor=#FF9900
$postTitleColor_a=#FF9900
$postHeadlineColor=#FF9900
$postFooterBgColor=#8FDFFF

$moduleHeadColor=#FF9900
$moduleBorderColor=#226699
$moduleText_a=#226699

$commentsBorderColor=#999
$commentsTextColor=#FFF
$commentsBgColor=#315562

*/


body {
font-size: small;
font-family: Verdana, Tahoma, Arial, Helvetica, sans-serif;
text-align:center;
margin:0px;
padding:0 0 20px 0;
color: $pageForeColor;
background-color: $pageBgColor;
}

...

写好这个CSS后,在windows命令行中执行cscript CSS-preprocessor.js current.src.css current.css,屏幕上显示:

#13     $pageForeColor = #FFF
#14 $pageBgColor = #CCC
#16 $pageHeadBgColor = #214552
#17 $pageHeadForeColor = #FFF
#18 $pageHeadForeColor_a = #FFF
#19 $pageHeadDescColor = #FFF
#21 $pageFooterBgColor = #FFF
#23 $boxBgColor = #FFF
#24 $contentForeColor = #FFF
#25 $contentBgColor = #214552
#27 $moduleBgColor = #CFDFBF
#28 $moduleForeColor = #564b47
#30 $unimportantColor = #999
#31 $headlineColor = #FF9900
#33 $textBlockBorderColor = #FFF
#34 $textBlockBgColor = #315562
#36 $postbodyForeColor = #FFF
#37 $postbodyForeColor_a = #8FDFFF
#38 $postDateColor = #446677
#39 $postTitleColor = #FF9900
#40 $postTitleColor_a = #FF9900
#41 $postHeadlineColor = #FF9900
#42 $postFooterBgColor = #8FDFFF
#44 $moduleHeadColor = #FF9900
#45 $moduleBorderColor = #226699
#46 $moduleText_a = #226699
#48 $commentsBorderColor = #999
#49 $commentsTextColor = #FFF
#50 $commentsBgColor = #315562
#61 $pageForeColor -> #FFF
#62 $pageBgColor -> #CCC
#67 $headlineColor -> #FF9900
#89 $textBlockBorderColor -> #FFF
#90 $textBlockBgColor -> #315562
#106 $boxBgColor -> #FFF
#128 $contentForeColor -> #FFF
#129 $contentBgColor -> #214552
#136 $moduleBgColor -> #CFDFBF
#141 $pageHeadBgColor -> #214552
#148 $pageFooterBgColor -> #FFF

每行的开头是行号,余下内容表示脚本在CSS源文件中的这一行找到了一个变量的定义或引用,分别用 = 和 -> 标识。

同时,转换后的CSS被输出到current.css文件中。

以下是jscript脚本的完整内容:

/*
CSS-preprocessor.js

CSS user defined variables preprocessor 1.0 - replace variables reference with their values.

the "variable" here is something defined in css remark by the following:

$<name>=<value>

and referenced like this, e.g.:

color: $pageForeColor;

seems like php variable, but essentially it's C/C++ macro.

how to use:
(1)define and use variables in css "source" file;
(2)process the css source file with this jscript, e.g.:

C:\>cscript this.js current.src.css current.css;

in css source file, anything with the form of "$name=value" is considered as a variable definition. note that any number of blank(including tab and newline) on both side of "=" is allowed, and, to define multiple variables in a single line is possible.

anything not variable definition with the form of "$name" is considered as a variable reference, and will be replaced with it's value defined before. a undefined variable reference will be replaced with a warning remark.

--
pzy 2008-12-6
*/

// user defined variables in CSS files
var varlst = new ActiveXObject("Scripting.Dictionary");

if (WScript.Arguments.Length < 2)
{
WScript.Echo("arg0: source css file;");
WScript.Echo("arg1: dest css file;");
}
else
{
ProcessCSSVariable(WScript.Arguments(0), WScript.Arguments(1));
}

function ProcessCSSVariable(input, output)
{
var fso, ts, fout, s;
var ForReading = 1;

fso = new ActiveXObject("Scripting.FileSystemObject");
ts = fso.OpenTextFile(input, ForReading);
fout = fso.CreateTextFile(output, true);

WScript.Echo(input + " => " + output);

while (!ts.AtEndOfStream)
{
s = ts.ReadLine();

var vardef = s.match(/\$[_\-0-9a-zA-Z]+[ \t\n]?=[ \t\n]?[#0-9a-fA-F]+/g);

if (vardef)
{
for (var i = 0; i < vardef.length; ++i)
{
var sep = vardef[i].indexOf("=");
var name = vardef[i].substr(0, sep);
var value = vardef[i].substr(sep + 1);

WScript.Echo("#" + (ts.line - 1) + "\t" + name + " = " + value);
varlst.add(name, value);
}

// output as-is
fout.WriteLine(s);
}
else
{
// output replaced line
fout.WriteLine(s.replace(/(\$[_\-0-9a-zA-Z]+)/g,
//varlst("$1")
function($0)
{
var value = varlst.Exists($0) ? varlst($0) : "/*WARNING: undefined: " + $0 + "*/";
WScript.Echo("#" + (ts.line - 1) + "\t" + $0 + " -> " + value);
return value;
}
));
}
}
}