Monday, November 15, 2010

Vim Tabs

If you are not used with the buffer concept as the buffers do not necessarily visible, and you also want to focus on the current file, you have the tabs in Vim just as you have in Editplus or Notepad++ or most of modern text editors. Here is my vim with two tabs each holding its own windows. Yes, it's important that each tab can hold multiple windows, isn't it cool or what!



Here is how you can work with tabs in Vim.

Create a new tab:

  • - vim -p file1 file2... : Open multiple files each in one tab.
  • - :tabnew [filename] : Crate a new tab, empty or possibly open a file at the same time.
  • - Ctrl-w T : If you have multiple windows opened in one tab, use this command to put the current window into a new tab.


Navigate between tabs:

  • - :tabs : list all opened tabs
  • - :tabn, :tabp: go to next or previous tab. Less convenient. 
  • - gt : go to next tab. Better.

Vim Windows

Vim is able to show your files in separated windows which is very handy in many situation. For example, if you are a programmer, very often you need to look at a .cpp file and its header .h at the same time. Or if you are simply writing some text and need to refer to certain part of the same file that can not fill in one screen because your text is quite long.

Then it's the time to think about multiple windows and it will helps a lot. Here is how vim looks like with multiple windows.

Basically, here I created three windows, left top, left bottom and the right one. Several interesting thing to mention here. First, as you can see, we are able to create vertically or horizontally separated windows. Then, we are able to crate multiple windows containing the same file. Finally, we have some important information for each window, the file name, the index of the buffer (the number before the file name), etc.

Here is how I use multiple windows.
To create new window:
  • - Ctrl-w s  will split the current window into two containing the same file.
  • - :sp same as above.
  • - :sp filename will create a new window with the file filename.
  • - Ctrl-w v Split the current window vertically. 
  • - :vs same as above
  • - :vs filename Vertical split with file filename.
To move between windows: All commands here start with Ctrl-w.
  • - h,j,k,l:  Navigate: same as move the cursor. 
  • - x: Switch positions of two neighbor windows.
  • - p: Go to previous windows, particularly useful when browsing between .h and .c files.
Close windows:
  • - Ctrl-w c or :q 

Sunday, November 14, 2010

My Favorite Software on Windows

I reinstalled my PC this weekend as you all know that Windows tend to slow down after some time.

I take this opportunity to make a collection of my favorite software on a Windows PC.

7-Zip
Adobe Reader
Google Chrome
Mozilla Firefox
Skype
PPTV
SPlayer
MKPlayer
Sogou Chinese Input Method
Thunder Download

...
To continue.

Sunday, October 10, 2010

Problem with System.Windows.Forms.WebBrowser

I used a lot System.Windows.Forms.WebBrowser in my LSSaver project to process the pages. Recently I got a feed back that LSSaver stops to load the blog titles and is blocked there. The problem seems to happen on a WinXp + IE6 platform.

After investigation, the problem comes from a null pointer exception, but why there is a null pointer? A step by step debug showed me that when using WebBrowser’s DOM to retrieve certain HTML element, the HtmlElement.NextSibling returns an invalid pointer even when there is no more sibling of the calling HtmlElement object. It seems that this is a known issue in the .NET framework:
http://connect.microsoft.com/VisualStudio/feedback/details/304466/htmlelement-nextsibling-returns-incorrect-value

Anyway, I won’t rely on the NextSibling is null or not, I get the number of children from the parent, then rely on this count when traversing all the children elements. The problem is fixed.

Thursday, September 30, 2010

Overloading operator << for containers

Today, I saw a line of code in one of our cpp files, it looks like this:
marshaller << obj_list;
what interesting is that obj_list is an instance of type std::vector, and one of my colleagues asked me if he can do similar things with an instance of type std::map<>.

The answer is "I don't know", because it depends on if the operator << is overloaded for the marshaller type for std::map<>.

The secret why "marshaller << obj_list;" works is that, the marshaller type has an overloaded operator << for std::vector. Something looks like this, assuming marshaller has type T:
T  &operator << (T &t, const vector avector){...}

Here is an example with cout:
ostream &operator << (ostream &out, const vector avector)
{
    vector ::const_iterator itr = avector.begin();
    for (; itr != avector.end(); ++itr)
    {
        out << (*itr);
    }
}

int main(void)
{
    vector str_vector;
    for (int i = 0; i < 10; i++)
    {
        stringstream str_stream;
        str_stream << i;
        str_vector.push_back(str_stream.str());
    }
    cout << str_vector;
}
The output is:
0123456789

So for this works with std::map<>, we need to overload << for std::map<>. 

Finally, it turned out that there is no such an overload, unfortunately. So we have to do it for each pare in the map.

Sunday, September 19, 2010

Do It in a Programmer's Way

DiPw, I'd like to pronounce it like "deepyou", is my preferred way of doing things, especially things related with my job as a programmer/developer.

Recently, I was assigned a job to migrate documents from the old system to the new one, and this is to be done for each of our customers. In order to secure the migration, I need to check many configurations on both systems, they need to be similarly configured so the migration is transparent for the customers, ideally. What complicates things is also we have test systems and production systems, and the migration need to be done first on test systems then on production systems. So as a result, I have a lot of things to check and compare. Even worse, the settings are managed by several GUI applications so I have to click many times to find one setting on the old system then, do it on a different GUI on the new system. That is not only boring but also fault prone.

A colleague of mine kindly told me that the content of the GUI applications are finally stored in the database and he also gave me some SQL to retrieve the values. That is a big help, however, I still have to manage two types of databases, Oracle and SqlLite.

Why I have to do it manually? It's time consuming and error prone. Why not write a program doing all of these jobs for me? With always DiPw in head, I decided to write a Python program doing these boring jobs and finally it took me one day. Voila, now with the program, I retrieve all need information on all systems for a given customer in 20 minutes and when needed, I can retrieve most up-to-date information whenever I want in 20 minutes, this is impossible without the program. And when it comes the time to migrate another customer, I just run the program for this customer.

Well, I admit that the job is not all about getting all the settings, but it is the most boring part, so let a program do it!

Monday, August 30, 2010

A Real-life Story about Bad Type Cast

We have a problem today in our soft. That is, in short, we have 285 lines of text to display but only 231 lines are displayed. The investigation is not so easy because the text to be displayed is converted from structured message and the number of lines are calculated on the fly.

Basically, there is a segment in the message that specifies the maximum allowed number of lines, the sender of the message has set it to 999, assuming it the maximum possible lines in the message.

So if you are really a geek in programming C/C++, you may already know where is going wrong. Yes, an integer 999 when assigned to a unsigned char, the latter will have value 231. In more detail: binary presentation of decimal 999 is 1111100111, when assigned to unsigned char, we have only the lower 8 bits left: 11100111, it equals decimal value 231.

The problem is quite clear, but it has been hard to find it out because it hides itself deep in one of the libraries our soft uses.

Another interesting thing is that the library code uses atoi to convert the maximum allowed size in the message to an integer value, but with a parameter like this: "999blabla", that is the value in string followed by other alphabetic characters. atoi is designed to handle this correctly, take a look at the specification of atoi:

int atoi ( const char * str );
Convert string to integer
Parses the C string str interpreting its content as an integral number, which is returned as an int value.

The function first discards as many whitespace characters as necessary until the first non-whitespace character is found. Then, starting from this character, takes an optional initial plus orminus sign followed by as many numerical digits as possible, and interprets them as a numerical value.

The string can contain additional characters after those that form the integral number, which are ignored and have no effect on the behavior of this function.

If the first sequence of non-whitespace characters in str is not a valid integral number, or if no such sequence exists because either str is empty or it contains only whitespace characters, no conversion is performed.