1 /*
2  *
3  * CLEX File Manager
4  *
5  * Copyright (C) 2001-2017 Vlado Potisk <vlado_potisk@clex.sk>
6  *
7  * CLEX is free software without warranty of any kind; see the
8  * GNU General Public License as set out in the "COPYING" document
9  * which accompanies the CLEX File Manager package.
10  *
11  * CLEX can be downloaded from http://www.clex.sk
12  *
13  */
14 
15 /*
16  * naming convention for strings and buffers:
17  *   #define XXX_STR is a buffer size, i.e. with the trailing null byte
18  *   #define XXX_LEN is max string length, i.e. without the null byte
19  */
20 
21 /* useful macros */
22 #define ARRAY_SIZE(X)	((int)(sizeof(X) / sizeof(X[0])))
23 #define TOGGLE(X)		((X) = !(X))
24 #define TSET(X)			((X) ? 1 : ((X) = 1, 0))	/* test & set */
25 #define TCLR(X)			((X) ? ((X) = 0, 1) : 0)	/* test & clear */
26 #define LIMIT_MIN(X,MIN)	do if ((X) < (MIN)) (X) = (MIN); while (0)
27 #define LIMIT_MAX(X,MAX)	do if ((X) > (MAX)) (X) = (MAX); while (0)
28 #define CH_CTRL(X)		((X) & 0x1F)				/* byte  ASCII ctrl-X */
29 #define WCH_CTRL(X)		((wchar_t)CH_CTRL(X))		/* wide char ASCII ctrl-X */
30 #define WCH_ESC			L'\033'						/* wchar ASCII escape */
31 /* CMP: no overflow and result is an int even if V1 and V2 are not */
32 #define CMP(V1,V2) ((V1) == (V2) ? 0 : (V1) < (V2) ? -1 : 1)
33 #define STR(X)	STRINGIZE(X)
34 #define STRINGIZE(X)	#X
35 
36 /* typedefs */
37 typedef unsigned short int FLAG;	/* true or false */
38 typedef short int CODE;				/* usually enum or some #define-d value */
39 
40 /* minimal required screen size */
41 #define MIN_COLS	64
42 #define MIN_LINES	12
43 
44 /* limits for prompts */
45 #define MAX_SHORT_CWD_LEN	((MIN_COLS * 2) / 5)	/* 40% */
46 #define MAX_PROMPT_WIDTH	((MIN_COLS * 4) / 5)	/* 80% */
47 
48 /* max textline lines - valid values: 3, 4 and 5 */
49 #define MAX_CMDLINES	4
50 
51 /* operation modes */
52 enum MODE_TYPE {
53 	/*
54 	 * value 0 is reserved, it means mode unchanged in control_loop()
55 	 * and also mode not set during startup
56 	 */
57 	MODE_VALUE_RESERVED = 0,
58 	/* regular modes */
59 	MODE_BM, MODE_BM_EDIT0, MODE_BM_EDIT1, MODE_BM_EDIT2,
60 	MODE_CFG, MODE_CFG_EDIT_NUM, MODE_CFG_EDIT_TXT, MODE_CFG_MENU,
61 	MODE_COMPL, MODE_CMP, MODE_CMP_SUM, MODE_DESELECT,
62 	MODE_DIR, MODE_DIR_SPLIT, MODE_FILE, MODE_FOPT, MODE_GROUP, MODE_HELP,
63 	MODE_HIST, MODE_INSCHAR, MODE_LOG, MODE_MAINMENU, MODE_NOTIF, MODE_PASTE,
64 	MODE_PREVIEW, MODE_RENAME, MODE_SELECT, MODE_SORT, MODE_USER,
65 	/* pseudo-modes */
66 	MODE_SPECIAL_QUIT, MODE_SPECIAL_RETURN
67 };
68 
69 /* info about screen display/layout/appearance */
70 typedef struct {
71 	FLAG curses;		/* curses active */
72 	FLAG wait;			/* a message has been written to the
73 						   text-mode screen, wait for a keypress
74 						   before starting curses */
75 	FLAG noenter;		/* if set, disable "press enter to continue" after command execution */
76 	unsigned int noenter_hash;		/* a hash value of the command line is saved in order to detect
77 									   modifications which cancel the 'noenter' feature */
78 	FLAG bs177;			/* KEY_BACKSPACE sends \177 (see control.c) */
79 	FLAG xterm;			/* TERM is xterm or similar type which can change window title */
80 	FLAG noxterm;		/* TERM is unable to change the window title */
81 						/* note: if not known, both xterm and noxterm are 0 */
82 	FLAG xwin;			/* running in X Window environment */
83 	FLAG mouse;			/* KEY_MOUSE suitable for xterm mouse tracking */
84 	FLAG mouse_swap;	/* left-handed mouse (swap left and right buttons) */
85 	int scrcols;		/* number of columns */
86 	int pancols;		/* number of columns in the panel area */
87 	int panrcol;		/* pancols adjusted for putwcs_trunc_col() */
88 	int scrlines;		/* number of lines */
89 	int cmdlines;		/* number of lines in the textline area */
90 	int panlines;		/* number of lines in the panel area */
91 	int date_len;		/* length of date/time field */
92 	int dir1end, dir2start;	/* columns of the directory names in the file panel title */
93 	wchar_t *layout_panel;	/* layout: file panel part */
94 	wchar_t *layout_line;	/* layout: info line part */
95 } DISP_DATA;
96 
97 /* info about language/encoding */
98 typedef struct {
99 	FLAG utf8;			/* UTF-8 mode */
100 	wchar_t sep000;		/* thousands separator */
101 	wchar_t repl;		/* replacement for unprintable characters */
102 	const wchar_t *time_fmt, *date_fmt;	/* time/date format strings (for strftime) */
103 } LANG_DATA;
104 
105 /* info about the user */
106 #define SHELL_SH	0	/* Bourne shell or similar */
107 #define SHELL_CSH	1	/* C-shell or similar */
108 #define SHELL_OTHER	2	/* other */
109 typedef struct {
110 	const char *login;			/* my login name */
111 	const wchar_t *loginw;		/* my login name */
112 	const char *host;			/* my host */
113 	const wchar_t *hostw;		/* my host */
114 	const char *homedir;		/* my home directory */
115 	const wchar_t *homedirw;	/* my home directory */
116 	const char *shell;			/* my login shell - full path */
117 	const wchar_t *shellw;		/* my login shell - basename only */
118 	const char *subdir;			/* configuration directory */
119 	const char *file_cfg;		/* configuration file */
120 	const char *file_opt;		/* options file */
121 	const char *file_bm;		/* bookmarks file */
122 	CODE shelltype;				/* one of SHELL_XXX */
123 	FLAG isroot;				/* effective uid is 0(root) */
124 	FLAG nowrite;				/* do not write config/options/bookmark file */
125 	FLAG noconfig;				/* no config file, cfg-clex recommended */
126 } USER_DATA;
127 
128 typedef struct {
129 	pid_t pid;					/* process ID */
130 	char pidstr[16];			/* PID as a string */
131 	mode_t umask;				/* umask value */
132 } CLEX_DATA;
133 
134 /* description of an editing operation */
135 enum OP_TYPE {
136 	OP_NONE = 0,	/* no change (cursor movement is OK) - value must be zero */
137 	OP_INS,			/* simple insert */
138 	OP_DEL,			/* simple deletion */
139 	OP_CHANGE		/* modification other than OP_INS or OP_DEL */
140 };
141 typedef struct {
142 	enum OP_TYPE code;
143 /* 'pos' and 'len' are used with OP_INSERT and OP_DELETE only */
144 	int pos;		/* position within the edited string */
145 	int len;		/* length of the inserted/deleted part */
146 } EDIT_OP;
147 
148 #define UNDO_LEVELS 10	/* undo steps */
149 
150 /* line of text where the user can enter and edit his/her input */
151 typedef struct {
152 	USTRINGW prompt;	/* prompt */
153 	int promptwidth;	/* prompt width in display columns */
154 	USTRINGW line;		/* user's input */
155 	int size;			/* number of chars in the line */
156 	int curs;			/* cursor position from 0 to 'size' */
157 	int offset;			/* offset - when the line is too long,
158 						   first 'offset' characters are hidden */
159 	/* values for the UNDO function */
160 	struct {
161 		USTRINGW save_line;
162 		int save_size;
163 		int save_curs;
164 		int save_offset;
165 	} undo [UNDO_LEVELS];	/* used in a circular manner */
166 	int undo_base;			/* index of the first entry */
167 	int undo_levels;		/* occupied entries for undo */
168 	int redo_levels;		/* freed entries usable for redo */
169 	EDIT_OP last_op;		/* last editing operation */
170 } TEXTLINE;
171 
172 /* minimalistic version of TEXTLINE used for panel filters */
173 #define INPUT_STR 23
174 typedef struct {
175 	wchar_t line[INPUT_STR];	/* user's input */
176 	int size;					/* number of chars in the line */
177 	int curs;					/* cursor position from 0 to 'size' */
178 	FLAG changed;				/* 'line' has been modified */
179 } INPUTLINE;
180 
181 /********************************************************************/
182 
183 /* keyboard and mouse input */
184 
185 typedef struct {
186 	CODE fkey;		/* 2 = not a key, but a mouse event, 1 = keypad or 0 = character */
187 	wint_t key;
188 	FLAG prev_esc;	/* previous key was an ESCAPE */
189 } KBD_INPUT;
190 
191 enum AREA_TYPE {
192 	/* from top to bottom */
193 	AREA_TITLE = 0, AREA_TOPFRAME, AREA_PANEL, AREA_BOTTOMFRAME,
194 	AREA_INFO, AREA_HELP, AREA_BAR, AREA_PROMPT, AREA_LINE,
195 	AREA_NONE
196 };
197 typedef struct {
198 	/* mouse data */
199 	int y, x;			/* zero-based coordinates: line and column */
200 	CODE button;		/* regular buttons: 1, 2 and 3, wheel: 4 and 5 */
201 	FLAG doubleclick;	/* a doubleclick (NOTE: first click is aslo reported!) */
202 	FLAG motion;		/* the mouse was in motion (drag) */
203 
204 	/* computed values */
205 	int area;			/* one of AREA_xxx */
206 	int ypanel;			/* panel screen line (AREA_PANEL only): 0 = top */
207 	int cursor;			/* calculated cursor position, see mouse_data() in inout.c */
208 } MOUSE_INPUT;
209 
210 /* shortcuts */
211 #define MI_B(X)		(minp.button == (X))
212 #define MI_DC(X)	(MI_B(X) && minp.doubleclick)
213 #define MI_CLICK	(minp.button == 1 || minp.button == 3)
214 #define MI_WHEEL	(minp.button == 4 || minp.button == 5)
215 #define MI_AREA(X)	(minp.area == AREA_ ## X)
216 #define MI_CURSBAR	(MI_AREA(PANEL) && VALID_CURSOR(panel) && panel->top + minp.ypanel == panel->curs)
217 #define MI_DRAG		(minp.motion)
218 #define MI_PASTE	(MI_B(3) && !MI_DRAG && MI_CURSBAR)
219 
220 /********************************************************************/
221 
222 /* panel types */
223 enum PANEL_TYPE {
224 	PANEL_TYPE_BM = 0, PANEL_TYPE_CFG, PANEL_TYPE_CFG_MENU, PANEL_TYPE_CMP, PANEL_TYPE_CMP_SUM,
225 	PANEL_TYPE_COMPL, PANEL_TYPE_DIR, PANEL_TYPE_DIR_SPLIT, PANEL_TYPE_FILE,
226 	PANEL_TYPE_FOPT, PANEL_TYPE_GROUP, PANEL_TYPE_HELP, PANEL_TYPE_HIST,
227 	PANEL_TYPE_LOG, PANEL_TYPE_MAINMENU, PANEL_TYPE_NOTIF, PANEL_TYPE_PASTE,
228 	PANEL_TYPE_PREVIEW, PANEL_TYPE_SORT, PANEL_TYPE_USER
229 };
230 
231 /*
232  * extra lines appear in a panel before the first regular line,
233  * extra lines:  -MIN .. -1
234  * regular lines:   0 .. MAX
235  */
236 typedef struct {
237 	const wchar_t *text;	/* text to be displayed in the panel */
238 							/* default (if null): "Exit this panel" */
239 	const wchar_t *info;	/* text to be displayed in the info line */
240 	/* when this extra line is selected: */
241 	CODE mode_next;			/* set next_mode to this mode and then ... */
242 	void (*fn)(void); 		/* ... invoke this function */
243 } EXTRA_LINE;
244 
245 /* description of a panel */
246 typedef struct {
247 	int cnt, top;	/* panel lines: total count, top of the screen */
248 	int curs, min;	/* panel lines: cursor bar, top of the panel */
249 	/*
250 	 * 'min' is used to insert extra lines before the real first line
251      * which is always line number 0; to insert N extra lines set
252 	 * 'min' to -N; the number of extra lines is not included in 'cnt'
253 	 */
254 	enum PANEL_TYPE type;
255 	FLAG norev;		/* do not show the current line in reversed video */
256 	EXTRA_LINE *extra;	/* extra panel lines */
257 	INPUTLINE *filter;	/* filter (if applicable to this panel type) */
258 	void (*drawfn)(int);/* function drawing one line of this panel */
259 	CODE filtering;		/* filter: 0 = off */
260 						/* 1 = on - focus on the filter string */
261 						/* 2 = on - focus on the command line */
262 	const wchar_t *help;	/* helpline override */
263 } PANEL_DESC;
264 
265 #define VALID_CURSOR(P) ((P)->cnt > 0 && (P)->curs >= 0 && (P)->curs < (P)->cnt)
266 
267 /********************************************************************/
268 
269 /*
270  * file types recognized in the file panel,
271  * if you change this, you must also update
272  * the type_symbol[] array in inout.c
273  */
274 #define FT_PLAIN_FILE		 0
275 #define FT_PLAIN_EXEC		 1
276 #define FT_PLAIN_SUID		 2
277 #define FT_PLAIN_SUID_ROOT	 3
278 #define FT_PLAIN_SGID		 4
279 #define FT_DIRECTORY		 5
280 #define FT_DIRECTORY_MNT	 6
281 #define FT_DEV_BLOCK		 7
282 #define FT_DEV_CHAR			 8
283 #define FT_FIFO				 9
284 #define FT_SOCKET			10
285 #define FT_OTHER			11
286 #define FT_NA				12
287 
288 /* file type tests */
289 #define IS_FT_PLAIN(X)		((X) >= 0 && (X) <= 4)
290 #define IS_FT_EXEC(X)		((X) >= 1 && (X) <= 4)
291 #define IS_FT_DIR(X)		((X) >= 5 && (X) <= 6)
292 #define IS_FT_DEV(X)		((X) >= 7 && (X) <= 8)
293 
294 /*
295  * if you change any of the FE_XXX_STR #defines, you must change
296  * the corresponding stat2xxx() function(s) in list.c accordingly
297  */
298 /* text buffer sizes */			/* examples: */
299 #define FE_LINKS_STR	 4		/* 1  999  max  */
300 #define FE_TIME_STR		23		/* 11:34:30_am_2010/12/01 */
301 #define FE_AGE_STR		10		/* -01:02:03 */
302 #define FE_SIZE_DEV_STR	12		/* 3.222.891Ki */
303 #define FE_MODE_STR 	 5		/* 0644 */
304 #define FE_NAME_STR		17		/* root */
305 #define FE_OWNER_STR	(2 * FE_NAME_STR)	/* root:mail */
306 
307 /*
308  * file description - exhausting, isn't it ?
309  * we allocate many of these, bitfields save memory
310  */
311 typedef struct {
312 	SDSTRING  file;			/* file name - as it is */
313 	SDSTRINGW filew;		/* file name - converted to wchar for the screen output */
314 	USTRING link;			/* where the symbolic link points to */
315 	USTRINGW linkw;			/* ditto */
316 	const char *extension;	/* file name extension (suffix) */
317 	time_t mtime;			/* last file modification */
318 	off_t size;				/* file size */
319 	dev_t devnum;			/* major/minor numbers (devices only) */
320 	CODE file_type;			/* one of FT_XXX */
321 	uid_t uid, gid;			/* owner and group */
322 	short int mode12;		/* file mode - low 12 bits */
323 	unsigned int select:1;		/* flag: this entry is selected */
324 	unsigned int symlink:1;		/* flag: it is a symbolic link */
325 	unsigned int dotdir:2;		/* . (1) or .. (2) directory */
326 	unsigned int fmatch:1;		/* flag: matches the filter */
327 	/*
328 	 * note: the structure members below are used
329 	 * only when the file panel layout requires them
330 	 */
331 	unsigned int normal_mode:1;	/* file mode same as "normal" file */
332 	unsigned int links:1;		/* has multiple hard links */
333 	wchar_t atime_str[FE_TIME_STR];	/* access time */
334 	wchar_t ctime_str[FE_TIME_STR];	/* inode change time */
335 	wchar_t mtime_str[FE_TIME_STR];	/* file modification time */
336 	wchar_t owner_str[FE_OWNER_STR];/* owner and group */
337 	char age_str[FE_AGE_STR];		/* time since the last modification ("file age") */
338 	char links_str[FE_LINKS_STR];	/* number of links */
339 	char mode_str[FE_MODE_STR];		/* file mode - octal number */
340 	char size_str[FE_SIZE_DEV_STR];	/* file size or dev major/minor */
341 } FILE_ENTRY;
342 
343 /*
344  * When a filter or the selection panel is activated or when panels are switched, the
345  * file panel will be refreshed if the contents are older than PANEL_EXPTIME seconds.
346  * This time is not configurable because it would confuse a typical user.
347  */
348 #define PANEL_EXPTIME 60
349 
350 typedef struct ppanel_file {
351 	PANEL_DESC *pd;
352 	USTRING dir;			/* working directory */
353 	USTRINGW dirw;			/* working directory for screen output */
354 	struct ppanel_file *other;	/* primary <--> secondary panel ptr */
355 	time_t timestamp;		/* when was the directory listed */
356 	FLAG expired;			/* expiration: panel needs to be re-read */
357 	FLAG filtype;			/* filter type: 0 = substring, 1 = pattern */
358 	CODE order;				/* sort order: one of SORT_XXX */
359 	CODE group;				/* group by type: one of GROUP_XXX */
360 	CODE hide;				/* ignore hidden .files: one of HIDE_XXX */
361 	FLAG hidden;			/* there exist hidden .files not shown */
362 	/* unfiltered data - access only in list.c and sort.c */
363 	int all_cnt;			/* number of all files */
364 	int all_alloc;			/* allocated FILE_ENTRies in 'all_files' below */
365 	FILE_ENTRY **all_files;	/* list of files in panel's working directory 'dir' */
366 	/* filtered data */
367 	int filt_alloc;
368 	int selected_out;		/* number of selected entries filtered out */
369 	FILE_ENTRY **filt_files;/* list of files selected by the filter */
370 	/* presented data */
371 	int selected;
372 	FILE_ENTRY **files;		/* 'all_files' or 'filt_files' depending on the filter status */
373 	/* column width information (undefined for unused fields) */
374 	/* number of blank leading characters */
375 	int cw_ln1;			/* $l */
376 	int cw_sz1;			/* $r,$s,$R,$S */
377 	int cw_ow1;			/* $o */
378 	int cw_age;			/* $g */
379 	/* field width */
380 	int cw_mod;			/* $M */
381 	int cw_lns;			/* $> */
382 	int cw_lnh;			/* $L */
383 	int cw_sz2;			/* $r,$s,$R,$S */
384 	int cw_ow2;			/* $o */
385 } PANEL_FILE;
386 
387 /********************************************************************/
388 
389 typedef struct bookmark {
390 	SDSTRINGW name;
391 	USTRING  dir;
392 	USTRINGW dirw;
393 } BOOKMARK;
394 
395 typedef struct {
396 	PANEL_DESC *pd;
397 	BOOKMARK **bm;
398 	int cw_name;	/* field width */
399 } PANEL_BM;
400 
401 typedef struct {
402 	PANEL_DESC *pd;
403 	BOOKMARK *bm;
404 } PANEL_BM_EDIT;
405 
406 /********************************************************************/
407 
408 /* notifications */
409 enum NOTIF_TYPE {
410 	NOTIF_RM = 0, NOTIF_LONG, NOTIF_DOTDIR, NOTIF_SELECTED, NOTIF_FUTURE,
411 	NOTIF_TOTAL_
412 };
413 
414 typedef struct {
415 	PANEL_DESC *pd;
416 	FLAG option[NOTIF_TOTAL_];
417 } PANEL_NOTIF;
418 
419 /* IMPORTANT: value 1 = notification disabled, 0 = enabled (default) */
420 #define NOPT(X)		(panel_notif.option[X])
421 
422 /********************************************************************/
423 
424 /*
425  * file sort order and grouping- if you change this, you must also update
426  * panel initization in start.c and descriptions in inout.c
427  */
428 enum SORT_TYPE {
429 	SORT_NAME_NUM = 0, SORT_NAME, SORT_EXT, SORT_SIZE,
430 	SORT_SIZE_REV, SORT_TIME, SORT_TIME_REV, SORT_EMAN,
431 	SORT_TOTAL_
432 };
433 
434 enum GROUP_TYPE {
435 	GROUP_NONE = 0, GROUP_DSP, GROUP_DBCOP,
436 	GROUP_TOTAL_
437 };
438 
439 enum HIDE_TYPE {
440 	HIDE_NEVER, HIDE_HOME, HIDE_ALWAYS,
441 	HIDE_TOTAL_
442 };
443 
444 typedef struct {
445 	PANEL_DESC *pd;
446 	/* current values: */
447 	CODE group;				/* group by type: one of GROUP_XXX */
448 	CODE order;				/* default file sort order: one of SORT_XXX */
449 	CODE hide;				/* do not show hidden .files */
450 	/* for the user interface menu: */
451 	CODE newgroup;
452 	CODE neworder;
453 	CODE newhide;
454 } PANEL_SORT;
455 
456 /********************************************************************/
457 
458 typedef struct {
459 	const char *name;		/* directory name */
460 	const wchar_t *namew;	/* directory name for display */
461 	int shlen;				/* length of the repeating 'namew' part */
462 } DIR_ENTRY;
463 
464 typedef struct {
465 	PANEL_DESC *pd;
466 	DIR_ENTRY *dir;			/* list of directories to choose from */
467 } PANEL_DIR;
468 
469 typedef struct {
470 	PANEL_DESC *pd;
471 	const char *name;		/* directory name */
472 } PANEL_DIR_SPLIT;
473 
474 /********************************************************************/
475 /* configuration variables in config panel order */
476 enum CFG_TYPE {
477 	/* appearance */
478 	CFG_FRAME, CFG_CMD_LINES, CFG_XTERM_TITLE, CFG_PROMPT,
479 	CFG_LAYOUT1, CFG_LAYOUT2, CFG_LAYOUT3, CFG_LAYOUT, CFG_KILOBYTE,
480 	CFG_FMT_TIME, CFG_FMT_DATE, CFG_TIME_DATE,
481 	/* command execution */
482 	CFG_CMD_F3, CFG_CMD_F4, CFG_CMD_F5, CFG_CMD_F6, CFG_CMD_F7,
483 	CFG_CMD_F8, CFG_CMD_F9, CFG_CMD_F10, CFG_CMD_F11, CFG_CMD_F12,
484 	/* mouse */
485 	CFG_MOUSE, CFG_MOUSE_SCROLL, CFG_DOUBLE_CLICK,
486 	/* other */
487 	CFG_QUOTE, CFG_C_SIZE, CFG_D_SIZE, CFG_H_SIZE,
488 	/* total count*/
489 	CFG_TOTAL_
490 };
491 
492 typedef struct {
493 	const char *var;		/* name of the variable */
494 	const wchar_t *help;	/* one line help */
495 	void *table;			/* -> internal table with details */
496 	unsigned int isnum:1;	/* is numeric (not string) */
497 	unsigned int changed:1;	/* value changed */
498 	unsigned int saveit:1;	/* value should be saved to disk */
499 } CFG_ENTRY;
500 
501 typedef struct {
502 	PANEL_DESC *pd;
503 	CFG_ENTRY *config;		/* list of all configuration variables */
504 } PANEL_CFG;
505 
506 typedef struct {
507 	PANEL_DESC *pd;
508 	const wchar_t **desc;	/* list of textual descriptions */
509 } PANEL_CFG_MENU;
510 
511 /********************************************************************/
512 
513 typedef struct {
514 	USTRINGW cmd;			/* command text */
515 	FLAG failed;			/* command failed or not */
516 } HIST_ENTRY;
517 
518 typedef struct {
519 	PANEL_DESC *pd;
520 	HIST_ENTRY **hist;		/* list of previously executed commands */
521 } PANEL_HIST;
522 
523 /********************************************************************/
524 
525 typedef struct {
526 	CODE type;				/* one of HL_XXX defined in help.h */
527 	const char *data;		/* value of HL_LINK, HL_PAGE or HL_VERSION */
528 	const wchar_t *text;	/* text of HL_TEXT... or HL_TITLE */
529 	int links;				/* number of links in the whole line
530 								(valid for leading HL_TEXT only) */
531 } HELP_LINE;
532 
533 typedef struct {
534 	PANEL_DESC *pd;
535 	CODE pagenum;			/* internal number of current page */
536 	const wchar_t *title;	/* title of the current help page */
537 	int lnk_act, lnk_ln;	/* multiple links in a single line:
538 							lnk_act = which link is active
539 							lnk_ln = for which line is lnk_act valid */
540 	HELP_LINE **line;
541 } PANEL_HELP;
542 
543 /********************************************************************/
544 
545 typedef struct {
546 	SDSTRINGW str;			/* name suitable for a completion */
547 	FLAG is_link;			/* filenames only: it is a symbolic link */
548 	CODE file_type;			/* filenames only: one of FT_XXX */
549 	const wchar_t *aux;		/* additional data (info line) */
550 } COMPL_ENTRY;
551 
552 typedef struct {
553 	PANEL_DESC *pd;
554 	FLAG filenames;			/* stored names are names of files */
555 	const wchar_t *aux;		/* type of additional data - as a string */
556 	const wchar_t *title;	/* panel title */
557 	COMPL_ENTRY **cand;		/* list of completion candidates */
558 } PANEL_COMPL;
559 
560 /********************************************************************/
561 
562 /* - must correspond with descriptions in draw_line_fopt() in inout.c */
563 /* - must correspond with panel_fopt initializer in start.c */
564 /* - fopt_saveopt(), fopt_restoreopt() must remain backward compatible */
565 enum FOPT_TYPE {
566 	FOPT_IC, FOPT_ALL, FOPT_SHOWDIR,
567 	FOPT_TOTAL_
568 };
569 
570 typedef struct {
571 	PANEL_DESC *pd;
572 	FLAG option[FOPT_TOTAL_];
573 } PANEL_FOPT;
574 #define FOPT(X)		(panel_fopt.option[X])
575 
576 /********************************************************************/
577 
578 /* - must correspond with descriptions in draw_line_cmp() in inout.c */
579 /* - must correspond with panel_cmp initializer in start.c */
580 /* - cmp_saveopt(), cmp_restoreopt() must remain backward compatible */
581 enum CMP_TYPE {
582 	CMP_REGULAR, CMP_SIZE, CMP_MODE, CMP_OWNER, CMP_DATA,
583 	CMP_TOTAL_
584 };
585 
586 typedef struct {
587 	PANEL_DESC *pd;
588 	FLAG option[CMP_TOTAL_];
589 } PANEL_CMP;
590 #define COPT(X)		(panel_cmp.option[X])
591 
592 /********************************************************************/
593 
594 #define LOG_LINES		50
595 #define TIMESTAMP_STR	48
596 
597 typedef struct {
598 	CODE level;					/* one of MSG_xxx (defined in log.h) */
599 	const char *levelstr;		/* level as a string */
600 	char timestamp[TIMESTAMP_STR];	/* time/date as a string */
601 	USTRINGW msg;				/* message */
602 	int cols;					/* message width in screen columns */
603 } LOG_ENTRY;
604 
605 typedef struct {
606 	PANEL_DESC *pd;			/* no additional data */
607 	int scroll;				/* amount of horizontal text scroll, normally 0 */
608 	int maxcols;			/* max message width */
609 	LOG_ENTRY *line[LOG_LINES];
610 } PANEL_LOG;
611 
612 /********************************************************************/
613 
614 typedef struct {
615 	PANEL_DESC *pd;			/* no additional data */
616 } PANEL_MENU;
617 
618 /********************************************************************/
619 
620 typedef struct {
621 	PANEL_DESC *pd;
622 	FLAG wordstart;			/* complete from: 0 = beginning of the word, 1 = cursor position */
623 } PANEL_PASTE;
624 
625 /********************************************************************/
626 
627 #define PREVIEW_LINES	400
628 #define PREVIEW_BYTES	16383	/* fr_open() adds 1 */
629 
630 typedef struct {
631 	PANEL_DESC *pd;
632 	int realcnt;				/* lines with real data, used for --end-- mark */
633 	wchar_t *title;				/* name of the file */
634 	USTRINGW line[PREVIEW_LINES];
635 } PANEL_PREVIEW;
636 
637 /********************************************************************/
638 
639 typedef struct {
640 	uid_t uid;
641 	const wchar_t *login;
642 	const wchar_t *gecos;
643 } USER_ENTRY;
644 
645 typedef struct {
646 	PANEL_DESC *pd;
647 	USER_ENTRY *users;
648 	int usr_alloc;			/* allocated entries in 'users' */
649 	size_t maxlen;			/* length of the longest name */
650 } PANEL_USER;
651 
652 typedef struct {
653 	gid_t gid;
654 	const wchar_t *group;
655 } GROUP_ENTRY;
656 
657 typedef struct {
658 	PANEL_DESC *pd;
659 	GROUP_ENTRY *groups;
660 	int grp_alloc;			/* allocated entries in 'groups' */
661 } PANEL_GROUP;
662 
663 /********************************************************************/
664 
665 typedef struct {
666 	PANEL_DESC *pd;
667 	int nonreg1, nonreg2, errors, names, equal;
668 } PANEL_CMP_SUM;
669 
670 /********************************************************************/
671 
672 /* global variables */
673 
674 extern const void *pcfg[CFG_TOTAL_];
675 
676 extern DISP_DATA disp_data;
677 extern LANG_DATA lang_data;
678 extern USER_DATA user_data;
679 extern CLEX_DATA clex_data;
680 
681 extern TEXTLINE *textline;		/* -> active line */
682 extern TEXTLINE line_cmd, line_dir, line_tmp, line_inschar;
683 
684 extern MOUSE_INPUT minp;
685 extern KBD_INPUT kinp;
686 
687 extern PANEL_DESC *panel;		/* -> description of the active panel */
688 extern PANEL_FILE *ppanel_file;
689 extern PANEL_CFG panel_cfg;
690 extern PANEL_CFG_MENU panel_cfg_menu;
691 extern PANEL_BM_EDIT panel_bm_edit;
692 extern PANEL_BM panel_bm;
693 extern PANEL_CMP panel_cmp;
694 extern PANEL_COMPL panel_compl;
695 extern PANEL_CMP_SUM panel_cmp_sum;
696 extern PANEL_DIR panel_dir;
697 extern PANEL_DIR_SPLIT panel_dir_split;
698 extern PANEL_FOPT panel_fopt;
699 extern PANEL_GROUP panel_group;
700 extern PANEL_HELP panel_help;
701 extern PANEL_HIST panel_hist;
702 extern PANEL_LOG panel_log;
703 extern PANEL_MENU panel_mainmenu;
704 extern PANEL_NOTIF panel_notif;
705 extern PANEL_PASTE panel_paste;
706 extern PANEL_PREVIEW panel_preview;
707 extern PANEL_SORT panel_sort;
708 extern PANEL_USER panel_user;
709 
710 extern CODE next_mode;			/* see control.c comments */
711 extern volatile FLAG ctrlc_flag;
712