2007-08-14 Michael Snyder <msnyder@access-company.com>
[external/binutils.git] / gdb / tui / tui-regs.c
1 /* TUI display registers in window.
2
3    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2007
4    Free Software Foundation, Inc.
5
6    Contributed by Hewlett-Packard Company.
7
8    This file is part of GDB.
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin Street, Fifth Floor,
23    Boston, MA 02110-1301, USA.  */
24
25 #include "defs.h"
26 #include "tui/tui.h"
27 #include "tui/tui-data.h"
28 #include "symtab.h"
29 #include "gdbtypes.h"
30 #include "gdbcmd.h"
31 #include "frame.h"
32 #include "regcache.h"
33 #include "inferior.h"
34 #include "target.h"
35 #include "gdb_string.h"
36 #include "tui/tui-layout.h"
37 #include "tui/tui-win.h"
38 #include "tui/tui-windata.h"
39 #include "tui/tui-wingeneral.h"
40 #include "tui/tui-file.h"
41 #include "reggroups.h"
42
43 #include "gdb_curses.h"
44
45
46 /*****************************************
47 ** STATIC LOCAL FUNCTIONS FORWARD DECLS    **
48 ******************************************/
49 static void
50 tui_display_register (struct tui_data_element *data,
51                       struct tui_gen_win_info *win_info);
52
53 static enum tui_status
54 tui_show_register_group (struct gdbarch *gdbarch, 
55                          struct reggroup *group,
56                          struct frame_info *frame, 
57                          int refresh_values_only);
58
59 static enum tui_status
60 tui_get_register (struct gdbarch *gdbarch, 
61                   struct frame_info *frame,
62                   struct tui_data_element *data, 
63                   int regnum, int *changedp);
64 static void tui_register_format (struct gdbarch *, 
65                                  struct frame_info *, 
66                                  struct tui_data_element*, 
67                                  int);
68 static void tui_scroll_regs_forward_command (char *, int);
69 static void tui_scroll_regs_backward_command (char *, int);
70
71
72
73 /*****************************************
74 ** PUBLIC FUNCTIONS                     **
75 ******************************************/
76
77 /* Answer the number of the last line in the regs display.  If there
78    are no registers (-1) is returned.  */
79 int
80 tui_last_regs_line_no (void)
81 {
82   int num_lines = (-1);
83
84   if (TUI_DATA_WIN->detail.data_display_info.regs_content_count > 0)
85     {
86       num_lines = (TUI_DATA_WIN->detail.data_display_info.regs_content_count /
87                   TUI_DATA_WIN->detail.data_display_info.regs_column_count);
88       if (TUI_DATA_WIN->detail.data_display_info.regs_content_count %
89           TUI_DATA_WIN->detail.data_display_info.regs_column_count)
90         num_lines++;
91     }
92   return num_lines;
93 }
94
95
96 /* Answer the line number that the register element at element_no is
97    on.  If element_no is greater than the number of register elements
98    there are, -1 is returned.  */
99 int
100 tui_line_from_reg_element_no (int element_no)
101 {
102   if (element_no < TUI_DATA_WIN->detail.data_display_info.regs_content_count)
103     {
104       int i, line = (-1);
105
106       i = 1;
107       while (line == (-1))
108         {
109           if (element_no <
110               (TUI_DATA_WIN->detail.data_display_info.regs_column_count * i))
111             line = i - 1;
112           else
113             i++;
114         }
115
116       return line;
117     }
118   else
119     return (-1);
120 }
121
122
123 /* Answer the index of the first element in line_no.  If line_no is
124    past the register area (-1) is returned.  */
125 int
126 tui_first_reg_element_no_inline (int line_no)
127 {
128   if ((line_no * TUI_DATA_WIN->detail.data_display_info.regs_column_count)
129       <= TUI_DATA_WIN->detail.data_display_info.regs_content_count)
130     return ((line_no + 1) *
131             TUI_DATA_WIN->detail.data_display_info.regs_column_count) -
132       TUI_DATA_WIN->detail.data_display_info.regs_column_count;
133   else
134     return (-1);
135 }
136
137
138 /* Answer the index of the last element in line_no.  If line_no is
139    past the register area (-1) is returned.  */
140 int
141 tui_last_reg_element_no_in_line (int line_no)
142 {
143   if ((line_no * TUI_DATA_WIN->detail.data_display_info.regs_column_count) <=
144       TUI_DATA_WIN->detail.data_display_info.regs_content_count)
145     return ((line_no + 1) *
146             TUI_DATA_WIN->detail.data_display_info.regs_column_count) - 1;
147   else
148     return (-1);
149 }
150
151 /* Show the registers of the given group in the data window
152    and refresh the window.  */
153 void
154 tui_show_registers (struct reggroup *group)
155 {
156   enum tui_status ret = TUI_FAILURE;
157   struct tui_data_info *display_info;
158
159   /* Make sure the curses mode is enabled.  */
160   tui_enable ();
161
162   /* Make sure the register window is visible.  If not, select an
163      appropriate layout.  */
164   if (TUI_DATA_WIN == NULL || !TUI_DATA_WIN->generic.is_visible)
165     tui_set_layout_for_display_command (DATA_NAME);
166
167   display_info = &TUI_DATA_WIN->detail.data_display_info;
168   if (group == 0)
169     group = general_reggroup;
170
171   /* Say that registers should be displayed, even if there is a
172      problem.  */
173   display_info->display_regs = TRUE;
174
175   if (target_has_registers && target_has_stack && target_has_memory)
176     {
177       ret = tui_show_register_group (current_gdbarch, group,
178                                      get_current_frame (),
179                                      group == display_info->current_group);
180     }
181   if (ret == TUI_FAILURE)
182     {
183       display_info->current_group = 0;
184       tui_erase_data_content (NO_REGS_STRING);
185     }
186   else
187     {
188       int i;
189
190       /* Clear all notation of changed values.  */
191       for (i = 0; i < display_info->regs_content_count; i++)
192         {
193           struct tui_gen_win_info *data_item_win;
194           struct tui_win_element *win;
195
196           data_item_win = &display_info->regs_content[i]
197             ->which_element.data_window;
198           win = (struct tui_win_element *) data_item_win->content[0];
199           win->which_element.data.highlight = FALSE;
200         }
201       display_info->current_group = group;
202       tui_display_all_data ();
203     }
204 }
205
206
207 /* Set the data window to display the registers of the register group
208    using the given frame.  Values are refreshed only when
209    refresh_values_only is TRUE.  */
210
211 static enum tui_status
212 tui_show_register_group (struct gdbarch *gdbarch, 
213                          struct reggroup *group,
214                          struct frame_info *frame, 
215                          int refresh_values_only)
216 {
217   enum tui_status ret = TUI_FAILURE;
218   int nr_regs;
219   int allocated_here = FALSE;
220   int regnum, pos;
221   char title[80];
222   struct tui_data_info *display_info = &TUI_DATA_WIN->detail.data_display_info;
223
224   /* Make a new title showing which group we display.  */
225   snprintf (title, sizeof (title) - 1, "Register group: %s",
226             reggroup_name (group));
227   xfree (TUI_DATA_WIN->generic.title);
228   TUI_DATA_WIN->generic.title = xstrdup (title);
229
230   /* See how many registers must be displayed.  */
231   nr_regs = 0;
232   for (regnum = 0;
233        regnum < gdbarch_num_regs (current_gdbarch)
234                 + gdbarch_num_pseudo_regs (current_gdbarch);
235        regnum++)
236     {
237       /* Must be in the group and have a name.  */
238       if (gdbarch_register_reggroup_p (gdbarch, regnum, group)
239           && gdbarch_register_name (gdbarch, regnum) != 0)
240         nr_regs++;
241     }
242
243   if (display_info->regs_content_count > 0 && !refresh_values_only)
244     {
245       tui_free_data_content (display_info->regs_content,
246                              display_info->regs_content_count);
247       display_info->regs_content_count = 0;
248     }
249
250   if (display_info->regs_content_count <= 0)
251     {
252       display_info->regs_content = tui_alloc_content (nr_regs, DATA_WIN);
253       allocated_here = TRUE;
254       refresh_values_only = FALSE;
255     }
256
257   if (display_info->regs_content != (tui_win_content) NULL)
258     {
259       if (!refresh_values_only || allocated_here)
260         {
261           TUI_DATA_WIN->generic.content = (void*) NULL;
262           TUI_DATA_WIN->generic.content_size = 0;
263           tui_add_content_elements (&TUI_DATA_WIN->generic, nr_regs);
264           display_info->regs_content
265             = (tui_win_content) TUI_DATA_WIN->generic.content;
266           display_info->regs_content_count = nr_regs;
267         }
268
269       /* Now set the register names and values.  */
270       pos = 0;
271       for (regnum = 0;
272            regnum < gdbarch_num_regs (current_gdbarch)
273                     + gdbarch_num_pseudo_regs (current_gdbarch);
274            regnum++)
275         {
276           struct tui_gen_win_info *data_item_win;
277           struct tui_data_element *data;
278           const char *name;
279
280           if (!gdbarch_register_reggroup_p (gdbarch, regnum, group))
281             continue;
282
283           name = gdbarch_register_name (gdbarch, regnum);
284           if (name == 0)
285             continue;
286
287           data_item_win =
288             &display_info->regs_content[pos]->which_element.data_window;
289           data =
290             &((struct tui_win_element *) data_item_win->content[0])->which_element.data;
291           if (data)
292             {
293               if (!refresh_values_only)
294                 {
295                   data->item_no = regnum;
296                   data->name = name;
297                   data->highlight = FALSE;
298                 }
299               if (data->value == (void*) NULL)
300                 data->value = (void*) xmalloc (MAX_REGISTER_SIZE);
301
302               tui_get_register (gdbarch, frame, data, regnum, 0);
303             }
304           pos++;
305         }
306
307       TUI_DATA_WIN->generic.content_size =
308         display_info->regs_content_count + display_info->data_content_count;
309       ret = TUI_SUCCESS;
310     }
311
312   return ret;
313 }
314
315 /* Function to display the registers in the content from
316    'start_element_no' until the end of the register content or the end
317    of the display height.  No checking for displaying past the end of
318    the registers is done here.  */
319 void
320 tui_display_registers_from (int start_element_no)
321 {
322   struct tui_data_info *display_info = &TUI_DATA_WIN->detail.data_display_info;
323
324   if (display_info->regs_content != (tui_win_content) NULL &&
325       display_info->regs_content_count > 0)
326     {
327       int i = start_element_no;
328       int j, value_chars_wide, item_win_width, cur_y;
329
330       int max_len = 0;
331       for (i = 0; i < display_info->regs_content_count; i++)
332         {
333           struct tui_data_element *data;
334           struct tui_gen_win_info *data_item_win;
335           char *p;
336           int len;
337
338           data_item_win = &display_info->regs_content[i]->which_element.data_window;
339           data = &((struct tui_win_element *)
340                    data_item_win->content[0])->which_element.data;
341           len = 0;
342           p = data->content;
343           if (p != 0)
344             while (*p)
345               {
346                 if (*p++ == '\t')
347                   len = 8 * ((len / 8) + 1);
348                 else
349                   len++;
350               }
351
352           if (len > max_len)
353             max_len = len;
354         }
355       item_win_width = max_len + 1;
356       i = start_element_no;
357
358       display_info->regs_column_count =
359         (TUI_DATA_WIN->generic.width - 2) / item_win_width;
360       if (display_info->regs_column_count == 0)
361         display_info->regs_column_count = 1;
362       item_win_width =
363         (TUI_DATA_WIN->generic.width - 2) / display_info->regs_column_count;
364
365       /* Now create each data "sub" window, and write the display into
366          it.  */
367       cur_y = 1;
368       while (i < display_info->regs_content_count &&
369              cur_y <= TUI_DATA_WIN->generic.viewport_height)
370         {
371           for (j = 0;
372                (j < display_info->regs_column_count &&
373                 i < display_info->regs_content_count); j++)
374             {
375               struct tui_gen_win_info *data_item_win;
376               struct tui_data_element *data_element_ptr;
377
378               /* Create the window if necessary.  */
379               data_item_win = &display_info->regs_content[i]
380                 ->which_element.data_window;
381               data_element_ptr = &((struct tui_win_element *)
382                                  data_item_win->content[0])->which_element.data;
383               if (data_item_win->handle != (WINDOW*) NULL
384                   && (data_item_win->height != 1
385                       || data_item_win->width != item_win_width
386                       || data_item_win->origin.x != (item_win_width * j) + 1
387                       || data_item_win->origin.y != cur_y))
388                 {
389                   tui_delete_win (data_item_win->handle);
390                   data_item_win->handle = 0;
391                 }
392                   
393               if (data_item_win->handle == (WINDOW *) NULL)
394                 {
395                   data_item_win->height = 1;
396                   data_item_win->width = item_win_width;
397                   data_item_win->origin.x = (item_win_width * j) + 1;
398                   data_item_win->origin.y = cur_y;
399                   tui_make_window (data_item_win, DONT_BOX_WINDOW);
400                   scrollok (data_item_win->handle, FALSE);
401                 }
402               touchwin (data_item_win->handle);
403
404               /* Get the printable representation of the register
405                  and display it.  */
406               tui_display_register (data_element_ptr, data_item_win);
407               i++;              /* Next register.  */
408             }
409           cur_y++;              /* Next row.  */
410         }
411     }
412 }
413
414
415 /* Function to display the registers in the content from
416    'start_element_no' on 'start_line_no' until the end of the register
417    content or the end of the display height.  This function checks
418    that we won't display off the end of the register display.  */
419 void
420 tui_display_reg_element_at_line (int start_element_no,
421                                  int start_line_no)
422 {
423   if (TUI_DATA_WIN->detail.data_display_info.regs_content != (tui_win_content) NULL &&
424       TUI_DATA_WIN->detail.data_display_info.regs_content_count > 0)
425     {
426       int element_no = start_element_no;
427
428       if (start_element_no != 0 && start_line_no != 0)
429         {
430           int last_line_no, first_line_on_last_page;
431
432           last_line_no = tui_last_regs_line_no ();
433           first_line_on_last_page = last_line_no - (TUI_DATA_WIN->generic.height - 2);
434           if (first_line_on_last_page < 0)
435             first_line_on_last_page = 0;
436
437           /* If there is no other data displayed except registers, and
438              the element_no causes us to scroll past the end of the
439              registers, adjust what element to really start the
440              display at.  */
441           if (TUI_DATA_WIN->detail.data_display_info.data_content_count <= 0 &&
442               start_line_no > first_line_on_last_page)
443             element_no = tui_first_reg_element_no_inline (first_line_on_last_page);
444         }
445       tui_display_registers_from (element_no);
446     }
447 }
448
449
450
451 /* Function to display the registers starting at line line_no in the
452    data window.  Answers the line number that the display actually
453    started from.  If nothing is displayed (-1) is returned.  */
454 int
455 tui_display_registers_from_line (int line_no, 
456                                  int force_display)
457 {
458   if (TUI_DATA_WIN->detail.data_display_info.regs_content_count > 0)
459     {
460       int line, element_no;
461
462       if (line_no < 0)
463         line = 0;
464       else if (force_display)
465         { /* If we must display regs (force_display is true), then
466              make sure that we don't display off the end of the
467              registers.  */
468           if (line_no >= tui_last_regs_line_no ())
469             {
470               if ((line = tui_line_from_reg_element_no (
471                  TUI_DATA_WIN->detail.data_display_info.regs_content_count - 1)) < 0)
472                 line = 0;
473             }
474           else
475             line = line_no;
476         }
477       else
478         line = line_no;
479
480       element_no = tui_first_reg_element_no_inline (line);
481       if (element_no < TUI_DATA_WIN->detail.data_display_info.regs_content_count)
482         tui_display_reg_element_at_line (element_no, line);
483       else
484         line = (-1);
485
486       return line;
487     }
488
489   return (-1);                  /* Nothing was displayed.  */
490 }
491
492
493 /* This function check all displayed registers for changes in values,
494    given a particular frame.  If the values have changed, they are
495    updated with the new value and highlighted.  */
496 void
497 tui_check_register_values (struct frame_info *frame)
498 {
499   if (TUI_DATA_WIN != NULL && TUI_DATA_WIN->generic.is_visible)
500     {
501       struct tui_data_info *display_info
502         = &TUI_DATA_WIN->detail.data_display_info;
503
504       if (display_info->regs_content_count <= 0 && display_info->display_regs)
505         tui_show_registers (display_info->current_group);
506       else
507         {
508           int i, j;
509
510           for (i = 0; (i < display_info->regs_content_count); i++)
511             {
512               struct tui_data_element *data;
513               struct tui_gen_win_info *data_item_win_ptr;
514               int was_hilighted;
515
516               data_item_win_ptr = &display_info->regs_content[i]->
517                 which_element.data_window;
518               data = &((struct tui_win_element *)
519                        data_item_win_ptr->content[0])->which_element.data;
520               was_hilighted = data->highlight;
521
522               tui_get_register (current_gdbarch, frame, data,
523                                 data->item_no, &data->highlight);
524
525               if (data->highlight || was_hilighted)
526                 {
527                   tui_display_register (data, data_item_win_ptr);
528                 }
529             }
530         }
531     }
532 }
533
534 /* Display a register in a window.  If hilite is TRUE, then the value
535    will be displayed in reverse video.  */
536 static void
537 tui_display_register (struct tui_data_element *data,
538                       struct tui_gen_win_info *win_info)
539 {
540   if (win_info->handle != (WINDOW *) NULL)
541     {
542       int i;
543
544       if (data->highlight)
545         wstandout (win_info->handle);
546       
547       wmove (win_info->handle, 0, 0);
548       for (i = 1; i < win_info->width; i++)
549         waddch (win_info->handle, ' ');
550       wmove (win_info->handle, 0, 0);
551       if (data->content)
552         waddstr (win_info->handle, data->content);
553
554       if (data->highlight)
555         wstandend (win_info->handle);
556       tui_refresh_win (win_info);
557     }
558 }
559
560 static void
561 tui_reg_next_command (char *arg, int from_tty)
562 {
563   if (TUI_DATA_WIN != 0)
564     {
565       struct reggroup *group
566         = TUI_DATA_WIN->detail.data_display_info.current_group;
567
568       group = reggroup_next (current_gdbarch, group);
569       if (group == 0)
570         group = reggroup_next (current_gdbarch, 0);
571
572       if (group)
573         tui_show_registers (group);
574     }
575 }
576
577 static void
578 tui_reg_float_command (char *arg, int from_tty)
579 {
580   tui_show_registers (float_reggroup);
581 }
582
583 static void
584 tui_reg_general_command (char *arg, int from_tty)
585 {
586   tui_show_registers (general_reggroup);
587 }
588
589 static void
590 tui_reg_system_command (char *arg, int from_tty)
591 {
592   tui_show_registers (system_reggroup);
593 }
594
595 static struct cmd_list_element *tuireglist;
596
597 static void
598 tui_reg_command (char *args, int from_tty)
599 {
600   printf_unfiltered (_("\"tui reg\" must be followed by the name of a "
601                      "tui reg command.\n"));
602   help_list (tuireglist, "tui reg ", -1, gdb_stdout);
603 }
604
605 void
606 _initialize_tui_regs (void)
607 {
608   struct cmd_list_element **tuicmd;
609
610   tuicmd = tui_get_cmd_list ();
611
612   add_prefix_cmd ("reg", class_tui, tui_reg_command,
613                   _("TUI commands to control the register window."),
614                   &tuireglist, "tui reg ", 0,
615                   tuicmd);
616
617   add_cmd ("float", class_tui, tui_reg_float_command,
618            _("Display only floating point registers."),
619            &tuireglist);
620   add_cmd ("general", class_tui, tui_reg_general_command,
621            _("Display only general registers."),
622            &tuireglist);
623   add_cmd ("system", class_tui, tui_reg_system_command,
624            _("Display only system registers."),
625            &tuireglist);
626   add_cmd ("next", class_tui, tui_reg_next_command,
627            _("Display next register group."),
628            &tuireglist);
629
630   if (xdb_commands)
631     {
632       add_com ("fr", class_tui, tui_reg_float_command,
633                _("Display only floating point registers\n"));
634       add_com ("gr", class_tui, tui_reg_general_command,
635                _("Display only general registers\n"));
636       add_com ("sr", class_tui, tui_reg_system_command,
637                _("Display only special registers\n"));
638       add_com ("+r", class_tui, tui_scroll_regs_forward_command,
639                _("Scroll the registers window forward\n"));
640       add_com ("-r", class_tui, tui_scroll_regs_backward_command,
641                _("Scroll the register window backward\n"));
642     }
643 }
644
645
646 /*****************************************
647 ** STATIC LOCAL FUNCTIONS                 **
648 ******************************************/
649
650 extern int pagination_enabled;
651
652 static void
653 tui_restore_gdbout (void *ui)
654 {
655   ui_file_delete (gdb_stdout);
656   gdb_stdout = (struct ui_file*) ui;
657   pagination_enabled = 1;
658 }
659
660 /* Get the register from the frame and make a printable representation
661    of it in the data element.  */
662 static void
663 tui_register_format (struct gdbarch *gdbarch, 
664                      struct frame_info *frame,
665                      struct tui_data_element *data_element, 
666                      int regnum)
667 {
668   struct ui_file *stream;
669   struct ui_file *old_stdout;
670   const char *name;
671   struct cleanup *cleanups;
672   char *p, *s;
673   int pos;
674   struct type *type = register_type (gdbarch, regnum);
675
676   name = gdbarch_register_name (gdbarch, regnum);
677   if (name == 0)
678     {
679       return;
680     }
681   
682   pagination_enabled = 0;
683   old_stdout = gdb_stdout;
684   stream = tui_sfileopen (256);
685   gdb_stdout = stream;
686   cleanups = make_cleanup (tui_restore_gdbout, (void*) old_stdout);
687   if (TYPE_VECTOR (type) != 0 && 0)
688     {
689       gdb_byte buf[MAX_REGISTER_SIZE];
690       int len;
691
692       len = register_size (current_gdbarch, regnum);
693       fprintf_filtered (stream, "%-14s ", name);
694       get_frame_register (frame, regnum, buf);
695       print_scalar_formatted (buf, type, 'f', len, stream);
696     }
697   else
698     {
699       gdbarch_print_registers_info (current_gdbarch, stream,
700                                     frame, regnum, 1);
701     }
702
703   /* Save formatted output in the buffer.  */
704   p = tui_file_get_strbuf (stream);
705
706   /* Remove the possible \n.  */
707   s = strrchr (p, '\n');
708   if (s && s[1] == 0)
709     *s = 0;
710
711   xfree (data_element->content);
712   data_element->content = xstrdup (p);
713   do_cleanups (cleanups);
714 }
715
716 /* Get the register value from the given frame and format it for the
717    display.  When changep is set, check if the new register value has
718    changed with respect to the previous call.  */
719 static enum tui_status
720 tui_get_register (struct gdbarch *gdbarch, 
721                   struct frame_info *frame,
722                   struct tui_data_element *data, 
723                   int regnum, int *changedp)
724 {
725   enum tui_status ret = TUI_FAILURE;
726
727   if (changedp)
728     *changedp = FALSE;
729   if (target_has_registers)
730     {
731       gdb_byte buf[MAX_REGISTER_SIZE];
732       get_frame_register (frame, regnum, buf);
733
734       if (changedp)
735         {
736           int size = register_size (gdbarch, regnum);
737           char *old = (char*) data->value;
738           int i;
739
740           for (i = 0; i < size; i++)
741             if (buf[i] != old[i])
742               {
743                 *changedp = TRUE;
744                 old[i] = buf[i];
745               }
746         }
747
748       /* Reformat the data content if the value changed.  */
749       if (changedp == 0 || *changedp == TRUE)
750         tui_register_format (gdbarch, frame, data, regnum);
751
752       ret = TUI_SUCCESS;
753     }
754   return ret;
755 }
756
757 static void
758 tui_scroll_regs_forward_command (char *arg, int from_tty)
759 {
760   tui_scroll (FORWARD_SCROLL, TUI_DATA_WIN, 1);
761 }
762
763
764 static void
765 tui_scroll_regs_backward_command (char *arg, int from_tty)
766 {
767   tui_scroll (BACKWARD_SCROLL, TUI_DATA_WIN, 1);
768 }