remove trailing whitespace at end of lines
[reactos.git] / rosapps / mc / src / view.c
1 /* {{{ Copyright notice */
2
3 /* View file module for the Midnight Commander
4 Copyright (C) 1994, 1995, 1996 The Free Software Foundation
5 Written by: 1994, 1995, 1998 Miguel de Icaza
6 1994, 1995 Janne Kukonlehto
7 1995 Jakub Jelinek
8 1996 Joseph M. Hinkle
9 1997 Norbert Warmuth
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
24
25 /* }}} */
26 /* {{{ Declarations */
27 #include <config.h>
28 #include "x.h"
29 #include <stdio.h>
30 #ifdef OS2_NT
31 # include <io.h>
32 #endif
33 #include <sys/types.h>
34 #ifdef HAVE_UNISTD_H
35 # include <unistd.h>
36 #endif
37 #include <string.h>
38 #include "tty.h"
39 #include <sys/stat.h>
40 #ifdef HAVE_MMAP
41 # include <sys/mman.h>
42 #endif
43 #include <fcntl.h>
44 #ifdef HAVE_UNISTD_H
45 # include <unistd.h>
46 #endif
47 #include <ctype.h> /* For toupper() */
48 #include <stdlib.h> /* atoi() */
49 #include <malloc.h>
50 #include <errno.h>
51 #include <limits.h>
52 #include <sys/param.h>
53 #include "mem.h"
54 #include "mad.h"
55 #include "util.h"
56 #include "dlg.h" /* Needed by widget.h */
57 #include "widget.h" /* Needed for buttonbar_new */
58 #include "color.h"
59 #include "dialog.h"
60 #include "file.h"
61 #include "mouse.h"
62 #include "global.h"
63 #include "help.h"
64 #include "key.h" /* For mi_getch() */
65 #include "layout.h"
66 #include "wtools.h" /* For query_set_sel() */
67 #if defined(HAVE_RX_H) && defined(HAVE_REGCOMP)
68 # include <rx.h>
69 #else
70 # include "regex.h"
71 #endif
72 #include "fs.h"
73 #include "../vfs/vfs.h"
74 #include "dir.h"
75 #include "panel.h" /* Needed for current_panel and other_panel */
76 #include "win.h"
77 #include "main.h" /* For the externs */
78 #define WANT_WIDGETS
79 #include "view.h"
80
81 #ifndef MAP_FILE
82 #define MAP_FILE 0
83 #endif
84
85 /* Block size for reading files in parts */
86 #define READ_BLOCK 8192
87 #define VIEW_PAGE_SIZE 8192
88
89 #ifdef IS_AIX
90 # define IFAIX(x) case (x):
91 #else
92 # define IFAIX(x)
93 #endif
94
95 /* Maxlimit for skipping updates */
96 int max_dirt_limit =
97 #ifdef OS2_NT
98 0;
99 #else
100 10;
101 #endif
102
103 /* Our callback */
104 static int view_callback (Dlg_head *h, WView *view, int msg, int par);
105
106 /* If set, show a ruler */
107 int ruler = 0;
108
109 /* Scrolling is done in pages or line increments */
110 int mouse_move_pages_viewer = 1;
111
112 /* Used to compute the bottom first variable */
113 int have_fast_cpu = 0;
114
115 /* wrap mode default */
116 int global_wrap_mode = 1;
117
118 int default_hex_mode = 0;
119 int default_hexedit_mode = 0;
120 int default_magic_flag = 1;
121 int default_nroff_flag = 1;
122 int altered_hex_mode = 0;
123 int altered_magic_flag = 0;
124 int altered_nroff_flag = 0;
125 /* }}} */
126
127 /* "$Id$" */
128
129 static char hex_char[] = "0123456789ABCDEF";
130
131 /* }}} */
132 /* {{{ Clean-up functions */
133
134 void
135 close_view_file (WView *view)
136 {
137 if (view->file != -1){
138 mc_close (view->file);
139 view->file = -1;
140 }
141 }
142
143 void
144 free_file (WView *view)
145 {
146 int i;
147
148 #ifdef HAVE_MMAP
149
150 if (view->mmapping){
151 mc_munmap (view->data, view->s.st_size);
152 close_view_file (view);
153 } else
154 #endif /* HAVE_MMAP */
155 {
156 if (view->reading_pipe){
157 /* Check error messages */
158 if (!view->have_frame)
159 check_error_pipe ();
160
161 /* Close pipe */
162 pclose (view->stdfile);
163 view->stdfile = NULL;
164
165 /* Ignore errors because we don't want to hear about broken pipe */
166 close_error_pipe (-1, NULL);
167 } else
168 close_view_file (view);
169 }
170 /* Block_ptr may be zero if the file was a file with 0 bytes */
171 if (view->growing_buffer && view->block_ptr){
172 for (i = 0; i < view->blocks; i++){
173 free (view->block_ptr [i].data);
174 }
175 free (view->block_ptr);
176 }
177 }
178
179 /* Valid parameters for second parameter to set_monitor */
180 enum { off, on };
181
182 /* Both views */
183 void
184 view_done (WView *view)
185 {
186 set_monitor (view, off);
187 #ifndef HAVE_MMAP
188 /* alex: release core, used to replace mmap */
189 if (!view->growing_buffer && view->data != (unsigned char*)0)
190 {
191 free(view->data);
192 view->data = NULL;
193 }
194 #endif /* HAVE_MMAP */
195
196 if (view->view_active){
197 if (view->localcopy)
198 mc_ungetlocalcopy (view->filename, view->localcopy, 0);
199 free_file (view);
200 free (view->filename);
201 if (view->command)
202 free (view->command);
203 }
204 view->view_active = 0;
205 default_hex_mode = view->hex_mode;
206 default_nroff_flag = view->viewer_nroff_flag;
207 default_magic_flag = view->viewer_magic_flag;
208 }
209
210 static void view_hook (void *);
211
212 void
213 view_destroy (WView *view)
214 {
215 view_done (view);
216 if (view->have_frame)
217 delete_hook (&select_file_hook, view_hook);
218 x_destroy_view (view);
219 }
220
221 static int
222 get_byte (WView *view, int byte_index)
223 {
224 int page = byte_index / VIEW_PAGE_SIZE + 1;
225 int offset = byte_index % VIEW_PAGE_SIZE;
226 int i, n;
227 block_ptr_t *tmp;
228
229 if (view->growing_buffer){
230 if (page > view->blocks){
231 tmp = xmalloc (sizeof (block_ptr_t) * page, "get_byte");
232 if (view->block_ptr){
233 bcopy (view->block_ptr, tmp, sizeof (block_ptr_t) *
234 view->blocks);
235 free (view->block_ptr);
236 }
237 view->block_ptr = tmp;
238 for (i = view->blocks; i < page; i++){
239 char *p = malloc (VIEW_PAGE_SIZE);
240 view->block_ptr [i].data = p;
241 if (!p)
242 return '\n';
243 if (view->stdfile != NULL)
244 n = fread (p, 1, VIEW_PAGE_SIZE, view->stdfile);
245 else
246 n = mc_read (view->file, p, VIEW_PAGE_SIZE);
247 if (n != -1)
248 view->bytes_read += n;
249 if (view->s.st_size < view->bytes_read){
250 view->bottom_first = -1; /* Invalidate cache */
251 view->s.st_size = view->bytes_read;
252 view->last_byte = view->bytes_read;
253 if (view->reading_pipe)
254 view->last_byte = view->first + view->bytes_read;
255 }
256 /* To force loading the next page */
257 if (n == VIEW_PAGE_SIZE && view->reading_pipe){
258 view->last_byte++;
259 }
260 }
261 view->blocks = page;
262 }
263 if (byte_index > view->bytes_read){
264 return -1;
265 } else
266 return view->block_ptr [page-1].data [offset];
267 } else {
268 if (byte_index >= view->last_byte)
269 return -1;
270 else
271 return view->data [byte_index];
272 }
273 }
274
275 static void
276 enqueue_change (struct hexedit_change_node **head, struct hexedit_change_node *node)
277 {
278 struct hexedit_change_node *curr = *head;
279
280 while (curr) {
281 if (node->offset < curr->offset) {
282 *head = node;
283 node->next = curr;
284 return;
285 }
286 head = (struct hexedit_change_node **) curr;
287 curr = curr->next;
288 }
289 *head = node;
290 node->next = curr;
291 }
292
293 static void move_right (WView *);
294
295 static void
296 put_editkey (WView *view, unsigned char key)
297 {
298 struct hexedit_change_node *node;
299 unsigned char byte_val;
300
301 if (!view->hexedit_mode || view->growing_buffer != 0)
302 return;
303
304 /* Has there been a change at this position ? */
305 node = view->change_list;
306 while (node) {
307 if (node->offset != view->edit_cursor)
308 node = node->next;
309 else
310 break;
311 }
312
313 if (view->view_side == view_side_left) {
314 /* Hex editing */
315
316 if (key >= '0' && key <= '9')
317 key -= '0';
318 else if (key >= 'A' && key <= 'F')
319 key -= '7';
320 else if (key >= 'a' && key <= 'f')
321 key -= 'W';
322 else
323 return;
324
325 if (node)
326 byte_val = node->value;
327 else
328 byte_val = get_byte(view, view->edit_cursor);
329
330 if (view->nib_shift == 0) {
331 byte_val = (byte_val & 0x0f) | (key << 4);
332 } else {
333 byte_val = (byte_val & 0xf0) | (key);
334 }
335 } else {
336 /* Text editing */
337 byte_val = key;
338 }
339 if (!node) {
340 node = (struct hexedit_change_node *)
341 xmalloc(sizeof(struct hexedit_change_node), "HexEdit");
342
343 if (node) {
344 #ifndef HAVE_MMAP
345 /*
346 ** alex@bcs.zaporizhzhe.ua: here we are using file copy
347 ** completely loaded into memory, so we can replace bytes
348 ** in view->data array to allow changes to be reflected
349 ** when user switches back to ascii mode
350 */
351 view->data[view->edit_cursor] = byte_val;
352 #endif /* HAVE_MMAP */
353 node->offset = view->edit_cursor;
354 node->value = byte_val;
355 enqueue_change (&view->change_list, node);
356 }
357 } else {
358 node->value = byte_val;
359 }
360 view->dirty++;
361 view_update (view);
362 move_right (view);
363 }
364
365 static void
366 free_change_list (WView *view)
367 {
368 struct hexedit_change_node *n = view->change_list;
369
370 while (n) {
371 view->change_list = n->next;
372 free (n);
373 n = view->change_list;
374 }
375 view->file_dirty = 0;
376 view->dirty++;
377 }
378
379 static void
380 save_edit_changes (WView *view)
381 {
382 struct hexedit_change_node *node = view->change_list;
383 int fp;
384
385 fp = open (view->filename, O_WRONLY);
386 if (fp >= 0) {
387 while (node) {
388 lseek (fp, node->offset, SEEK_SET);
389 write (fp, &node->value, 1);
390 node = node->next;
391 }
392 close (fp);
393 }
394 free_change_list (view);
395 }
396
397 static int
398 view_ok_to_quit (WView *view)
399 {
400 int r;
401 char *text;
402
403 if (!view->change_list)
404 return 1;
405
406 query_set_sel (1);
407 text = copy_strings (_("File: \n\n "), view->filename,
408 _("\n\nhas been modified, do you want to save the changes?\n"), NULL);
409
410 r = query_dialog (_(" Save changes "), text, 2, 3, _("&Yes"), _("&No"), _("&Cancel"));
411 free (text);
412
413 switch (r) {
414 case 0:
415 save_edit_changes (view);
416 return 1;
417 case 1:
418 free_change_list (view);
419 return 1;
420 default:
421 return 0;
422 }
423 }
424
425 static char *
426 set_view_init_error (WView *view, char *msg)
427 {
428 view->growing_buffer = 0;
429 view->reading_pipe = 0;
430 view->first = 0;
431 view->last_byte = 0;
432 if (msg){
433 view->bytes_read = strlen (msg);
434 return strdup (msg);
435 }
436 return 0;
437 }
438
439 /* return values: 0 for success, else points to error message */
440 static char *
441 init_growing_view (WView *view, char *name, char *filename)
442 {
443 view->growing_buffer = 1;
444
445 if (name){
446 view->reading_pipe = 1;
447 view->s.st_size = 0;
448
449 open_error_pipe ();
450 if ((view->stdfile = popen (name, "r")) == NULL){
451 close_error_pipe (view->have_frame?-1:1, view->data);
452 return set_view_init_error (view, _(" Can't spawn child program "));
453 }
454
455 #ifndef HAVE_XVIEW
456 /* First, check if filter produced any output */
457 get_byte (view, 0);
458 if (view->bytes_read <= 0){
459 pclose (view->stdfile);
460 view->stdfile = NULL;
461 close_error_pipe (view->have_frame?-1:1, view->data);
462 return set_view_init_error (view, _(" Empty output from child filter "));
463 }
464 #endif
465 } else {
466 view->stdfile = NULL;
467 if ((view->file = mc_open (filename, O_RDONLY)) == -1)
468 return set_view_init_error (view, _(" Could not open file "));
469 }
470 return 0;
471 }
472
473 /* Load filename into core */
474 /* returns:
475 -1 on failure.
476 if (have_frame), we return success, but data points to a
477 error message instead of the file buffer (quick_view feature).
478 */
479 static char *load_view_file (WView *view, char *filename)
480 {
481 char *cmd;
482 int type;
483
484 if ((view->file = mc_open (filename, O_RDONLY)) < 0){
485 set_view_init_error (view, 0);
486 return (copy_strings (_(" Can't open file \""),
487 filename, "\"\n ",
488 unix_error_string (errno), " ", 0));
489
490 }
491 if (mc_fstat (view->file, &view->s) < 0){
492 set_view_init_error (view, 0);
493 close_view_file (view);
494 return copy_strings (_(" Can't stat file \n "),
495 unix_error_string (errno), " ", 0);
496 }
497 if (S_ISDIR (view->s.st_mode) || S_ISSOCK (view->s.st_mode)
498 || S_ISFIFO (view->s.st_mode)){
499 close_view_file (view);
500 return set_view_init_error (view, _(" Can't view: not a regular file "));
501 }
502
503 if (view->s.st_size == 0){
504 /* Must be one of those nice files that grow (/proc) */
505 close_view_file (view);
506 return init_growing_view (view, 0, filename);
507 }
508
509 /* First, try to open a compressed file */
510 if (view->viewer_magic_flag && (is_gunzipable (view->file, &type)) != 0){
511 close_view_file (view);
512 if (vfs_file_is_local (filename)) {
513 char *tmp = name_quote (filename, 0);
514 cmd = copy_strings (decompress_command (type), " ", tmp, 0);
515 free (tmp);
516 }
517 else {
518 char *tmp;
519 if ((view->localcopy = mc_getlocalcopy (filename)) == 0)
520 return set_view_init_error (view, _(" Can not fetch local copy ") );
521 tmp = name_quote (view->localcopy, 0);
522 cmd = copy_strings (decompress_command (type), " ", tmp, 0);
523 free (tmp);
524 }
525 return init_growing_view (view, cmd, filename);
526 }
527
528 /* Otherwise, the file wasn't compressed */
529 #ifdef HAVE_MMAP
530 view->data = mc_mmap (0, view->s.st_size, PROT_READ, MAP_FILE | MAP_SHARED,
531 view->file, 0);
532 if ((caddr_t) view->data == (caddr_t) -1){
533 close_view_file (view);
534 /* set_view_init_error (view, 0);
535 return copy_strings (" Can't mmap file \n ",
536 unix_error_string (errno), " ", 0);*/
537 return init_growing_view (view, 0, filename);
538
539 }
540
541 view->first = 0;
542 view->bytes_read = view->s.st_size;
543 view->mmapping = 1;
544 return 0;
545 #else /* ! HAVE_MMAP */
546 /*
547 ** For those OS that dont provide mmap call. Try to load all the file
548 ** into memory (alex@bcs.zaporizhzhe.ua)
549 */
550 view->data = (unsigned char*) xmalloc (view->s.st_size, "load_view_file");
551 if (view->data == (unsigned char*) 0
552 || mc_lseek(view->file,0,0) != 0
553 || mc_read(view->file, view->data, view->s.st_size) != view->s.st_size
554 ) {
555 if (view->data != (unsigned char*)0)
556 free(view->data);
557 close_view_file (view);
558 return init_growing_view (view, 0, filename);
559 }
560 view->first = 0;
561 view->bytes_read = view->s.st_size;
562 return 0;
563 #endif
564 }
565
566 /* Return zero on success, -1 on failure */
567 int
568 do_view_init (WView *view, char *_command, char *_file, int start_line)
569 {
570 char *error = 0;
571 int i;
572
573 if (view->view_active)
574 view_done (view);
575
576 /* Set up the state */
577 view->block_ptr = 0;
578 view->data = NULL;
579 view->growing_buffer = 0;
580 view->reading_pipe = 0;
581 view->mmapping = 0;
582 view->blocks = 0;
583 view->block_ptr = 0;
584 view->first = view->bytes_read = 0;
585 view->last_byte = 0;
586 view->filename = 0;
587 view->localcopy = 0;
588 view->command = 0;
589 view->last = view->first + ((LINES-2) * view->bytes_per_line);
590
591 /* Clear the markers */
592 view->marker = 0;
593 for (i = 0; i < 10; i++)
594 view->marks [i] = 0;
595
596
597 if (!view->have_frame){
598 view->start_col = 0;
599 }
600 if (_command && (view->viewer_magic_flag || _file[0] == '\0'))
601 error = init_growing_view (view, _command, _file);
602 else
603 error = load_view_file (view, _file);
604
605 if (error){
606 if (!view->have_frame){
607 message (1, MSG_ERROR, error);
608 free (error);
609 return -1;
610 }
611 }
612
613 view->view_active = 1;
614 view->filename = strdup (_file);
615 if (_command)
616 view->command = strdup (_command);
617 else
618 view->command = 0;
619 view->search_start = view->start_display = view->start_save = view->first;
620 view->found_len = 0;
621 view->start_col = 0;
622 view->last_search = 0; /* Start a new search */
623
624 /* Special case: The data points to the error message */
625 if (error){
626 view->data = error;
627 view->s.st_size = view->bytes_read = strlen (view->data);
628 }
629 view->last_byte = view->first + view->s.st_size;
630
631 if (start_line > 1 && !error){
632 int saved_wrap_mode = view->wrap_mode;
633
634 view->wrap_mode = 0;
635 get_byte (view, 0);
636 view_move_forward (view, start_line - 1);
637 view->wrap_mode = saved_wrap_mode;
638 }
639 view->edit_cursor = view->first;
640 view->file_dirty = 0;
641 view->nib_shift = 0;
642 view->view_side = view_side_left;
643 view->change_list = NULL;
644
645 return 0;
646 }
647
648
649 /* Both views */
650 /* Return zero on success, -1 on failure */
651 int
652 view_init (WView *view, char *_command, char *_file, int start_line)
653 {
654 int cols;
655
656 if (view->have_frame)
657 cols = view->widget.cols - 2;
658 else
659 cols = view->widget.cols;
660
661 view->bottom_first = -1;
662 view->bytes_per_line = 2 * (cols - 7) / 9;
663 view->bytes_per_line &= 0xfffc;
664 view->dirty = max_dirt_limit + 1; /* To force refresh */
665 if (!view->view_active || strcmp (_file, view->filename) || altered_magic_flag)
666 return do_view_init (view, _command, _file, start_line);
667 else
668 return 0;
669 }
670
671 /* }}} */
672
673 /* {{{ Screen update functions */
674
675 #ifndef HAVE_X
676 void
677 view_percent (WView *view, int p, int w)
678 {
679 int percent;
680
681 percent = (view->s.st_size == 0 || view->last_byte == view->last) ? 100 :
682 (p > (INT_MAX/100) ?
683 p / (view->s.st_size / 100) :
684 p * 100 / view->s.st_size);
685
686 #if 0
687 percent = view->s.st_size == 0 ? 100 :
688 (view->last_byte == view->last ? 100 :
689 (p)*100 / view->s.st_size);
690 #endif
691
692 widget_move (view, view->have_frame, w - 5);
693 printw ("%3d%% ", percent);
694 }
695
696 void
697 view_status (WView *view)
698 {
699 int w = view->widget.cols - (view->have_frame * 2);
700 int i;
701
702 attrset (SELECTED_COLOR);
703 widget_move (view, view->have_frame, view->have_frame);
704 hline (' ', w);
705 if (w > 6){
706 i = w > 24 ? 18 : w - 6;
707 printw (_("File: %s"), name_trunc (view->filename ? view->filename:
708 view->command ? view->command:"", i));
709 if (w > 30){
710 widget_move (view, view->have_frame, 24);
711 if (view->hex_mode)
712 printw (_("Offset 0x%08x"), view->edit_cursor);
713 else
714 printw (_("Col %d"), -view->start_col);
715 }
716 if (w > 60){
717 widget_move (view, view->have_frame, 42);
718 printw (_("%s bytes"), size_trunc (view->s.st_size));
719 }
720 if (w > 70){
721 printw (" ");
722 if (view->growing_buffer)
723 addstr (_(" [grow]"));
724 }
725 if (w - i > 4)
726 if (view->hex_mode)
727 view_percent (view, view->edit_cursor - view->first, w);
728 else
729 view_percent (view, view->start_display - view->first, w);
730 }
731 attrset (SELECTED_COLOR);
732 }
733
734 #define view_set_color(view,font) attrset (font)
735
736 static inline void
737 view_display_clean (WView *view, int height, int width)
738 {
739 /* FIXME: Should I use widget_erase only and repaint the box? */
740 if (view->have_frame){
741 int i;
742
743 draw_double_box (view->widget.parent, view->widget.y, view->widget.x,
744 view->widget.lines, view->widget.cols);
745 for (i = 1; i < height; i++){
746 widget_move (view, i, 1);
747 printw ("%*s", width-1, "");
748 }
749 } else
750 widget_erase ((Widget *) view);
751 }
752
753 #define view_add_character(view,c) addch (c)
754 #define view_add_string(view,s) addstr (s)
755 #define view_gotoyx(v,r,c) widget_move (v,r,c)
756 #endif
757
758 #ifndef HAVE_TK
759 /* Both the text mode and gnome editions use this */
760 #define BOLD_COLOR MARKED_COLOR
761 #define UNDERLINE_COLOR VIEW_UNDERLINED_COLOR
762 #define MARK_COLOR SELECTED_COLOR
763 #define DEF_COLOR NORMAL_COLOR
764 #endif
765
766 #ifndef PORT_HAS_VIEW_FREEZE
767 # define view_freeze(view)
768 # define view_thaw(view)
769 #endif
770
771 #ifdef HAVE_GNOME
772 # define PICK_COLOR(a,b) BOLD_COLOR : DEF_COLOR
773 #else
774 # define PICK_COLOR(a,b) a : b
775 #endif
776
777 /* Shows the file pointed to by *start_display on view_win */
778 static long
779 display (WView *view)
780 {
781 #ifdef HAVE_X
782 # define frame_shift 0
783 # define STATUS_LINES 0
784 #else
785 const int frame_shift = view->have_frame;
786 # define STATUS_LINES 1
787 #endif
788 int col = 0 + frame_shift;
789 int row = STATUS_LINES + frame_shift;
790 int height, width;
791 long from;
792 int c;
793 int boldflag = 0;
794 struct hexedit_change_node *curr = view->change_list;
795
796 height = view->widget.lines - frame_shift;
797 width = view->widget.cols - frame_shift;
798 from = view->start_display;
799 view_set_color (view, DEF_COLOR);
800
801 view_freeze (view);
802 view_display_clean (view, height, width);
803
804 /* Optionally, display a ruler */
805 if ((!view->hex_mode) && (ruler)){
806 char r_buff[4];
807 int cl;
808
809 view_set_color (view, BOLD_COLOR);
810 for (c = frame_shift; c < width; c++) {
811 cl = c-view->start_col;
812 if (ruler == 1)
813 view_gotoyx (view, row, c);
814 else
815 view_gotoyx (view, row+height-2, c);
816 r_buff[0] = '-';
817 if ((cl % 10) == 0)
818 r_buff[0] = '|';
819 else
820 if ((cl % 5) == 0)
821 r_buff[0] = '*';
822 view_add_character (view, r_buff[0]);
823 if ((cl != 0) && (cl % 10) == 0){
824 sprintf(r_buff, "%03d", cl);
825 if (ruler == 1)
826 widget_move (view, row + 1, c - 1);
827 else
828 widget_move (view, row + height - 3, c - 1);
829 view_add_string (view, r_buff);
830 }
831 }
832 view_set_color (view, DEF_COLOR);
833 if (ruler == 1)
834 row += 2;
835 else
836 height -= 2;
837 }
838
839 /* Find the first displayable changed byte */
840 while (curr) {
841 if (curr->offset < from)
842 curr = curr->next;
843 else
844 break;
845 }
846 if (view->hex_mode){
847 char hex_buff[10]; /* A temporary buffer for sprintf and mvwaddstr */
848 int bytes; /* Number of bytes already printed on the line */
849
850 /* Start of text column */
851 int text_start = width - view->bytes_per_line - 1 + frame_shift;
852
853 for (;row < height && from < view->last_byte; row++){
854 /* Print the hex offset */
855 sprintf (hex_buff, "%05X", (int) (from - view->first));
856 widget_move (view, row, frame_shift);
857 view_add_string (view, hex_buff);
858
859 /* Hex dump starts from column seven */
860 col = 7;
861
862 /* Each hex number is two digits */
863 hex_buff[2] = 0;
864 for (bytes = 0; bytes < view->bytes_per_line
865 && from < view->last_byte; bytes++, from++){
866 /* Display and mark changed bytes */
867 if (curr && from == curr->offset) {
868 c = curr->value;
869 curr = curr->next;
870 boldflag = 3;
871 view_set_color (view, 7);
872 } else
873 c = (unsigned char) get_byte (view, from);
874
875 if (view->found_len && from >= view->search_start
876 && from < view->search_start + view->found_len){
877 boldflag = 1;
878 view_set_color (view, BOLD_COLOR);
879 }
880 /* Display the navigation cursor */
881 if (from == view->edit_cursor) {
882 if (view->view_side == view_side_left){
883 view->cursor_row = row;
884 view->cursor_col = col;
885 }
886 boldflag = 2;
887 view_set_color (view, view->view_side == view_side_left ? PICK_COLOR (15, 31));
888 }
889
890 /* Print a hex number (sprintf is too slow) */
891 hex_buff [0] = hex_char [(c >> 4)];
892 hex_buff [1] = hex_char [c & 15];
893 view_gotoyx (view, row, col);
894 view_add_string (view, hex_buff);
895 col += 3;
896 /* Turn off the cursor or changed byte highlighting here */
897 if (boldflag > 1)
898 view_set_color (view, DEF_COLOR);
899 if ((bytes & 3) == 3 && bytes + 1 < view->bytes_per_line){
900 /* Turn off the search highlighting */
901 if (boldflag == 1 &&
902 from == view->search_start + view->found_len - 1)
903 view_set_color (view, DEF_COLOR);
904
905 /* Hex numbers are printed in the groups of four */
906 /* Groups are separated by a vline */
907
908 view_add_character (view, ' ');
909 one_vline ();
910 view_gotoyx (view, row, col + 1);
911 col += 2;
912
913 if (boldflag && from==view->search_start+view->found_len-1)
914 view_set_color (view, BOLD_COLOR);
915
916 }
917 if (boldflag && from < view->search_start + view->found_len - 1
918 && bytes != view->bytes_per_line - 1)
919 view_add_character (view, ' ');
920
921 /* Print the corresponding ascii character */
922 view_gotoyx (view, row, text_start + bytes);
923
924 if (!is_printable (c))
925 c = '.';
926 switch (boldflag) {
927 default:
928 break;
929 case 1:
930 view_set_color (view, BOLD_COLOR);
931 goto setcursor;
932 case 2:
933 view_set_color (view, view->view_side == view_side_left ? PICK_COLOR (31, 15));
934 goto setcursor;
935 case 3:
936 view_set_color (view, 7);
937
938 setcursor:
939 if (view->view_side == view_side_right){
940 view->cursor_col = text_start + bytes;
941 view->cursor_row = row;
942 }
943 }
944 view_add_character (view, c);
945
946 if (boldflag){
947 boldflag = 0;
948 view_set_color (view, DEF_COLOR);
949 }
950 }
951 }
952 } else {
953 if (view->growing_buffer && from == view->last_byte)
954 get_byte (view, from);
955 for (; row < height && from < view->last_byte; from++){
956 c = get_byte (view, from);
957 if ((c == '\n') || (col == width && view->wrap_mode)){
958 col = frame_shift;
959 row++;
960 if (c == '\n' || row >= height)
961 continue;
962 }
963 if (c == '\r')
964 continue;
965 if (c == '\t'){
966 col = ((col - frame_shift)/8)*8 + 8 + frame_shift;
967 continue;
968 }
969 if (view->viewer_nroff_flag && c == '\b'){
970 if (from + 1 < view->last_byte
971 && is_printable (get_byte (view, from + 1)) &&
972 from > view->first
973 && is_printable (get_byte (view, from - 1)))
974 {
975 if (col <= frame_shift){
976 /* So it has to be wrap_mode - do not need to check for it */
977 if (row == 1 + frame_shift){
978 from++;
979 continue; /* There had to be a bold character on the rightmost position
980 of the previous undisplayed line */
981 }
982 row--;
983 col = width;
984 }
985 col--;
986 boldflag = 1;
987 if (get_byte (view, from - 1) == '_' && get_byte (view, from + 1) != '_')
988 view_set_color (view, UNDERLINE_COLOR);
989 else
990 view_set_color (view, BOLD_COLOR);
991 continue;
992 }
993 }
994 if (view->found_len && from >= view->search_start
995 && from < view->search_start + view->found_len){
996 boldflag = 1;
997 view_set_color (view, MARK_COLOR);
998 }
999 if (col >= frame_shift-view->start_col
1000 && col < width-view->start_col)
1001 {
1002 view_gotoyx (view, row, col+view->start_col);
1003 if (!is_printable (c))
1004 c = '.';
1005
1006 view_add_character (view, c);
1007 }
1008 col++;
1009 if (boldflag){
1010 boldflag = 0;
1011 view_set_color (view, DEF_COLOR);
1012 }
1013
1014 /* Very last thing */
1015 if (view->growing_buffer && from+1 == view->last_byte)
1016 get_byte (view, from+1);
1017 }
1018 #ifdef HAVE_TK
1019 view_gotoyx (view, view->current_line+1, 0);
1020 #endif
1021 }
1022 view->last = from;
1023 view_thaw (view);
1024 return from;
1025 }
1026
1027 void
1028 view_place_cursor (WView *view)
1029 {
1030 int shift;
1031
1032 if (view->view_side == view_side_left)
1033 shift = view->nib_shift;
1034 else
1035 shift = 0;
1036
1037 widget_move (&view->widget, view->cursor_row, view->cursor_col + shift);
1038 }
1039
1040 void
1041 view_update (WView *view)
1042 {
1043 static int dirt_limit = 1;
1044
1045 if (view->dirty > dirt_limit){
1046 /* Too many updates skipped -> force a update */
1047 display (view);
1048 view_status (view);
1049 view->dirty = 0;
1050 /* Raise the update skipping limit */
1051 dirt_limit++;
1052 if (dirt_limit > max_dirt_limit)
1053 dirt_limit = max_dirt_limit;
1054 }
1055 if (view->dirty){
1056 if (is_idle ()){
1057 /* We have time to update the screen properly */
1058 display (view);
1059 view_status (view);
1060 view->dirty = 0;
1061 if (dirt_limit > 1)
1062 dirt_limit--;
1063 } else {
1064 /* We are busy -> skipping full update,
1065 only the status line is updated */
1066 view_status (view);
1067 }
1068 /* Here we had a refresh, if fast scrolling does not work
1069 restore the refresh, although this should not happen */
1070 }
1071 }
1072
1073 static inline void
1074 my_define (Dlg_head *h, int idx, char *text,
1075 void (*fn)(WView *), WView *view)
1076 {
1077 define_label_data (h, (Widget *) view, idx, text, (buttonbarfn) fn, view);
1078 }
1079
1080 /* }}} */
1081 /* {{{ Movement functions */
1082 /* If the last parameter is nonzero, it means we want get the count of lines
1083 from current up to the the upto position inclusive */
1084 static long
1085 move_forward2 (WView *view, long current, int lines, long upto)
1086 {
1087 long p, q;
1088 int line;
1089 int col = 0;
1090
1091 if (view->hex_mode){
1092 p = current + lines * view->bytes_per_line;
1093 p = (p >= view->last_byte) ? current : p;
1094 if (lines == 1) {
1095 q = view->edit_cursor + view->bytes_per_line;
1096 line = q / view->bytes_per_line;
1097 col = (view->last_byte-1) / view->bytes_per_line;
1098 view->edit_cursor = (line > col) ? view->edit_cursor : q;
1099 view->edit_cursor = (view->edit_cursor < view->last_byte) ?
1100 view->edit_cursor : view->last_byte-1;
1101 q = current + ((LINES-2) * view->bytes_per_line);
1102 p = (view->edit_cursor < q) ? current : p;
1103 } else {
1104 view->edit_cursor = (view->edit_cursor < p) ?
1105 p : view->edit_cursor;
1106 }
1107 return p;
1108 } else {
1109 if (upto){
1110 lines = -1;
1111 q = upto;
1112 } else
1113 q = view->last_byte;
1114 if (get_byte (view, q) != '\n')
1115 q++;
1116 for (line = col = 0, p = current; p < q; p++){
1117 int c;
1118
1119 if (lines != -1 && line >= lines)
1120 return p;
1121
1122 c = get_byte (view, p);
1123
1124 if (view->wrap_mode){
1125 if (c == '\r')
1126 continue; /* This characters is never displayed */
1127 else if (c == '\t')
1128 col = ((col - view->have_frame)/8)*8 +8+ view->have_frame;
1129 else
1130 col++;
1131 if (view->viewer_nroff_flag && c == '\b'){
1132 if (p + 1 < view->last_byte
1133 && is_printable (get_byte (view, p + 1))
1134 && p > view->first
1135 && is_printable (get_byte (view, p - 1)))
1136 col -= 2;
1137 } else if (col == vwidth){
1138 /* FIXME: the c in is_printable was a p, that is a bug,
1139 I suspect I got that fix from Jakub, same applies
1140 for d. */
1141 int d = get_byte (view, p+2);
1142
1143 if (p + 2 >= view->last_byte || !is_printable (c) ||
1144 !view->viewer_nroff_flag || get_byte (view, p + 1) != '\b' ||
1145 !is_printable (d)){
1146 col = 0;
1147
1148 if (c == '\n' || get_byte (view, p+1) != '\n')
1149 line++;
1150 }
1151 } else if (c == '\n'){
1152 line++;
1153 col = 0;
1154 }
1155 } else if (c == '\n')
1156 line++;
1157 }
1158 if (upto)
1159 return line;
1160 }
1161 return current;
1162 }
1163
1164 /* returns the new current pointer */
1165 /* Cause even the forward routine became very complex, we in the wrap_mode
1166 just find the nearest '\n', use move_forward2(p, 0, q) to get the count
1167 of lines up to there and then use move_forward2(p, something, 0), which we
1168 return */
1169 static long
1170 move_backward2 (WView *view, long current, int lines)
1171 {
1172 long p, q, pm;
1173 int line;
1174
1175 if (!view->hex_mode && current == view->first)
1176 return current;
1177
1178 if (view->hex_mode){
1179 p = current - lines * view->bytes_per_line;
1180 p = (p < view->first) ? view->first : p;
1181 if (lines == 1) {
1182 q = view->edit_cursor - view->bytes_per_line;
1183 view->edit_cursor = (q < view->first) ? view->edit_cursor : q;
1184 p = (view->edit_cursor >= current) ? current : p;
1185 } else {
1186 q = p + ((LINES-2) * view->bytes_per_line);
1187 view->edit_cursor = (view->edit_cursor >= q) ?
1188 p : view->edit_cursor;
1189 }
1190 return p;
1191 } else {
1192 if (current == view->last_byte
1193 && get_byte (view, current - 1) != '\n')
1194 /* There is one virtual '\n' at the end,
1195 so that the last line is shown */
1196 line = 1;
1197 else
1198 line = 0;
1199 for (q = p = current - 1; p >= view->first; p--)
1200 if (get_byte (view, p) == '\n' || p == view->first) {
1201 pm = p > view->first ? p + 1 : view->first;
1202 if (!view->wrap_mode){
1203 if (line == lines)
1204 return pm;
1205 line++;
1206 } else {
1207 line += move_forward2 (view, pm, 0, q);
1208 if (line >= lines){
1209 if (line == lines)
1210 return pm;
1211 else
1212 return move_forward2 (view, pm, line - lines, 0);
1213 }
1214 q = p + 1;
1215 }
1216 }
1217 }
1218 return p > view->first ? p : view->first;
1219 }
1220
1221 void
1222 view_move_backward (WView *view, int i)
1223 {
1224 view->search_start = view->start_display =
1225 move_backward2 (view, view->start_display, i);
1226 view->found_len = 0;
1227 view->last = view->first + ((LINES-2) * view->bytes_per_line);
1228 view->dirty++;
1229 }
1230
1231 static long
1232 get_bottom_first (WView *view, int do_not_cache, int really)
1233 {
1234 int bottom_first;
1235
1236 if (!have_fast_cpu && !really)
1237 return INT_MAX;
1238
1239 if (!do_not_cache && view->bottom_first != -1)
1240 return view->bottom_first;
1241
1242 /* Force loading */
1243 if (view->growing_buffer){
1244 int old_last_byte;
1245
1246 old_last_byte = -1;
1247 while (old_last_byte != view->last_byte){
1248 old_last_byte = view->last_byte;
1249 get_byte (view, view->last_byte+VIEW_PAGE_SIZE);
1250 }
1251 }
1252
1253 bottom_first = move_backward2 (view, view->last_byte, vheight - 1);
1254
1255 if (view->hex_mode)
1256 bottom_first = (bottom_first + view->bytes_per_line - 1)
1257 / view->bytes_per_line * view->bytes_per_line;
1258 view->bottom_first = bottom_first;
1259
1260 return view->bottom_first;
1261 }
1262
1263 void
1264 view_move_forward (WView *view, int i)
1265 {
1266 view->start_display = move_forward2 (view, view->start_display, i, 0);
1267 if (!view->reading_pipe && view->start_display > get_bottom_first (view, 0, 0))
1268 view->start_display = view->bottom_first;
1269 view->search_start = view->start_display;
1270 view->found_len = 0;
1271 view->last = view->first + ((LINES-2) * view->bytes_per_line);
1272 view->dirty++;
1273 }
1274
1275
1276 static void
1277 move_to_top (WView *view)
1278 {
1279 view->search_start = view->start_display = view->first;
1280 view->found_len = 0;
1281 view->last = view->first + ((LINES-2) * view->bytes_per_line);
1282 view->nib_shift = 0;
1283 view->edit_cursor = view->start_display;
1284 view->dirty++;
1285 }
1286
1287 static void
1288 move_to_bottom (WView *view)
1289 {
1290 view->search_start = view->start_display = get_bottom_first (view, 0, 1);
1291 view->found_len = 0;
1292 view->last = view->first + ((LINES-2) * view->bytes_per_line);
1293 view->edit_cursor = (view->edit_cursor < view->start_display) ?
1294 view->start_display : view->edit_cursor;
1295 view->dirty++;
1296 }
1297
1298 /* Scroll left/right the view panel functions */
1299 static void
1300 move_right (WView *view)
1301 {
1302 if (view->wrap_mode && !view->hex_mode)
1303 return;
1304 if (view->hex_mode) {
1305 view->last = view->first + ((LINES-2) * view->bytes_per_line);
1306
1307 if (view->hex_mode && view->view_side == view_side_left) {
1308 view->nib_shift = 1 - view->nib_shift;
1309 if (view->nib_shift == 1)
1310 return;
1311 }
1312 view->edit_cursor = (++view->edit_cursor < view->last_byte) ?
1313 view->edit_cursor : view->last_byte - 1;
1314 if (view->edit_cursor >= view->last) {
1315 view->edit_cursor -= view->bytes_per_line;
1316 view_move_forward(view, 1);
1317 }
1318 } else
1319 if (--view->start_col > 0)
1320 view->start_col = 0;
1321 view->dirty++;
1322 }
1323
1324 static void
1325 move_left (WView *view)
1326 {
1327 if (view->wrap_mode && !view->hex_mode)
1328 return;
1329 if (view->hex_mode) {
1330 if (view->hex_mode && view->view_side == view_side_left) {
1331 view->nib_shift = 1 - view->nib_shift;
1332 if (view->nib_shift == 0)
1333 return;
1334 }
1335 view->edit_cursor = (--view->edit_cursor < view->first) ?
1336 view->first : view->edit_cursor;
1337 if (view->edit_cursor < view->start_display) {
1338 view->edit_cursor += view->bytes_per_line;
1339 view_move_backward(view, 1);
1340 }
1341 } else
1342 if (++view->start_col > 0)
1343 view->start_col = 0;
1344 view->dirty++;
1345 }
1346
1347 /* }}} */
1348 /* {{{ Search routines */
1349
1350 /* Case insensitive search of text in data */
1351 static int
1352 icase_search_p (WView *view, char *text, char *data, int nothing)
1353 {
1354 int p = 0, lng;
1355 char *q;
1356
1357 p = (q = _icase_search (text, data, &lng)) != 0;
1358 if (p) {
1359 view->found_len = lng;
1360 view->search_start = q - data - view->found_len;
1361 }
1362 return p;
1363 }
1364
1365 static char *
1366 grow_string_buffer (char *text, int *size)
1367 {
1368 char *new;
1369 int old_size = *size;
1370
1371 /* The grow steps */
1372 *size += 160;
1373 new = xmalloc (*size, "grow_string_buffer");
1374 if (text){
1375 strncpy (new, text, old_size);
1376 free (text);
1377 } else {
1378 *new = 0;
1379 }
1380 return new;
1381 }
1382
1383 static char *
1384 get_line_at (WView *view, long *p)
1385 {
1386 char *buffer = 0;
1387 int buffer_size, usable_size;
1388 int ch;
1389 int direction;
1390 long pos = *p;
1391 long i;
1392
1393 direction = view->direction;
1394 buffer_size = usable_size = 0;
1395
1396 i = ch = 0;
1397 for (;pos >= 0 && (ch = get_byte (view, pos))!= -1; pos += direction, i++){
1398
1399 /* skip over all the possible zeros in the file */
1400 if (ch == 0 && i == 0){
1401 while (pos >= 0 && ((ch = get_byte (view, pos)) != -1) && ch == 0)
1402 pos+= direction;
1403 if (ch == -1)
1404 break;
1405 }
1406 if (i == usable_size){
1407 buffer = grow_string_buffer (buffer, &buffer_size);
1408 usable_size = buffer_size - 2;
1409 buffer [0] = ' '; /* This makes possible strcpy of buffer */
1410 }
1411 buffer [i+1] = ch;
1412 if (ch == '\n' || !ch || ch == -1){
1413 pos += direction; i++;
1414 break;
1415 }
1416 }
1417 if (buffer){
1418 i--;
1419 buffer [0] = ' ';
1420 buffer [i+1] = 0;
1421
1422 /* If we are searching backwards, reverse the string */
1423 if (view->direction < 0)
1424 reverse_string (buffer);
1425 }
1426
1427 *p = pos;
1428 return buffer;
1429 }
1430
1431 /** Search status optmizations **/
1432
1433 /* The number of bytes between percent increments */
1434 int update_steps;
1435
1436 /* Last point where we updated the status */
1437 long update_activate;
1438
1439 static void
1440 search_update_steps (WView *view)
1441 {
1442 if (view->s.st_size)
1443 update_steps = 40000;
1444 else
1445 update_steps = view->last_byte / 100;
1446
1447 /* Do not update the percent display but every 20 ks */
1448 if (update_steps < 20000)
1449 update_steps = 20000;
1450 }
1451
1452 static void
1453 search (WView *view, char *text, int (*search)(WView *, char *, char *, int))
1454 {
1455 int w = view->widget.cols - (view->have_frame * 2);
1456 char *s = NULL; /* The line we read from the view buffer */
1457 long p, beginning;
1458 int ch;
1459 int isatbeg; /* Nonzero means we start search at beginning of some line */
1460 int found_len, search_start;
1461 Dlg_head *d = 0;
1462 int search_status;
1463
1464 /* Used to keep track of where the line starts, when looking forward */
1465 /* is the index before transfering the line; the reverse case uses */
1466 /* the position returned after the line has been read */
1467 long forward_line_start;
1468 long reverse_line_start;
1469 long t;
1470 /* Clear interrupt status */
1471 got_interrupt ();
1472
1473 if (verbose){
1474 d = message (D_INSERT, _(" Search "), _("Searching %s"), text);
1475 mc_refresh ();
1476 }
1477 ch = 0;
1478 if (view->direction == 1){
1479 p = view->found_len ? view->search_start + 1 : view->search_start;
1480 } else {
1481 p = (view->found_len ? view->search_start : view->last) - 1;
1482 }
1483 beginning = p;
1484
1485 isatbeg = view->found_len == 0;
1486 found_len = view->found_len;
1487 search_start = view->search_start;
1488
1489 /* Compute the percent steps */
1490 search_update_steps (view);
1491 update_activate = 0;
1492
1493 for (; ; isatbeg = 1, free (s)){
1494 #ifdef PORT_HAS_FLUSH_EVENTS
1495 static int count;
1496
1497 if ((count++ % 32) == 0)
1498 x_flush_events ();
1499 if (!d->running)
1500 break;
1501 #endif
1502 if (p >= update_activate){
1503 update_activate += update_steps;
1504 if (verbose){
1505 view_percent (view, p, w);
1506 mc_refresh ();
1507 }
1508 if (got_interrupt ())
1509 break;
1510 }
1511 forward_line_start = p;
1512 disable_interrupt_key ();
1513 s = get_line_at (view, &p);
1514 reverse_line_start = p;
1515 enable_interrupt_key ();
1516 if (!s)
1517 break;
1518
1519 search_status = (*search) (view, text, s + 1, match_normal);
1520 if (search_status < 0)
1521 break;
1522
1523 if (search_status == 0)
1524 continue;
1525
1526 /* We found the string */
1527
1528 if (!isatbeg && !view->search_start){
1529
1530 /* We do not want to match a
1531 * ^ regexp when not at the real
1532 * beginning of some line
1533 */
1534 view->found_len = found_len;
1535 view->search_start = search_start;
1536 if ((*search) (view, text, s, match_normal) <= 0)
1537 continue;
1538 (*search) (view, text, s + 1, match_normal);
1539 }
1540 /* Record the position used to continue the search */
1541 if (view->direction == 1)
1542 t = forward_line_start;
1543 else
1544 t = reverse_line_start ? reverse_line_start + 3 : 0;
1545 view->search_start += t;
1546
1547 if (t != beginning){
1548 if (t > get_bottom_first (view, 0, 0))
1549 view->start_display = view->bottom_first;
1550 else
1551 view->start_display = t;
1552 }
1553
1554 free (s);
1555 break;
1556 }
1557 disable_interrupt_key ();
1558 if (verbose){
1559 dlg_run_done (d);
1560 destroy_dlg (d);
1561 }
1562
1563 if (!s){
1564 message (0, _(" Search "), _(" Search string not found "));
1565 view->found_len = 0;
1566 }
1567 }
1568
1569 /* Search buffer (it's size is len) in the complete buffer */
1570 /* returns the position where the block was found or -1 if not found */
1571 static long
1572 block_search (WView *view, char *buffer, int len)
1573 {
1574 int w = view->widget.cols - (view->have_frame * 2);
1575 char *d = buffer, b;
1576 long e;
1577
1578 /* clear interrupt status */
1579 got_interrupt ();
1580 enable_interrupt_key ();
1581 e = view->found_len ? view->search_start + 1 : view->search_start;
1582
1583 search_update_steps (view);
1584 update_activate = 0;
1585
1586 for (; e < view->last_byte; e++){
1587 if (e >= update_activate){
1588 update_activate += update_steps;
1589 if (verbose){
1590 view_percent (view, e, w);
1591 mc_refresh ();
1592 }
1593 if (got_interrupt ())
1594 break;
1595 }
1596 b = get_byte (view, e);
1597
1598 if (*d == b){
1599 d++;
1600 } else {
1601 e -= d - buffer;
1602 d = buffer;
1603 }
1604 if (d - buffer == len){
1605 disable_interrupt_key ();
1606 return e - len;
1607 }
1608 }
1609 disable_interrupt_key ();
1610 return -1;
1611 }
1612
1613 /* States of our funny recognizer */
1614 enum {
1615 normal,
1616 inside_quotes,
1617 zero,
1618 hex1,
1619 hex2,
1620 oct1
1621 };
1622
1623 /* This routine doesn't report all the user mistakes, it just ignores them */
1624 static void
1625 hex_search (WView *view, char *text)
1626 {
1627 char buffer [120]; /* Where we hold the information */
1628 int i, block_len;
1629 int v = 0;
1630 long pos; /* Where did we found the string */
1631 char *p; /* Temporary */
1632 int state = normal; /* Initial state of the micro-scanner */
1633
1634 /* First convert the string to a stream of bytes */
1635 for (i = block_len = 0; text [i] && block_len < sizeof (buffer); i++){
1636 switch (state){
1637 case inside_quotes:
1638 if (text [i] == '"')
1639 state = normal;
1640 else
1641 buffer [block_len++] = text [i];
1642 break;
1643
1644 case normal:
1645 if (text [i] == '"'){
1646 state = inside_quotes;
1647 break;
1648 }
1649 if (text [i] == '0'){
1650 state = zero;
1651 break;
1652 }
1653 if (text [i] == 'x'){
1654 state = hex1;
1655 break;
1656 }
1657 break;
1658
1659 case zero:
1660 if (text [i] == 'x')
1661 state = hex1;
1662 break;
1663
1664 case hex1:
1665 v = 0;
1666 text [i] = toupper (text [i]);
1667 if ((p = strchr (hex_char, text [i])) != 0){
1668 v = (p - hex_char) << 4;
1669 state = hex2;
1670 }
1671 break;
1672
1673 case hex2:
1674 text [i] = toupper (text [i]);
1675 if ((p = strchr (hex_char, text [i])) != 0){
1676 v |= (p - hex_char);
1677 state = normal;
1678 }
1679 buffer [block_len++] = v;
1680 break;
1681 }
1682 }
1683 /* Then start the search */
1684 pos = block_search (view, buffer, block_len);
1685 if (pos == -1){
1686 message (0, _(" Search "), _(" Search string not found "));
1687 view->found_len = 0;
1688 return;
1689 }
1690
1691 view->search_start = pos + 1;
1692 view->found_len = block_len;
1693 /* Set the edit cursor to the search position, left nibble */
1694 view->edit_cursor = view->search_start;
1695 view->nib_shift = 0;
1696
1697 /* Adjust the file offset */
1698 view->start_display = (pos & (~(view->bytes_per_line-1)));
1699 if (view->start_display > get_bottom_first (view, 0, 0))
1700 view->start_display = view->bottom_first;
1701 }
1702
1703 static int regexp_view_search (WView *view, char *pattern, char *string, int match_type)
1704 {
1705 static regex_t r;
1706 static char *old_pattern = NULL;
1707 static int old_type;
1708 regmatch_t pmatch[1];
1709 int i, flags = REG_ICASE;
1710
1711 if (!old_pattern || strcmp (old_pattern, pattern) || old_type != match_type){
1712 if (old_pattern){
1713 regfree (&r);
1714 free (old_pattern);
1715 old_pattern = 0;
1716 }
1717 for (i = 0; pattern[i] != 0; i++){
1718 if (isupper ((unsigned char) pattern[i])){
1719 flags = 0;
1720 break;
1721 }
1722 }
1723 flags |= REG_EXTENDED;
1724 if (regcomp (&r, pattern, flags)){
1725 message (1, MSG_ERROR, _(" Invalid regular expression "));
1726 return -1;
1727 }
1728 old_pattern = strdup (pattern);
1729 old_type = match_type;
1730 }
1731 if (regexec (&r, string, 1, pmatch, 0) != 0)
1732 return 0;
1733 view->found_len = pmatch[0].rm_eo - pmatch[0].rm_so;
1734 view->search_start = pmatch[0].rm_so;
1735 return 1;
1736 }
1737
1738 static void do_regexp_search (void *xview, char *regexp)
1739 {
1740 WView *view = (WView *) xview;
1741
1742 view->search_exp = regexp;
1743 search (view, regexp, regexp_view_search);
1744 /* Had a refresh here */
1745 view->dirty++;
1746 view_update (view);
1747 }
1748
1749 static void do_normal_search (void *xview, char *text)
1750 {
1751 WView *view = (WView *) xview;
1752
1753 view->search_exp = text;
1754 if (view->hex_mode)
1755 hex_search (view, text);
1756 else
1757 search (view, text, icase_search_p);
1758 /* Had a refresh here */
1759 view->dirty++;
1760 view_update (view);
1761 }
1762
1763 /* }}} */
1764 /* {{{ Mouse and keyboard handling */
1765
1766 /* Real view only */
1767 static void help_cmd (void)
1768 {
1769 char *hlpfile = concat_dir_and_file (mc_home, "mc.hlp");
1770 interactive_display (hlpfile, "[Internal File Viewer]");
1771 free (hlpfile);
1772 /*
1773 view_refresh (0);
1774 */
1775 }
1776
1777 /* Both views */
1778 void toggle_wrap_mode (WView *view)
1779 {
1780 if (view->hex_mode) {
1781 if (view->growing_buffer != 0) {
1782 return;
1783 }
1784 get_bottom_first (view, 1, 1);
1785 if (view->hexedit_mode) {
1786 view->view_side = 1 - view->view_side;
1787 } else {
1788 view->hexedit_mode = 1 - view->hexedit_mode;
1789 }
1790 view_labels (view);
1791 view->dirty++;
1792 view_update (view);
1793 return;
1794 }
1795 view->wrap_mode = 1 - view->wrap_mode;
1796 get_bottom_first (view, 1, 1);
1797 if (view->wrap_mode)
1798 view->start_col = 0;
1799 else {
1800 if (have_fast_cpu){
1801 if (view->bottom_first < view->start_display)
1802 view->search_start = view->start_display = view->bottom_first;
1803 view->found_len = 0;
1804 }
1805 }
1806 view_labels (view);
1807 view->dirty++;
1808 view_update (view);
1809 }
1810
1811 /* Both views */
1812 void
1813 toggle_hex_mode (WView *view)
1814 {
1815 view->hex_mode = 1 - view->hex_mode;
1816
1817 if (view->hex_mode){
1818 /* Shift the line start to 0x____0 on entry, restore it for Ascii */
1819 view->start_save = view->start_display;
1820 view->start_display -= view->start_display % view->bytes_per_line;
1821 view->edit_cursor = view->start_display;
1822 view->widget.options |= W_WANT_CURSOR;
1823 view->widget.parent->raw = 1;
1824 } else {
1825 view->start_display = view->start_save;
1826 view->widget.parent->raw = 0;
1827 view->widget.options &= ~W_WANT_CURSOR;
1828 }
1829 altered_hex_mode = 1;
1830 get_bottom_first (view, 1, 1);
1831 view_labels (view);
1832 view->dirty++;
1833 view_update (view);
1834 }
1835
1836 /* Both views */
1837 void
1838 toggle_hexedit_mode(WView *view)
1839 {
1840 view->hexedit_mode = 1 - view->hexedit_mode;
1841 }
1842
1843 /* Both views */
1844 void
1845 goto_line (WView *view)
1846 {
1847 char *line, prompt [100];
1848 int i, oldline = 1;
1849 int saved_wrap_mode = view->wrap_mode;
1850
1851 view->wrap_mode = 0;
1852 for (i = view->first; i < view->start_display; i++)
1853 if (get_byte (view, i) == '\n')
1854 oldline ++;
1855 sprintf (prompt, _(" The current line number is %d.\n"
1856 " Enter the new line number:"), oldline);
1857 line = input_dialog (_(" Goto line "), prompt, "");
1858 if (line){
1859 if (*line){
1860 move_to_top (view);
1861 view_move_forward (view, atoi (line) - 1);
1862 }
1863 free (line);
1864 }
1865 view->dirty++;
1866 view->wrap_mode = saved_wrap_mode;
1867 view_update (view);
1868 }
1869
1870 /* Both views */
1871 void
1872 regexp_search (WView *view, int direction)
1873 {
1874 char *regexp = "";
1875 static char *old = 0;
1876
1877 /* This is really an F6 key handler */
1878 if (view->hex_mode){
1879 /* Save it without a confirmation prompt */
1880 save_edit_changes(view);
1881 return;
1882 }
1883
1884 regexp = old ? old : regexp;
1885 regexp = input_dialog (_(" Search "), _(" Enter regexp:"), regexp);
1886 if ((!regexp) || (!*regexp)){
1887 return;
1888 }
1889 if (old)
1890 free (old);
1891 old = regexp;
1892 #if 0
1893 /* Mhm, do we really need to load all the file in the core? */
1894 if (view->bytes_read < view->last_byte)
1895 get_byte (view, view->last_byte-1);/* Get the whole file in to memory */
1896 #endif
1897 view->direction = direction;
1898 do_regexp_search (view, regexp);
1899
1900 view->last_search = do_regexp_search;
1901 }
1902
1903 void
1904 regexp_search_cmd (WView *view)
1905 {
1906 regexp_search (view, 1);
1907 }
1908
1909 /* Both views */
1910 void
1911 normal_search (WView *view, int direction)
1912 {
1913 static char *old;
1914 char *exp = "";
1915
1916 exp = old ? old : exp;
1917 exp = input_dialog (_(" Search "), _(" Enter search string:"), exp);
1918 if ((!exp) || (!*exp)){
1919 return;
1920 }
1921 if (old)
1922 free (old);
1923 old = exp;
1924
1925 view->direction = direction;
1926 do_normal_search (view, exp);
1927 view->last_search = do_normal_search;
1928 }
1929
1930 void
1931 normal_search_cmd (WView *view)
1932 {
1933 normal_search (view, 1);
1934 }
1935
1936 void
1937 change_viewer (WView *view)
1938 {
1939 char *s;
1940 char *t;
1941
1942
1943 if (*view->filename) {
1944 altered_magic_flag = 1;
1945 view->viewer_magic_flag = !view->viewer_magic_flag;
1946 s = strdup (view->filename);
1947 if (view->command)
1948 t = strdup (view->command);
1949 else
1950 t = 0;
1951
1952 view_done (view);
1953 view_init (view, t, s, 0);
1954 free (s);
1955 if (t)
1956 free (t);
1957 view_labels (view);
1958 view->dirty++;
1959 view_update (view);
1960 }
1961 }
1962
1963 void
1964 change_nroff (WView *view)
1965 {
1966 view->viewer_nroff_flag = !view->viewer_nroff_flag;
1967 altered_nroff_flag = 1;
1968 view_labels (view);
1969 view->dirty++;
1970 view_update (view);
1971 }
1972
1973 /* Real view only */
1974 static void
1975 view_quit_cmd (WView *view)
1976 {
1977 if (view_ok_to_quit (view))
1978 dlg_stop (view->widget.parent);
1979 }
1980
1981 /* Both views */
1982 void
1983 view_labels (WView *view)
1984 {
1985 Dlg_head *h = view->widget.parent;
1986
1987 define_label (h, (Widget *) view, 1, _("Help"), help_cmd);
1988
1989 my_define (h, 10, _("Quit"), view_quit_cmd, view);
1990 my_define (h, 4, view->hex_mode ? _("Ascii"): _("Hex"), toggle_hex_mode, view);
1991 my_define (h, 5, _("Line"), goto_line, view);
1992 my_define (h, 6, view->hex_mode ? _("Save") : _("RxSrch"), regexp_search_cmd, view);
1993
1994 my_define (h, 2, view->hex_mode ? view->hexedit_mode ?
1995 view->view_side == view_side_left ? _("EdText") : _("EdHex") :
1996 view->growing_buffer ? "" : _("Edit") :
1997 view->wrap_mode ? _("UnWrap") : _("Wrap"),
1998 toggle_wrap_mode, view);
1999
2000 my_define (h, 7, view->hex_mode ? _("HxSrch") : _("Search"),
2001 normal_search_cmd, view);
2002
2003 my_define (h, 8, view->viewer_magic_flag ? _("Raw") : _("Parse"),
2004 change_viewer, view);
2005
2006 if (!view->have_frame){
2007 my_define (h, 9, view->viewer_nroff_flag ? _("Unform") : _("Format"),
2008 change_nroff, view);
2009 my_define (h, 3, _("Quit"), view_quit_cmd, view);
2010 }
2011
2012 redraw_labels (h, (Widget *) view);
2013 }
2014
2015 /* Both views */
2016 static int
2017 check_left_right_keys (WView *view, int c)
2018 {
2019 if (c == KEY_LEFT)
2020 move_left (view);
2021 else if (c == KEY_RIGHT)
2022 move_right (view);
2023 else return 0;
2024
2025 return 1;
2026 }
2027
2028 void
2029 set_monitor (WView *view, int set_on)
2030 {
2031 int old = view->monitor;
2032
2033 view->monitor = set_on;
2034
2035 if (view->monitor){
2036 move_to_bottom (view);
2037 view->bottom_first = -1;
2038 set_idle_proc (view->widget.parent, 1);
2039 } else {
2040 if (old)
2041 set_idle_proc (view->widget.parent, 0);
2042 }
2043 }
2044
2045 void
2046 continue_search (WView *view)
2047 {
2048 if (view->last_search){
2049 (*view->last_search)(view, view->search_exp);
2050 } else {
2051 /* if not... then ask for an expression */
2052 normal_search (view, 1);
2053 }
2054 }
2055
2056 /* Both views */
2057 static int
2058 view_handle_key (WView *view, int c)
2059 {
2060 int prev_monitor = view->monitor;
2061
2062 set_monitor (view, off);
2063
2064 if (view->hex_mode) {
2065 switch (c) {
2066 case 0x09: /* Tab key */
2067 view->view_side = 1 - view->view_side;
2068 view->dirty++;
2069 return 1;
2070
2071 case XCTRL('a'): /* Beginning of line */
2072 view->edit_cursor -= view->edit_cursor % view->bytes_per_line;
2073 view->dirty++;
2074 return 1;
2075
2076 case XCTRL('b'): /* Character back */
2077 move_left(view);
2078 return 1;
2079
2080 case XCTRL('e'): /* End of line */
2081 view->edit_cursor -= view->edit_cursor % view->bytes_per_line;
2082 view->edit_cursor += view->bytes_per_line - 1;
2083 view->dirty++;
2084 return 1;
2085
2086 case XCTRL('f'): /* Character forward */
2087 move_right(view);
2088 return 1;
2089 }
2090
2091 /* Trap 0-9,A-F,a-f for left side data entry (hex editing) */
2092 if (view->view_side == view_side_left){
2093 if ((c >= '0' && c <= '9') ||
2094 (c >= 'A' && c <= 'F') ||
2095 (c >= 'a' && c <= 'f')){
2096
2097 put_editkey (view, c);
2098 return 1;
2099 }
2100 }
2101
2102 /* Trap all printable characters for right side data entry */
2103 /* Also enter the value of the Enter key */
2104 if (view->view_side == view_side_right){
2105 if (c < 256 && (is_printable (c) || (c == '\n'))){
2106 put_editkey(view, c);
2107 return 1;
2108 }
2109 }
2110 }
2111
2112 if (check_left_right_keys (view, c))
2113 return 1;
2114
2115 if (check_movement_keys (c, 1, vheight, view, (movefn) view_move_backward, (movefn) view_move_forward,
2116 (movefn) move_to_top, (movefn) move_to_bottom)){
2117 return 1;
2118 }
2119 switch (c){
2120
2121 case '?':
2122 regexp_search (view, -1);
2123 return 1;
2124
2125 case '/':
2126 regexp_search (view, 1);
2127 return 1;
2128
2129 /* Continue search */
2130 case XCTRL('s'):
2131 case 'n':
2132 case KEY_F(17):
2133 continue_search (view);
2134 return 1;
2135
2136 case XCTRL('r'):
2137 if (view->last_search){
2138 (*view->last_search)(view, view->search_exp);
2139 } else {
2140 normal_search (view, -1);
2141 }
2142 return 1;
2143
2144 /* toggle ruler */
2145 case ALT('r'):
2146 switch (ruler){
2147 case 0:
2148 ruler = 1; break;
2149 case 1:
2150 ruler = 2; break;
2151 default:
2152 ruler = 0; break;
2153 }
2154 view->dirty++;
2155 return 1;
2156
2157 case 'h':
2158 move_left (view);
2159 return 1;
2160
2161 case 'j':
2162 case '\n':
2163 case 'e':
2164 view_move_forward (view, 1);
2165 return 1;
2166
2167 case 'd':
2168 view_move_forward (view, vheight / 2);
2169 return 1;
2170
2171 case 'u':
2172 view_move_backward (view, vheight / 2);
2173 return 1;
2174
2175 case 'k':
2176 case 'y':
2177 view_move_backward (view, 1);
2178 return 1;
2179
2180 case 'l':
2181 move_right (view);
2182 return 1;
2183
2184 case ' ':
2185 case 'f':
2186 view_move_forward (view, vheight - 1);
2187 return 1;
2188
2189 case '!':
2190 exec_shell ();
2191 return 1;
2192
2193 case 'F':
2194 set_monitor (view, on);
2195 return 1;
2196
2197 case 'b':
2198 view_move_backward (view, vheight - 1);
2199 return 1;
2200
2201 case KEY_IC:
2202 view_move_backward (view, 2);
2203 return 1;
2204
2205 case KEY_DC:
2206 view_move_forward (view, 2);
2207 return 1;
2208
2209 case 'm':
2210 view->marks [view->marker] = view->start_display;
2211 return 1;
2212
2213 case 'r':
2214 view->start_display = view->marks [view->marker];
2215 view->dirty++;
2216 return 1;
2217
2218 /* Use to indicate parent that we want to see the next/previous file */
2219 /* Only works on full screen mode */
2220 case XCTRL('f'):
2221 case XCTRL('b'):
2222 if (!view->have_frame)
2223 view->move_dir = c == XCTRL('f') ? 1 : -1;
2224 /* fall */
2225
2226 case 'q':
2227 case XCTRL('g'):
2228 case ESC_CHAR:
2229 if (view_ok_to_quit (view))
2230 view->view_quit = 1;
2231 return 1;
2232
2233 }
2234 if (c >= '0' && c <= '9')
2235 view->marker = c - '0';
2236
2237 /* Restore the monitor status */
2238 set_monitor (view, prev_monitor);
2239
2240 /* Key not used */
2241 return 0;
2242 }
2243
2244 /* Both views */
2245 int
2246 view_event (WView *view, Gpm_Event *event, int *result)
2247 {
2248 *result = MOU_NORMAL;
2249 if (event->type & (GPM_DOWN|GPM_DRAG)){
2250 if (!view->wrap_mode){
2251 if (event->x < view->widget.cols / 4){
2252 move_left (view);
2253 *result = MOU_REPEAT;
2254 return 1;
2255 }
2256 if (event->x > 3 * vwidth / 4){
2257 move_right (view);
2258 *result = MOU_REPEAT;
2259 return 1;
2260 }
2261 }
2262 if (event->y < view->widget.lines / 3){
2263 if (mouse_move_pages_viewer)
2264 view_move_backward (view, view->widget.lines / 2 - 1);
2265 else
2266 view_move_backward (view, 1);
2267 *result = MOU_REPEAT;
2268 return 1;
2269 }
2270 else if (event->y > 2 * vheight /3){
2271 if (mouse_move_pages_viewer)
2272 view_move_forward (view, vheight / 2 - 1);
2273 else
2274 view_move_forward (view, 1);
2275 *result = MOU_REPEAT;
2276 return 1;
2277 }
2278 }
2279 return 0;
2280 }
2281
2282 /* Real view only */
2283 int
2284 real_view_event (Gpm_Event *event, void *x)
2285 {
2286 int result;
2287
2288 if (view_event ((WView *) x, event, &result))
2289 view_update ((WView *) x);
2290 return result;
2291 }
2292
2293 /* }}} */
2294 /* {{{ Window creation, destruction and a driver stub for real view */
2295
2296 static int
2297 view_mode_callback (struct Dlg_head *h, int id, int msg)
2298 {
2299 return default_dlg_callback (h, id, msg);
2300 }
2301
2302 #ifdef HAVE_XVIEW
2303 /* Real view only */
2304
2305 void
2306 view_adjust_size (Dlg_head *unused)
2307 {
2308 }
2309
2310 int
2311 view (char *_command, char *_file, int *move_dir_p, int start_line)
2312 {
2313 int midnight_colors [4];
2314 int error;
2315 WView *wview;
2316
2317 wview = view_new (0, 0, COLS, LINES - 1, 0);
2318
2319 error = view_init (wview, _command, _file, start_line);
2320 if (!error){
2321 x_view (wview);
2322 }
2323 *move_dir_p = 0;
2324 return !error;
2325 }
2326 #endif
2327
2328 #ifndef PORT_WANTS_VIEW
2329 void
2330 view_adjust_size (Dlg_head *h)
2331 {
2332 WView *view;
2333 WButtonBar *bar;
2334
2335 /* Look up the viewer and the buttonbar, we assume only two widgets here */
2336 view = (WView *) find_widget_type (h, (callback_fn) view_callback);
2337 bar = (WButtonBar *) view->widget.parent->current->next->widget;
2338 widget_set_size (&view->widget, 0, 0, LINES-1, COLS);
2339 widget_set_size (&bar->widget, LINES-1, 0, 1, COLS);
2340 }
2341
2342 /* Only the text mode edition uses this */
2343 Dlg_head *view_dlg;
2344
2345 /* Real view only */
2346 int
2347 view (char *_command, char *_file, int *move_dir_p, int start_line)
2348 {
2349 int midnight_colors [4];
2350 int error;
2351 WView *wview;
2352 WButtonBar *bar;
2353 Dlg_head *our_dlg;
2354
2355 /* Create dialog and widgets, put them on the dialog */
2356 our_dlg = create_dlg (0, 0, LINES, COLS, midnight_colors,
2357 view_mode_callback, "[Internal File Viewer]",
2358 "view",
2359 DLG_NONE);
2360
2361 #ifndef HAVE_X
2362 view_dlg = our_dlg;
2363 #endif
2364 wview = view_new (0, 0, COLS, LINES-1, 0);
2365
2366 bar = buttonbar_new (1);
2367
2368 add_widget (our_dlg, wview);
2369 add_widget (our_dlg, bar);
2370
2371 error = view_init (wview, _command, _file, start_line);
2372 if (move_dir_p)
2373 *move_dir_p = 0;
2374
2375 /* Please note that if you add another widget,
2376 * you have to modify view_adjust_size to
2377 * be aware of it
2378 */
2379 if (!error){
2380 run_dlg (our_dlg);
2381 if (move_dir_p)
2382 *move_dir_p = wview->move_dir;
2383 }
2384 destroy_dlg (our_dlg);
2385
2386 return !error;
2387 }
2388 #endif
2389
2390 static void
2391 view_hook (void *v)
2392 {
2393 WView *view = (WView *) v;
2394 WPanel *panel;
2395 struct stat s;
2396
2397 /* If the user is busy typing, wait until he finishes to update the
2398 screen */
2399 if (!is_idle ()){
2400 if (!hook_present (idle_hook, view_hook))
2401 add_hook (&idle_hook, view_hook, v);
2402 return;
2403 }
2404
2405 delete_hook (&idle_hook, view_hook);
2406
2407 if (get_current_type () == view_listing)
2408 panel = cpanel;
2409 else if (get_other_type () == view_listing)
2410 panel = other_panel;
2411 else
2412 return;
2413
2414 if (S_ISLNK (panel->dir.list [panel->selected].buf.st_mode)){
2415 if (mc_stat (panel->dir.list [panel->selected].fname, &s) != 0)
2416 return;
2417 if (!S_ISREG (s.st_mode))
2418 return;
2419 } else {
2420 if (!S_ISREG (panel->dir.list [panel->selected].buf.st_mode))
2421 return;
2422 }
2423
2424 view_init (view, 0, panel->dir.list [panel->selected].fname, 0);
2425 display (view);
2426 view_status (view);
2427 }
2428
2429 static int
2430 view_callback (Dlg_head *h, WView *v, int msg, int par)
2431 {
2432 WView *view = (WView *) v;
2433 int i;
2434
2435 switch (msg){
2436 case WIDGET_INIT:
2437 x_create_viewer (view);
2438 if (view->have_frame)
2439 add_hook (&select_file_hook, view_hook, view);
2440 else
2441 view_labels (view);
2442 break;
2443
2444 case WIDGET_DRAW:
2445 display (view);
2446 view_status (view);
2447 break;
2448
2449 case WIDGET_CURSOR:
2450 if (view->hex_mode)
2451 view_place_cursor (view);
2452 break;
2453
2454 case WIDGET_KEY:
2455 i = view_handle_key ((WView *)view, par);
2456 if (view->view_quit)
2457 dlg_stop (h);
2458 else {
2459 view_update (view);
2460 }
2461 return i;
2462
2463 case WIDGET_IDLE:
2464 /* This event is generated when the user is using the 'F' flag */
2465 view->bottom_first = -1;
2466 move_to_bottom (view);
2467 display (view);
2468 view_status (view);
2469 sleep (1);
2470 return 1;
2471
2472 case WIDGET_FOCUS:
2473 x_focus_view (view);
2474 view_labels (view);
2475 return 1;
2476
2477 }
2478 return default_proc (h, msg, par);
2479 }
2480
2481 WView *
2482 view_new (int y, int x, int cols, int lines, int is_panel)
2483 {
2484 WView *view = xmalloc (sizeof (WView), "view_new");
2485
2486 init_widget (&view->widget, y, x, lines, cols,
2487 (callback_fn) view_callback,
2488 (destroy_fn) view_destroy,
2489 (mouse_h) real_view_event, NULL);
2490
2491 view->filename = 0;
2492 view->view_active = 0;
2493 view->bottom_first = 0;
2494 view->start_col = 0;
2495 view->dirty = 0;
2496 view->hex_mode = default_hex_mode;
2497 view->hexedit_mode = default_hexedit_mode;
2498 view->viewer_magic_flag = default_magic_flag;
2499 view->viewer_nroff_flag = default_nroff_flag;
2500 view->view_quit = 0;
2501 view->move_dir = 0;
2502 view->have_frame = is_panel;
2503 view->last_byte = -1;
2504 view->monitor = 0;
2505 view->wrap_mode = global_wrap_mode;
2506
2507 x_init_view (view);
2508
2509 widget_want_cursor (view->widget, 0);
2510
2511 return view;
2512 }
2513
2514 /* }}} */
2515 /* {{{ Emacs local variables */
2516 /*
2517 Cause emacs to enter folding mode for this file:
2518 Local variables:
2519 end:
2520 */
2521 /* }}} */