diff options
Diffstat (limited to 'doc/HACKING')
-rw-r--r-- | doc/HACKING | 388 |
1 files changed, 388 insertions, 0 deletions
diff --git a/doc/HACKING b/doc/HACKING new file mode 100644 index 0000000..15cc1de --- /dev/null +++ b/doc/HACKING @@ -0,0 +1,388 @@ +This document +============= + +This document is a guide how to develop GNU Midnight Commander. It's +quite incomplete, but may be worth reading anyway. + +The document was written by Miguel de Icaza and reworked by Pavel +Roskin and later from Patrick Winnertz. + Some parts were taken from the messages posted in the mailing +lists. + + +Compiling from GIT +================== + +To compile GNU Midnight commander from GIT, the following software is +required: + +Autoconf 2.64 and above (latest is recommended) +Automake 1.12 and above (latest is recommended) +Gettext 0.18.2 and above +Glib 2.30 and above + +Full list of requirements you can see at: +https://www.midnight-commander.org/wiki/doc/buildAndInstall/req + +It is recommended that all those tools are installed with the same +prefix. Make sure that the tools with the right version are first in +PATH. + +Once you have the right tools, run `autogen.sh' - it will generate +everything necessary for the build `configure'. Then run 'configure' +and `make' as usually. + +The distribution tarball is created by the command `make distcheck'. +This command can take a while. + +Currently snapshots are made on Debian unstable and use the versions of +the tools from the unstable repository. Yes, the rpm packages are made +on Debian too. + +Note that the version of gettext doesn't affect the snapshot because the +distributed files are installed by gettext from archives for the version +used in the AM_GNU_GETTEXT_VERSION macro, which is 0.18.2. + + + +Working with GNU Midnight Commander +=================================== + +Please use the GIT version. It may be quite different from the released +versions. A lot of cleanup is going on. The GIT version may be easier +to understand, in addition to the obvious fact that the merging is +easier with the GIT version. + +In order to compile GNU Midnight Commander from a clean GIT checkout you +should use 'autogen.sh && ./configure' instead of 'configure'. + +GNU Midnight Commander uses Autoconf and Automake, with make it fairly +portable. However, GNU Make is strongly recommended for development +because other versions of make may not track dependencies properly. +This is very important for correct compilation, especially if you change +any header files. + +If you add or remove any files, please change Makefile.am in the same +directory accordingly. When doing significant changes in the tree +structure, "make distcheck" is strongly recommended. + +GNU Autoconf allows you to test several different configurations are +once. To do so, use the so called out-of-tree (or VPATH) compilation. +Create separate empty directories and run configure with full path from +those directories, like this: + +cd /usr/local/src +mkdir mc-slang +mkdir mc-ncurses +cd mc-slang +/usr/local/src/mc/configure && make all +cd ../mc-ncurses +/usr/local/src/mc/configure --with-screen=ncurses && make all + +Please use the same indentation as other developers. To indent a block, +select in the internal editor and use Shift-F9 to call the external +indent. For historic reasons, GNU Midnight Commander used formatting +that is not default for GNU Indent. Please put following text to your +~/.indent.pro file to make GNU Indent follow the style used in GNU +Midnight Commander: + +--gnu-style +--format-first-column-comments +--indent-level4 +--brace-indent0 +--line-length100 +--no-tabs +--blank-lines-after-procedures + +or in short notation: + +indent -gnu -fc1 -i4 -bli0 -nut -bap -l100 + +It's OK to indent the whole function if you edit it. However, please +refrain from it if you are posting your patch for review. In this case +you would save time of other developers if you only include significant +changes. The developer applying your patch can format the code for you. + +Please keep in mind that the VFS subsystem is licensed under LGPL, while +the rest of the code uses GPL. + + +Code structure - outline +======================== + +The code is located in following directories. + +vfs - Virtual File System. + +This library provides filesystem-like access to various data, such are +archives and remote filesystems. To use VFS, you should use wrappers +around POSIX calls. The wrappers have names composed from "mc_" and the +standard name of the function. For example, to open a file on VFS, use +mc_open() instead. + +edit - the internal editor. + +This code has been contributed by Paul Sheer, the author of Cooledit. +The internal editor shares some code with Cooledit, but now it's +developed as part of GNU Midnight Commander. + +src - the main part of the code. + +This code includes the dialog manager written by Radek Doulik and source +code of the main application. + +Code structure - details +======================== + +GNU Midnight Commander uses extensively the dialog manager written by +Radek Doulik. To understand how the dialog manager works, please read +the dialog.c. You will find the basic widgets in the files widget.c. +Some more high-level functions, e.g. to display a message box, are +located in wtools.c. This file also contains the Quick Dialog code, +which makes it easier to create complex dialogs. + +The files util.c and utilunix.c have a lot of utility functions. Get +familiar with them, they are very simple. + +glib is used for memory allocation and for some utility functions, such +as manipulation with lists and trees. gmodule (part of the glib +distribution) is used to load some libraries dynamically at the run +time. + +Thanks to glib, the code has almost no hardcoded limits, since there are +many ways to avoid them. For example, when you want to concatenate +strings, use the g_strconcat() function: + + new_text = g_strconcat (username, " ", password, (char *)0); + +This allocates new memory for the string, so you should use g_free() on +the result. + +The parent of all dialogs is called midnight_dlg. Both panels are +widgets in that dialog. Other widgets include the menu, the command +line and the button bar. + + +Input handling +============== + +The routines for input handling on the Midnight Commander are: +getch, get_key_code, mi_getch and get_event. + +getch is an interface to the low level system input mechanism. It +does not deal with the mouse. + + In the case of ncurses, this is a function implemented in the + ncurses library that translates key sequences to key codes (\E[A to + something like KEY_UP and so on). + + In the case of S-Lang there is no such conversion, that's why we + load a set of extra definitions. + +The get_key_code routine converts the data from getch to the +constants the Midnight Commander uses. + + In the case of S-Lang, it will actually do all the jobs that getch + does for curses. In the case of curses it patches a couple of + sequences that are not available on some terminal databases. This + routine is the one you want to use if you want a character without + the mouse support. + +get_event is the routine you want to use if you want to handle mouse +events, it will return 0 on a mouse event, -1 if no input is available +or a key code if there is some input available. This routine in turn +uses get_key_code to decode the input stream and convert it to useful +constants. + +mi_getch is just a wrapper around get_event that ignores all the mouse +events. It's used only in a couple of places, this routine may return +-1 if no input is available (if you have set the nodelay option of +ncurses or S-Lang with nodelay) or a character code if no such option is +available. + + +Mouse support +============= + +The mouse support in the Midnight Commander is based on the get_event +routine. The core of the mouse event dispatching is in the +dlg.c:run_dlg routine. + + +ncurses +======= + +Although S-Lang is now used by default, we still support ncurses. We +basically are using a small subset of ncurses because we want to be +compatible with Slang. + + +The Dialog manager and the Widgets +================================== + +The Dialog manager and the Widget structure are implemented in +src/dialog.c. Everything shown on screen is a dialog. Dialogs contain +widgets, but not everything on screen is a widget. Dialogs can draw +themselves. + +Dialogs are connected into a singly linked list using "parent" field. +Currently active dialog is saved in current_dlg variable. The toplevel +dialog has parent NULL. Usually it's midnight_dlg. + + parent parent +current_dlg ------->another dialog-- ... -->midnight_dlg + +When the screen needs to be refreshed, every dialog asks its parent to +refresh first, and then refreshes itself. + +A dialog is created by create_dlg(). Then it's populated by widgets +using add_widget(). Then the dialog is run by calling run_dlg(), which +returns the id of the button selected by the user. Finally, the dialog +is destroyed by calling destroy_dlg(). + +Widgets are placed to a doubly linked circular list. Each widget has +previous and next widget. + + prev next prev next +widget1 <---------> widget2 <---------> widget3 + ^ ^ + ----------------------------------------- + next prev + +Pressing Tab moves focus to the "next" widget, pressing Shift-Tab moves +focus to "prev". The tab order is equal to the add order except some +old code that use the reverse order by setting DLG_REVERSE flag in +create_dlg() call. Please don't use reverse order in the new code. + +The initial widget to get focus can be selected by calling +dlg_select_widget(). + +When creating a dialog, you may want to use a callback that would +intercept some dialog events. However, many widgets will do the right +thing by default, so some dialogs can work just fine without callbacks. + +There are also widget events, which are sent by the dialog to individual +widgets. Some widgets also have user callbacks. + +To create your own widget, use init_widget(). In this case, you must +provide a callback function. Please note that it's not the same as the +user callback in some widgets. + + +Where to Find Bug Reports and Patches +===================================== + +The official place for bug reports is: + + https://www.midnight-commander.org/ + + +There are various unofficial sources where bug reports and patches can +be found (NOT maintained by the MC team). + + +http://bugs.debian.org/mc + The bug tracking system for Debian, a package collection mainly + for GNU/Linux and the Hurd. + +http://bugzilla.redhat.com/bugzilla/buglist.cgi?component=mc + Bugs reported in Redhat Linux. + +http://www.openbsd.org/cgi-bin/cvsweb/ports/misc/mc/patches/ + The patches that are applied for the OpenBSD version of MC. + +http://www.freebsd.org/cgi/cvsweb.cgi/ports/misc/mc/files/ + The patches that are applied for the FreeBSD version of MC. + +http://cvsweb.netbsd.org/bsdweb.cgi/pkgsrc/sysutils/mc/patches/ + The patches that are applied for the NetBSD version of MC. + +http://sources.gentoo.org/cgi-bin/viewvc.cgi/gentoo-x86/app-misc/mc/files/?hideattic=1 + The patches that are applied for the Gentoo Linux version of MC. + + +Programming Tips +================ + +(This list should be sorted alphabetically.) + +?: This operator has a precedence that is easy to use the wrong way. You + might think that + + int right = 25 + have_frame() ? 1 : 0; /* WRONG */ + + results in either 25 or 26. This is not the case. The C compiler + sees this as: + + int right = (25 + have_frame()) ? 1 : 0; /* WRONG */ + + To avoid this, put the ?: in parentheses, like this + + int right = 25 + (have_frame() ? 1 : 0); /* RIGHT */ + + If the condition is more complicated, put it in additional + parentheses: + + int right = 25 + ((have_frame()) ? 1 : 0); /* RIGHT */ + +const: For every function taking a string argument, decide whether you + (as a user of the function) would expect that the string is modi- + fied by the function. If not, declare the string argument as + "const char *". If your implementation needs to modify the string, + use g_strdup to create a local copy. + +const_cast: Has been replaced by str_unconst. + +g_free: g_free handles NULL argument too, no need for the comparison. + Bad way: + if (old_dir) g_free (old_dir); + Right way: + g_free (old_dir); + +g_strdup: When you use g_strdup to create a local copy of a string, use + the following pattern to keep the reference. + + char * const pathref = g_strdup(argument); + /* ... */ + g_free (pathref); + + The "const" will make the pointer unmodifiable (pathref++ + is not possible), but you can still modify the string contents. + +NULL: When you pass NULL as an argument of a varargs function, cast the + 0 to the appropriate data type. If a system #defines NULL to + be 0 (at least NetBSD and OpenBSD do), and the sizes of int and + a pointer are different, the argument will be passed as int 0, + not as a pointer. + + This tip applies at least to catstrs (edit/edit.h), execl(3), + execle(3), execlp(3), g_strconcat (glib), parent_call + (src/background.h), parent_call_string (src/background.h). + + example: + char *path = g_strconcat("dir", "/", "file", (char *)0); + +size_t: This data type is suitable for expressing sizes of memory or the + length of strings. This type is unsigned, so you need not check + if the value is >= 0. + +strncpy: Don't use this function in newly created code. It is slow, insecure + and hard to use. A much better alternative is g_strlcpy (see there). + +str_unconst: We use many libraries that do not know about "const char *" + and thus declare their functions to require "char *". If you + know for sure that an external function does not modify the + string, you can "unconst" a string using the function + str_unconst(). If you are not sure whether the function modifies + the string, you should use g_strdup() to pass a copy of a string + to the function. Don't forget to call g_free() after work is done. + +unused: Unused arguments of a function can be marked like this: + + void do_nothing(int data) + { + (void) &data; + } + + This tells the GNU C Compiler not to emit a warning, and has no + side effects for other compilers. |