TimothyQiu's Blog

keep it simple stupid

SSH Escape Sequences

前阵子因为要折腾 VPS 的缘故把博客暂时放在了 @likounin 童鞋的服务器上,不想最近他的服务器出了点问题,于是只能赶紧把 VPS 重新折腾回原样,然后把博客搬回来。

慌忙折腾之中遇到个问题:在 SSH 里卡住了,没法 Ctrl-C(因为这种按键会直接发给远端),该怎么正常退出?

想来也应该有个转义序列可以直接对 SSH 做操作……于是,那就是 ~ 键。

SSH 到服务器后,确保之前按过一次回车,然后按 ~?,就会列出一堆可用的转义序列,比如:

Supported escape sequences:
~. - terminate connection
~B - send a BREAK to the remote system
~C - open a command line
~R - Request rekey (SSH protocol 2 only)
~^Z - suspend ssh
~# - list forwarded connections
~& - background ssh (when waiting for connections to terminate)
~? - this message
~~ - send the escape character by typing it twice
(Note that escapes are only recognized immediately after newline.)

总之,要退出已经卡住的 SSH 程序,可以在按一次回车(见上面帮助信息的最后一行)之后,按下 ~.

话说回来,转义字符也只是默认是这个 ~ 字符而已,如果不喜欢的话,ssh_config 文件中有一个选项叫 EscapeChar 可以修改转义字符。

以上。

WM_IME_CHAR

于是又是一篇木有技术含量的笔记。

对于 Unicode 窗口,WM_IME_CHARWM_CHAR 没有区别,wParam 都是一个 WCHAR,即输入的字符。

对于非 Unicode (DBCS) 窗口,WM_IME_CHARwParam 即由输入法生成的一个字符。这个字符既有可能是单字节字符也有可能是双字节字符。如果是单字节字符,那么和 WM_CHAR 没什么区别;如果是一个双字节字符,那么 wParam 高 8 位为 Leading byte,低 8 位为 Continuation Byte。

所有经由输入法产生的字符都会产生 WM_IME_CHAR 消息而不是 WM_CHAR,但 DefWindowProc 会把 WM_IME_CHAR 转换为相应的一个或两个 WM_CHAR 消息。

例如:

去掉 WinMain 和控制台窗口

微软什么的最讨厌啦~写个 GUI 程序要么带个控制台窗口,要么就得用非主流的 WinMain 函数作入口。

用 gcc 的话,这其实不是个问题,带上一个 -mwindows 参数即可顺利解决掉控制台窗口并且抛弃 WinMain

而到了 Visual Studio,似乎很两难:

于是困惑了。好在今天在 Irrlicht 的教程中见到了解法:

Linker 参数中的 SubSystem 继续选择 Windows,与此同时将 Entry Point 设置为 mainCRTStartup 即可兼得鱼和熊掌。

以命令行参数形式就是:/SUBSYSTEM:windows /ENTRY:mainCRTStartup

要点就是 ENTRY 参数有三种:mainCRTStartup、WinMainCRTStartup、和 _DllMainCRTStartup,分别对应调用 mainWinMain、和 DllMain,默认是根据 /DLL 和 /SUBSYSTEM 参数自动选择的。

以上。

Vim 中删除符合条件的行

一说筛选数据首先映入脑海的是 grep,但 Windows 下就悲了个具了,从别程序复制(这时候觉得 GUI 不能管道真是太糟糕了)了一坨纯文本数据要筛选,为了这个还要临时保存个文件然后再开个 Cygwin 啊~MSYS 啊什么的真是太不适合我这种懒人了。于是还是要拜托好用的 Vim 来处理。

假设要在某坨数据中删除含有「kernel32」的行,可以执行:

:g/kernel32/d

其中中间的条件部分 kernel32 和一般的查找条件格式相同,最后部分的 d 则和一般的命令按键相同。如果要保留匹配的行则可以把开头的 g 替换为 g!

这样的写法实际是使用了 VIM 的「Multiple Repeats」功能,完整格式是这样的:

:[range]g[lobal]/{pattern}/[cmd]

详情请参考 :help :g :)

Lua 学习笔记:贰

最近不是特别忙,于是就抽空开始继续看 PIL 了。

变量声明与 C 语言的不同

Lua 中有一个常见的用法,不论变量、函数都可以用下面这种方法保存到局部变量中(同时加快访问速度):

local foo = foo

书里加了个括号来解释这种写法:

The local foo becomes visible only after its declaration.

这一点需要瞎扯的是 C 语言里相应的东西。

int foo = 12;
int bar = 6;

void foobar(void)
{
    int foo = foo;
    int bar[bar];
}

与 Lua 不同,在 C 语言中初始赋值是声明之后的事情。所以这里函数 foobar 中的 foo 会被初始化为自己(而不是全局的 foo,所以值不确定),bar 却被合法地定义为一个含有 6 个元素的数组。

看似多余的限制

另一个有趣的现象是在 4.4 节中说到:

For syntactic reasons, a break or return can appear only as the last statement of a block; in other words, as the last statement in your chunk or just before an end, an else, or an until.

乍一看觉得加上这个限制真是麻烦,但想想这不正是 break/return 的正确用法么?因为其后的语句都永远不会被执行到,所以如果不是在块的最后写 break/return 是毫无意义的(调试除外)。虽然看上去是挺多余的一段话,但也算是说出了事物的本源。

函数的本质

第六章 More About Functions 中说到我们平时在 Lua 中写的函数声明

function foo (x) return 2*x end

其实是一种语法糖,本质上我们可以把它写成如下代码:

foo = function (x) return 2*x end

于是也就可以说

终于有用的知识

在第 47 页看到了一段令人泪流满面的代码和运行结果:

function derivative (f, delta)
  delta = delta or 1e-4
  return function (x)
           return (f(x + delta) - f(x))/delta
         end
end

c = derivative(math.sin)
print(math.cos(10), c(10))
  --> -0.83907152907645 -0.83904432662041

最初我并不知道 derivative 是什么意思,但看了示例代码和运行结果,顿时恍然大悟:这货不就是导数吗?

高数里的东西竟然真的在现实生活中出现了!顿时觉得世界真美好 =ω=