S010's homepage

 


Tags:
64, _intro, c, epdfview, firefox, gtk2, interesting, japan, keyholetv, patch, pdf, pitfall, programming, radio, siliness, software, tv, tweak, unix

Fun with C operators

ctime:2010-09-02 01:01:09
mtime:2010-09-02 01:06:44

While writing some C code today, I suddenly felt an urge to write something perlish, like:

&important_action() or die("failed!");

I was about to shove this idea away, since C is basically a high-level assembler, but then it occurred to me that it is in fact possible:

... important_action() || die("failed!"); ...

The order of evaluation is guaranteed to be the same as it appears in program's text for &&, ||, ?: and `,' operators. The catch here is that the expression on the right must yield a value, that is, the function die() must be a non-void returning function. Otherwise, the code won't compile, at least it doesn't on GCC. Aww, but the standard UNIX routines, err(3) and errx(3), don't return anything! Wait.. What if we use the comma operator?

... important_action() || (errx(1, "failed!"), 1); ...

The comma operator yields the expression to it's right, so the || operator is satisfied. The parentheses are needed because the comma operator has the lowest precedence in C.

Of course, this last version will probably confuse the reader instead of clarifying the program... But it's still neat that you can do that.

C function declarations on AMD64

ctime:2010-08-22 00:33:15
mtime:2010-08-22 02:03:00

Stumbled upon interesting problem just now.

There is a function in the standard C library on UNIX, inet_ntoa(3), it formats a 'struct in_addr' in human readable form and returns a pointer to a character array.

So I had a line in my program, which looked something like:

snprintf(buf, sizeof buf, "%s:%i", inet_ntoa(sin->sin_addr), (int) ntohs(sin->sin_port));

The program would crash every time it reached this line, somewhere deep inside libc, in strlen call. In an attempt to figure out what's going on, I started experimenting. At some point, I ended up with

strlcpy(buf, inet_ntoa(sin->sin_addr), sizeof buf);

when I tried to compile the program, the compiler issued a warning that I was supposedly trying to pass strlcpy() an integer instead of a pointer as the second argument. And then it struck me, maybe I didn't include some header file which contained the declaration for inet_ntoa(), so the C compiler assumed the function to be of type 'int'. On AMD64, the addresses are 64-bits long whereas the C-type 'int' is 32-bits long.

I found that in fact, I didn't include one file which was mentioned in inet_ntoa(3) manpage: . So I included it and the program started working. Then I took a look at what assembler code the compiler was generating, out of interest, and what do you know...

Without arpa/inet.h:

With arpa/inet.h:

... #NO_APP movw %ax, -308(%rbp) movzwl -308(%rbp), %eax movzwl %ax, %ebx movq -336(%rbp), %rax movl 4(%rax), %edi movl $0, %eax call inet_ntoa movl %eax, %ecx leaq -48(%rbp), %rdi movl %ebx, %r8d movl $.LC6, %edx movl $22, %esi movl $0, %eax call snprintf ...

... #NO_APP movw %ax, -308(%rbp) movzwl -308(%rbp), %eax movzwl %ax, %ebx movq -336(%rbp), %rax movl 4(%rax), %edi call inet_ntoa movq %rax, %rcx leaq -48(%rbp), %rdi movl %ebx, %r8d movl $.LC6, %edx movl $22, %esi movl $0, %eax call snprintf ...

It works perfectly fine on i386 because both integers and adresses are 32-bits long there.

History buttons for epdfview

ctime:2010-07-25 21:57:21
mtime:2010-07-25 23:01:26

My favourite PDF reader is epdfview, it's a really simple and light-weight program, depends only on GTK2 and Poppler. It does have it's weak spots though. One such weak spot is the lack of history buttons (so that you could go back after clicking a cross-reference link for example). A few days ago I got really fed up with this and decided to add history myself.

The task turned out to be a little more complicated then I anticipated: first of all, after I actually added the buttons and made them work, I realized that when you go back or forth in history, you must also save the position on page and restore it, otherwise, it's not that much better than having no history at all; second of all, the program is done object-orientedly and the way entities communicate with each other -- is basically by notifications, when you look at epdfview's source code, it seems really well-organized and all, but when you're trying to modify it, you stumble upon this fact that, say, you can't just directly call some function to get information you want -- you have to make that other thing call you, and sometimes, there isn't a direct route between where you need the information and where it is located. But then again, maybe I'm just a bad programmer :D

Anyways, here's the modified source code: epdfview-trunk.tar.gz and a screenshot:

P.S. I should really read other people's code more often. Every time I do -- I learn some new neat trick or some good idea. This time, I learned the following trick with assert:
gassert(data && "Invalid argument: data is NULL");
When the assert is triggered, it not only will output the file name and line number where the assertion failed, it might also output a meaningful message.

KeyHoleTV: peeking on Japanese TV and radio programmes

ctime:2009-11-22 03:04:40
mtime:2009-11-22 03:04:40

Image Hosted by ImageShack.us
Caught One Piece anime on FujiTV =)

KeyHoleTV is an interesting little program, available for Windows, Mac and Linux, which lets you watch Japanese TV programmes and listen to Japanese radio stations. The quality of sound and picture is far from being 'high', but I guess it's better than nothing at all.

More info:

Firefox: remapping mouse buttons

ctime:2009-11-18 20:56:49
mtime:2009-11-19 01:31:52

Recently I changed my Firefox usage pattern. Instead of opening FF fullscreen, I now tend to open FF alongside some other window/s, like xterm or gvim.

Naturally, some or even many websites don't quite fit into the little space that is given to them now and so the problem of scrolling the page sideways as well as vertically arises. I remembered a feature called 'Autoscroll' and enabled it. When 'Autosroll' is enabled you can press the middle mouse button (which nowadays is almost always a scrolling-wheel, not a button), drag the mouse and the page scrolls in the direction you drag the mouse.

But as I used autoscroll, little by little, I got frustrated with the 'middle-button'. Scrolling-wheel was not designed to be pressed too often, I would've preffered to use an ordinary button any day.

That's when I remembered that Firefox -- is an open-source browser. I decided to download it's sources and implement the ability to remap mouse buttons arbitrarily.

The first thing I did when I got FF's source was find . -iname '*mouse*'. I found a file with intriguing name, content/events/src/nsDOMMouseEvent.cpp, tried to modify it, but there was no effect.

Then I found widget/src/gtk2/nsWindow.cpp, which is one of the files that interfaces FF with GTK2 and which translates GTK2 events to FF's. At first I tried out to make a hardcoded remap, i.e. changed

... PRUint16 domButton; switch (aEvent->button) { case 1: domButton = nsMouseEvent::eLeftButton; break; case 2: domButton = nsMouseEvent::eMiddleButton; break; case 3: domButton = nsMouseEvent::eRightButton; break; ...

in the nsWindow::OnButtonPressEvent function to

... PRUint16 domButton; switch (aEvent->button) { case 1: domButton = nsMouseEvent::eLeftButton; break; case 2: domButton = nsMouseEvent::eRightButton; break; case 3: domButton = nsMouseEvent::eMiddleButton; break; ...

It worked, so next I added a new about:config variable, mozilla.widget.mouse-button-map:

Free Image Hosting at www.ImageShack.us

And wrote a function, which when the Firefox starts up, parses this variable, if it's present, and maps the buttons accordingly.

The format of the variable... Hm, that'll be a bit hard to explain...
The position in the string, is the GDK button number of the mouse button you want to remap. The number on this position in the string, is also a GDK mouse button number and denotes to which button you want to remap the button! If there is an 'm' on the given position, then it means the previous button will invoke the context menu (Look through the nsWindow::OnButtonPressEvent function, the context menu button is kind of mapped separately). If you don't want to remap the button on this position, put any char there other than [0-9m].
For example, given a value "13m2", the buttons will be remapped in the following way:

  1. left mouse button -- will be remapped to left mouse button =)
  2. middle mouse button -- will be remapped to right mouse button and it will also invoke context menu when pressed
  3. right mouse button -- will be remapped to left mouse button
The scrolling function of the mouse will stay as it was, because scrolling is processed separately.

And so, now I can autoscroll with the right mouse button =) And I'm also so looking forward to using this on my laptop *types make extract patch*...

Here's the patch: ff_mouse_button_remap.patch.