1 /*
2 DF-SHOW: An interactive directory/file browser written for Unix-like systems.
3 Based on the applications from the PC-DOS DF-EDIT suite by Larry Kroeker.
4 Copyright (C) 2018-2021 Robert Ian Hawdon
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #define _GNU_SOURCE
21 #include <ncurses.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <ctype.h>
25 #include <regex.h>
26 #include "menu.h"
27 #include "display.h"
28 #include "settings.h"
29 #include "common.h"
30 #include "sf.h"
31 #include "colors.h"
32 #include "input.h"
33
34 int c;
35 int * pc = &c;
36
37 int abortinput = 0;
38
39 bool findSet = false;
40
41 menuDef *fileMenu;
42 int fileMenuSize = 0;
43 wchar_t *fileMenuLabel;
44
45 menuDef *caseMenu;
46 int caseMenuSize = 0;
47 wchar_t *caseMenuLabel;
48
49 extern menuDef *settingsMenu;
50 extern int settingsMenuSize;
51 extern wchar_t *settingsMenuLabel;
52
53 extern char regexinput[1024];
54 extern FILE *file;
55 extern int topline;
56 extern int leftcol;
57 extern char fileName[4096];
58 extern int displaysize;
59 extern int totallines;
60 extern int longestlongline;
61 extern int viewmode;
62
63 extern int wrap;
64 extern int wrapmode;
65
66 extern FILE *stream;
67 extern char *line;
68
69 extern long int *filePos;
70 extern wchar_t *longline;
71
generateDefaultMenus()72 void generateDefaultMenus(){
73 // File Menu
74 addMenuItem(&fileMenu, &fileMenuSize, "f_01", L"<F1>-Down", 265);
75 addMenuItem(&fileMenu, &fileMenuSize, "f_02", L"<F2>-Up", 266);
76 addMenuItem(&fileMenu, &fileMenuSize, "f_03", L"<F3>-Top", 267);
77 addMenuItem(&fileMenu, &fileMenuSize, "f_04", L"<F4>-Bottom", 268);
78 addMenuItem(&fileMenu, &fileMenuSize, "f_config", L"!Config", 'c');
79 addMenuItem(&fileMenu, &fileMenuSize, "f_find", L"!Find", 'f');
80 addMenuItem(&fileMenu, &fileMenuSize, "f_help", L"!Help", 'h');
81 addMenuItem(&fileMenu, &fileMenuSize, "f_position", L"!Position", 'p');
82 addMenuItem(&fileMenu, &fileMenuSize, "f_quit", L"!Quit", 'q');
83 if (wrap){
84 addMenuItem(&fileMenu, &fileMenuSize, "f_wrap", L"!Wrap-off", 'w');
85 } else {
86 addMenuItem(&fileMenu, &fileMenuSize, "f_wrap", L"!Wrap-on", 'w');
87 }
88
89 // Case Menu
90 addMenuItem(&caseMenu, &caseMenuSize, "c1_ignore", L"!Ignore-case", 'i');
91 addMenuItem(&caseMenu, &caseMenuSize, "c2_sensitive", L"!Case-sensitive", 'c');
92
93 // Setings Menu
94 addMenuItem(&settingsMenu, &settingsMenuSize, "s_quit", L"!Quit", 'q');
95 addMenuItem(&settingsMenu, &settingsMenuSize, "s_revert", L"!Revert", 'r');
96 addMenuItem(&settingsMenu, &settingsMenuSize, "s_save", L"!Save", 's');
97 }
98
refreshMenuLabels()99 void refreshMenuLabels(){
100 fileMenuLabel = genMenuDisplayLabel(L"", fileMenu, fileMenuSize, L"", 1);
101 caseMenuLabel = genMenuDisplayLabel(L"", caseMenu, caseMenuSize, L"(enter = I)", 0);
102 settingsMenuLabel = genMenuDisplayLabel(L"SF Settings Menu -", settingsMenu, settingsMenuSize, L"", 1);
103 }
104
unloadMenuLabels()105 void unloadMenuLabels(){
106 free(fileMenuLabel);
107 free(caseMenuLabel);
108 free(settingsMenuLabel);
109 }
110
show_file_find(bool charcase,bool useLast)111 void show_file_find(bool charcase, bool useLast)
112 {
113 int regexcase;
114 int result;
115 char inputmessage[32];
116 char errormessage[1024];
117 if (!useLast){
118 if (charcase){
119 regexcase = 0;
120 strcpy(inputmessage, "Match Case - Enter string:");
121 } else {
122 regexcase = REG_ICASE;
123 strcpy(inputmessage, "Ignore Case - Enter string:");
124 }
125 move(0,0);
126 clrtoeol();
127 mvprintw(0, 0, inputmessage);
128 curs_set(TRUE);
129 move(0, strlen(inputmessage) + 1);
130 curs_set(FALSE);
131 if (readline(regexinput, 1024, regexinput) == -1 ){
132 abortinput = 1;
133 }
134 }
135 if (abortinput != 1) {
136 findSet = true;
137 result = findInFile(fileName, regexinput, regexcase);
138 if ( result > 0 ){
139 topline = result;
140 updateView();
141 } else if ( result == -2 ){
142 // Not a feature in DF-EDIT 2.3d, but a nice to have
143 sprintf(errormessage, "No further references to '%s' found.", regexinput);
144 topLineMessage(errormessage);
145 }
146 }
147 }
148
show_file_find_case_input()149 int show_file_find_case_input()
150 {
151 int result;
152 move(0,0);
153 clrtoeol();
154 wPrintMenu(0,0,caseMenuLabel);
155 while(1)
156 {
157 *pc = getch10th();
158 if (*pc == menuHotkeyLookup(caseMenu, "c1_ignore", caseMenuSize) || *pc == 10){
159 result = 0;
160 break;
161 } else if (*pc == menuHotkeyLookup(caseMenu, "c2_sensitive", caseMenuSize)){
162 result = 1;
163 break;
164 } else if (*pc == 27){
165 // ESC
166 result = -1;
167 break;
168 }
169 }
170 return(result);
171 }
172
show_file_position_input(int currentpos)173 void show_file_position_input(int currentpos)
174 {
175 char newpos[11];
176 char *filePosText;
177 int filePosTextLen;
178 int status;
179 // Fun fact, in DF-EDIT 2.3d, the following text input typoed "absolute" as "absolue", this typo also exists in the Windows version from 1997 (2.3d-76), however, the 1986 documentation correctly writes it as "absolute".
180 filePosTextLen = snprintf(NULL, 0, "Position relative (<+num> || <-num>) or absolute (<num>):");
181 filePosText = malloc(sizeof(char) * (filePosTextLen + 1));
182 sprintf(filePosText, "Position relative (<+num> || <-num>) or absolute (<num>):");
183 viewmode = 2;
184 move(0,0);
185 clrtoeol();
186 printMenu(0,0,filePosText);
187 free(filePosText);
188 curs_set(TRUE);
189 move(0,52);
190 status = readline(newpos, 11, ""); // DF-EDIT defaulted to 0, but it also defaulted to overtype mode, so for ease of use, we'll leave the default blank.
191 curs_set(FALSE);
192 if ((status != -1) && (strcmp(newpos,"") != 0)){
193 if (check_first_char(newpos, "+")){
194 memmove(newpos, newpos+1, strlen(newpos));
195 if (check_numbers_only(newpos)){
196 topline = topline + atoi(newpos);
197 }
198 } else if (check_first_char(newpos, "-")) {
199 memmove(newpos, newpos+1, strlen(newpos));
200 if (check_numbers_only(newpos)){
201 topline = topline - atoi(newpos);
202 }
203 } else {
204 if (check_numbers_only(newpos)){
205 topline = atoi(newpos);
206 }
207 }
208 }
209 wPrintMenu(0, 0, fileMenuLabel);
210 }
211
show_file_inputs()212 void show_file_inputs()
213 {
214 int e = 0;
215 wPrintMenu(0, 0, fileMenuLabel);
216 while(1)
217 {
218 *pc = getch10th();
219 if (*pc == menuHotkeyLookup(fileMenu,"f_find", fileMenuSize)){
220 e = show_file_find_case_input();
221 if (e != -1){
222 show_file_find(e, false);
223 } else {
224 abortinput = 0;
225 }
226 wPrintMenu(0, 0, fileMenuLabel);
227 } else if (*pc == 6){
228 if (findSet){
229 show_file_find(false, true);
230 }
231 wPrintMenu(0, 0, fileMenuLabel);
232 } else if (*pc == menuHotkeyLookup(fileMenu, "f_help", fileMenuSize)){
233 showManPage("sf");
234 wPrintMenu(0, 0, fileMenuLabel);
235 refreshScreen();
236 } else if (*pc == menuHotkeyLookup(fileMenu, "f_position", fileMenuSize)){
237 show_file_position_input(topline);
238 if (topline > totallines + 1){
239 topline = totallines + 1;
240 } else if (topline < 1){
241 topline = 1;
242 }
243 updateView();
244 } else if (*pc == menuHotkeyLookup(fileMenu, "f_config", fileMenuSize)){
245 settingsMenuView();
246 wPrintMenu(0, 0, fileMenuLabel);
247 if(wrap){
248 leftcol = 1;
249 }
250 refreshScreen();
251 // updateView();
252 } else if (*pc == menuHotkeyLookup(fileMenu, "f_quit", fileMenuSize)){
253 free(longline);
254 free(filePos);
255 fclose(stream);
256 exittoshell();
257 } else if (*pc == menuHotkeyLookup(fileMenu, "f_wrap", fileMenuSize)){
258 if (wrap){
259 updateMenuItem(&fileMenu, &fileMenuSize, "f_wrap", L"!Wrap-on");
260 wrap = 0;
261 } else {
262 updateMenuItem(&fileMenu, &fileMenuSize, "f_wrap", L"!Wrap-off");
263 leftcol = 1;
264 wrap = 1;
265 }
266 unloadMenuLabels();
267 refreshMenuLabels();
268 wPrintMenu(0,0,fileMenuLabel);
269 updateView();
270 } else if (*pc == menuHotkeyLookup(fileMenu, "f_01", fileMenuSize) || *pc == 338){
271 topline = topline + displaysize;
272 if (topline > totallines + 1){
273 topline = totallines + 1;
274 }
275 updateView();
276 } else if (*pc == menuHotkeyLookup(fileMenu, "f_02", fileMenuSize) || *pc == 339){
277 topline = topline - displaysize;
278 if (topline < 1){
279 topline = 1;
280 }
281 updateView();
282 } else if (*pc == menuHotkeyLookup(fileMenu, "f_03", fileMenuSize)){
283 topline = 1;
284 updateView();
285 } else if (*pc == menuHotkeyLookup(fileMenu, "f_04", fileMenuSize)){
286 topline = totallines + 1; // Show EOF
287 updateView();
288 } else if (*pc == 258){
289 // Down Arrow
290 if (topline < totallines + 1){
291 topline++;
292 //loadFile(fileName);
293 updateView();
294 }
295 } else if (*pc == 259){
296 // Up Arrow
297 if (topline > 1){
298 topline--;
299 updateView();
300 }
301 } else if (*pc == 260){
302 // Left Arrow
303 if ((leftcol > 1) && (wrap != 1)){
304 leftcol--;
305 updateView();
306 }
307 } else if (*pc == 261){
308 // Right Arrow
309 if ((leftcol < longestlongline) && (wrap != 1)){
310 leftcol++;
311 updateView();
312 }
313 } else if (*pc == 262){
314 // Home
315 // Let's not disable this key when Wrapping is on, just in case.
316 leftcol = 1;
317 updateView();
318 } else if (*pc == 360){
319 // End
320 if (wrap != 1){
321 leftcol = longestlongline;
322 updateView();
323 }
324 }
325 }
326 }
327
show_file_file_input()328 void show_file_file_input()
329 {
330 char *rewrite;
331 move(0,0);
332 clrtoeol(); // Probably not needed as this is only ever displayed when launching without a file
333 mvprintw(0,0,"Show File - Enter pathname:");
334 curs_set(TRUE);
335 move(0,28);
336 readline(fileName, 4096, "");
337 curs_set(FALSE);
338 if (check_first_char(fileName, "~")){
339 rewrite = str_replace(fileName, "~", getenv("HOME"));
340 strcpy(fileName, rewrite);
341 free(rewrite);
342 }
343 file_view(fileName);
344 }
345