OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [gdb-5.3/] [gdb/] [completer.c] - Blame information for rev 1181

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1181 sfurman
/* Line completion stuff for GDB, the GNU debugger.
2
   Copyright 2000, 2001 Free Software Foundation, Inc.
3
 
4
   This file is part of GDB.
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 2 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, write to the Free Software
18
   Foundation, Inc., 59 Temple Place - Suite 330,
19
   Boston, MA 02111-1307, USA.  */
20
 
21
#include "defs.h"
22
#include "symtab.h"
23
#include "gdbtypes.h"
24
#include "expression.h"
25
#include "filenames.h"          /* for DOSish file names */
26
 
27
#include "cli/cli-decode.h"
28
 
29
/* FIXME: This is needed because of lookup_cmd_1().
30
   We should be calling a hook instead so we eliminate the CLI dependency. */
31
#include "gdbcmd.h"
32
 
33
/* Needed for rl_completer_word_break_characters() and for
34
   filename_completion_function.  */
35
#include <readline/readline.h>
36
 
37
/* readline defines this.  */
38
#undef savestring
39
 
40
#include "completer.h"
41
 
42
/* Prototypes for local functions */
43
char *line_completion_function (char *text, int matches, char *line_buffer,
44
                                int point);
45
 
46
/* readline uses the word breaks for two things:
47
   (1) In figuring out where to point the TEXT parameter to the
48
   rl_completion_entry_function.  Since we don't use TEXT for much,
49
   it doesn't matter a lot what the word breaks are for this purpose, but
50
   it does affect how much stuff M-? lists.
51
   (2) If one of the matches contains a word break character, readline
52
   will quote it.  That's why we switch between
53
   gdb_completer_word_break_characters and
54
   gdb_completer_command_word_break_characters.  I'm not sure when
55
   we need this behavior (perhaps for funky characters in C++ symbols?).  */
56
 
57
/* Variables which are necessary for fancy command line editing.  */
58
static char *gdb_completer_word_break_characters =
59
" \t\n!@#$%^&*()+=|~`}{[]\"';:?/>.<,-";
60
 
61
/* When completing on command names, we remove '-' from the list of
62
   word break characters, since we use it in command names.  If the
63
   readline library sees one in any of the current completion strings,
64
   it thinks that the string needs to be quoted and automatically supplies
65
   a leading quote. */
66
static char *gdb_completer_command_word_break_characters =
67
" \t\n!@#$%^&*()+=|~`}{[]\"';:?/>.<,";
68
 
69
/* When completing on file names, we remove from the list of word
70
   break characters any characters that are commonly used in file
71
   names, such as '-', '+', '~', etc.  Otherwise, readline displays
72
   incorrect completion candidates.  */
73
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
74
/* MS-DOS and MS-Windows use colon as part of the drive spec, and most
75
   programs support @foo style response files.  */
76
static char *gdb_completer_file_name_break_characters = " \t\n*|\"';?><@";
77
#else
78
static char *gdb_completer_file_name_break_characters = " \t\n*|\"';:?><";
79
#endif
80
 
81
/* These are used when completing on locations, which can mix file
82
   names and symbol names separated by a colon.  */
83
static char *gdb_completer_loc_break_characters = " \t\n*|\"';:?><,";
84
 
85
/* Characters that can be used to quote completion strings.  Note that we
86
   can't include '"' because the gdb C parser treats such quoted sequences
87
   as strings. */
88
static char *gdb_completer_quote_characters = "'";
89
 
90
/* Accessor for some completer data that may interest other files. */
91
 
92
char *
93
get_gdb_completer_word_break_characters (void)
94
{
95
  return gdb_completer_word_break_characters;
96
}
97
 
98
char *
99
get_gdb_completer_quote_characters (void)
100
{
101
  return gdb_completer_quote_characters;
102
}
103
 
104
/* Line completion interface function for readline.  */
105
 
106
char *
107
readline_line_completion_function (char *text, int matches)
108
{
109
  return line_completion_function (text, matches, rl_line_buffer, rl_point);
110
}
111
 
112
/* This can be used for functions which don't want to complete on symbols
113
   but don't want to complete on anything else either.  */
114
char **
115
noop_completer (char *text, char *prefix)
116
{
117
  return NULL;
118
}
119
 
120
/* Complete on filenames.  */
121
char **
122
filename_completer (char *text, char *word)
123
{
124
  int subsequent_name;
125
  char **return_val;
126
  int return_val_used;
127
  int return_val_alloced;
128
 
129
  return_val_used = 0;
130
  /* Small for testing.  */
131
  return_val_alloced = 1;
132
  return_val = (char **) xmalloc (return_val_alloced * sizeof (char *));
133
 
134
  subsequent_name = 0;
135
  while (1)
136
    {
137
      char *p;
138
      p = filename_completion_function (text, subsequent_name);
139
      if (return_val_used >= return_val_alloced)
140
        {
141
          return_val_alloced *= 2;
142
          return_val =
143
            (char **) xrealloc (return_val,
144
                                return_val_alloced * sizeof (char *));
145
        }
146
      if (p == NULL)
147
        {
148
          return_val[return_val_used++] = p;
149
          break;
150
        }
151
      /* We need to set subsequent_name to a non-zero value before the
152
         continue line below, because otherwise, if the first file seen
153
         by GDB is a backup file whose name ends in a `~', we will loop
154
         indefinitely.  */
155
      subsequent_name = 1;
156
      /* Like emacs, don't complete on old versions.  Especially useful
157
         in the "source" command.  */
158
      if (p[strlen (p) - 1] == '~')
159
        continue;
160
 
161
      {
162
        char *q;
163
        if (word == text)
164
          /* Return exactly p.  */
165
          return_val[return_val_used++] = p;
166
        else if (word > text)
167
          {
168
            /* Return some portion of p.  */
169
            q = xmalloc (strlen (p) + 5);
170
            strcpy (q, p + (word - text));
171
            return_val[return_val_used++] = q;
172
            xfree (p);
173
          }
174
        else
175
          {
176
            /* Return some of TEXT plus p.  */
177
            q = xmalloc (strlen (p) + (text - word) + 5);
178
            strncpy (q, word, text - word);
179
            q[text - word] = '\0';
180
            strcat (q, p);
181
            return_val[return_val_used++] = q;
182
            xfree (p);
183
          }
184
      }
185
    }
186
#if 0
187
  /* There is no way to do this just long enough to affect quote inserting
188
     without also affecting the next completion.  This should be fixed in
189
     readline.  FIXME.  */
190
  /* Insure that readline does the right thing
191
     with respect to inserting quotes.  */
192
  rl_completer_word_break_characters = "";
193
#endif
194
  return return_val;
195
}
196
 
197
/* Complete on locations, which might be of two possible forms:
198
 
199
       file:line
200
   or
201
       symbol+offset
202
 
203
   This is intended to be used in commands that set breakpoints etc.  */
204
char **
205
location_completer (char *text, char *word)
206
{
207
  int n_syms = 0, n_files = 0;
208
  char ** fn_list = NULL;
209
  char ** list = NULL;
210
  char *p;
211
  int quote_found = 0;
212
  int quoted = *text == '\'' || *text == '"';
213
  int quote_char = '\0';
214
  char *colon = NULL;
215
  char *file_to_match = NULL;
216
  char *symbol_start = text;
217
  char *orig_text = text;
218
  size_t text_len;
219
 
220
  /* Do we have an unquoted colon, as in "break foo.c::bar"?  */
221
  for (p = text; *p != '\0'; ++p)
222
    {
223
      if (*p == '\\' && p[1] == '\'')
224
        p++;
225
      else if (*p == '\'' || *p == '"')
226
        {
227
          quote_found = *p;
228
          quote_char = *p++;
229
          while (*p != '\0' && *p != quote_found)
230
            {
231
              if (*p == '\\' && p[1] == quote_found)
232
                p++;
233
              p++;
234
            }
235
 
236
          if (*p == quote_found)
237
            quote_found = 0;
238
          else
239
            break;              /* hit the end of text */
240
        }
241
#if HAVE_DOS_BASED_FILE_SYSTEM
242
      /* If we have a DOS-style absolute file name at the beginning of
243
         TEXT, and the colon after the drive letter is the only colon
244
         we found, pretend the colon is not there.  */
245
      else if (p < text + 3 && *p == ':' && p == text + 1 + quoted)
246
        ;
247
#endif
248
      else if (*p == ':' && !colon)
249
        {
250
          colon = p;
251
          symbol_start = p + 1;
252
        }
253
      else if (strchr (gdb_completer_word_break_characters, *p))
254
        symbol_start = p + 1;
255
    }
256
 
257
  if (quoted)
258
    text++;
259
  text_len = strlen (text);
260
 
261
  /* Where is the file name?  */
262
  if (colon)
263
    {
264
      char *s;
265
 
266
      file_to_match = (char *) xmalloc (colon - text + 1);
267
      strncpy (file_to_match, text, colon - text + 1);
268
      /* Remove trailing colons and quotes from the file name.  */
269
      for (s = file_to_match + (colon - text);
270
           s > file_to_match;
271
           s--)
272
        if (*s == ':' || *s == quote_char)
273
          *s = '\0';
274
    }
275
  /* If the text includes a colon, they want completion only on a
276
     symbol name after the colon.  Otherwise, we need to complete on
277
     symbols as well as on files.  */
278
  if (colon)
279
    {
280
      list = make_file_symbol_completion_list (symbol_start, word,
281
                                               file_to_match);
282
      xfree (file_to_match);
283
    }
284
  else
285
    {
286
      list = make_symbol_completion_list (symbol_start, word);
287
      /* If text includes characters which cannot appear in a file
288
         name, they cannot be asking for completion on files.  */
289
      if (strcspn (text, gdb_completer_file_name_break_characters) == text_len)
290
        fn_list = make_source_files_completion_list (text, text);
291
    }
292
 
293
  /* How many completions do we have in both lists?  */
294
  if (fn_list)
295
    for ( ; fn_list[n_files]; n_files++)
296
      ;
297
  if (list)
298
    for ( ; list[n_syms]; n_syms++)
299
      ;
300
 
301
  /* Make list[] large enough to hold both lists, then catenate
302
     fn_list[] onto the end of list[].  */
303
  if (n_syms && n_files)
304
    {
305
      list = xrealloc (list, (n_syms + n_files + 1) * sizeof (char *));
306
      memcpy (list + n_syms, fn_list, (n_files + 1) * sizeof (char *));
307
      xfree (fn_list);
308
    }
309
  else if (n_files)
310
    {
311
      /* If we only have file names as possible completion, we should
312
         bring them in sync with what rl_complete expects.  The
313
         problem is that if the user types "break /foo/b TAB", and the
314
         possible completions are "/foo/bar" and "/foo/baz"
315
         rl_complete expects us to return "bar" and "baz", without the
316
         leading directories, as possible completions, because `word'
317
         starts at the "b".  But we ignore the value of `word' when we
318
         call make_source_files_completion_list above (because that
319
         would not DTRT when the completion results in both symbols
320
         and file names), so make_source_files_completion_list returns
321
         the full "/foo/bar" and "/foo/baz" strings.  This produces
322
         wrong results when, e.g., there's only one possible
323
         completion, because rl_complete will prepend "/foo/" to each
324
         candidate completion.  The loop below removes that leading
325
         part.  */
326
      for (n_files = 0; fn_list[n_files]; n_files++)
327
        {
328
          memmove (fn_list[n_files], fn_list[n_files] + (word - text),
329
                   strlen (fn_list[n_files]) + 1 - (word - text));
330
        }
331
      /* Return just the file-name list as the result.  */
332
      list = fn_list;
333
    }
334
  else if (!n_syms)
335
    {
336
      /* No completions at all.  As the final resort, try completing
337
         on the entire text as a symbol.  */
338
      list = make_symbol_completion_list (orig_text, word);
339
    }
340
 
341
  return list;
342
}
343
 
344
/* Complete on command names.  Used by "help".  */
345
char **
346
command_completer (char *text, char *word)
347
{
348
  return complete_on_cmdlist (cmdlist, text, word);
349
}
350
 
351
 
352
/* Here are some useful test cases for completion.  FIXME: These should
353
   be put in the test suite.  They should be tested with both M-? and TAB.
354
 
355
   "show output-" "radix"
356
   "show output" "-radix"
357
   "p" ambiguous (commands starting with p--path, print, printf, etc.)
358
   "p "  ambiguous (all symbols)
359
   "info t foo" no completions
360
   "info t " no completions
361
   "info t" ambiguous ("info target", "info terminal", etc.)
362
   "info ajksdlfk" no completions
363
   "info ajksdlfk " no completions
364
   "info" " "
365
   "info " ambiguous (all info commands)
366
   "p \"a" no completions (string constant)
367
   "p 'a" ambiguous (all symbols starting with a)
368
   "p b-a" ambiguous (all symbols starting with a)
369
   "p b-" ambiguous (all symbols)
370
   "file Make" "file" (word break hard to screw up here)
371
   "file ../gdb.stabs/we" "ird" (needs to not break word at slash)
372
 */
373
 
374
/* Generate completions all at once.  Returns a NULL-terminated array
375
   of strings.  Both the array and each element are allocated with
376
   xmalloc.  It can also return NULL if there are no completions.
377
 
378
   TEXT is the caller's idea of the "word" we are looking at.
379
 
380
   LINE_BUFFER is available to be looked at; it contains the entire text
381
   of the line.  POINT is the offset in that line of the cursor.  You
382
   should pretend that the line ends at POINT.  */
383
 
384
char **
385
complete_line (char *text, char *line_buffer, int point)
386
{
387
  char **list = NULL;
388
  char *tmp_command, *p;
389
  /* Pointer within tmp_command which corresponds to text.  */
390
  char *word;
391
  struct cmd_list_element *c, *result_list;
392
 
393
  /* Choose the default set of word break characters to break completions.
394
     If we later find out that we are doing completions on command strings
395
     (as opposed to strings supplied by the individual command completer
396
     functions, which can be any string) then we will switch to the
397
     special word break set for command strings, which leaves out the
398
     '-' character used in some commands.  */
399
 
400
  rl_completer_word_break_characters =
401
    gdb_completer_word_break_characters;
402
 
403
      /* Decide whether to complete on a list of gdb commands or on symbols. */
404
  tmp_command = (char *) alloca (point + 1);
405
  p = tmp_command;
406
 
407
  strncpy (tmp_command, line_buffer, point);
408
  tmp_command[point] = '\0';
409
  /* Since text always contains some number of characters leading up
410
     to point, we can find the equivalent position in tmp_command
411
     by subtracting that many characters from the end of tmp_command.  */
412
  word = tmp_command + point - strlen (text);
413
 
414
  if (point == 0)
415
    {
416
      /* An empty line we want to consider ambiguous; that is, it
417
         could be any command.  */
418
      c = (struct cmd_list_element *) -1;
419
      result_list = 0;
420
    }
421
  else
422
    {
423
      c = lookup_cmd_1 (&p, cmdlist, &result_list, 1);
424
    }
425
 
426
  /* Move p up to the next interesting thing.  */
427
  while (*p == ' ' || *p == '\t')
428
    {
429
      p++;
430
    }
431
 
432
  if (!c)
433
    {
434
      /* It is an unrecognized command.  So there are no
435
         possible completions.  */
436
      list = NULL;
437
    }
438
  else if (c == (struct cmd_list_element *) -1)
439
    {
440
      char *q;
441
 
442
      /* lookup_cmd_1 advances p up to the first ambiguous thing, but
443
         doesn't advance over that thing itself.  Do so now.  */
444
      q = p;
445
      while (*q && (isalnum (*q) || *q == '-' || *q == '_'))
446
        ++q;
447
      if (q != tmp_command + point)
448
        {
449
          /* There is something beyond the ambiguous
450
             command, so there are no possible completions.  For
451
             example, "info t " or "info t foo" does not complete
452
             to anything, because "info t" can be "info target" or
453
             "info terminal".  */
454
          list = NULL;
455
        }
456
      else
457
        {
458
          /* We're trying to complete on the command which was ambiguous.
459
             This we can deal with.  */
460
          if (result_list)
461
            {
462
              list = complete_on_cmdlist (*result_list->prefixlist, p,
463
                                          word);
464
            }
465
          else
466
            {
467
              list = complete_on_cmdlist (cmdlist, p, word);
468
            }
469
          /* Insure that readline does the right thing with respect to
470
             inserting quotes.  */
471
          rl_completer_word_break_characters =
472
            gdb_completer_command_word_break_characters;
473
        }
474
    }
475
  else
476
    {
477
      /* We've recognized a full command.  */
478
 
479
      if (p == tmp_command + point)
480
        {
481
          /* There is no non-whitespace in the line beyond the command.  */
482
 
483
          if (p[-1] == ' ' || p[-1] == '\t')
484
            {
485
              /* The command is followed by whitespace; we need to complete
486
                 on whatever comes after command.  */
487
              if (c->prefixlist)
488
                {
489
                  /* It is a prefix command; what comes after it is
490
                     a subcommand (e.g. "info ").  */
491
                  list = complete_on_cmdlist (*c->prefixlist, p, word);
492
 
493
                  /* Insure that readline does the right thing
494
                         with respect to inserting quotes.  */
495
                  rl_completer_word_break_characters =
496
                    gdb_completer_command_word_break_characters;
497
                }
498
              else if (c->enums)
499
                {
500
                  list = complete_on_enum (c->enums, p, word);
501
                  rl_completer_word_break_characters =
502
                    gdb_completer_command_word_break_characters;
503
                }
504
              else
505
                {
506
                  /* It is a normal command; what comes after it is
507
                     completed by the command's completer function.  */
508
                  if (c->completer == filename_completer)
509
                    {
510
                      /* Many commands which want to complete on
511
                         file names accept several file names, as
512
                         in "run foo bar >>baz".  So we don't want
513
                         to complete the entire text after the
514
                         command, just the last word.  To this
515
                         end, we need to find the beginning of the
516
                         file name by starting at `word' and going
517
                         backwards.  */
518
                      for (p = word;
519
                           p > tmp_command
520
                             && strchr (gdb_completer_file_name_break_characters, p[-1]) == NULL;
521
                           p--)
522
                        ;
523
                      rl_completer_word_break_characters =
524
                        gdb_completer_file_name_break_characters;
525
                    }
526
                  else if (c->completer == location_completer)
527
                    {
528
                      /* Commands which complete on locations want to
529
                         see the entire argument.  */
530
                      for (p = word;
531
                           p > tmp_command
532
                             && p[-1] != ' ' && p[-1] != '\t';
533
                           p--)
534
                        ;
535
                    }
536
                  list = (*c->completer) (p, word);
537
                }
538
            }
539
          else
540
            {
541
              /* The command is not followed by whitespace; we need to
542
                 complete on the command itself.  e.g. "p" which is a
543
                 command itself but also can complete to "print", "ptype"
544
                 etc.  */
545
              char *q;
546
 
547
              /* Find the command we are completing on.  */
548
              q = p;
549
              while (q > tmp_command)
550
                {
551
                  if (isalnum (q[-1]) || q[-1] == '-' || q[-1] == '_')
552
                    --q;
553
                  else
554
                    break;
555
                }
556
 
557
              list = complete_on_cmdlist (result_list, q, word);
558
 
559
                  /* Insure that readline does the right thing
560
                     with respect to inserting quotes.  */
561
              rl_completer_word_break_characters =
562
                gdb_completer_command_word_break_characters;
563
            }
564
        }
565
      else
566
        {
567
          /* There is non-whitespace beyond the command.  */
568
 
569
          if (c->prefixlist && !c->allow_unknown)
570
            {
571
              /* It is an unrecognized subcommand of a prefix command,
572
                 e.g. "info adsfkdj".  */
573
              list = NULL;
574
            }
575
          else if (c->enums)
576
            {
577
              list = complete_on_enum (c->enums, p, word);
578
            }
579
          else
580
            {
581
              /* It is a normal command.  */
582
              if (c->completer == filename_completer)
583
                {
584
                  /* See the commentary above about the specifics
585
                     of file-name completion.  */
586
                  for (p = word;
587
                       p > tmp_command
588
                         && strchr (gdb_completer_file_name_break_characters, p[-1]) == NULL;
589
                       p--)
590
                    ;
591
                  rl_completer_word_break_characters =
592
                    gdb_completer_file_name_break_characters;
593
                }
594
              else if (c->completer == location_completer)
595
                {
596
                  for (p = word;
597
                       p > tmp_command
598
                         && p[-1] != ' ' && p[-1] != '\t';
599
                       p--)
600
                    ;
601
                }
602
              list = (*c->completer) (p, word);
603
            }
604
        }
605
    }
606
 
607
  return list;
608
}
609
 
610
/* Generate completions one by one for the completer.  Each time we are
611
   called return another potential completion to the caller.
612
   line_completion just completes on commands or passes the buck to the
613
   command's completer function, the stuff specific to symbol completion
614
   is in make_symbol_completion_list.
615
 
616
   TEXT is the caller's idea of the "word" we are looking at.
617
 
618
   MATCHES is the number of matches that have currently been collected from
619
   calling this completion function.  When zero, then we need to initialize,
620
   otherwise the initialization has already taken place and we can just
621
   return the next potential completion string.
622
 
623
   LINE_BUFFER is available to be looked at; it contains the entire text
624
   of the line.  POINT is the offset in that line of the cursor.  You
625
   should pretend that the line ends at POINT.
626
 
627
   Returns NULL if there are no more completions, else a pointer to a string
628
   which is a possible completion, it is the caller's responsibility to
629
   free the string.  */
630
 
631
char *
632
line_completion_function (char *text, int matches, char *line_buffer, int point)
633
{
634
  static char **list = (char **) NULL;  /* Cache of completions */
635
  static int index;             /* Next cached completion */
636
  char *output = NULL;
637
 
638
  if (matches == 0)
639
    {
640
      /* The caller is beginning to accumulate a new set of completions, so
641
         we need to find all of them now, and cache them for returning one at
642
         a time on future calls. */
643
 
644
      if (list)
645
        {
646
          /* Free the storage used by LIST, but not by the strings inside.
647
             This is because rl_complete_internal () frees the strings. */
648
          xfree (list);
649
        }
650
      index = 0;
651
      list = complete_line (text, line_buffer, point);
652
    }
653
 
654
  /* If we found a list of potential completions during initialization then
655
     dole them out one at a time.  The vector of completions is NULL
656
     terminated, so after returning the last one, return NULL (and continue
657
     to do so) each time we are called after that, until a new list is
658
     available. */
659
 
660
  if (list)
661
    {
662
      output = list[index];
663
      if (output)
664
        {
665
          index++;
666
        }
667
    }
668
 
669
#if 0
670
  /* Can't do this because readline hasn't yet checked the word breaks
671
     for figuring out whether to insert a quote.  */
672
  if (output == NULL)
673
    /* Make sure the word break characters are set back to normal for the
674
       next time that readline tries to complete something.  */
675
    rl_completer_word_break_characters =
676
      gdb_completer_word_break_characters;
677
#endif
678
 
679
  return (output);
680
}
681
/* Skip over a possibly quoted word (as defined by the quote characters
682
   and word break characters the completer uses).  Returns pointer to the
683
   location after the "word". */
684
 
685
char *
686
skip_quoted (char *str)
687
{
688
  char quote_char = '\0';
689
  char *scan;
690
 
691
  for (scan = str; *scan != '\0'; scan++)
692
    {
693
      if (quote_char != '\0')
694
        {
695
          /* Ignore everything until the matching close quote char */
696
          if (*scan == quote_char)
697
            {
698
              /* Found matching close quote. */
699
              scan++;
700
              break;
701
            }
702
        }
703
      else if (strchr (gdb_completer_quote_characters, *scan))
704
        {
705
          /* Found start of a quoted string. */
706
          quote_char = *scan;
707
        }
708
      else if (strchr (gdb_completer_word_break_characters, *scan))
709
        {
710
          break;
711
        }
712
    }
713
  return (scan);
714
}
715
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.