File: HACKING

package info (click to toggle)
mc 1:4.6.0-4.6.1-pre3-3sarge1
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 15,224 kB
  • ctags: 11,992
  • sloc: ansic: 93,654; sh: 5,102; perl: 1,961; makefile: 1,107; yacc: 316; cs: 43; sed: 16
file content (372 lines) | stat: -rw-r--r-- 14,194 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
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.  Some parts were taken from the messages posted in the mailing
lists.


Compiling from CVS
==================

To compile GNU Midnight commander from CVS, the following software is
required:

Autoconf 2.52 and above (latest is recommended)
Automake 1.5 and above (latest is recommended)
Gettext 0.11.5 and above
Glib 1.2.6 and above (2.x is recommended)

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 and run `configure'.  Arguments given
to `autogen.sh' are passed to `configure'.  Then run `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.11.5.



Working with GNU Midnight Commander
===================================

Please use the CVS version.  It may be quite different from the released
versions.  A lot of cleanup is going on.  The CVS version may be easier
to understand, in addition to the obvious fact that the merging is
easier with the CVS version.

There are some tools in the maint directory on CVS.  They are not
included with releases or snapshots.  You may be interested to look at
them if you are going to work on the project for an extended period of
time.  In particular, the release procedure is described there.

In order to compile GNU Midnight Commander from a clean CVS checkout you
should use autogen.sh instead of configure.  Arguments passed to
autogen.sh are passed to configure after it's generated.

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.

If you have etags installed, you can run "make tags" and use tags in
emacs to find functions or variables.  But you can also use the internal
editor and the "Find File" command to find any text in the source tree.

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:

-kr -i4 -pcs -psl --ignore-newlines

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.

slang - stripped down S-Lang library.

It's provided to allow compilation that don't have the S-Lang library
with complete headers or the library is broken.  Please avoid changing
this code.  If you do change it, please consider contributing your
changes to the maintainers of S-Lang.


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.

Files findme.c, popt.c, poptconfig.c, popthelp.c and poptparse.c come
from the popt library used to parse the command line.  They should not
be modified unless absolutely necessary.

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, NULL);

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
=====================================

There are various sources where bug reports and patches can be found.

http://savannah.gnu.org/bugs/?group=mc
	The primary bug tracking system for MC.

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://savannah.gnu.org/patch/?group=mc
	Patches reported in the GNU Savannah project.

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://cvs.sourceforge.net/viewcvs.py/pkgsrc-wip/wip/mc/patches/
	The patches for the work-in-progress NetBSD package of MC.

http://www.gentoo.org/cgi-bin/viewcvs.cgi/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.)

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: We use many libraries that do not know about "const char *" and
	thus declare their functions to require "char *". In cases where we
	know the function does not modify the string, we can use the macro
	const_cast(char *, string_var) instead of a simple (char *) string_var
	to make the intent clear. In cases where we are not sure what the
	function does with the string, we should use g_strdup to pass
	dynamically allocated strings.

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.
	
g_strlcpy: Whenever you use this function, be sure to add "glibcompat.h"
	to the included headers. This is because in glib-1.2 there is
	no such function.

NULL: When you pass NULL as an argument of a varargs function, cast the
	NULL 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),
	rpc_get (vfs/mcfsutil.h), rpc_send (vfs/mcfsutil.h).

	example:
	char *path = g_strconcat("dir", "/", "file", (char *) NULL);

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).