home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / git-4.3 / git-4 / git-4.3.11 / src / git.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-06-06  |  58.8 KB  |  2,855 lines

  1. /* git.c -- The main git file.  */
  2.  
  3. /* Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
  4.  
  5.    This program is free software; you can redistribute it and/or modify
  6.    it under the terms of the GNU General Public License as published by
  7.    the Free Software Foundation; either version 2, or (at your option)
  8.    any later version.
  9.  
  10.    This program is distributed in the hope that it will be useful,
  11.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.    GNU General Public License for more details.
  14.  
  15.    You should have received a copy of the GNU General Public License
  16.    along with this program; if not, write to the Free Software
  17.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19. /* Written by Tudor Hulubei and Andrei Pitis.  */
  20.  
  21.  
  22. #ifdef HAVE_CONFIG_H
  23. #include <config.h>
  24. #endif
  25.  
  26. #include <stdio.h>
  27.  
  28. #ifdef HAVE_STDLIB_H
  29. #include <stdlib.h>
  30. #else /* !HAVE_STDLIB_H */
  31. #include "ansi_stdlib.h"
  32. #endif /* !HAVE_STDLIB_H */
  33.  
  34. #include <sys/types.h>
  35. #include "file.h"
  36. #include <ctype.h>
  37. #include <signal.h>
  38. #include <pwd.h>
  39. #include <grp.h>
  40. #include <limits.h>
  41. #include <sys/wait.h>
  42.  
  43. #ifdef HAVE_UNISTD_H
  44. #include <unistd.h>
  45. #endif /* HAVE_UNISTD_H */
  46.  
  47. #include "stdc.h"
  48. #include "xstring.h"
  49. #include "xmalloc.h"
  50. #include "xio.h"
  51. #include "tty.h"
  52. #include "window.h"
  53. #include "inputline.h"
  54. #include "status.h"
  55. #include "panel.h"
  56. #include "configure.h"
  57. #include "signals.h"
  58. #include "system.h"
  59. #include "history.h"
  60. #include "tilde.h"
  61. #include "misc.h"
  62.  
  63.  
  64. #ifndef HAVE_PUTENV
  65. #ifndef HAVE_SETENV
  66. #ifdef NeXT
  67. #define HAVE_PUTENV 1
  68. #undef HAVE_SETENV
  69. extern int putenv PROTO ((char *));
  70. #endif /* NeXT */
  71. #endif /* HAVE_SETENV */
  72. #endif /* HAVE_PUTENV */
  73.  
  74.  
  75. extern int suspend_allowed;
  76. extern int signals_status;
  77.  
  78.  
  79. #define MAX_STATIC_SIZE 50
  80.  
  81.  
  82. #ifdef HAVE_LINUX
  83. extern int LinuxConsole;
  84. #endif /* HAVE_LINUX */
  85.  
  86.  
  87. #ifdef HAVE_LINUX
  88. int AnsiColors = ON;
  89. #else   /* !HAVE_LINUX */
  90. int AnsiColors = OFF;
  91. #endif  /* !HAVE_LINUX */
  92.  
  93. int TypeSensitivity = ON;
  94.  
  95. /* These are the only possible current_mode values. Used while resuming
  96.    from suspended mode in order to correctly refresh the display. */
  97. #define GIT_SCREEN_MODE         0
  98. #define GIT_TERMINAL_MODE       1
  99.  
  100.  
  101. pid_t pid;
  102. char *home;
  103. char *program;
  104. int two_panel_mode = 1;
  105. int SCREEN_X;
  106. int SCREEN_Y;
  107. int current_mode = GIT_SCREEN_MODE;
  108.  
  109. int wait_msg = 0;
  110.  
  111. int UseLastScreenChar;
  112.  
  113. char cSection[]  = "[GIT-Color]";
  114. char bwSection[] = "[GIT-Monochrome]";
  115.  
  116. #ifdef HAVE_GCC
  117. char title[] = " "PRODUCT" "VERSION;
  118. #else
  119. char title[] = " GNU Interactive Tools 4.3.11";
  120. #endif /* !HAVE_GCC */
  121.  
  122. char login[] = "User:";
  123. char tty[] = "tty:";
  124.  
  125. char lock_think[] = "Wait, I am thinking...";
  126. char lock_ok[]    = "Wait, I am thinking... well, it looks good.";
  127. char lock_bad[]   = "Wait, I am thinking... well, lets try again.";
  128.  
  129. #ifdef HAVE_GCC
  130. char exit_msg[] = "Exit "PRODUCT" ? ";
  131. #else
  132. char exit_msg[] = "Exit GNU Interactive Tools ? ";
  133. #endif /* !HAVE_GCC */
  134.  
  135. char *screen;
  136. char PS1[4] = " $ ";
  137. panel_t *left_panel, *right_panel, *src_panel, *dest_panel, *temp_panel;
  138.  
  139. char *TempDirectory = "";
  140.  
  141. static char *NormalModeHelp      = "";
  142. static char *CommandLineModeHelp = "";
  143. static int  ConfirmOnExit;
  144.  
  145. /* Directory history stuff.  */
  146. char **dir_history;
  147. int dir_history_count;
  148. int dir_history_point;
  149.  
  150. #define BUILTIN_OPERATIONS                       77
  151.  
  152. #define BUILTIN_copy                -1
  153. #define BUILTIN_move                -2
  154. #define BUILTIN_make_directory            -3
  155. #define BUILTIN_delete                -4
  156. #define BUILTIN_exit                -5
  157. #define BUILTIN_previous_history_element    -6
  158. #define BUILTIN_tty_mode            -7
  159. #define BUILTIN_refresh                -8
  160. #define BUILTIN_switch_panels            -9
  161. #define BUILTIN_next_history_element        -10
  162. #define BUILTIN_panel_enable_next_mode        -11
  163. #define BUILTIN_panel_enable_owner_group    -12
  164. #define BUILTIN_panel_enable_date_time        -13
  165. #define BUILTIN_panel_enable_size        -14
  166. #define BUILTIN_panel_enable_mode        -15
  167. #define BUILTIN_panel_enable_full_name        -16
  168. #define BUILTIN_panel_sort_next_method        -17
  169. #define BUILTIN_panel_sort_by_name        -18
  170. #define BUILTIN_panel_sort_by_extension        -19
  171. #define BUILTIN_panel_sort_by_size        -20
  172. #define BUILTIN_panel_sort_by_date        -21
  173. #define BUILTIN_panel_sort_by_mode        -22
  174. #define BUILTIN_panel_sort_by_owner_id        -23
  175. #define BUILTIN_panel_sort_by_group_id        -24
  176. #define BUILTIN_panel_sort_by_owner_name    -25
  177. #define BUILTIN_panel_sort_by_group_name    -26
  178. #define BUILTIN_select_file            -27
  179. #define BUILTIN_file_to_input_line        -28
  180. #define BUILTIN_beginning_of_panel        -29
  181. #define BUILTIN_end_of_panel            -30
  182. #define BUILTIN_scroll_down            -31
  183. #define BUILTIN_scroll_up            -32
  184. #define BUILTIN_previous_line            -33
  185. #define BUILTIN_next_line            -34
  186. #define BUILTIN_other_panel            -35
  187. #define BUILTIN_change_directory        -36
  188. #define BUILTIN_hard_refresh            -37
  189. #define BUILTIN_select_files_matching_pattern    -38
  190. #define BUILTIN_unselect_files_matching_pattern    -39
  191. #define BUILTIN_adapt_current_directory        -40
  192. #define BUILTIN_adapt_other_directory        -41
  193. #define BUILTIN_other_path_to_input_line    -42
  194. #define BUILTIN_selected_files_to_input_line    -43
  195. #define BUILTIN_backward_char            -44
  196. #define BUILTIN_forward_char            -45
  197. #define BUILTIN_backward_word            -46
  198. #define BUILTIN_forward_word            -47
  199. #define BUILTIN_beginning_of_line        -48
  200. #define BUILTIN_end_of_line            -49
  201. #define BUILTIN_delete_char            -50
  202. #define BUILTIN_backward_delete_char        -51
  203. #define BUILTIN_kill_word            -52
  204. #define BUILTIN_backward_kill_word        -53
  205. #define BUILTIN_kill_line            -54
  206. #define BUILTIN_kill_to_beginning_of_line    -55
  207. #define BUILTIN_kill_to_end_of_line        -56
  208. #define BUILTIN_just_one_space            -57
  209. #define BUILTIN_delete_horizontal_space        -58
  210. #define BUILTIN_downcase_word            -59
  211. #define BUILTIN_upcase_word            -60
  212. #define BUILTIN_capitalize_word            -61
  213. #define BUILTIN_action                -62
  214. #define BUILTIN_set_mark            -63
  215. #define BUILTIN_kill_region            -64
  216. #define BUILTIN_kill_ring_save            -65
  217. #define BUILTIN_yank                -66
  218. #define BUILTIN_exchange_point_and_mark        -67
  219. #define BUILTIN_set_scroll_step            -68
  220. #define BUILTIN_isearch_backward        -69
  221. #define BUILTIN_isearch_forward            -70
  222. #define BUILTIN_previous_directory        -71
  223. #define BUILTIN_next_directory            -72
  224. #define BUILTIN_reset_directory_history        -73
  225. #define BUILTIN_enlarge_panel            -74
  226. #define BUILTIN_enlarge_other_panel        -75
  227. #define BUILTIN_two_panels            -76
  228. #define BUILTIN_lock                -77
  229.  
  230.  
  231. #define MAX_BUILTIN_NAME             35
  232.  
  233.  
  234. char built_in[BUILTIN_OPERATIONS][MAX_BUILTIN_NAME] =
  235. {
  236.     "copy",
  237.     "move",
  238.     "make-directory",
  239.     "delete",
  240.     "exit",
  241.     "previous-history-element",
  242.     "tty-mode",
  243.     "refresh",
  244.     "switch-panels",
  245.     "next-history-element",
  246.     "panel-enable-next-mode",
  247.     "panel-enable-owner-group",
  248.     "panel-enable-date-time",
  249.     "panel-enable-size",
  250.     "panel-enable-mode",
  251.     "panel-enable-full-name",
  252.     "panel-sort-next-method",
  253.     "panel-sort-by-name",
  254.     "panel-sort-by-extension",
  255.     "panel-sort-by-size",
  256.     "panel-sort-by-date",
  257.     "panel-sort-by-mode",
  258.     "panel-sort-by-owner-id",
  259.     "panel-sort-by-group-id",
  260.     "panel-sort-by-owner-name",
  261.     "panel-sort-by-group-name",
  262.     "select-file",
  263.     "file-to-input-line",
  264.     "beginning-of-panel",
  265.     "end-of-panel",
  266.     "scroll-down",
  267.     "scroll-up",
  268.     "previous-line",
  269.     "next-line",
  270.     "other-panel",
  271.     "change-directory",
  272.     "hard-refresh",
  273.     "select-files-matching-pattern",
  274.     "unselect-files-matching-pattern",
  275.     "adapt-current-directory",
  276.     "adapt-other-directory",
  277.     "other-path-to-input-line",
  278.     "selected-files-to-input-line",
  279.     "backward-char",
  280.     "forward-char",
  281.     "backward-word",
  282.     "forward-word",
  283.     "beginning-of-line",
  284.     "end-of-line",
  285.     "delete-char",
  286.     "backward-delete-char",
  287.     "kill-word",
  288.     "backward-kill-word",
  289.     "kill-line",
  290.     "kill-to-beginning-of-line",
  291.     "kill-to-end-of-line",
  292.     "just-one-space",
  293.     "delete-horizontal-space",
  294.     "downcase-word",
  295.     "upcase-word",
  296.     "capitalize-word",
  297.     "action",
  298.     "set-mark",
  299.     "kill-region",
  300.     "kill-ring-save",
  301.     "yank",
  302.     "exchange-point-and-mark",
  303.     "set-scroll-step",
  304.     "isearch-backward",
  305.     "isearch-forward",
  306.     "previous-directory",
  307.     "next-directory",
  308.     "reset-directory-history",
  309.     "enlarge-panel",
  310.     "enlarge-other-panel",
  311.     "two-panels",
  312.     "lock",
  313. };
  314.  
  315.  
  316. typedef struct
  317. {
  318.     char *name;         /* the command name.  */
  319.     char *body;         /* the unexpanded command body.  */
  320.     char *new_dir;      /* if exit code == 0, goto this directory.  */
  321.     char  save_screen;  /* save the screen contents (if possible).  */
  322.     char  pause;        /* wait for a key before restoring the panels.  */
  323.     char  hide;         /* hide the output, emulating a builtin command.  */
  324.     char  builtin;      /* this is a builtin command.  */
  325.     char *sequence;     /* the ascii representation of the key sequence on
  326.                which the command is binded; used only for error
  327.                reporting purposes.  */
  328.     xstack_t *history;  /* the history of the strings used to expand the
  329.                command body.  */
  330. } command_t;
  331.  
  332.  
  333. #define MAX_KEYS        2048      /* enough ?   :-) */
  334. #define KEYSDATA_FIELDS    8
  335.  
  336.  
  337. #define TITLE_FIELDS    5
  338.  
  339. static char *TitleFields[TITLE_FIELDS] =
  340. {
  341.     "TitleForeground",
  342.     "TitleBackground",
  343.     "TitleBrightness",
  344.     "UserName",
  345.     "TtyName",
  346. };
  347.  
  348. #ifdef HAVE_LINUX
  349. static int TitleColors[TITLE_FIELDS] =
  350. {
  351.     CYAN, BLUE, ON, YELLOW, YELLOW
  352. };
  353. #else   /* !HAVE_LINUX */
  354. static int TitleColors[TITLE_FIELDS] =
  355. {
  356.     WHITE, BLACK, ON, WHITE, WHITE
  357. };
  358. #endif  /* !HAVE_LINUX */
  359.  
  360. #define TitleForeground TitleColors[0]
  361. #define TitleBackground TitleColors[1]
  362. #define TitleBrightness TitleColors[2]
  363. #define UserName        TitleColors[3]
  364. #define TtyName         TitleColors[4]
  365.  
  366.  
  367.  
  368. /*****************************************/
  369. /* The GIT interface to the input line.  */
  370. /*****************************************/
  371.  
  372. #define IL_ISEARCH_BEGIN        0
  373. #define IL_ISEARCH_BACKWARD     1
  374. #define IL_ISEARCH_FORWARD      2
  375. #define IL_ISEARCH_END          3
  376.  
  377.  
  378. int   il_dispatch_commands PROTO ((int, int));
  379. char *il_fix_text PROTO ((char *));
  380. char *il_build_help_from_string PROTO ((char *));
  381. char *il_isearch PROTO ((char *, char **, int, int *));
  382. char  il_read_char PROTO ((char *, char *, int));
  383. char *il_read_line PROTO ((char *, char **, char *, xstack_t *));
  384.  
  385.  
  386. /*
  387.  * Add a string to the history.
  388.  */
  389.  
  390. void
  391. il_history_add_entry(history, text)
  392.     xstack_t *history;
  393.     char *text;
  394. {
  395.     char *history_text;
  396.  
  397.     /* Avoid duplicates.  */
  398.     if (xstack_preview(history, &history_text, 1) &&
  399.     strcmp(history_text, text) == 0)
  400.     return;
  401.  
  402.     history_text = xstrdup(text);
  403.     xstack_push(history, &history_text);
  404. }
  405.  
  406.  
  407. /*
  408.  * Preview a history string.
  409.  */
  410.  
  411. char *
  412. il_history_view_entry(history, offset)
  413.     xstack_t *history;
  414.     int offset;
  415. {
  416.     char *history_text;
  417.  
  418.     return xstack_preview(history, &history_text, offset) ?
  419.        history_text : NULL;
  420. }
  421.  
  422.  
  423. /*
  424.  * Dispatch input line commands. key is the actual command while flags is
  425.  * a set of IL_*s or-ed together, allowing us to customize the  behaviour
  426.  * of the input line.  If IL_MOVE is not specified, the  IL_EDIT  flag is
  427.  * ignored.  Returns 1 if key has been processed and 0 otherwise.
  428.  */
  429.  
  430. int
  431. il_dispatch_commands(key, flags)
  432.     int key;
  433.     int flags;
  434. {
  435.     if ((flags & IL_MOVE) == 0)
  436.     return 0;
  437.  
  438.     switch (key)
  439.     {
  440.     case BUILTIN_backward_char:
  441.         il_backward_char();
  442.         break;
  443.  
  444.     case BUILTIN_forward_char:
  445.         il_forward_char();
  446.         break;
  447.  
  448.     case BUILTIN_backward_word:
  449.         il_backward_word();
  450.         break;
  451.  
  452.     case BUILTIN_forward_word:
  453.         il_forward_word();
  454.         break;
  455.  
  456.     case BUILTIN_beginning_of_line:
  457.         il_beginning_of_line();
  458.         break;
  459.  
  460.     case BUILTIN_end_of_line:
  461.         il_end_of_line();
  462.         break;
  463.  
  464.     case BUILTIN_delete_char:
  465.         if (flags & IL_EDIT)
  466.         il_delete_char();
  467.         break;
  468.  
  469.     case BUILTIN_backward_delete_char:
  470.         if (flags & IL_EDIT)
  471.         il_backward_delete_char();
  472.         break;
  473.  
  474.     case BUILTIN_kill_word:
  475.         if (flags & IL_EDIT)
  476.         il_kill_word();
  477.         break;
  478.  
  479.     case BUILTIN_backward_kill_word:
  480.         if (flags & IL_EDIT)
  481.         il_backward_kill_word();
  482.         break;
  483.  
  484.     case BUILTIN_kill_line:
  485.         if (flags & IL_EDIT)
  486.         il_kill_line(IL_STORE);
  487.         break;
  488.  
  489.     case BUILTIN_kill_to_beginning_of_line:
  490.         if (flags & IL_EDIT)
  491.         il_kill_to_beginning_of_line();
  492.         break;
  493.  
  494.     case BUILTIN_kill_to_end_of_line:
  495.         if (flags & IL_EDIT)
  496.         il_kill_to_end_of_line();
  497.         break;
  498.  
  499.     case BUILTIN_just_one_space:
  500.         if (flags & IL_EDIT)
  501.         il_just_one_space();
  502.         break;
  503.  
  504.     case BUILTIN_delete_horizontal_space:
  505.         if (flags & IL_EDIT)
  506.         il_delete_horizontal_space();
  507.         break;
  508.  
  509.     case BUILTIN_downcase_word:
  510.         if (flags & IL_EDIT)
  511.         il_downcase_word();
  512.         break;
  513.  
  514.     case BUILTIN_upcase_word:
  515.         if (flags & IL_EDIT)
  516.         il_upcase_word();
  517.         break;
  518.  
  519.     case BUILTIN_capitalize_word:
  520.         if (flags & IL_EDIT)
  521.         il_capitalize_word();
  522.         break;
  523.  
  524.     case BUILTIN_set_mark:
  525.         il_set_mark();
  526.         break;
  527.  
  528.     case BUILTIN_kill_region:
  529.         if (flags & IL_EDIT)
  530.         il_kill_region();
  531.         break;
  532.  
  533.     case BUILTIN_kill_ring_save:
  534.         il_kill_ring_save();
  535.         break;
  536.  
  537.     case BUILTIN_yank:
  538.         if (flags & IL_EDIT)
  539.         il_yank();
  540.         break;
  541.  
  542.     case BUILTIN_exchange_point_and_mark:
  543.         il_exchange_point_and_mark();
  544.         break;
  545.  
  546.     default:
  547.         if ((flags & IL_EDIT) && is_print(key))
  548.         il_insert_char(key);
  549.         else
  550.         return 0;
  551.         break;
  552.     }
  553.  
  554.     return 1;
  555. }
  556.  
  557.  
  558. /*
  559.  * Fix the text.  Replace non-printable characters with spaces and expand
  560.  * tabs.  Return a malloc-ed pointer to the fixed text.  The caller should
  561.  * free the new text.
  562.  */
  563.  
  564. char *
  565. il_fix_text(text)
  566.    char *text;
  567. {
  568.     int i, j;
  569.     char *fixed_text;
  570.     size_t fixed_text_length;
  571.  
  572.  
  573.     if (text == NULL)
  574.     return NULL;
  575.  
  576.     fixed_text = xmalloc(fixed_text_length = (strlen(text) + 1));
  577.  
  578.     for (i = 0, j = 0; text[i]; i++)
  579.     if (text[i] == '\t')
  580.     {
  581.         fixed_text = xrealloc(fixed_text, fixed_text_length += 8);
  582.         memcpy(&fixed_text[j], "        ", 8);
  583.         j += 8;
  584.     }
  585.     else
  586.         if (is_print(text[i]))
  587.         fixed_text[j++] = text[i];
  588.         else
  589.         fixed_text[j++] = ' ';
  590.  
  591.     fixed_text[j] = 0;
  592.  
  593.     return fixed_text;
  594. }
  595.  
  596.  
  597. char *
  598. il_build_help_from_string(options)
  599.     char *options;
  600. {
  601.     size_t len = 0;
  602.     char *options_ptr = options;
  603.     char *help = xmalloc(1 + strlen(options) * 3 + 8);
  604.  
  605.     help[len++] = '(';
  606.  
  607.     for (; *(options_ptr + 1); options_ptr++)
  608.     {
  609.     help[len++] = *options_ptr;
  610.     help[len++] = ',';
  611.     help[len++] = ' ';
  612.     }
  613.  
  614.     help[len++] = *options_ptr;
  615.     help[len++] = ')';
  616.     help[len++] = ' ';
  617.     help[len++] = '\0';
  618.  
  619.     return help;
  620. }
  621.  
  622.  
  623. /*
  624.  * Read only one char from the input line.  message is a string explaining
  625.  * what is this all about.  options is a string containing only those
  626.  * characters that are valid answers, NULL if any character is a valid
  627.  * answer.  The default char is the first char in the options string.
  628.  * Returns 0 if it was interrupted, a valid character otherwise.
  629.  */
  630.  
  631. char
  632. il_read_char(message, options, flags)
  633.     char *message;
  634.     char *options;
  635.     int flags;
  636. {
  637.     char *help;
  638.     tty_key_t *ks;
  639.     int key, repeat_count;
  640.     command_t *command;
  641.     input_line_t *saved_il = NULL;
  642.  
  643.     if (flags & IL_SAVE)
  644.     saved_il = il_save();
  645.  
  646.     il_reset_line();
  647.  
  648.     if (message)
  649.     {
  650.     char *text = il_fix_text(message);
  651.  
  652.     if (flags & IL_ERROR)
  653.     {
  654.         il_insert_text("*** ");
  655.         il_set_error_flag(1);
  656.     }
  657.  
  658.     il_insert_text(text);
  659.  
  660.     xfree(text);
  661.  
  662.     if (options)
  663.     {
  664.         help = il_build_help_from_string(options);
  665.         il_insert_text(help);
  666.         xfree(help);
  667.     }
  668.     }
  669.  
  670.     il_full_update();
  671.  
  672.     if (flags & IL_BEEP)
  673.     tty_beep();
  674.  
  675.     while (1)
  676.     {
  677.     ks  = tty_get_key(&repeat_count);
  678.     key = ks->key_seq[0];
  679.  
  680.     command = (command_t *)ks->aux_data;
  681.  
  682.     if (command && command->builtin)
  683.         key = - 1 - (command->name - built_in[0]) / MAX_BUILTIN_NAME;
  684.  
  685.     switch (key)
  686.     {
  687.         case BUILTIN_action:
  688.         if (options != NULL)
  689.             key = *options;
  690.  
  691.         case key_INTERRUPT:
  692.         goto done;
  693.  
  694.         default:
  695.         while (repeat_count--)
  696.             if (il_dispatch_commands(key, flags) == 0)
  697.             goto il_error;
  698.  
  699.         il_update();
  700.         break;
  701.  
  702.           il_error:
  703.  
  704.         if (options == NULL)
  705.             goto done;
  706.  
  707.         if (options && strchr(options, key))
  708.             goto done;
  709.  
  710.         tty_beep();
  711.         break;
  712.     }
  713.  
  714.     il_update_point();
  715.     }
  716.  
  717.   done:
  718.  
  719.     il_set_error_flag(0);
  720.  
  721.     if ((flags & IL_SAVE) && saved_il)
  722.     {
  723.     il_restore(saved_il);
  724.     il_full_update();
  725.     }
  726.  
  727.     return (key == key_INTERRUPT) ? 0 : key;
  728. }
  729.  
  730.  
  731. /*
  732.  * WARNING: dest *must* be a pointer to a NULL pointer or a pointer to a
  733.  * pointer allocated with xmalloc.  In  the  first case,  il_read_line()
  734.  * will return a string allocated with xmalloc(). In the second case, it
  735.  * will reallocate the pointer as needed using xrealloc. You should free
  736.  * this pointer yourself.
  737.  */
  738.  
  739. char *
  740. il_read_line(static_text, dest, default_string, history)
  741.     char *static_text;
  742.     char **dest;
  743.     char *default_string;
  744.     xstack_t *history;
  745. {
  746.     tty_key_t *ks;
  747.     char *history_text;
  748.     command_t *command;
  749.     int key, repeat_count, offset = 0;
  750.  
  751.  
  752.     il_reset_line();
  753.  
  754.     if (static_text)
  755.     il_set_static_text(static_text);
  756.  
  757.     if (default_string)
  758.     il_insert_text(default_string);
  759.  
  760.     if (history && default_string)
  761.     {
  762.     il_history_add_entry(history, default_string);
  763.     offset = 1;
  764.     }
  765.  
  766.     il_full_update();
  767.  
  768.     while (1)
  769.     {
  770.     ks  = tty_get_key(&repeat_count);
  771.     key = ks->key_seq[0];
  772.  
  773.     command = (command_t *)ks->aux_data;
  774.  
  775.     if (command && command->builtin)
  776.         key = - 1 - (command->name - built_in[0]) / MAX_BUILTIN_NAME;
  777.  
  778.     switch (key)
  779.     {
  780.         case BUILTIN_previous_line:
  781.         case BUILTIN_previous_history_element:
  782.         if (history == NULL)
  783.             break;
  784.  
  785.         history_text = il_history_view_entry(history, ++offset);
  786.  
  787.         if (history_text == NULL)
  788.         {
  789.             offset--;
  790.             tty_beep();
  791.         }
  792.         else
  793.         {
  794.             il_kill_line(IL_DONT_STORE);
  795.             il_insert_text(history_text);
  796.             il_full_update();
  797.         }
  798.         break;
  799.  
  800.         case BUILTIN_next_line:
  801.         case BUILTIN_next_history_element:
  802.         if (history == NULL)
  803.             break;
  804.  
  805.         if (offset == 0)
  806.         {
  807.             il_kill_line(IL_DONT_STORE);
  808.             il_full_update();
  809.             break;
  810.         }
  811.  
  812.         il_kill_line(IL_DONT_STORE);
  813.  
  814.         offset--;
  815.  
  816.         if (offset > 0)
  817.         {
  818.             history_text = il_history_view_entry(history, offset);
  819.             il_insert_text(history_text);
  820.         }
  821.  
  822.         il_full_update();
  823.         break;
  824.  
  825.         case BUILTIN_action:
  826.         il_get_contents(dest);
  827.  
  828.         case key_INTERRUPT:
  829.         goto done;
  830.  
  831.         default:
  832.         while (repeat_count--)
  833.             if (il_dispatch_commands(key, IL_MOVE | IL_EDIT) == 0)
  834.             {
  835.             tty_beep();
  836.             goto done;
  837.             }
  838.  
  839.         il_update();
  840.         break;
  841.     }
  842.  
  843.     il_update_point();
  844.     }
  845.  
  846.   done:
  847.  
  848.     if (key == BUILTIN_action)
  849.     {
  850.     if (history)
  851.         il_history_add_entry(history, *dest);
  852.     return *dest;
  853.     }
  854.     else
  855.     return NULL;
  856. }
  857.  
  858.  
  859. /*
  860.  * status = IL_ISEARCH_BEGIN    -> we are beginning to isearch; initialize
  861.  * status = IL_ISEARCH_BACKWARD -> we are in the middle of an isearch-backward
  862.  * status = IL_ISEARCH_FORWARD  -> we are in the middle of an isearch-forward
  863.  * status = IL_ISEARCH_END      -> isearch complete; clean up
  864.  *
  865.  * *action = IL_ISEARCH_ACTION_DECREASE -> the user pressed the backspace key
  866.  *                       so if there is no matching element
  867.  *                       in the panel stack, we should delete
  868.  *                       the last character in the input line
  869.  * *action = IL_ISEARCH_ACTION_RETRY    -> the user pressed the isearch-forward
  870.  *                       character again, so we should try to
  871.  *                       find a new match for the current
  872.  *                       string
  873.  * *action = IL_ISEARCH_ACTION_INCREASE -> a new character has been inserted
  874.  *                       into the input line so we should try
  875.  *                       to find a match for the new string
  876.  */
  877.  
  878. char *
  879. il_isearch(static_text, dest, status, action)
  880.     char *static_text;
  881.     char **dest;
  882.     int status;
  883.     int *action;
  884. {
  885.     int key;
  886.     tty_key_t *ks;
  887.     static input_line_t *saved_il;
  888.     command_t *command;
  889.  
  890.  
  891.     if (status == IL_ISEARCH_BEGIN)
  892.     {
  893.     saved_il = il_save();
  894.     il_reset_line();
  895.  
  896.     if (static_text)
  897.         il_set_static_text(static_text);
  898.  
  899.     return NULL;
  900.     }
  901.  
  902.     if (status == IL_ISEARCH_END)
  903.     {
  904.     il_restore(saved_il);
  905.     il_full_update();
  906.     return NULL;
  907.     }
  908.  
  909.     if (action == NULL)
  910.     return NULL;
  911.  
  912.     *action = IL_ISEARCH_ACTION_NONE;
  913.  
  914.     il_full_update();
  915.  
  916.     ks  = tty_get_key(NULL);
  917.     key = ks->key_seq[0];
  918.  
  919.     command = (command_t *)ks->aux_data;
  920.  
  921.     if (command && command->builtin)
  922.     key = - 1 - (command->name - built_in[0]) / MAX_BUILTIN_NAME;
  923.  
  924.     switch (key)
  925.     {
  926.     case key_INTERRUPT:
  927.     case BUILTIN_action:
  928.         break;
  929.  
  930.     case BUILTIN_backward_delete_char:
  931.         /* If the input line is empty, just beep.  */
  932.         if (il_is_empty())
  933.         tty_beep();
  934.         else
  935.         {
  936.         *action = IL_ISEARCH_ACTION_DECREASE;
  937.         /* Don't call il_backward_delete_char().  There might be
  938.            several history elements in the panel stack that match
  939.            the current string so we have to delay the call to
  940.            il_backward_delete_char() until all the matching elements
  941.            have been pop-ed.  */
  942.         }
  943.  
  944.         break;
  945.  
  946.     default:
  947.         if ((key == BUILTIN_isearch_backward &&
  948.          status == IL_ISEARCH_BACKWARD)         ||
  949.         (key == BUILTIN_isearch_forward  &&
  950.          status == IL_ISEARCH_FORWARD))
  951.         {
  952.         if (!il_is_empty())
  953.         {
  954.             *action = IL_ISEARCH_ACTION_RETRY;
  955.             break;
  956.         }
  957.         }
  958.  
  959.         if (is_print(key))
  960.         {
  961.         il_insert_char(key);
  962.         *action = IL_ISEARCH_ACTION_INCREASE;
  963.         }
  964.         else
  965.         key = key_INTERRUPT;    /* Force a NULL return value.  */
  966.  
  967.         break;
  968.     }
  969.  
  970.     il_full_update();
  971.     il_get_contents(dest);
  972.  
  973.     return (key == BUILTIN_action || key == key_INTERRUPT) ? NULL : *dest;
  974. }
  975.  
  976.  
  977. /****************************************/
  978. /* The directory history function set.  */
  979. /****************************************/
  980.  
  981.  
  982. void
  983. dir_history_reset()
  984. {
  985.     if (dir_history)
  986.     {
  987.     int i;
  988.  
  989.     for (i = 0; i < dir_history_count; i++)
  990.         xfree(dir_history[i]);
  991.  
  992.     xfree(dir_history);
  993.     dir_history = NULL;
  994.     }
  995.  
  996.     dir_history_count = 0;
  997.     dir_history_point = 0;
  998. }
  999.  
  1000.  
  1001. void
  1002. dir_history_add(directory)
  1003.     char *directory;
  1004. {
  1005.     dir_history_point = dir_history_count;
  1006.  
  1007.     dir_history = (char **)xrealloc(dir_history, ++dir_history_count *
  1008.                          sizeof(char *));
  1009.  
  1010.     dir_history[dir_history_point] = xstrdup(directory);
  1011. }
  1012.  
  1013.  
  1014. void
  1015. dir_history_next(this, link)
  1016.     panel_t *this;
  1017.     panel_t *link;
  1018. {
  1019.     if (dir_history_point < dir_history_count - 1)
  1020.     panel_action(this, act_CHDIR, link,
  1021.              dir_history[++dir_history_point], 1);
  1022.     else
  1023.     tty_beep();
  1024. }
  1025.  
  1026.  
  1027. void
  1028. dir_history_prev(this, link)
  1029.     panel_t *this;
  1030.     panel_t *link;
  1031. {
  1032.     if (dir_history_point)
  1033.     panel_action(this, act_CHDIR, link,
  1034.              dir_history[--dir_history_point], 1);
  1035.     else
  1036.     tty_beep();
  1037. }
  1038.  
  1039.  
  1040. void
  1041. clean_up()
  1042. {
  1043.     tty_exit(NULL);
  1044.  
  1045.     /* It is better not to do this here.  It can lead to an endless loop
  1046.        if xmalloc fails in write_history because xmalloc will call fatal
  1047.        and fatal will call clean_up again...  */
  1048. #if 0
  1049.     if (il)
  1050.     il_end();
  1051. #endif
  1052.  
  1053.     status_end();
  1054.     removelog();
  1055. }
  1056.  
  1057.  
  1058. void
  1059. fatal(postmsg)
  1060.     char *postmsg;
  1061. {
  1062.     clean_up();
  1063.     fprintf(stderr, "%s: fatal error: %s.\n", program, postmsg);
  1064.     exit(1);
  1065. }
  1066.  
  1067.  
  1068. void
  1069. settitle()
  1070. {
  1071.     char *buf;
  1072.     size_t len;
  1073.     tty_status_t status;
  1074.     window_t *title_win = window_init(0, 0, 1, SCREEN_X);
  1075.  
  1076.     tty_save(&status);
  1077.  
  1078.     tty_colors(TitleBrightness, TitleForeground, TitleBackground);
  1079.  
  1080.     window_goto(title_win, 0, 0);
  1081.     window_puts(title, strlen(title));
  1082.  
  1083.     buf = xmalloc(SCREEN_X + 1);
  1084.  
  1085.     len = (sizeof(login) - 1) + 1 + login_name_len + 2 +
  1086.       (sizeof(tty)   - 1) + 1 + tty_name_len;
  1087.  
  1088.     memset(buf, ' ', len = SCREEN_X - strlen(title) - len - 1);
  1089.     window_goto(title_win, 0, strlen(title));
  1090.     window_puts(buf, len);
  1091.  
  1092.     xfree(buf);
  1093.  
  1094.     window_goto(title_win, 0, strlen(title) + len);
  1095.     window_puts(login, sizeof(login) - 1);
  1096.     window_putc(' ');
  1097.     tty_foreground(UserName);
  1098.     window_puts(login_name, login_name_len);
  1099.     window_putc(' ');
  1100.     window_putc(' ');
  1101.     tty_foreground(TitleForeground);
  1102.     window_puts(tty, sizeof(tty) - 1);
  1103.     window_putc(' ');
  1104.     tty_foreground(TtyName);
  1105.     window_puts(tty_name, tty_name_len);
  1106.  
  1107.     tty_foreground(TitleForeground);
  1108.     window_putc(' ');
  1109.  
  1110.     tty_restore(&status);
  1111. }
  1112.  
  1113.  
  1114. /*
  1115.  * This function is a mess. Don't try to understand what it does
  1116.  * ... :-( It basically expands a configuration line macros.  The
  1117.  * return value is 0 on error, -1 if some condition failed (the
  1118.  * command contains a %d but the current entry is not a directory), 1
  1119.  * if everything is ok, 2 if the command was correctly expanded and it
  1120.  * contains a '%i' and 3 if it contains a '%I'.
  1121.  */
  1122.  
  1123. int
  1124. command_expand(command, dest, p, l)
  1125.     command_t *command;
  1126.     char **dest;
  1127.     panel_t *p, *l;
  1128. {
  1129.     char c;
  1130.     uid_t uid;
  1131.     gid_t gid;
  1132.     int retval;
  1133.     panel_t *t;
  1134.     size_t len;
  1135.     struct group *grp;
  1136.     struct passwd *pwd;
  1137.     static int busy = 0;
  1138.     char *answer = NULL;
  1139.     char *question = NULL;
  1140.     int i_flag = 0, entry;
  1141.     size_t oldtmplen, tmplen;
  1142.     char *ptr, *tmp = NULL, *d, *flag;
  1143.     char *src = command->body, *save_body;
  1144.  
  1145.  
  1146.     d = *dest = xmalloc(len = (strlen(src) + 1));
  1147.  
  1148.     while (*src)
  1149.     {
  1150.     if (*src != '%')
  1151.         *d++ = *src++;
  1152.     else
  1153.     {
  1154.         t = islower(*++src) ? p : l;
  1155.  
  1156.         switch (*src)
  1157.         {
  1158.         case '?':
  1159.  
  1160.             if (busy)
  1161.             {
  1162.             busy = 0;
  1163.             goto bad_command;
  1164.             }
  1165.  
  1166.             if (*++src != '{')
  1167.             goto bad_command;
  1168.  
  1169.             if ((ptr = strchr(++src, '}')) == NULL)
  1170.             goto bad_command;
  1171.  
  1172.             *ptr = 0;
  1173.              c = il_read_char(src, "yn", IL_MOVE);
  1174.             *ptr = '}';
  1175.  
  1176.             if (c != 'y')
  1177.             goto strings_dont_match;
  1178.  
  1179.             src = ptr;
  1180.  
  1181.             break;
  1182.  
  1183.         case 's':
  1184.  
  1185.             if (busy)
  1186.             {
  1187.             busy = 0;
  1188.             goto bad_command;
  1189.             }
  1190.  
  1191.             if (*++src != '{')
  1192.             goto bad_command;
  1193.  
  1194.             if ((ptr = strchr(++src, ',')) == NULL)
  1195.             goto bad_command;
  1196.  
  1197.             *ptr = 0;
  1198.             busy = 1;
  1199.  
  1200.             save_body = command->body;
  1201.             command->body = src;
  1202.             retval = command_expand(command, &answer, p, l);
  1203.             command->body = save_body;
  1204.  
  1205.             busy = 0;
  1206.  
  1207.             if (retval < 1)
  1208.             {
  1209.             *ptr = ',';
  1210.             if (retval == 0)
  1211.                 goto bad_command;
  1212.             else
  1213.                 goto strings_dont_match;
  1214.             }
  1215.  
  1216.             question = xmalloc(16 + strlen(command->name) +
  1217.                        strlen(answer) + 1);
  1218.             sprintf(question, "%s: %s", command->name, answer);
  1219.             xfree(answer);
  1220.             answer =  NULL;
  1221.             *ptr++ = ',';
  1222.  
  1223.             if ((src = strchr(ptr, '}')) == NULL)
  1224.             goto bad_command;
  1225.  
  1226.             *src = 0;
  1227.  
  1228.             if (strlen(question) > MAX_STATIC_SIZE)
  1229.             question[MAX_STATIC_SIZE] = 0;
  1230.  
  1231.             busy = 1;
  1232.  
  1233.             save_body = command->body;
  1234.             command->body = ptr;
  1235.             retval = command_expand(command, &answer, p, l);
  1236.             command->body = save_body;
  1237.  
  1238.             busy = 0;
  1239.  
  1240.             if (retval < 1)
  1241.             {
  1242.             *src = '}';
  1243.             xfree(question);
  1244.             question = NULL;
  1245.             if (retval == 0)
  1246.                 goto bad_command;
  1247.             goto strings_dont_match;
  1248.             }
  1249.  
  1250.             flag = il_read_line(question, &tmp, answer,
  1251.                     command->history);
  1252.  
  1253.             xfree(question);
  1254.             xfree(answer);
  1255.             question = answer = NULL;
  1256.  
  1257.             if (flag == NULL)
  1258.             {
  1259.             *src = '}';
  1260.             goto strings_dont_match;
  1261.             }
  1262.  
  1263.             *src = '}';
  1264.             break;
  1265.  
  1266.         case 'f':
  1267.         case 'F':
  1268.  
  1269.             if (panel_get_current_file_type(t) != FILE_ENTRY)
  1270.             goto strings_dont_match;
  1271.  
  1272.           get_file_name:
  1273.  
  1274.             ptr = panel_get_current_file_name(t);
  1275.             tmp = xmalloc(1 + strlen(ptr) + 1 + 1);
  1276.             sprintf(tmp, "\"%s\"", ptr);
  1277.             break;
  1278.  
  1279.         case 'd':
  1280.         case 'D':
  1281.  
  1282.             if (panel_get_current_file_type(t) != DIR_ENTRY)
  1283.             goto strings_dont_match;
  1284.             goto get_file_name;
  1285.  
  1286.         case 'l':
  1287.         case 'L':
  1288.  
  1289.             if (panel_get_current_file_type(t) != SYMLINK_ENTRY)
  1290.             goto strings_dont_match;
  1291.             goto get_file_name;
  1292.  
  1293.         case 't':
  1294.         case 'T':
  1295.  
  1296.             if (panel_get_current_file_type(t) != FIFO_ENTRY)
  1297.             goto strings_dont_match;
  1298.             goto get_file_name;
  1299.  
  1300.         case 'z':
  1301.         case 'Z':
  1302.  
  1303.             if (panel_get_current_file_type(t) != SOCKET_ENTRY)
  1304.             goto strings_dont_match;
  1305.             goto get_file_name;
  1306.  
  1307.         case 'a':
  1308.         case 'A':
  1309.  
  1310.             goto get_file_name;
  1311.  
  1312.         case 'm':
  1313.         case 'M':
  1314.  
  1315.             tmp = xmalloc(16);
  1316.             sprintf(tmp, "%o",
  1317.                 (int)panel_get_current_file_mode(t) & 07777);
  1318.             break;
  1319.  
  1320.         case 'o':
  1321.         case 'O':
  1322.  
  1323.             uid = panel_get_current_file_uid(t);
  1324.             pwd = getpwuid(uid);
  1325.  
  1326.             if (pwd)
  1327.             tmp = xstrdup(pwd->pw_name);
  1328.             else
  1329.             {
  1330.             tmp = xmalloc(16);
  1331.             sprintf(tmp, "%o", (int)uid);
  1332.             }
  1333.  
  1334.             break;
  1335.  
  1336.         case 'g':
  1337.         case 'G':
  1338.  
  1339.             gid = panel_get_current_file_gid(t);
  1340.             grp = getgrgid(gid);
  1341.  
  1342.             if (grp)
  1343.             tmp = xstrdup(grp->gr_name);
  1344.             else
  1345.             {
  1346.             tmp = xmalloc(16);
  1347.             sprintf(tmp, "%o", (int)gid);
  1348.             }
  1349.  
  1350.             break;
  1351.  
  1352.         case 'p':
  1353.         case 'P':
  1354.  
  1355.             tmp = xmalloc(1 + strlen(t->path) + 1 + 1);
  1356.             sprintf(tmp, "\"%s\"", t->path);
  1357.             break;
  1358.  
  1359.         case 'b':
  1360.         case 'B':
  1361.  
  1362.             ptr = strrchr(t->path, '/');
  1363.             ptr = (*++ptr) ? ptr : "/root";
  1364.             tmp = xmalloc(1 + strlen(ptr) + 1 + 1);
  1365.             sprintf(tmp, "\"%s\"", ptr);
  1366.             break;
  1367.  
  1368.         case 'i':
  1369.         case 'I':
  1370.  
  1371.             i_flag = (*src == 'i') ? 1 : 2;
  1372.  
  1373.             if (busy && t->selected_files)
  1374.             {
  1375.             tmplen = 20;
  1376.             tmp = xmalloc(tmplen + 1);
  1377.             strcpy(tmp, "selected file(s)");
  1378.             break;
  1379.             }
  1380.  
  1381.             tmp = NULL;
  1382.             tmplen = 0;
  1383.  
  1384.             panel_init_iterator(t);
  1385.  
  1386.             while ((entry = panel_get_next(t)) != -1)
  1387.             {
  1388.             oldtmplen = tmplen;
  1389.             tmplen += 1 + strlen(t->dir_entry[entry].name) + 1 + 1;
  1390.             tmp = xrealloc(tmp, tmplen + 1);
  1391.             tmp[oldtmplen] = '"';
  1392.             strcpy(tmp + oldtmplen + 1, t->dir_entry[entry].name);
  1393.             tmp[tmplen - 2] = '"';
  1394.             tmp[tmplen - 1] = ' ';
  1395.             tmp[tmplen    ] = 0;
  1396.             }
  1397.  
  1398.             /* This can happen when there is no selected file
  1399.                and the current file is "..".  */
  1400.             if (tmplen == 0)
  1401.             goto strings_dont_match;
  1402.  
  1403.             break;
  1404.  
  1405.         default:
  1406.  
  1407.             goto bad_command;
  1408.         }
  1409.  
  1410.         src++;
  1411.         *d = 0;
  1412.  
  1413.         if (tmp)
  1414.         {
  1415.         *dest = xrealloc(*dest, len += strlen(tmp));
  1416.         strcat(*dest, tmp);
  1417.         d = *dest + strlen(*dest);
  1418.         xfree(tmp);
  1419.         tmp = NULL;
  1420.         }
  1421.     }
  1422.     }
  1423.  
  1424.     *d = 0;
  1425.     return 1 + i_flag;
  1426.  
  1427.   bad_command:
  1428.  
  1429.     xfree(*dest);
  1430.     *dest = NULL;
  1431.     return 0;
  1432.  
  1433.   strings_dont_match:
  1434.  
  1435.     if (tmp)
  1436.     xfree(tmp);
  1437.  
  1438.     *dest = NULL;
  1439.     return -1;
  1440. }
  1441.  
  1442.  
  1443. void
  1444. refresh_after_suspend(mode)
  1445.     int mode;
  1446. {
  1447.     char *cmdln = NULL;
  1448.     char PWD[MAX_STATIC_SIZE + 1];
  1449.  
  1450.     if (mode == GIT_SCREEN_MODE)
  1451.     {
  1452.     /* switch back to noncanonical mode. */
  1453.     tty_set_mode(TTY_NONCANONIC);
  1454.     tty_defaults();
  1455.  
  1456.     settitle();
  1457.  
  1458.     status(NULL, 0, 0, 1, MSG_OK, MSG_CENTERED);
  1459.  
  1460.     panel_no_optimizations(src_panel);
  1461.     panel_no_optimizations(dest_panel);
  1462.     panel_action(src_panel, act_REFRESH, dest_panel, (void *)-1, 1);
  1463.     panel_action(dest_panel, act_REFRESH, src_panel, (void *)-1, 1);
  1464.  
  1465.     panel_set_focus(src_panel, ON);
  1466.  
  1467.     il_get_contents(&cmdln);
  1468.     il_reset_line();
  1469.     il_set_static_text(strcat(
  1470.                 truncate_string(panel_get_path(src_panel),
  1471.                         PWD, MAX_STATIC_SIZE),
  1472.                   PS1));
  1473.     il_insert_text(cmdln);
  1474.     il_full_update();
  1475.  
  1476.     signals(SIG_ON);
  1477.     }
  1478.     else
  1479.     {
  1480.     /* switch back to noncanonical mode. */
  1481.     tty_set_mode(TTY_NONCANONIC);
  1482.     tty_defaults();
  1483.  
  1484.     panel_no_optimizations(src_panel);
  1485.     panel_no_optimizations(dest_panel);
  1486.     tty_put_screen(screen);
  1487.     status(CommandLineModeHelp, 0, 0, 0, MSG_OK, MSG_CENTERED);
  1488.     il_full_update();
  1489.     }
  1490. }
  1491.  
  1492.  
  1493. void
  1494. add_to_environment(variable, alternate_variable, value)
  1495.     char *variable, *alternate_variable, *value;
  1496. {
  1497.     int result;
  1498.     char *alternate_value, *environment_string;
  1499.  
  1500.     if (getenv(variable) == NULL)
  1501.     {
  1502.     if (alternate_variable && (alternate_value=getenv(alternate_variable)))
  1503.     {
  1504. #ifdef HAVE_PUTENV
  1505.         environment_string = xmalloc(strlen(variable) + 1 +
  1506.                      strlen(alternate_value) + 1);
  1507.         sprintf(environment_string, "%s=%s", variable, alternate_value);
  1508.         result = putenv(environment_string);
  1509. #else
  1510.         result = setenv(variable, alternate_value, 1);
  1511. #endif /* !HAVE_PUTENV */
  1512.     }
  1513.     else
  1514.     {
  1515. #ifdef HAVE_PUTENV
  1516.         environment_string = xmalloc(strlen(variable) + 1 +
  1517.                      strlen(value) + 1);
  1518.         sprintf(environment_string, "%s=%s", variable, value);
  1519.         result = putenv(environment_string);
  1520. #else
  1521.         result = setenv(variable, value, 1);
  1522. #endif /* !HAVE_PUTENV */
  1523.     }
  1524.  
  1525.     if (result == -1)
  1526.         fprintf(stderr, "%s: warning: cannot add '%s' to environment\n",
  1527.             program, variable);
  1528.     }
  1529. }
  1530.  
  1531.  
  1532. /* Reads keys from the current section ([GIT-Keys] is supposed to  be
  1533.    in use when read_keys() is called).  Returns the number of keys read.  */
  1534.  
  1535. int
  1536. read_keys(keys)
  1537.     int keys;
  1538. {
  1539.     int i, j, need_convertion;
  1540.     command_t *command;
  1541.     unsigned char key_seq[80];
  1542.     char *contents[KEYSDATA_FIELDS - 2];
  1543.  
  1544.  
  1545.     for (i = keys; i < MAX_KEYS; i++)
  1546.     {
  1547.     configuration_getvarinfo((char *)key_seq, contents,
  1548.                  KEYSDATA_FIELDS - 2, NO_SEEK);
  1549.  
  1550.     if (*key_seq == 0)
  1551.         break;
  1552.  
  1553.     if (*key_seq != '^')
  1554.     {
  1555.         char *key_seq_ptr = tty_get_symbol_key_seq((char *)key_seq);
  1556.  
  1557.         if (!(need_convertion = key_seq_ptr == NULL))
  1558.         strcpy((char *)key_seq, key_seq_ptr);
  1559.     }
  1560.     else
  1561.         need_convertion = 1;
  1562.  
  1563.     command = (command_t *)xcalloc(1, sizeof(command_t));
  1564.  
  1565.     if (contents[0])
  1566.         command->name = xstrdup(contents[0]);
  1567.     else
  1568.     {
  1569.         xfree(command);
  1570.         continue;
  1571.     }
  1572.  
  1573.     command->history = xstack_init(sizeof(char *));
  1574.  
  1575.     if (contents[2])
  1576.         command->new_dir = xstrdup(contents[2]);
  1577.  
  1578.     if (contents[1])
  1579.         command->body = xstrdup(contents[1]);
  1580.     else
  1581.         goto insert;
  1582.  
  1583.     if (contents[3])
  1584.         command->save_screen = ((tolower(contents[3][0])=='y')?1:0);
  1585.     else
  1586.         command->save_screen = 1;
  1587.  
  1588.     if (contents[4])
  1589.         command->pause = ((tolower(contents[4][0]) == 'y') ? 1:0);
  1590.  
  1591.     if (contents[5])
  1592.         command->hide = ((tolower(contents[5][0]) == 'y') ? 1:0);
  1593.  
  1594.       insert:
  1595.  
  1596.     /* This speeds up the process.  It is not a limitation because,
  1597.        by convention, all the build-in command names don't contain
  1598.        uppercase letters.  Avoid searching through the list of
  1599.        built-in command names.  */
  1600.     if (islower(command->name[0]))
  1601.         for (j = 0; j < BUILTIN_OPERATIONS; j++)
  1602.         {
  1603.         if (strcmp(command->name, built_in[j]) == 0)
  1604.         {
  1605.             xfree(command->name);
  1606.             command->name = built_in[j];
  1607.             command->builtin = 1;
  1608.             break;
  1609.         }
  1610.         }
  1611.  
  1612.     command->sequence = xstrdup((char *)key_seq);
  1613.  
  1614.     if (command->builtin || command->body || command->new_dir)
  1615.         if (!need_convertion || tty_key_convert(key_seq))
  1616.         tty_key_list_insert(key_seq, (void *)command);
  1617.     }
  1618.  
  1619.     return i;
  1620. }
  1621.  
  1622.  
  1623. int
  1624. main(argc, argv)
  1625.     int argc;
  1626.     char *argv[];
  1627. {
  1628.     tty_key_t *ks;
  1629.     command_t *command;
  1630.     size_t len = 0, ptrlen;
  1631.     int previous_isearch_failed;
  1632.     input_line_t *saved_il = NULL;
  1633.     char PWD[MAX_STATIC_SIZE + 1];
  1634.     char *lock_password, *unlock_password;
  1635.     int child_exit_code, repeat_count, keys;
  1636.     int panel_no = 0, action_status, i, retval;
  1637.     int entry, key, app_end = 0, first_time = 1;
  1638.     char *data = NULL, *cmdln = NULL, *input = NULL, *ptr, *srcptr;
  1639.  
  1640.  
  1641. #if defined(SIGTSTP) && defined(SIGCONT)
  1642.     /* Job control stuff. */
  1643.     signal(SIGTSTP, suspend);
  1644.     signal(SIGCONT, resume);
  1645. #endif
  1646.  
  1647.     signal(SIGSEGV, fatal_signal);
  1648.     signal(SIGHUP,  fatal_signal);
  1649.  
  1650.     signals(SIG_OFF);
  1651.     ignore_signals();
  1652.  
  1653.     printf("\n");
  1654.  
  1655. #ifdef HAVE_GCC
  1656.     printf(PRODUCT" "VERSION" (%s), %s %s\n",
  1657.        HOST, __TIME__, __DATE__);
  1658. #else
  1659.     printf("GNU Interactive Tools (%s)\n",
  1660.        HOST);
  1661. #endif /* !HAVE_GCC */
  1662.  
  1663.     printf("GIT is free software; you can redistribute it and/or modify it under the\n");
  1664.     printf("terms of the GNU General Public License as published by the Free Software\n");
  1665.     printf("Foundation; either version 2, or (at your option) any later version.\n");
  1666.     printf("Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.\n");
  1667.     printf("Written by Tudor Hulubei and Andrei Pitis, students at PUB, Romania\n\n");
  1668.  
  1669.     program = argv[0];
  1670.     pid     = getpid();
  1671.  
  1672.     home = getenv("HOME");
  1673.     if (home == NULL)
  1674.     home = ".";
  1675.  
  1676.     get_tty_name();
  1677.     get_login_name();
  1678.  
  1679. /*
  1680.     Well, this seems to work differently on BSDs, so just forget about it.
  1681.     My guess is that you do have a command processor :-)
  1682.  
  1683.     if (system(NULL) == 0)
  1684.     fprintf(stderr, "%s: warning: cannot find a command processor\n",
  1685.         program);
  1686. */
  1687.  
  1688.     add_to_environment("GIT_EDITOR",   "EDITOR", "vi");
  1689.     add_to_environment("GIT_SHELL",    "SHELL",  "/bin/sh");
  1690.     add_to_environment("GIT_RMAIL",    NULL,     "emacs -f rmail");
  1691.     add_to_environment("GIT_PAGER",    NULL,     "more");
  1692.     add_to_environment("GIT_COMPRESS", NULL,     "gzip -r9");
  1693.     add_to_environment("GIT_VMSTAT",   NULL,     "free");
  1694.  
  1695.     tty_get_capabilities();
  1696.     tty_kbdinit(TTY_RESTRICTED_INPUT);
  1697.  
  1698.     common_configuration_init();
  1699.  
  1700.     use_section("[GIT-FTI]");
  1701.     get_file_type_info();
  1702.     use_section("[GIT-Keys]");
  1703.     keys = read_keys(0);
  1704.     configuration_end();
  1705.  
  1706.     wait_msg = specific_configuration_init() == 0;
  1707.  
  1708.  
  1709.     use_section("[Setup]");
  1710.  
  1711.     configuration_getvarinfo("TempDirectory", &data, 1, DO_SEEK);
  1712.     TempDirectory = data ? tilde_expand(data) : "/tmp";
  1713.  
  1714.     stdout_log_name = xmalloc(32 + strlen(TempDirectory) + 1);
  1715.     stderr_log_name = xmalloc(32 + strlen(TempDirectory) + 1);
  1716.     sprintf(stdout_log_name, "%s/git.1.%d", TempDirectory, (int)pid);
  1717.     sprintf(stderr_log_name, "%s/git.2.%d", TempDirectory, (int)pid);
  1718.  
  1719.     AnsiColors        = get_flag_var("AnsiColors", OFF);
  1720.     UseLastScreenChar = get_flag_var("UseLastScreenChar",  OFF);
  1721.  
  1722.  
  1723.     use_section("[GIT-Setup]");
  1724.  
  1725.     if (AnsiColors == ON)
  1726.     TypeSensitivity = get_flag_var("TypeSensitivity", ON);
  1727.     else
  1728.     TypeSensitivity = OFF;
  1729.  
  1730.     ConfirmOnExit       = get_flag_var("ConfirmOnExit", OFF);
  1731.     NormalModeHelp      = get_string_var("NormalModeHelp",      "");
  1732.     CommandLineModeHelp = get_string_var("CommandLineModeHelp", "");
  1733.  
  1734.  
  1735.     use_section(AnsiColors ? cSection : bwSection);
  1736.  
  1737.     get_colorset_var(TitleColors, TitleFields, TITLE_FIELDS);
  1738.  
  1739.     use_section("[GIT-FTI]");
  1740.     get_file_type_info();
  1741.  
  1742.     use_section("[GIT-Keys]");
  1743.     keys = read_keys(keys);
  1744.  
  1745.     if (keys == MAX_KEYS)
  1746.     fprintf(stderr, "%s: too many key sequences; only %d are allowed.\n",
  1747.         program, MAX_KEYS);
  1748.  
  1749.     tty_get_size(&SCREEN_X, &SCREEN_Y);
  1750.     tty_startup(UseLastScreenChar);
  1751.  
  1752. #ifndef HAVE_LONG_FILE_NAMES
  1753.     fprintf(stderr,
  1754.         "%s: warning: your system doesn't support long file names.",
  1755.         program);
  1756. #endif /* !HAVE_LONG_FILE_NAMES */
  1757.  
  1758. #ifdef HAVE_LINUX
  1759.     if (LinuxConsole)
  1760.     screen = xmalloc(4 + SCREEN_X * SCREEN_Y * 2);
  1761. #endif  /* HAVE_LINUX */
  1762.  
  1763.     status_init(SCREEN_X, SCREEN_Y - 1, NormalModeHelp);
  1764.  
  1765.     if (getuid() == 0)
  1766.     PS1[1] = '#';
  1767.  
  1768.     il_init(SCREEN_X, SCREEN_Y - 2);
  1769.  
  1770.     {
  1771.     int left_panel_x  = (SCREEN_X >> 1) + (SCREEN_X & 1);
  1772.     int right_panel_x = (SCREEN_X >> 1);
  1773.  
  1774.     left_panel =panel_init(0,            1, SCREEN_Y-3, left_panel_x, ".");
  1775.     right_panel=panel_init(left_panel_x, 1, SCREEN_Y-3, right_panel_x,".");
  1776.     }
  1777.  
  1778.     configuration_end();
  1779.  
  1780.     tty_get_screen(screen);
  1781.     tty_set_mode(TTY_NONCANONIC);
  1782.     tty_defaults();
  1783.  
  1784.     dir_history       = NULL;
  1785.     dir_history_count = 0;
  1786.     dir_history_point = 0;
  1787.  
  1788.   restart:
  1789.  
  1790.     signals(SIG_OFF);
  1791.  
  1792.     il_restore(saved_il);
  1793.  
  1794.     if (wait_msg)
  1795.     {
  1796.     fprintf(stdout, "Press any key to continue\n");
  1797.     tty_goto(SCREEN_Y - 1, 0);
  1798.     tty_get_key(NULL);
  1799.     wait_msg = 0;
  1800.     }
  1801.  
  1802.     settitle();
  1803.  
  1804.     status(NULL, 0, 0, 1, MSG_OK, MSG_CENTERED);
  1805.  
  1806.     src_panel  = panel_no ? right_panel : left_panel;
  1807.     dest_panel = panel_no ?  left_panel : right_panel;
  1808.  
  1809.     /* Save the input line contents.  */
  1810.     saved_il = il_save();
  1811.  
  1812.     panel_action(src_panel, act_REFRESH, dest_panel, (void *)-1, 1);
  1813.     panel_action(dest_panel, act_REFRESH, src_panel, (void *)-1, 1);
  1814.  
  1815.     /* Restore the input line contents.  */
  1816.     il_restore(saved_il);
  1817.  
  1818.     panel_set_focus(src_panel, ON);
  1819.  
  1820.     if (first_time)
  1821.     {
  1822.     dir_history_add(panel_get_path(src_panel));
  1823.     first_time = 0;
  1824.     }
  1825.  
  1826.     signals(SIG_ON);
  1827.  
  1828.     il_set_static_text(strcat(truncate_string(panel_get_path(src_panel),
  1829.                           PWD,
  1830.                           MAX_STATIC_SIZE),
  1831.                   PS1));
  1832.     saved_il = il_save();
  1833.  
  1834.     while(!app_end)
  1835.     {
  1836.     il_restore(saved_il);
  1837.     saved_il = il_save();
  1838.     il_full_update();
  1839.     il_get_contents(&cmdln);
  1840.  
  1841.     UserHeartAttack = 0;
  1842.     suspend_allowed = ON;
  1843.     ks  = tty_get_key(&repeat_count);
  1844.     key = ks->key_seq[0];
  1845.     suspend_allowed = OFF;
  1846.  
  1847.     signals(SIG_OFF);
  1848.  
  1849.     command = (command_t *)ks->aux_data;
  1850.  
  1851.     if (command)
  1852.         if (command->builtin)
  1853.         key = - 1 - (command->name-built_in[0]) / MAX_BUILTIN_NAME;
  1854.      else
  1855.      {
  1856.         if (command->name)
  1857.         {
  1858.         panel_no_optimizations(src_panel);
  1859.         panel_no_optimizations(dest_panel);
  1860.  
  1861.         if (command->body)
  1862.         {
  1863.             char *cmd = NULL;
  1864.  
  1865.             retval = command_expand(command, &cmd,
  1866.                         src_panel, dest_panel);
  1867.  
  1868.             if (retval)
  1869.             {
  1870.             if (retval > 0)
  1871.             {
  1872.                 size_t msglen = 32 + strlen(command->name) +
  1873.                         strlen(cmd) + 1;
  1874.                 char *msg = xmalloc(msglen);
  1875.  
  1876.                 sprintf(msg, "%s: %s", command->name, cmd);
  1877.                 status(msg, 0, 0, 0, MSG_STATUS, 0);
  1878.                 xfree(msg);
  1879.  
  1880.                 if (command->hide)
  1881.                 {
  1882.                 msg = xmalloc(64 + strlen(command->name) + 1);
  1883.                 sprintf(msg, "Wait, running %s command %s...",
  1884.                     "user-defined", command->name);
  1885.                 il_message(msg);
  1886.                 xfree(msg);
  1887.                 }
  1888.  
  1889.                 child_exit_code = start(cmd, command->hide);
  1890.                 xfree(cmd);
  1891.  
  1892.                 if (command->hide)
  1893.                 {
  1894.                 if (child_exit_code != 0)
  1895.                 {
  1896.                     tty_beep();
  1897.                     display_errors(command->name);
  1898.                 }
  1899.                 }
  1900.                 else
  1901.                 {
  1902.                 if (command->save_screen)
  1903.                     tty_get_screen(screen);
  1904.  
  1905.                 tty_touch();
  1906.  
  1907.                 if (command->pause)
  1908.                     wait_msg = 1;
  1909.                 }
  1910.  
  1911.                 if (child_exit_code == 0 && command->new_dir)
  1912.                 {
  1913.                 char *expanded_dir =
  1914.                     tilde_expand(command->new_dir);
  1915.  
  1916.                 panel_action(src_panel, act_CHDIR,
  1917.                          dest_panel, expanded_dir, 1);
  1918.  
  1919.                 dir_history_add(panel_get_path(src_panel));
  1920.                 xfree(expanded_dir);
  1921.                 }
  1922.  
  1923.                 if (child_exit_code == 0)
  1924.                 if (retval == 2)
  1925.                     panel_unselect_all(src_panel);
  1926.                 else
  1927.                     if (retval == 3)
  1928.                     panel_unselect_all(dest_panel);
  1929.  
  1930.                 goto restart;
  1931.             }
  1932.             else
  1933.                 continue;
  1934.             }
  1935.             else
  1936.             {
  1937.             char *msg = xmalloc(80+strlen((char *)ks->key_seq)+1);
  1938.  
  1939.             sprintf(msg,"%s: invalid command on key sequence %s !",
  1940.                 command->name, command->sequence);
  1941.             il_read_char(msg, NULL, IL_FREEZED | IL_BEEP |
  1942.                         IL_SAVE    | IL_ERROR);
  1943.             xfree(msg);
  1944.             continue;
  1945.             }
  1946.         }
  1947.         else
  1948.         {
  1949.             if (command->new_dir)
  1950.             {
  1951.             char *expanded_dir = tilde_expand(command->new_dir);
  1952.  
  1953.             panel_action(src_panel, act_CHDIR, dest_panel,
  1954.                      expanded_dir, 1);
  1955.  
  1956.             dir_history_add(panel_get_path(src_panel));
  1957.             xfree(expanded_dir);
  1958.             }
  1959.  
  1960.             goto restart;
  1961.         }
  1962.          }
  1963.     }
  1964.  
  1965.     signals(SIG_ON);
  1966.  
  1967.     switch (key)
  1968.     {
  1969.         case key_INTERRUPT:
  1970.         il_free(saved_il);
  1971.         il_kill_line(IL_DONT_STORE);
  1972.         saved_il = il_save();
  1973.         break;
  1974.  
  1975.         case BUILTIN_other_panel:
  1976.  
  1977.         signals(SIG_OFF);
  1978.  
  1979.         if (!two_panel_mode)
  1980.             goto one_panel_mode;
  1981.  
  1982.         if ((repeat_count & 1) == 0)
  1983.             break;
  1984.  
  1985.         panel_set_focus(src_panel, OFF);
  1986.  
  1987.         temp_panel = src_panel;
  1988.         src_panel  = dest_panel;
  1989.         dest_panel = temp_panel;
  1990.  
  1991.         panel_no = !panel_no;
  1992.         panel_set_focus(src_panel, ON);
  1993.  
  1994.         il_free(saved_il);
  1995.         il_set_static_text(strcat(
  1996.             truncate_string(panel_get_path(src_panel),  PWD,
  1997.                     MAX_STATIC_SIZE),
  1998.             PS1));
  1999.         saved_il = il_save();
  2000.  
  2001.         break;
  2002.  
  2003.         case BUILTIN_previous_line:
  2004.  
  2005.         signals(SIG_OFF);
  2006.         panel_action(src_panel,act_UP,dest_panel,NULL,repeat_count);
  2007.         break;
  2008.  
  2009.         case BUILTIN_next_line:
  2010.  
  2011.         signals(SIG_OFF);
  2012.         panel_action(src_panel,act_DOWN,dest_panel,NULL,repeat_count);
  2013.         break;
  2014.  
  2015.         case BUILTIN_action:
  2016.  
  2017.         action_status = 0;
  2018.         il_free(saved_il);
  2019.         il_get_contents(&cmdln);
  2020.  
  2021.         switch (*cmdln)
  2022.         {
  2023.             case '+':
  2024.             action_status = panel_action(src_panel, act_SELECT_ALL,
  2025.                              dest_panel, NULL, 1);
  2026.             break;
  2027.  
  2028.             case '-':
  2029.             action_status = panel_action(src_panel,
  2030.                              act_UNSELECT_ALL,
  2031.                              dest_panel, NULL, 1);
  2032.             break;
  2033.  
  2034.             case '*':
  2035.             action_status = panel_action(src_panel, act_TOGGLE,
  2036.                              dest_panel, NULL, 1);
  2037.             break;
  2038.  
  2039.             case 0:
  2040.             signals(SIG_OFF);
  2041.             action_status = panel_action(src_panel, act_ENTER,
  2042.                              dest_panel, screen, 1);
  2043.             break;
  2044.  
  2045.             default:
  2046.             {
  2047.                 char *output_string;
  2048.  
  2049.                 if (history_expand(cmdln, &output_string) >= 0)
  2050.                 {
  2051.                 int bg_cmd;
  2052.  
  2053.                 if (is_an_empty_command(output_string))
  2054.                 {
  2055.                     saved_il = il_save();
  2056.                     il_read_char("Void command.", NULL,
  2057.                          IL_FREEZED | IL_BEEP |
  2058.                          IL_SAVE    | IL_ERROR);
  2059.                     break;
  2060.                 }
  2061.  
  2062.                 bg_cmd = is_a_bg_command(output_string);
  2063.  
  2064.                 il_kill_line(IL_DONT_STORE);
  2065.                 il_insert_text(output_string);
  2066.                 start(output_string, bg_cmd);
  2067.  
  2068.                 if (bg_cmd)
  2069.                 {
  2070.                     il_history(IL_RECORD);
  2071.                     il_kill_line(IL_DONT_STORE);
  2072.                 }
  2073.                 else
  2074.                 {
  2075.                     panel_no_optimizations(src_panel);
  2076.                     panel_no_optimizations(dest_panel);
  2077.                     tty_touch();
  2078.                     action_status = -1;
  2079.                     wait_msg = 1;
  2080.                 }
  2081.                 }
  2082.                 else
  2083.                 {
  2084.                 il_read_char(output_string, NULL,
  2085.                          IL_FREEZED | IL_BEEP |
  2086.                          IL_SAVE    | IL_ERROR);
  2087.                 }
  2088.             }
  2089.             break;
  2090.         }
  2091.  
  2092.         if (action_status == 1)
  2093.         {
  2094.             il_set_static_text(
  2095.             strcat(truncate_string(panel_get_path(src_panel), PWD,
  2096.                            MAX_STATIC_SIZE),
  2097.                    PS1));
  2098.             il_kill_line(IL_DONT_STORE);
  2099.         }
  2100.         else
  2101.             if (action_status == -1)
  2102.             {
  2103.             tty_get_screen(screen);
  2104.             il_history(IL_RECORD);
  2105.             il_kill_line(IL_DONT_STORE);
  2106.  
  2107.             saved_il = il_save();
  2108.             goto restart;
  2109.             }
  2110.  
  2111.         saved_il = il_save();
  2112.         break;
  2113.  
  2114.         case BUILTIN_select_file:
  2115.  
  2116.         signals(SIG_OFF);
  2117.  
  2118.         for (i = 0; i < repeat_count; i++)
  2119.             panel_action(src_panel, act_SELECT, dest_panel, NULL, 1);
  2120.         break;
  2121.  
  2122.         case BUILTIN_scroll_down:
  2123.  
  2124.         signals(SIG_OFF);
  2125.  
  2126.         for (i = 0; i < repeat_count; i++)
  2127.             panel_action(src_panel, act_PGUP, dest_panel, NULL, 1);
  2128.  
  2129.         break;
  2130.  
  2131.         case BUILTIN_scroll_up:
  2132.  
  2133.         signals(SIG_OFF);
  2134.  
  2135.         for (i = 0; i < repeat_count; i++)
  2136.             panel_action(src_panel, act_PGDOWN, dest_panel, NULL, 1);
  2137.         break;
  2138.  
  2139.         case BUILTIN_beginning_of_panel:
  2140.  
  2141.         signals(SIG_OFF);
  2142.         panel_action(src_panel, act_HOME, dest_panel, NULL, 1);
  2143.         break;
  2144.  
  2145.         case BUILTIN_end_of_panel:
  2146.  
  2147.         signals(SIG_OFF);
  2148.         panel_action(src_panel, act_END, dest_panel, NULL, 1);
  2149.         break;
  2150.  
  2151.         case BUILTIN_hard_refresh:
  2152.  
  2153.         tty_touch();
  2154.  
  2155.         case BUILTIN_refresh:
  2156.  
  2157.         panel_no_optimizations(src_panel);
  2158.         panel_no_optimizations(dest_panel);
  2159.  
  2160.         goto restart;
  2161.  
  2162.         case BUILTIN_tty_mode:
  2163.  
  2164.         if ((repeat_count & 1) == 0)
  2165.             break;
  2166.  
  2167.         tty_put_screen(screen);
  2168.         status(CommandLineModeHelp, 0, 0, 0, MSG_OK, MSG_CENTERED);
  2169.  
  2170.         while (1)
  2171.         {
  2172.             il_restore(saved_il);
  2173.             saved_il = il_save();
  2174.             il_full_update();
  2175.             il_get_contents(&cmdln);
  2176.  
  2177.             current_mode = GIT_TERMINAL_MODE;
  2178.             suspend_allowed = ON;
  2179.             ks  = tty_get_key(&repeat_count);
  2180.             key = ks->key_seq[0];
  2181.             suspend_allowed = OFF;
  2182.  
  2183.             command = (command_t *)ks->aux_data;
  2184.             if (command && command->builtin)
  2185.             key = - 1 - (command->name - built_in[0]) /
  2186.                      MAX_BUILTIN_NAME;
  2187.  
  2188.             if (key == BUILTIN_tty_mode && (repeat_count & 1))
  2189.             {
  2190.             il_free(saved_il);
  2191.             saved_il = il_save();
  2192.             break;
  2193.             }
  2194.  
  2195.             switch (key)
  2196.             {
  2197.             case key_INTERRUPT:
  2198.                 il_free(saved_il);
  2199.                 il_kill_line(IL_DONT_STORE);
  2200.                 saved_il = il_save();
  2201.                 break;
  2202.  
  2203.             case BUILTIN_action:
  2204.  
  2205.                 if (*cmdln)
  2206.                 {
  2207.                 char *output_string;
  2208.  
  2209.                 il_free(saved_il);
  2210.  
  2211.                 if (history_expand(cmdln, &output_string) < 0)
  2212.                 {
  2213.                     il_read_char(output_string, NULL,
  2214.                          IL_FREEZED | IL_BEEP |
  2215.                          IL_SAVE    | IL_ERROR);
  2216.                     saved_il = il_save();
  2217.                     break;
  2218.                 }
  2219.  
  2220.                 tty_put_screen(screen);
  2221.                 il_kill_line(IL_DONT_STORE);
  2222.                 il_insert_text(output_string);
  2223.                 start(output_string, 0);
  2224.                 tty_get_screen(screen);
  2225.                 il_history(IL_RECORD);
  2226.                 status(CommandLineModeHelp, 0, 0, 0,
  2227.                        MSG_OK, MSG_CENTERED);
  2228.                 il_kill_line(IL_DONT_STORE);
  2229.                 saved_il = il_save();
  2230.                 }
  2231.                 break;
  2232.  
  2233.             case BUILTIN_previous_history_element:
  2234.             case BUILTIN_previous_line:
  2235.  
  2236.                 il_free(saved_il);
  2237.  
  2238.                 for (i = 0; i < repeat_count; i++)
  2239.                 il_history(IL_PREVIOUS);
  2240.  
  2241.                 saved_il = il_save();
  2242.                 break;
  2243.  
  2244.             case BUILTIN_next_history_element:
  2245.             case BUILTIN_next_line:
  2246.  
  2247.                 il_free(saved_il);
  2248.  
  2249.                 for (i = 0; i < repeat_count; i++)
  2250.                 il_history(IL_NEXT);
  2251.  
  2252.                 saved_il = il_save();
  2253.                 break;
  2254.  
  2255.             case BUILTIN_refresh:
  2256.  
  2257.                 panel_no_optimizations(src_panel);
  2258.                 panel_no_optimizations(dest_panel);
  2259.                 tty_put_screen(screen);
  2260.                 status(CommandLineModeHelp, 0, 0, 0,
  2261.                    MSG_OK, MSG_CENTERED);
  2262.                 break;
  2263.  
  2264.             case BUILTIN_exit:
  2265.  
  2266.                 if (ConfirmOnExit == OFF ||
  2267.                 il_read_char(exit_msg,"yn",IL_FREEZED) == 'y')
  2268.                 {
  2269.                 app_end = 1;
  2270.                 goto end_tty_mode;
  2271.                 }
  2272.  
  2273.                 status(CommandLineModeHelp, 0, 0, 0,
  2274.                    MSG_OK, MSG_CENTERED);
  2275.                 break;
  2276.  
  2277.             default:
  2278.  
  2279.                 if (key)
  2280.                 {
  2281.                 il_free(saved_il);
  2282.  
  2283.                 while (repeat_count--)
  2284.                     il_dispatch_commands(key, IL_MOVE|IL_EDIT);
  2285.  
  2286.                 saved_il = il_save();
  2287.                 }
  2288.                 break;
  2289.             }
  2290.         }
  2291.  
  2292.           end_tty_mode:
  2293.  
  2294.         panel_no_optimizations(src_panel);
  2295.         panel_no_optimizations(dest_panel);
  2296.         tty_touch();
  2297.         status(NULL, 0, 0, 1, MSG_OK, MSG_CENTERED);
  2298.  
  2299.         current_mode = GIT_SCREEN_MODE;
  2300.  
  2301.         if (app_end)
  2302.             continue;
  2303.  
  2304.         goto restart;
  2305.  
  2306.         case BUILTIN_copy:
  2307.  
  2308.         panel_action(src_panel, act_COPY, dest_panel, NULL, 1);
  2309.         break;
  2310.  
  2311.         case BUILTIN_move:
  2312.  
  2313.         panel_action(src_panel, act_MOVE, dest_panel, NULL, 1);
  2314.         break;
  2315.  
  2316.         case BUILTIN_make_directory:
  2317.  
  2318.         signals(SIG_OFF);
  2319.         panel_action(src_panel, act_MKDIR, dest_panel, NULL, 1);
  2320.         break;
  2321.  
  2322.         case BUILTIN_delete:
  2323.  
  2324.         panel_action(src_panel, act_DELETE, dest_panel, NULL, 1);
  2325.         break;
  2326.  
  2327.         case BUILTIN_panel_enable_next_mode:
  2328.  
  2329.         case BUILTIN_panel_enable_owner_group:
  2330.         case BUILTIN_panel_enable_date_time:
  2331.         case BUILTIN_panel_enable_size:
  2332.         case BUILTIN_panel_enable_mode:
  2333.         case BUILTIN_panel_enable_full_name:
  2334.  
  2335.         signals(SIG_OFF);
  2336.         panel_action(src_panel,
  2337.                  act_ENABLE_NEXT_MODE -
  2338.                  (key - BUILTIN_panel_enable_next_mode),
  2339.                  NULL, NULL, 1);
  2340.         break;
  2341.  
  2342.         case BUILTIN_panel_sort_next_method:
  2343.  
  2344.         case BUILTIN_panel_sort_by_name:
  2345.         case BUILTIN_panel_sort_by_extension:
  2346.         case BUILTIN_panel_sort_by_size:
  2347.         case BUILTIN_panel_sort_by_date:
  2348.         case BUILTIN_panel_sort_by_mode:
  2349.         case BUILTIN_panel_sort_by_owner_id:
  2350.         case BUILTIN_panel_sort_by_group_id:
  2351.         case BUILTIN_panel_sort_by_owner_name:
  2352.         case BUILTIN_panel_sort_by_group_name:
  2353.  
  2354.         signals(SIG_OFF);
  2355.         panel_action(src_panel,
  2356.                  act_SORT_NEXT_METHOD -
  2357.                  (key - BUILTIN_panel_sort_next_method),
  2358.                  NULL, NULL, 1);
  2359.         break;
  2360.  
  2361.         case BUILTIN_exit:
  2362.  
  2363.         signals(SIG_OFF);
  2364.  
  2365.         if (ConfirmOnExit == OFF ||
  2366.             il_read_char(exit_msg, "yn", IL_FREEZED) == 'y')
  2367.             app_end = 1;
  2368.  
  2369.         break;
  2370.  
  2371.         case BUILTIN_file_to_input_line:
  2372.  
  2373.         signals(SIG_OFF);
  2374.         len = strlen(cmdln);
  2375.  
  2376.         srcptr = panel_get_current_file_name(src_panel);
  2377.         ptr = xmalloc(ptrlen = 1 + 1 + strlen(srcptr) + 1 + 1 + 1);
  2378.  
  2379.           copy_to_cmdln:
  2380.  
  2381.         il_free(saved_il);
  2382.         sprintf(ptr, " \"%s\" ", srcptr);
  2383.         cmdln = xrealloc(cmdln, len + ptrlen);
  2384.  
  2385.         for (i = 0; ptr[i]; i++)
  2386.             if (!is_print(ptr[i]))
  2387.             {
  2388.             tty_beep();
  2389.             ptr[i] = 0;
  2390.             break;
  2391.             }
  2392.  
  2393.         strcpy(&cmdln[len], ptr);
  2394.         il_insert_text(ptr);
  2395.         xfree(ptr);
  2396.         saved_il = il_save();
  2397.         break;
  2398.  
  2399.         case BUILTIN_other_path_to_input_line:
  2400.  
  2401.         signals(SIG_OFF);
  2402.  
  2403.         ptrlen = 1 + 1 + dest_panel->pathlen + 1 + 1 + 1;
  2404.         ptr = xmalloc(ptrlen);
  2405.         srcptr = dest_panel->path;
  2406.  
  2407.         goto copy_to_cmdln;
  2408.  
  2409.         case BUILTIN_selected_files_to_input_line:
  2410.  
  2411.         signals(SIG_OFF);
  2412.         len = strlen(cmdln);
  2413.         il_free(saved_il);
  2414.  
  2415.         panel_init_iterator(src_panel);
  2416.  
  2417.         while ((entry = panel_get_next(src_panel)) != -1)
  2418.         {
  2419.             srcptr = src_panel->dir_entry[entry].name;
  2420.             ptr = xmalloc(ptrlen = 1 + 1 + strlen(srcptr) + 1 + 1 + 1);
  2421.             sprintf(ptr, " \"%s\" ", srcptr);
  2422.             cmdln = xrealloc(cmdln, len + ptrlen);
  2423.  
  2424.             for (i = 0; ptr[i]; i++)
  2425.             if (!is_print(ptr[i]))
  2426.             {
  2427.                 tty_beep();
  2428.                 ptr[i] = 0;
  2429.                 saved_il = il_save();
  2430.                 break;
  2431.             }
  2432.  
  2433.             strcpy(&cmdln[len], ptr);
  2434.             il_insert_text(ptr);
  2435.             xfree(ptr);
  2436.         }
  2437.  
  2438.         saved_il = il_save();
  2439.         break;
  2440.  
  2441.         case BUILTIN_previous_history_element:
  2442.  
  2443.         signals(SIG_OFF);
  2444.         il_free(saved_il);
  2445.  
  2446.         for (i = 0; i < repeat_count; i++)
  2447.             il_history(IL_PREVIOUS);
  2448.  
  2449.         saved_il = il_save();
  2450.         break;
  2451.  
  2452.         case BUILTIN_next_history_element:
  2453.  
  2454.         signals(SIG_OFF);
  2455.         il_free(saved_il);
  2456.  
  2457.         for (i = 0; i < repeat_count; i++)
  2458.             il_history(IL_NEXT);
  2459.  
  2460.         saved_il = il_save();
  2461.         break;
  2462.  
  2463.         case BUILTIN_switch_panels:
  2464.  
  2465.         if ((repeat_count & 1) == 0)
  2466.             break;
  2467.  
  2468.         signals(SIG_OFF);
  2469.         panel_no_optimizations(src_panel);
  2470.         panel_no_optimizations(dest_panel);
  2471.         panel_action(src_panel, act_SWITCH, dest_panel, NULL, 1);
  2472.         panel_action(dest_panel, act_REFRESH, src_panel, (void*)-1, 1);
  2473.         panel_action(src_panel, act_REFRESH, dest_panel, (void*)-1, 1);
  2474.         break;
  2475.  
  2476.         case BUILTIN_change_directory:
  2477.  
  2478.         signals(SIG_OFF);
  2479.  
  2480.         if (il_read_line("Directory: ", &input, NULL,
  2481.                  command->history))
  2482.         {
  2483.             char *expanded_input;
  2484.  
  2485.             if (input[0] == 0)
  2486.             break;
  2487.  
  2488.             panel_action(src_panel, act_CHDIR, dest_panel,
  2489.                  expanded_input = tilde_expand(input), 1);
  2490.  
  2491.             dir_history_add(panel_get_path(src_panel));
  2492.  
  2493.             xfree(expanded_input);
  2494.             xfree(input);
  2495.             input = NULL;
  2496.  
  2497.             il_restore(saved_il);
  2498.             il_set_static_text(strcat(
  2499.             truncate_string(panel_get_path(src_panel), PWD,
  2500.                     MAX_STATIC_SIZE),
  2501.             PS1));
  2502.             saved_il = il_save();
  2503.         }
  2504.  
  2505.         break;
  2506.  
  2507.         case BUILTIN_select_files_matching_pattern:
  2508.  
  2509.         signals(SIG_OFF);
  2510.  
  2511.         if (il_read_line("Select files matching pattern: ",
  2512.                  &input, NULL, command->history))
  2513.         {
  2514.             if (input[0] == 0)
  2515.             break;
  2516.  
  2517.             panel_action(src_panel, act_PATTERN_SELECT,
  2518.                  dest_panel, input, 1);
  2519.  
  2520.             xfree(input);
  2521.             input = NULL;
  2522.         }
  2523.  
  2524.         break;
  2525.  
  2526.         case BUILTIN_unselect_files_matching_pattern:
  2527.  
  2528.         signals(SIG_OFF);
  2529.  
  2530.         if (il_read_line("Unselect files matching pattern: ",
  2531.                  &input, NULL, command->history))
  2532.         {
  2533.             if (input[0] == 0)
  2534.             break;
  2535.  
  2536.             panel_action(src_panel, act_PATTERN_UNSELECT,
  2537.                  dest_panel, input, 1);
  2538.  
  2539.             xfree(input);
  2540.             input = NULL;
  2541.         }
  2542.  
  2543.         break;
  2544.  
  2545.         case BUILTIN_adapt_current_directory:
  2546.  
  2547.         signals(SIG_OFF);
  2548.  
  2549.         panel_action(src_panel, act_CHDIR, dest_panel,
  2550.                  dest_panel->path, 1);
  2551.  
  2552.         dir_history_add(panel_get_path(src_panel));
  2553.  
  2554.         il_free(saved_il);
  2555.         il_set_static_text(strcat(
  2556.             truncate_string(panel_get_path(src_panel), PWD,
  2557.                     MAX_STATIC_SIZE),
  2558.             PS1));
  2559.         saved_il = il_save();
  2560.  
  2561.         break;
  2562.  
  2563.         case BUILTIN_adapt_other_directory:
  2564.  
  2565.         signals(SIG_OFF);
  2566.  
  2567.         panel_action(dest_panel, act_CHDIR, src_panel,
  2568.                  src_panel->path, 1);
  2569.  
  2570.         dir_history_add(panel_get_path(dest_panel));
  2571.  
  2572.         break;
  2573.  
  2574.         case BUILTIN_set_scroll_step:
  2575.  
  2576.         signals(SIG_OFF);
  2577.  
  2578.         if (il_read_line("Scroll step: ", &input, NULL,
  2579.                  command->history))
  2580.         {
  2581.             if (input[0] == 0)
  2582.             break;
  2583.  
  2584.             panel_action(src_panel, act_SET_SCROLL_STEP,
  2585.                  dest_panel, input, 1);
  2586.  
  2587.             xfree(input);
  2588.             input = NULL;
  2589.         }
  2590.  
  2591.         break;
  2592.  
  2593.         case BUILTIN_isearch_backward:
  2594.  
  2595.         signals(SIG_OFF);
  2596.  
  2597.         previous_isearch_failed = 0;
  2598.         il_isearch("I-search backward: ",NULL,IL_ISEARCH_BEGIN,NULL);
  2599.         panel_action(src_panel, act_ISEARCH_BEGIN,
  2600.                  dest_panel, NULL, 1);
  2601.  
  2602.         for(;;)
  2603.         {
  2604.             isearch_aux_t iai;
  2605.  
  2606.             if (il_isearch(NULL, &input, IL_ISEARCH_BACKWARD,
  2607.                    &iai.action) == NULL)
  2608.             break;
  2609.  
  2610.             /* Wrap around.  */
  2611.             if (iai.action == IL_ISEARCH_ACTION_RETRY &&
  2612.             previous_isearch_failed)
  2613.             {
  2614.             panel_set_wrapped_isearch_flag(src_panel);
  2615.             previous_isearch_failed = 0;
  2616.             }
  2617.  
  2618.             iai.string = input;
  2619.             panel_action(src_panel, act_ISEARCH_BACKWARD,
  2620.                  dest_panel, &iai, 1);
  2621.  
  2622.             if (iai.action == IL_ISEARCH_ACTION_FAILED)
  2623.             {
  2624.             previous_isearch_failed = 1;
  2625.             tty_beep();
  2626.             }
  2627.             else
  2628.             if (iai.length < strlen(input))
  2629.             {
  2630.                 il_backward_delete_char();
  2631.                 il_full_update();
  2632.             }
  2633.         }
  2634.  
  2635.         panel_action(src_panel, act_ISEARCH_END, dest_panel, NULL, 1);
  2636.         il_isearch(NULL, NULL, IL_ISEARCH_END, NULL);
  2637.         break;
  2638.  
  2639.         case BUILTIN_isearch_forward:
  2640.  
  2641.         signals(SIG_OFF);
  2642.  
  2643.         previous_isearch_failed = 0;
  2644.         il_isearch("I-search: ", NULL, IL_ISEARCH_BEGIN, NULL);
  2645.         panel_action(src_panel, act_ISEARCH_BEGIN,
  2646.                  dest_panel, NULL, 1);
  2647.  
  2648.         for(;;)
  2649.         {
  2650.             isearch_aux_t iai;
  2651.  
  2652.             if (il_isearch(NULL, &input, IL_ISEARCH_FORWARD,
  2653.                    &iai.action) == NULL)
  2654.             break;
  2655.  
  2656.             /* Wrap around.  */
  2657.             if (iai.action == IL_ISEARCH_ACTION_RETRY &&
  2658.             previous_isearch_failed)
  2659.             {
  2660.             panel_set_wrapped_isearch_flag(src_panel);
  2661.             previous_isearch_failed = 0;
  2662.             }
  2663.  
  2664.             iai.string = input;
  2665.             panel_action(src_panel, act_ISEARCH_FORWARD,
  2666.                  dest_panel, &iai, 1);
  2667.  
  2668.             if (iai.action == IL_ISEARCH_ACTION_FAILED)
  2669.             {
  2670.             previous_isearch_failed = 1;
  2671.             tty_beep();
  2672.             }
  2673.             else
  2674.             if (iai.length < strlen(input))
  2675.             {
  2676.                 il_backward_delete_char();
  2677.                 il_full_update();
  2678.             }
  2679.         }
  2680.  
  2681.         panel_action(src_panel, act_ISEARCH_END, dest_panel, NULL, 1);
  2682.         il_isearch(NULL, NULL, IL_ISEARCH_END, NULL);
  2683.         break;
  2684.  
  2685.         case BUILTIN_reset_directory_history:
  2686.  
  2687.         signals(SIG_OFF);
  2688.  
  2689.         dir_history_reset();
  2690.         dir_history_add(panel_get_path(src_panel));
  2691.         break;
  2692.  
  2693.         case BUILTIN_previous_directory:
  2694.  
  2695.         signals(SIG_OFF);
  2696.  
  2697.         dir_history_prev(src_panel, dest_panel);
  2698.  
  2699.         il_restore(saved_il);
  2700.         il_set_static_text(strcat(
  2701.             truncate_string(panel_get_path(src_panel), PWD,
  2702.                     MAX_STATIC_SIZE),
  2703.             PS1));
  2704.         saved_il = il_save();
  2705.  
  2706.         break;
  2707.  
  2708.         case BUILTIN_next_directory:
  2709.  
  2710.         signals(SIG_OFF);
  2711.  
  2712.         dir_history_next(src_panel, dest_panel);
  2713.  
  2714.         il_restore(saved_il);
  2715.         il_set_static_text(strcat(
  2716.             truncate_string(panel_get_path(src_panel), PWD,
  2717.                     MAX_STATIC_SIZE),
  2718.             PS1));
  2719.         saved_il = il_save();
  2720.  
  2721.         break;
  2722.  
  2723.         case BUILTIN_enlarge_other_panel:
  2724.  
  2725.         signals(SIG_OFF);
  2726.  
  2727.           one_panel_mode:
  2728.  
  2729.         panel_set_focus(src_panel, OFF);
  2730.  
  2731.         temp_panel = src_panel;
  2732.         src_panel  = dest_panel;
  2733.         dest_panel = temp_panel;
  2734.  
  2735.         panel_no = !panel_no;
  2736.         panel_set_focus(src_panel, ON);
  2737.         panel_activate(src_panel);
  2738.  
  2739.         il_free(saved_il);
  2740.         il_set_static_text(strcat(
  2741.             truncate_string(panel_get_path(src_panel),  PWD,
  2742.                     MAX_STATIC_SIZE),
  2743.             PS1));
  2744.         saved_il = il_save();
  2745.  
  2746.         case BUILTIN_enlarge_panel:
  2747.  
  2748.         signals(SIG_OFF);
  2749.  
  2750.         panel_no_optimizations(src_panel);
  2751.         panel_no_optimizations(dest_panel);
  2752.         tty_touch();
  2753.         panel_deactivate(dest_panel);
  2754.         panel_resize(src_panel, 0, 1, SCREEN_Y - 3, SCREEN_X);
  2755.  
  2756.         two_panel_mode = 0;
  2757.         panel_action(src_panel,  act_ENABLE_ALL, NULL, NULL, 1);
  2758.         panel_action(dest_panel, act_ENABLE_ALL, NULL, NULL, 1);
  2759.  
  2760.         break;
  2761.  
  2762.         case BUILTIN_two_panels:
  2763.  
  2764.         signals(SIG_OFF);
  2765.  
  2766.         panel_no_optimizations(src_panel);
  2767.         panel_no_optimizations(dest_panel);
  2768.         tty_touch();
  2769.         panel_activate(dest_panel);
  2770.         panel_resize(src_panel, 0, 1,
  2771.                  SCREEN_Y - 3, SCREEN_X >> 1);
  2772.         panel_resize(dest_panel, SCREEN_X >> 1, 1,
  2773.                  SCREEN_Y - 3, SCREEN_X >> 1);
  2774.  
  2775.         two_panel_mode = 1;
  2776.         panel_action(src_panel,  act_ENABLE_SIZE, NULL, NULL, 1);
  2777.         panel_action(dest_panel, act_ENABLE_SIZE, NULL, NULL, 1);
  2778.  
  2779.         break;
  2780.  
  2781.         case BUILTIN_lock:
  2782.  
  2783.         /* Turn echo off.  */
  2784.         il_echo(0);
  2785.  
  2786.         lock_password = NULL;
  2787.         il_read_line("Enter a password: ", &lock_password, NULL, NULL);
  2788.  
  2789.         if (lock_password == NULL || *lock_password == '\0')
  2790.         {
  2791.             il_echo(1);
  2792.             break;
  2793.         }
  2794.  
  2795.         for (unlock_password = NULL;;)
  2796.         {
  2797.             il_read_line("Enter password to unlock: ",
  2798.                  &unlock_password, NULL, NULL);
  2799.             il_message(lock_think);
  2800.             sleep(1);
  2801.  
  2802.             if (unlock_password &&
  2803.             strcmp(lock_password, unlock_password) == 0)
  2804.             break;
  2805.  
  2806.             il_message(lock_bad);
  2807.             tty_beep();
  2808.             sleep(2);
  2809.         }
  2810.  
  2811.         il_message(lock_ok);
  2812.         sleep(1);
  2813.         xfree(lock_password);
  2814.         xfree(unlock_password);
  2815.  
  2816.         /* Turn echo back on.  */
  2817.         il_echo(1);
  2818.         break;
  2819.  
  2820.         default:
  2821.  
  2822.         signals(SIG_OFF);
  2823.  
  2824.         if (key)
  2825.         {
  2826.             il_free(saved_il);
  2827.  
  2828.             while (repeat_count--)
  2829.             il_dispatch_commands(key, IL_MOVE | IL_EDIT);
  2830.  
  2831.             saved_il = il_save();
  2832.         }
  2833.         break;
  2834.     }
  2835.  
  2836.     signals(SIG_ON);
  2837.     }
  2838.  
  2839.     signals(SIG_OFF);
  2840.     panel_end(left_panel);
  2841.     panel_end(right_panel);
  2842.     tty_set_mode(TTY_CANONIC);
  2843.     tty_defaults();
  2844.  
  2845.     if (il)
  2846.     il_end();
  2847.  
  2848.     status_end();
  2849.     removelog();
  2850.  
  2851.     tty_exit(screen);
  2852.  
  2853.     return 0;
  2854. }
  2855.