Friday, August 25, 2006

Emacs Lisp 学习(二) -- 基本函数

引用自《GNU Emacs Lisp 编程入门》(中译版,2001年5月,P21。以下简称《Elisp》):
“除了一些基本函数是用 C 语言编写的之外,其他所有函数都是用别的函数来定义的。”
“当你在 Emacs Lisp 中编写代码时,你无法分清在 C 语言中编写的函数和在 Emacs Lisp 中编写的函数。它们之间的区别是不相关的。之所以提到它们的区别是因为知道这一点很有趣。实际上,除非你深入研究,否则你将不知道已经编写好的函数是用 Emacs Lisp 编写的还是用 C 语言编写的。”

以下的基本上也引用《Elisp》,因为它总结的太好了,不想破坏它。但个别地方会加以更改:

  • eval-last-sexp

  • 对光标所处的位点前的最后一个符号表达式求值。如果这个函数被激活时没有带参量,返回值输出在回显区中。如果这个函数被激活时带有参量,其输出打印在当前缓冲区中。这个命令一般被绑定到 C-x C-e.


  • defun

  • 定义函数。这个特殊表最多可以有五个部分:函数名,传送给函数的参量的模板、文档、一个可选的交互函数声明以及函数体。
     (defun function-name (arguments ...)
    "optional-documentation ..."
    (interactive argument-passing-info)
    body ...)
  • interactive

  • 设定函数可被交互使用。这个特殊表可以用一个字符串,分成一个部分或者几个部分,依次传送信息到这个函数的参数。这些部分也可以告诉 Lisp 解释器提示这些信息。字符串的每一个部分用换行符 "\n" 分开。(这里字符串即上面所显示的“argument-passing-info”)
    其中常用到的控制字符是:
    b 一个已经存在的缓冲区的名字。
    f 一个已经存在的文件的名字。
    p 数字前缀参量。(注意,这个字符是小写 "p"。)
    r 位点和标记,作为两个数字参量,小的在前面。这是唯一定义两个连续参量而不是一个参量的控制符。


  • let

  • 声明在 let 表达式主体中使用的变量列表并给它们赋初始值,初始值要么是 nil,要么是一个指定的值;然后对 let 表达式主体的其他表达式求值并返回最后一个表达式的值。在 let 表达式主体中,Lisp 解释器看不到被绑定在 let 表达式之外的同名变量的值。
    例如,
    (let ((foo (buffer-name))
    (bar (buffer-size)))
    (message "This buffer is %s and has %d characters."
    foo bar))
  • save-excursion

  • 在对这个特殊表主体求值前,记录位点和标记的值以及当前缓冲区。求值之后恢复原来位点和标记的值以及缓冲区。
    例如,
    (message "We are %d characters into this buffer.
    (- (point)
    (save-excursion
    (goto-char (point-min)) (point))))
  • if

  • 对函数的第一个参量求值;如果这个值是“真”,则对第二个参量求值;否则,如果有第三个参量的话就对第三个参量求值。
    if 特殊表被称作一个条件表达式。在 Emace Lisp 中还有其他条件表达式,但是 if 条件表达式可能是其中最经常使用的。
    例如,
    (if (string= (int-to-string 19)
    (substring (emacs-version) 10 12))
    (message "This is version 19 Emacs")
    (message "This is not version 19 Emacs"))
  • equal、eq

  • 测试两个对象是否相同。如果两个对象有相似的结构和内容,equal 则返回“真”。如果两个参量确实是完全相同的对象,则另一个函数 eq 返回“真”。


  • < 、> 、<= 、>=

  • < 函数测试其第一个参量是否小于第二个参量。与之对应的 > 函数则测试其第一个参量是否大于第二个参量。同样地,<= 函数测试其第一个函数是否小于或者等于第二个参量,>= 函数则测试第一个参量是否大于或者等于第二个参量。所有这些函数使用的参量都是数字。


  • message

  • 这个函数往回显区中打印一条消息。打印的消息只可以有一行。这个函数的第一个参量是一个字符串,这个字符串中能够包含“%s”、“%d”或者“%c”,以打印字符串后面的参量的值。用来替代“%s”的参量必须是一个字符串或者一个符号;用来替代“%d”的参量必须是一个数字。而用来替代“%c”的参量必须是一个数字,它将打印出具有相应数值的 ASCII 字符。


  • setq 、set

  • setq 函数将其第一个参量的值设置为第二个参量的值。第一个参量由这个 setq 函数自动地加上引号。这个函数对后续的成对参量执行同样的赋值操作。另外一个 set 函数只能接受两个参量,并在将其第一个参量返回的值设置为其第二个参量返回的值之前对它们求值。


  • buffer-name

  • 这个函数不需要参量,它将缓冲区的名字以一个字符串的形式返回。


  • buffer-file-name

  • 这个函数不需要参量,它返回缓冲区正在访问的文件的名字。


  • current-buffer

  • 返回 Emacs 中当前缓冲区的名字,这个当前缓冲区可能并不是屏幕上看到的缓冲区。


  • other-buffer

  • 返回最近选择过的缓冲区(既不是作为参量传送给 other-buffer 函数的缓冲区,也不是当前缓冲区。


  • switch-to-buffer

  • 这个函数为 Emacs 选择一个活动的缓冲区,并将它显示在当前的窗口,以使用户能够看到它。这个函数经常被绑定到 C-x b 键序列。


  • set-buffer

  • 将 Emacs 的注意力切换到另一个运行程序的缓冲区。不要改变当前窗口正在显示的内容。


  • buffer-size

  • 返回当前缓冲区中的字符数。


  • point

  • 返回当前光标位置对应的值,这个值是从缓冲区的开始处直到光标所在位置所占的总的字符数。


  • point-min

  • 返回当前缓冲区中位点的最小可能值。如果变窄没有开启,这个值就是1。


  • point-max

  • 返回当前缓冲区中位点的最大可能值。如果变窄没有开启,这个值就是缓冲区末尾对应的值。

Thursday, August 24, 2006

Emacs Lisp 学习(一)

对于 Emacs Lisp 的语法来说,它的解释方式相当于我们在数据结构中所说的“前缀表达式”,因为它的所有操作都是放在一个列表的第一项的。而如果在一列表的左括号前放了一个"'"号,那么这个列表相当于被认作为一数组,其第一个元素不会再被认作是函数,而是数据。

但由于 Lisp 的语法特性 -- 如果一种语言的语法看上去像是数据表,那么它的程序清单就可以被其它程序当作数据使用。 -- 因此,即便你没有在一列表的左括号前放置"'"号,你的列表头项也可以看作数据。

几个有用的 Elisp 函数:
1. (message "Strings %d %s" AInteger AString) -- 在回显区显示信息
2. (set 'variable value) -- 赋值,一般用 setq 来代替
3. (setq variable1 value1 variable2 value2 ...) -- 赋值,
相对 set 函数来说要简单,而且可同时为多变量赋值

4. (buffer-name) -- 获得缓冲区名
5. (buffer-file-name) -- 获得缓冲区文件名
6. (switch-to-buffer (other-buffer)) -- 切换缓冲区
7. (buffer-size) -- 缓冲区大小,也即对这个缓冲区中的字符数计数
8. (point) -- 当前光标所在的缓冲区的位置(用字符数计数)

Wednesday, August 23, 2006

Linux Runlevel -- Linux 运行级别

在 Ubuntu 中,系统的运行级别 Runlevel 设置与普通的其它 Linux 的设置不一样,当你修改 /etc/inittab 文件中的 runlevel 为 3 时,Unbuntu 并不是将你带入多用户的虚拟终端,而是同 runlevel=2 时一样地进入到图形界面。这是怎么一回事呢?

原来,在看过 /etc/rc.d 文件后才晓得,系统是通过一系列的脚本来启动进入 Linux 的。当在 /etc/inittab 文件中将 runlevel 设置为 3 时,系统将执行所有在 /etc/rc3.d 目录下的脚本;当设置为 2 时,系统将执行所有在 /etc/rc2.d 目录下的脚本…

/etc/rc<运行级别>.d 目录中的文件一般都是符号连接,指向 /etc/init.d 目录中服务型程序,如 apache, sendmail。而且它们都是以 S 或 K 开头,后面跟上两位数字,再跟上程序名。这里的 S 是 Start,即运行某项服务,而 K 是 Kill,即杀死某项服务。因此当系统转入某个运行级别时,它将运行相应的服务程序,遇到 S 开头的服务时启动它,遇到 K 开头的服务时则杀死它。而数字则表示这些程序的运行优先级,数字小的先执行,数字大的后执行。(这是显然的,当文件首字母一致时,文件又以升序排列,那么数字小的自然排在了前头。)

在终端中,我们可以键入
init <运行级别>
来切换运行级别来达到某种目的,如输入 init 0 使系统关机,输入 init 6 使系统重启。

Ubuntu 默认的 /etc/rc3.d 中有个名为 S20gdm 的符号链接文件,所以当我们把 /etc/inittab 中的 runlevel 设置为 3 时,系统依然会运行图形登录界面 GDM 。因此如果我们将 S20gdm 文件删除掉,再重启,会发现我们进入的不再是图形界面了。

依样画葫芦,如果想在启动系统的时候即启动 apache,我们只需在需要的 rc?.d 目录中加入首字母为 S 的符号链接,使其指向 /etc/init.d/apache 就可以了。

彻底杜绝warning: Cannot add header information - headers already sent in......

标题:彻底杜绝warning: Cannot add header information - headers already sent in......
作者:esayr
出自:www.phpv.net

只要你写过PHP代码,相信都遇上过这个大多时候都令人莫明其妙的warning吧..今天我们就来搞定它...............

看了PHP手册,回答如下:

6. 我得到消息“Warning: Cannot send session cookie - headers already sent...”或者“Cannot add header information - headers already sent...”。

函 数 header(),setcookie() 和 session 函数需要在输出流中增加头信息。但是头信息只能在其它任何输出内容之前发送。在使用这些函数前不能有任何(如 HTML)的输出。函数 headers_sent() 能够检查您的脚本是否已经发送了头信息。请参阅“输出控制函数”。

意思是:不要在使用上面的函数前有任何文字,空行,回车,空格等.但...问题是,这答案并不令人满意.



首先:这错误是怎么产生的呢?让我们来看看PHP是如何处理HTTP header输出和主体输出的。

PHP 脚本开始执行时,它可以同时发送header(标题)信息和主体信息. Header信息(来自 header() 或 SetCookie() 函数)并不会立即发送,相反,它被保存到一个列表中. 这样就可以允许你修改标题信息,包括缺省的标题(例如 Content-Type 标题).但是,一旦脚本发送了任何非标题的输出(例如,使用 HTML 或 print() 调用),那么PHP就必须先发送完所有的Header,然后终止 HTTP header.而后继续发送主体数据.从这时开始,任何添加或修改Header信息的试图都是不允许的,并会发送上述的错误消息之一.

好!那我们来解决它:

笨方法:把错误警告全不显示!
掩耳盗铃之计,具体方法就不说了 ^_^#

解决方案:

1)适用于有权限编辑PHP.INI的人

打开php.ini文件(你应试比我清楚你的php.ini在哪里),找到

output_buffering =改为on或者任何数字.如果是IIS6,请一定改为ON,不然你的PHP效率会奇慢.

2)使用虚拟主机,不能编辑PHP.INI,怎么办?

简单:

在你的空间根目录下建立一个.htaccess文件,内容如下:

AllowOverride All
PHP_FLAG output_buffering On

不幸的情况是:还是不行?全部网页都不能显示啦?

那么,你可以打电话骂一通空间商,然后让他给你把apache的.htaccess AllowOverride打开

3)在PHP文件里解决

ob_start()
启用output buffering机制。 Output buffering支持多层次 -- 例如,可以多次调用 ob_start() 函数。

ob_end_flush()
发送output buffer(输出缓冲)并禁用output buffering机制。

ob_end_clean()
清除output buffer但不发送,并禁用output buffering。

ob_get_contents()
将当前的output buffer返回成一个字符串。允许你处理脚本发出的任何输出。

原理:

output_buffering 被启用时,在脚本发送输出时,PHP并不发送HTTP header。相反,它将此输出通过管道(pipe)输入到动态增加的缓存中(只能在PHP 4.0中使用,它具有中央化的输出机制)。你仍然可以修改/添加header,或者设置cookie,因为header实际上并没有发送。当全部脚本终止 时,PHP将自动发送HTTP header到浏览器,然后再发送输出缓冲中的内容。

在 Linux 中手动设置 IP

在 Linux 中手动设置 IP 可用:

1. 系统自带的可视化工具
2. /sbin/ifconfig
3. 修改 /etc/network/interfaces

配置好的 interfaces 文件内容形如:

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
address
netmask <子网掩码>
gateway <网关>

auto eth1
iface eth1 inet dhcp

auto eth2
iface eth2 inet dhcp

更改终端的字符

安装好 Linux 后,终端的字体可能默认为中文字体,如果在全字符终端下工作有些将会显示不正常。解决方法是:

先用 export 查看当前用户的环境变量设置,可以看到一堆环境变量及它在当前用户下的值。我们可以在命令行下输入:

export LC_ALL="en"

将该变量临时改变。也可以在 $HOME/.bash_profile 中加入上面的命令,这样可以永久改变。

让别人远程使用你的系统

使用 vnc 可以远程登录和使用桌面。我们可以配置 vncserver 或运行 vino-preferences 来供他人远程登录,也可通过 vnc 客户端工具远程登录他人的桌面。

我们还可以使用 ssh 远程登录其它系统,如:

$ ssh username@hostname.hostdomain

或者使用公钥系统 RSA 分发生成的公钥到须远程登录的系统中同名用户的主目录下的 .ssh 目录中,将生成的公钥放在自己的主目录下的 .ssh 目录中,这样使用 ssh 登录到那台系统中时就不需要密码了。

Ubuntu 的 sudo 揭密

今天第一次安装了 Ubuntu (6.0 Desktop) ,发现与其它 Linux 有非常大的差别。最让人发慌的莫过于 sudo ── 我还没给它发任何指令它就能够做所有 root 级的操作!它让我感觉到一丝的不安~

于是我做了个实验,再用 useradd 加了个用户,结果证明了我的孤陋寡闻 ── 新加的这个用户甚至连与它同名的组名、/home 下的同名目录都没有!而它不能用 sudo 来做 root 的事!

Ubuntu 比我预先想的还要安全。它将 root 用户的密码置为空,这就意味着本地用户和远程用户无法登录到 root 用户下为所欲为。而所有超级指令则完全由第一个用户 ── 也就是安装时设置的用户 ── 来做。这就在一定程度上避免了悲剧的发生(总有人会在 root 用户下使用 "rm -rf /" 命令),因为我们习惯上是不加 sudo 在命令前的。经过进一步和研究发现,这种机制的实现是很简单的,实际上就是将一个普通用户的用户名加在 /etc/group 的某个组名之后(在 Ubuntu 中就是 admin:x:70:myname,其中 70 是组号,myname 是用户名),再将这个组名加入到 /etc/sudoers 中,形如:

%admin ALL=(ALL) ALL

这样就可以在其它 Linux 下也实现同样的功能了。

Blogger 终于又可用了

好久的等待,Blogger 终于又可用了!之前用我的帐户可以登入,发表文章后却无法查看,真是气死我了。现在好了,我又可以重新拾起这个博客了!