summaryrefslogtreecommitdiffstats
path: root/doc/HACKING
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--doc/HACKING388
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.