1/*
2 * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
3 *
4 * All rights reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, and/or sell copies of the Software, and to permit persons
11 * to whom the Software is furnished to do so, provided that the above
12 * copyright notice(s) and this permission notice appear in all copies of
13 * the Software and that both the above copyright notice(s) and this
14 * permission notice appear in supporting documentation.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
19 * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
20 * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
21 * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
22 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
23 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
24 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
25 *
26 * Except as contained in this notice, the name of a copyright holder
27 * shall not be used in advertising or otherwise to promote the sale, use
28 * or other dealings in this Software without prior written authorization
29 * of the copyright holder.
30 */
31
32/*
33 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
34 * Use is subject to license terms.
35 */
36
37#pragma ident	"%Z%%M%	%I%	%E% SMI"
38
39/*
40 * Standard includes.
41 */
42#include <stdlib.h>
43#include <stdio.h>
44#include <string.h>
45#include <errno.h>
46
47/*
48 * Local includes.
49 */
50#include "libtecla.h"
51#include "ioutil.h"
52#include "stringrp.h"
53#include "pathutil.h"
54#include "cplfile.h"
55#include "cplmatch.h"
56#include "errmsg.h"
57
58/*
59 * Specify the number of strings to allocate when the string free-list
60 * is exhausted. This also sets the number of elements to expand the
61 * matches[] array by whenever it is found to be too small.
62 */
63#define STR_BLK_FACT 100
64
65/*
66 * Set the default number of spaces place between columns when listing
67 * a set of completions.
68 */
69#define CPL_COL_SEP 2
70
71/*
72 * Completion matches are recorded in containers of the following
73 * type.
74 */
75struct WordCompletion {
76  ErrMsg *err;            /* The error reporting buffer */
77  StringGroup *sg;        /* Memory for a group of strings */
78  int matches_dim;        /* The allocated size of result.matches[] */
79  CplMatches result;      /* Completions to be returned to the caller */
80#ifndef WITHOUT_FILE_SYSTEM
81  CompleteFile *cf;       /* The resources used for filename completion */
82#endif
83};
84
85static void cpl_sort_matches(WordCompletion *cpl);
86static void cpl_zap_duplicates(WordCompletion *cpl);
87static void cpl_clear_completions(WordCompletion *cpl);
88static int cpl_cmp_matches(const void *v1, const void *v2);
89static int cpl_cmp_suffixes(const void *v1, const void *v2);
90
91/*
92 * The new_CplFileConf() constructor sets the integer first member of
93 * the returned object to the following magic number. On seeing this,
94 * cpl_file_completions() knows when it is passed a valid CplFileConf
95 * object.
96 */
97#define CFC_ID_CODE 4568
98
99#ifndef WITHOUT_FILE_SYSTEM
100/*
101 * A pointer to a structure of the following type can be passed to
102 * the builtin file-completion callback function to modify its behavior.
103 */
104struct CplFileConf {
105  int id;             /* new_CplFileConf() sets this to CFC_ID_CODE */
106  int escaped;        /* If none-zero, backslashes in the input line are */
107                      /*  interpreted as escaping special characters and */
108                      /*  spaces, and any special characters and spaces in */
109                      /*  the listed completions will also be escaped with */
110                      /*  added backslashes. This is the default behaviour. */
111                      /* If zero, backslashes are interpreted as being */
112                      /*  literal parts of the filename, and none are added */
113                      /*  to the completion suffixes. */
114  int file_start;     /* The index in the input line of the first character */
115                      /*  of the filename. If you specify -1 here, */
116                      /*  cpl_file_completions() identifies the */
117                      /*  the start of the filename by looking backwards for */
118                      /*  an unescaped space, or the beginning of the line. */
119  CplCheckFn *chk_fn; /* If not zero, this argument specifies a */
120                      /*  function to call to ask whether a given */
121                      /*  file should be included in the list */
122                      /*  of completions. */
123  void *chk_data;     /* Anonymous data to be passed to check_fn(). */
124};
125
126static void cpl_init_FileConf(CplFileConf *cfc);
127
128/*
129 * When file-system access is being excluded, define a dummy structure
130 * to satisfy the typedef in libtecla.h.
131 */
132#else
133struct CplFileConf {int dummy;};
134#endif
135
136/*
137 * Encapsulate the formatting information needed to layout a
138 * multi-column listing of completions.
139 */
140typedef struct {
141  int term_width;     /* The width of the terminal (characters) */
142  int column_width;   /* The number of characters within in each column. */
143  int ncol;           /* The number of columns needed */
144  int nline;          /* The number of lines needed */
145} CplListFormat;
146
147/*
148 * Given the current terminal width, and a list of completions, determine
149 * how to best use the terminal width to display a multi-column listing
150 * of completions.
151 */
152static void cpl_plan_listing(CplMatches *result, int term_width,
153			     CplListFormat *fmt);
154
155/*
156 * Display a given line of a multi-column list of completions.
157 */
158static int cpl_format_line(CplMatches *result, CplListFormat *fmt, int lnum,
159			   GlWriteFn *write_fn, void *data);
160
161/*.......................................................................
162 * Create a new string-completion object.
163 *
164 * Output:
165 *  return    WordCompletion *  The new object, or NULL on error.
166 */
167WordCompletion *new_WordCompletion(void)
168{
169  WordCompletion *cpl;  /* The object to be returned */
170/*
171 * Allocate the container.
172 */
173  cpl = (WordCompletion *) malloc(sizeof(WordCompletion));
174  if(!cpl) {
175    errno = ENOMEM;
176    return NULL;
177  };
178/*
179 * Before attempting any operation that might fail, initialize the
180 * container at least up to the point at which it can safely be passed
181 * to del_WordCompletion().
182 */
183  cpl->err = NULL;
184  cpl->sg = NULL;
185  cpl->matches_dim = 0;
186  cpl->result.suffix = NULL;
187  cpl->result.cont_suffix = NULL;
188  cpl->result.matches = NULL;
189  cpl->result.nmatch = 0;
190#ifndef WITHOUT_FILE_SYSTEM
191  cpl->cf = NULL;
192#endif
193/*
194 * Allocate a place to record error messages.
195 */
196  cpl->err = _new_ErrMsg();
197  if(!cpl->err)
198    return del_WordCompletion(cpl);
199/*
200 * Allocate an object that allows a group of strings to be allocated
201 * efficiently by placing many of them in contiguous string segments.
202 */
203#ifdef WITHOUT_FILE_SYSTEM
204  cpl->sg = _new_StringGroup(MAX_PATHLEN_FALLBACK);
205#else
206  cpl->sg = _new_StringGroup(_pu_pathname_dim());
207#endif
208  if(!cpl->sg)
209    return del_WordCompletion(cpl);
210/*
211 * Allocate an array for matching completions. This will be extended later
212 * if needed.
213 */
214  cpl->matches_dim = STR_BLK_FACT;
215  cpl->result.matches = (CplMatch *) malloc(sizeof(cpl->result.matches[0]) *
216					    cpl->matches_dim);
217  if(!cpl->result.matches) {
218    errno = ENOMEM;
219    return del_WordCompletion(cpl);
220  };
221/*
222 * Allocate a filename-completion resource object.
223 */
224#ifndef WITHOUT_FILE_SYSTEM
225  cpl->cf = _new_CompleteFile();
226  if(!cpl->cf)
227    return del_WordCompletion(cpl);
228#endif
229  return cpl;
230}
231
232/*.......................................................................
233 * Delete a string-completion object.
234 *
235 * Input:
236 *  cpl    WordCompletion *  The object to be deleted.
237 * Output:
238 *  return WordCompletion *  The deleted object (always NULL).
239 */
240WordCompletion *del_WordCompletion(WordCompletion *cpl)
241{
242  if(cpl) {
243    cpl->err = _del_ErrMsg(cpl->err);
244    cpl->sg = _del_StringGroup(cpl->sg);
245    if(cpl->result.matches) {
246      free(cpl->result.matches);
247      cpl->result.matches = NULL;
248#ifndef WITHOUT_FILE_SYSTEM
249      cpl->cf = _del_CompleteFile(cpl->cf);
250#endif
251    };
252    free(cpl);
253  };
254  return NULL;
255}
256
257/*.......................................................................
258 * This function is designed to be called by CplMatchFn callback
259 * functions. It adds one possible completion of the token that is being
260 * completed to an array of completions. If the completion needs any
261 * special quoting to be valid when displayed in the input line, this
262 * quoting must be included in the string.
263 *
264 * Input:
265 *  cpl     WordCompletion *  The argument of the same name that was passed
266 *                            to the calling CplMatchFn callback function.
267 *  line        const char *  The input line, as received by the callback
268 *                            function.
269 *  word_start         int    The index within line[] of the start of the
270 *                            word that is being completed.
271 *  word_end           int    The index within line[] of the character which
272 *                            follows the incomplete word, as received by the
273 *                            calling callback function.
274 *  suffix      const char *  The appropriately quoted string that could
275 *                            be appended to the incomplete token to complete
276 *                            it. A copy of this string will be allocated
277 *                            internally.
278 *  type_suffix const char *  When listing multiple completions, gl_get_line()
279 *                            appends this string to the completion to indicate
280 *                            its type to the user. If not pertinent pass "".
281 *                            Otherwise pass a literal or static string.
282 *  cont_suffix const char *  If this turns out to be the only completion,
283 *                            gl_get_line() will append this string as
284 *                            a continuation. For example, the builtin
285 *                            file-completion callback registers a directory
286 *                            separator here for directory matches, and a
287 *                            space otherwise. If the match were a function
288 *                            name you might want to append an open
289 *                            parenthesis, etc.. If not relevant pass "".
290 *                            Otherwise pass a literal or static string.
291 * Output:
292 *  return             int    0 - OK.
293 *                            1 - Error.
294 */
295int cpl_add_completion(WordCompletion *cpl, const char *line,
296		       int word_start, int word_end, const char *suffix,
297		       const char *type_suffix, const char *cont_suffix)
298{
299  CplMatch *match; /* The container of the new match */
300  char *string;    /* A newly allocated copy of the completion string */
301  size_t len;
302/*
303 * Check the arguments.
304 */
305  if(!cpl)
306    return 1;
307  if(!suffix)
308    return 0;
309  if(!type_suffix)
310    type_suffix = "";
311  if(!cont_suffix)
312    cont_suffix = "";
313/*
314 * Do we need to extend the array of matches[]?
315 */
316  if(cpl->result.nmatch+1 > cpl->matches_dim) {
317    int needed = cpl->matches_dim + STR_BLK_FACT;
318    CplMatch *matches = (CplMatch *) realloc(cpl->result.matches,
319			    sizeof(cpl->result.matches[0]) * needed);
320    if(!matches) {
321      _err_record_msg(cpl->err,
322		      "Insufficient memory to extend array of matches.",
323		      END_ERR_MSG);
324      return 1;
325    };
326    cpl->result.matches = matches;
327    cpl->matches_dim = needed;
328  };
329/*
330 * Allocate memory to store the combined completion prefix and the
331 * new suffix.
332 */
333  len = strlen(suffix);
334  string = _sg_alloc_string(cpl->sg, word_end-word_start + len);
335  if(!string) {
336    _err_record_msg(cpl->err, "Insufficient memory to extend array of matches.",
337		    END_ERR_MSG);
338    return 1;
339  };
340/*
341 * Compose the string.
342 */
343  strncpy(string, line + word_start, word_end - word_start);
344  strlcpy(string + word_end - word_start, suffix, len + 1);
345/*
346 * Record the new match.
347 */
348  match = cpl->result.matches + cpl->result.nmatch++;
349  match->completion = string;
350  match->suffix = string + word_end - word_start;
351  match->type_suffix = type_suffix;
352/*
353 * Record the continuation suffix.
354 */
355  cpl->result.cont_suffix = cont_suffix;
356  return 0;
357}
358
359/*.......................................................................
360 * Sort the array of matches.
361 *
362 * Input:
363 *  cpl   WordCompletion *  The completion resource object.
364 */
365static void cpl_sort_matches(WordCompletion *cpl)
366{
367  qsort(cpl->result.matches, cpl->result.nmatch,
368	sizeof(cpl->result.matches[0]), cpl_cmp_matches);
369}
370
371/*.......................................................................
372 * This is a qsort() comparison function used to sort matches.
373 *
374 * Input:
375 *  v1, v2   void *  Pointers to the two matches to be compared.
376 * Output:
377 *  return    int    -1 -> v1 < v2.
378 *                    0 -> v1 == v2
379 *                    1 -> v1 > v2
380 */
381static int cpl_cmp_matches(const void *v1, const void *v2)
382{
383  const CplMatch *m1 = (const CplMatch *) v1;
384  const CplMatch *m2 = (const CplMatch *) v2;
385  return strcmp(m1->completion, m2->completion);
386}
387
388/*.......................................................................
389 * Sort the array of matches in order of their suffixes.
390 *
391 * Input:
392 *  cpl   WordCompletion *  The completion resource object.
393 */
394static void cpl_sort_suffixes(WordCompletion *cpl)
395{
396  qsort(cpl->result.matches, cpl->result.nmatch,
397	sizeof(cpl->result.matches[0]), cpl_cmp_suffixes);
398}
399
400/*.......................................................................
401 * This is a qsort() comparison function used to sort matches in order of
402 * their suffixes.
403 *
404 * Input:
405 *  v1, v2   void *  Pointers to the two matches to be compared.
406 * Output:
407 *  return    int    -1 -> v1 < v2.
408 *                    0 -> v1 == v2
409 *                    1 -> v1 > v2
410 */
411static int cpl_cmp_suffixes(const void *v1, const void *v2)
412{
413  const CplMatch *m1 = (const CplMatch *) v1;
414  const CplMatch *m2 = (const CplMatch *) v2;
415  return strcmp(m1->suffix, m2->suffix);
416}
417
418/*.......................................................................
419 * Find the common prefix of all of the matching completion matches,
420 * and record a pointer to it in cpl->result.suffix. Note that this has
421 * the side effect of sorting the matches into suffix order.
422 *
423 * Input:
424 *  cpl   WordCompletion *  The completion resource object.
425 * Output:
426 *  return           int    0 - OK.
427 *                          1 - Error.
428 */
429static int cpl_common_suffix(WordCompletion *cpl)
430{
431  CplMatches *result;       /* The result container */
432  const char *first, *last; /* The first and last matching suffixes */
433  int length;               /* The length of the common suffix */
434/*
435 * Get the container of the array of matching files.
436 */
437  result = &cpl->result;
438/*
439 * No matching completions?
440 */
441  if(result->nmatch < 1)
442    return 0;
443/*
444 * Sort th matches into suffix order.
445 */
446  cpl_sort_suffixes(cpl);
447/*
448 * Given that the array of matches is sorted, the first and last
449 * suffixes are those that differ most in their prefixes, so the common
450 * prefix of these strings is the longest common prefix of all of the
451 * suffixes.
452 */
453  first = result->matches[0].suffix;
454  last = result->matches[result->nmatch - 1].suffix;
455/*
456 * Find the point at which the first and last matching strings
457 * first difffer.
458 */
459  while(*first && *first == *last) {
460    first++;
461    last++;
462  };
463/*
464 * How long is the common suffix?
465 */
466  length = first - result->matches[0].suffix;
467/*
468 * Allocate memory to record the common suffix.
469 */
470  result->suffix = _sg_alloc_string(cpl->sg, length);
471  if(!result->suffix) {
472    _err_record_msg(cpl->err,
473		    "Insufficient memory to record common completion suffix.",
474		    END_ERR_MSG);
475    return 1;
476  };
477/*
478 * Record the common suffix.
479 */
480  strncpy(result->suffix, result->matches[0].suffix, length);
481  result->suffix[length] = '\0';
482  return 0;
483}
484
485/*.......................................................................
486 * Discard the contents of the array of possible completion matches.
487 *
488 * Input:
489 *  cpl   WordCompletion *  The word-completion resource object.
490 */
491static void cpl_clear_completions(WordCompletion *cpl)
492{
493/*
494 * Discard all of the strings.
495 */
496  _clr_StringGroup(cpl->sg);
497/*
498 * Record the fact that the array is now empty.
499 */
500  cpl->result.nmatch = 0;
501  cpl->result.suffix = NULL;
502  cpl->result.cont_suffix = "";
503/*
504 * Also clear the error message.
505 */
506  _err_clear_msg(cpl->err);
507  return;
508}
509
510/*.......................................................................
511 * Given an input line and the point at which it completion is to be
512 * attempted, return an array of possible completions.
513 *
514 * Input:
515 *  cpl    WordCompletion *  The completion resource object.
516 *  line             char *  The current input line.
517 *  word_end          int    The index of the character in line[] which
518 *                           follows the end of the token that is being
519 *                           completed.
520 *  data             void *  Anonymous 'data' to be passed to match_fn().
521 *  match_fn   CplMatchFn *  The function that will identify the prefix
522 *                           to be completed from the input line, and
523 *                           record completion matches.
524 * Output:
525 *  return     CplMatches *  The container of the array of possible
526 *                           completions. The returned pointer refers
527 *                           to a container owned by the parent WordCompletion
528 *                           object, and its contents thus potentially
529 *                           change on every call to cpl_matches().
530 *                           On error, NULL is returned, and a description
531 *                           of the error can be acquired by calling
532 *                           cpl_last_error(cpl).
533 */
534CplMatches *cpl_complete_word(WordCompletion *cpl, const char *line,
535			      int word_end, void *data,
536			      CplMatchFn *match_fn)
537{
538  int line_len;   /* The total length of the input line */
539/*
540 * How long is the input line?
541 */
542  line_len = strlen(line);
543/*
544 * Check the arguments.
545 */
546  if(!cpl || !line || !match_fn || word_end < 0 || word_end > line_len) {
547    if(cpl) {
548      _err_record_msg(cpl->err, "cpl_complete_word: Invalid arguments.",
549		      END_ERR_MSG);
550    };
551    return NULL;
552  };
553/*
554 * Clear the return container.
555 */
556  cpl_clear_completions(cpl);
557/*
558 * Have the matching function record possible completion matches in
559 * cpl->result.matches.
560 */
561  if(match_fn(cpl, data, line, word_end)) {
562    if(_err_get_msg(cpl->err)[0] == '\0')
563      _err_record_msg(cpl->err, "Error completing word.", END_ERR_MSG);
564    return NULL;
565  };
566/*
567 * Record a copy of the common initial part of all of the prefixes
568 * in cpl->result.common.
569 */
570  if(cpl_common_suffix(cpl))
571    return NULL;
572/*
573 * Sort the matches into lexicographic order.
574 */
575  cpl_sort_matches(cpl);
576/*
577 * Discard any duplicate matches.
578 */
579  cpl_zap_duplicates(cpl);
580/*
581 * If there is more than one match, discard the continuation suffix.
582 */
583  if(cpl->result.nmatch > 1)
584    cpl->result.cont_suffix = "";
585/*
586 * Return the array of matches.
587 */
588  return &cpl->result;
589}
590
591/*.......................................................................
592 * Recall the return value of the last call to cpl_complete_word().
593 *
594 * Input:
595 *  cpl    WordCompletion *  The completion resource object.
596 * Output:
597 *  return     CplMatches *  The container of the array of possible
598 *                           completions, as returned by the last call to
599 *                           cpl_complete_word(). The returned pointer refers
600 *                           to a container owned by the parent WordCompletion
601 *                           object, and its contents thus potentially
602 *                           change on every call to cpl_complete_word().
603 *                           On error, either in the execution of this
604 *                           function, or in the last call to
605 *                           cpl_complete_word(), NULL is returned, and a
606 *                           description of the error can be acquired by
607 *                           calling cpl_last_error(cpl).
608 */
609CplMatches *cpl_recall_matches(WordCompletion *cpl)
610{
611  return (!cpl || *_err_get_msg(cpl->err)!='\0') ? NULL : &cpl->result;
612}
613
614/*.......................................................................
615 * Print out an array of matching completions.
616 *
617 * Input:
618 *  result  CplMatches *   The container of the sorted array of
619 *                         completions.
620 *  fp            FILE *   The output stream to write to.
621 *  term_width     int     The width of the terminal.
622 * Output:
623 *  return         int     0 - OK.
624 *                         1 - Error.
625 */
626int cpl_list_completions(CplMatches *result, FILE *fp, int term_width)
627{
628  return _cpl_output_completions(result, _io_write_stdio, fp, term_width);
629}
630
631/*.......................................................................
632 * Print an array of matching completions via a callback function.
633 *
634 * Input:
635 *  result   CplMatches *  The container of the sorted array of
636 *                         completions.
637 *  write_fn  GlWriteFn *  The function to call to write the completions,
638 *                         or 0 to discard the output.
639 *  data           void *  Anonymous data to pass to write_fn().
640 *  term_width      int    The width of the terminal.
641 * Output:
642 *  return          int     0 - OK.
643 *                          1 - Error.
644 */
645int _cpl_output_completions(CplMatches *result, GlWriteFn *write_fn, void *data,
646			    int term_width)
647{
648  CplListFormat fmt; /* List formatting information */
649  int lnum;          /* The sequential number of the line to print next */
650/*
651 * Not enough space to list anything?
652 */
653  if(term_width < 1)
654    return 0;
655/*
656 * Do we have a callback to write via, and any completions to be listed?
657 */
658  if(write_fn && result && result->nmatch>0) {
659/*
660 * Work out how to arrange the listing into fixed sized columns.
661 */
662    cpl_plan_listing(result, term_width, &fmt);
663/*
664 * Print the listing via the specified callback.
665 */
666    for(lnum=0; lnum < fmt.nline; lnum++) {
667      if(cpl_format_line(result, &fmt, lnum, write_fn, data))
668	return 1;
669    };
670  };
671  return 0;
672}
673
674/*.......................................................................
675 * Return a description of the string-completion error that occurred.
676 *
677 * Input:
678 *  cpl   WordCompletion *  The string-completion resource object.
679 * Output:
680 *  return    const char *  The description of the last error.
681 */
682const char *cpl_last_error(WordCompletion *cpl)
683{
684  return cpl ? _err_get_msg(cpl->err) : "NULL WordCompletion argument";
685}
686
687/*.......................................................................
688 * When an error occurs while performing a completion, you registerf a
689 * terse description of the error by calling cpl_record_error(). This
690 * message will then be returned on the next call to cpl_last_error().
691 *
692 * Input:
693 *  cpl   WordCompletion *  The string-completion resource object that was
694 *                          originally passed to the callback.
695 *  errmsg    const char *  The description of the error.
696 */
697void cpl_record_error(WordCompletion *cpl, const char *errmsg)
698{
699  if(cpl && errmsg)
700    _err_record_msg(cpl->err, errmsg, END_ERR_MSG);
701}
702
703/*.......................................................................
704 * This is the builtin completion callback function which performs file
705 * completion.
706 *
707 * Input:
708 *  cpl  WordCompletion *  An opaque pointer to the object that will
709 *                         contain the matches. This should be filled
710 *                         via zero or more calls to cpl_add_completion().
711 *  data           void *  Either NULL to request the default
712 *                         file-completion behavior, or a pointer to a
713 *                         CplFileConf structure, whose members specify
714 *                         a different behavior.
715 *  line           char *  The current input line.
716 *  word_end        int    The index of the character in line[] which
717 *                         follows the end of the token that is being
718 *                         completed.
719 * Output
720 *  return          int    0 - OK.
721 *                         1 - Error.
722 */
723CPL_MATCH_FN(cpl_file_completions)
724{
725#ifdef WITHOUT_FILE_SYSTEM
726  return 0;
727#else
728  const char *start_path;  /* The pointer to the start of the pathname */
729                           /*  in line[]. */
730  CplFileConf *conf;       /* The new-style configuration object. */
731/*
732 * The following configuration object will be used if the caller didn't
733 * provide one.
734 */
735  CplFileConf default_conf;
736/*
737 * This function can be called externally, so check its arguments.
738 */
739  if(!cpl)
740    return 1;
741  if(!line || word_end < 0) {
742    _err_record_msg(cpl->err, "cpl_file_completions: Invalid arguments.",
743		    END_ERR_MSG);
744    return 1;
745  };
746/*
747 * The 'data' argument is either a CplFileConf pointer, identifiable
748 * by having an integer id code as its first member, or the deprecated
749 * CplFileArgs pointer, or can be NULL to request the default
750 * configuration.
751 */
752  if(data && *(int *)data == CFC_ID_CODE) {
753    conf = (CplFileConf *) data;
754  } else {
755/*
756 * Select the defaults.
757 */
758    conf = &default_conf;
759    cpl_init_FileConf(&default_conf);
760/*
761 * If we have been passed an instance of the deprecated CplFileArgs
762 * structure, copy its configuration parameters over the defaults.
763 */
764    if(data) {
765      CplFileArgs *args = (CplFileArgs *) data;
766      conf->escaped = args->escaped;
767      conf->file_start = args->file_start;
768    };
769  };
770/*
771 * Get the start of the filename. If not specified by the caller
772 * identify it by searching backwards in the input line for an
773 * unescaped space or the start of the line.
774 */
775  if(conf->file_start < 0) {
776    start_path = _pu_start_of_path(line, word_end);
777    if(!start_path) {
778      _err_record_msg(cpl->err, "Unable to find the start of the filename.",
779		      END_ERR_MSG);
780      return 1;
781    };
782  } else {
783    start_path = line + conf->file_start;
784  };
785/*
786 * Perform the completion.
787 */
788  if(_cf_complete_file(cpl, cpl->cf, line, start_path - line, word_end,
789		      conf->escaped, conf->chk_fn, conf->chk_data)) {
790    cpl_record_error(cpl, _cf_last_error(cpl->cf));
791    return 1;
792  };
793  return 0;
794#endif
795}
796
797/*.......................................................................
798 * Initialize a CplFileArgs structure with default configuration
799 * parameters. Note that the CplFileArgs configuration type is
800 * deprecated. The opaque CplFileConf object should be used in future
801 * applications.
802 *
803 * Input:
804 *  cfa  CplFileArgs *  The configuration object of the
805 *                      cpl_file_completions() callback.
806 */
807void cpl_init_FileArgs(CplFileArgs *cfa)
808{
809  if(cfa) {
810    cfa->escaped = 1;
811    cfa->file_start = -1;
812  };
813}
814
815#ifndef WITHOUT_FILE_SYSTEM
816/*.......................................................................
817 * Initialize a CplFileConf structure with default configuration
818 * parameters.
819 *
820 * Input:
821 *  cfc  CplFileConf *  The configuration object of the
822 *                      cpl_file_completions() callback.
823 */
824static void cpl_init_FileConf(CplFileConf *cfc)
825{
826  if(cfc) {
827    cfc->id = CFC_ID_CODE;
828    cfc->escaped = 1;
829    cfc->file_start = -1;
830    cfc->chk_fn = 0;
831    cfc->chk_data = NULL;
832  };
833}
834#endif
835
836/*.......................................................................
837 * Create a new CplFileConf object and initialize it with defaults.
838 *
839 * Output:
840 *  return  CplFileConf *  The new object, or NULL on error.
841 */
842CplFileConf *new_CplFileConf(void)
843{
844#ifdef WITHOUT_FILE_SYSTEM
845  errno = EINVAL;
846  return NULL;
847#else
848  CplFileConf *cfc;  /* The object to be returned */
849/*
850 * Allocate the container.
851 */
852  cfc = (CplFileConf *)malloc(sizeof(CplFileConf));
853  if(!cfc)
854    return NULL;
855/*
856 * Before attempting any operation that might fail, initialize the
857 * container at least up to the point at which it can safely be passed
858 * to del_CplFileConf().
859 */
860  cpl_init_FileConf(cfc);
861  return cfc;
862#endif
863}
864
865/*.......................................................................
866 * Delete a CplFileConf object.
867 *
868 * Input:
869 *  cfc    CplFileConf *  The object to be deleted.
870 * Output:
871 *  return CplFileConf *  The deleted object (always NULL).
872 */
873CplFileConf *del_CplFileConf(CplFileConf *cfc)
874{
875#ifndef WITHOUT_FILE_SYSTEM
876  if(cfc) {
877/*
878 * Delete the container.
879 */
880    free(cfc);
881  };
882#endif
883  return NULL;
884}
885
886/*.......................................................................
887 * If backslashes in the filename should be treated as literal
888 * characters, call the following function with literal=1. Otherwise
889 * the default is to treat them as escape characters, used for escaping
890 * spaces etc..
891 *
892 * Input:
893 *  cfc    CplFileConf *  The cpl_file_completions() configuration object
894 *                        to be configured.
895 *  literal        int    Pass non-zero here to enable literal interpretation
896 *                        of backslashes. Pass 0 to turn off literal
897 *                        interpretation.
898 */
899void cfc_literal_escapes(CplFileConf *cfc, int literal)
900{
901#ifndef WITHOUT_FILE_SYSTEM
902  if(cfc)
903    cfc->escaped = !literal;
904#endif
905}
906
907/*.......................................................................
908 * Call this function if you know where the index at which the
909 * filename prefix starts in the input line. Otherwise by default,
910 * or if you specify start_index to be -1, the filename is taken
911 * to start after the first unescaped space preceding the cursor,
912 * or the start of the line, which ever comes first.
913 *
914 * Input:
915 *  cfc    CplFileConf *  The cpl_file_completions() configuration object
916 *                        to be configured.
917 *  start_index    int    The index of the start of the filename in
918 *                        the input line, or -1 to select the default.
919 */
920void cfc_file_start(CplFileConf *cfc, int start_index)
921{
922#ifndef WITHOUT_FILE_SYSTEM
923  if(cfc)
924    cfc->file_start = start_index;
925#endif
926}
927
928/*.......................................................................
929 * If you only want certain types of files to be included in the
930 * list of completions, you use the following function to specify a
931 * callback function which will be called to ask whether a given file
932 * should be included.
933 *
934 * Input:
935 *  cfc    CplFileConf *  The cpl_file_completions() configuration object
936 *                        to be configured.
937 *  chk_fn  CplCheckFn *  Zero to disable filtering, or a pointer to a
938 *                        function that returns 1 if a given file should
939 *                        be included in the list of completions.
940 *  chk_data      void *  Anonymous data to be passed to chk_fn()
941 *                        every time that it is called.
942 */
943void cfc_set_check_fn(CplFileConf *cfc, CplCheckFn *chk_fn, void *chk_data)
944{
945#ifndef WITHOUT_FILE_SYSTEM
946  if(cfc) {
947    cfc->chk_fn = chk_fn;
948    cfc->chk_data = chk_data;
949  };
950#endif
951}
952
953/*.......................................................................
954 * The following CplCheckFn callback returns non-zero if the specified
955 * filename is that of an executable.
956 */
957CPL_CHECK_FN(cpl_check_exe)
958{
959#ifdef WITHOUT_FILE_SYSTEM
960  return 0;
961#else
962  return _pu_path_is_exe(pathname);
963#endif
964}
965
966/*.......................................................................
967 * Remove duplicates from a sorted array of matches.
968 *
969 * Input:
970 *  cpl   WordCompletion *  The completion resource object.
971 */
972static void cpl_zap_duplicates(WordCompletion *cpl)
973{
974  CplMatch *matches;       /* The array of matches */
975  int nmatch;              /* The number of elements in matches[] */
976  const char *completion;  /* The completion string of the last unique match */
977  const char *type_suffix; /* The type of the last unique match */
978  int src;                 /* The index of the match being considered */
979  int dst;                 /* The index at which to record the next */
980                           /*  unique match. */
981/*
982 * Get the array of matches and the number of matches that it
983 * contains.
984 */
985  matches = cpl->result.matches;
986  nmatch = cpl->result.nmatch;
987/*
988 * No matches?
989 */
990  if(nmatch < 1)
991    return;
992/*
993 * Initialize the comparison strings with the first match.
994 */
995  completion = matches[0].completion;
996  type_suffix = matches[0].type_suffix;
997/*
998 * Go through the array of matches, copying each new unrecorded
999 * match at the head of the array, while discarding duplicates.
1000 */
1001  for(src=dst=1; src<nmatch; src++) {
1002    CplMatch *match = matches + src;
1003    if(strcmp(completion, match->completion) != 0 ||
1004       strcmp(type_suffix, match->type_suffix) != 0) {
1005      if(src != dst)
1006	matches[dst] = *match;
1007      dst++;
1008      completion = match->completion;
1009      type_suffix = match->type_suffix;
1010    };
1011  };
1012/*
1013 * Record the number of unique matches that remain.
1014 */
1015  cpl->result.nmatch = dst;
1016  return;
1017}
1018
1019/*.......................................................................
1020 * Work out how to arrange a given array of completions into a listing
1021 * of one or more fixed size columns.
1022 *
1023 * Input:
1024 *  result   CplMatches *   The set of completions to be listed.
1025 *  term_width      int     The width of the terminal. A lower limit of
1026 *                          zero is quietly enforced.
1027 * Input/Output:
1028 *  fmt   CplListFormat *   The formatting information will be assigned
1029 *                          to the members of *fmt.
1030 */
1031static void cpl_plan_listing(CplMatches *result, int term_width,
1032			     CplListFormat *fmt)
1033{
1034  int maxlen;    /* The length of the longest matching string */
1035  int i;
1036/*
1037 * Ensure that term_width >= 0.
1038 */
1039  if(term_width < 0)
1040    term_width = 0;
1041/*
1042 * Start by assuming the worst case, that either nothing will fit
1043 * on the screen, or that there are no matches to be listed.
1044 */
1045  fmt->term_width = term_width;
1046  fmt->column_width = 0;
1047  fmt->nline = fmt->ncol = 0;
1048/*
1049 * Work out the maximum length of the matching strings.
1050 */
1051  maxlen = 0;
1052  for(i=0; i<result->nmatch; i++) {
1053    CplMatch *match = result->matches + i;
1054    int len = strlen(match->completion) + strlen(match->type_suffix);
1055    if(len > maxlen)
1056      maxlen = len;
1057  };
1058/*
1059 * Nothing to list?
1060 */
1061  if(maxlen == 0)
1062    return;
1063/*
1064 * Split the available terminal width into columns of
1065 * maxlen + CPL_COL_SEP characters.
1066 */
1067  fmt->column_width = maxlen;
1068  fmt->ncol = fmt->term_width / (fmt->column_width + CPL_COL_SEP);
1069/*
1070 * If the column width is greater than the terminal width, zero columns
1071 * will have been selected. Set a lower limit of one column. Leave it
1072 * up to the caller how to deal with completions who's widths exceed
1073 * the available terminal width.
1074 */
1075  if(fmt->ncol < 1)
1076    fmt->ncol = 1;
1077/*
1078 * How many lines of output will be needed?
1079 */
1080  fmt->nline = (result->nmatch + fmt->ncol - 1) / fmt->ncol;
1081  return;
1082}
1083
1084/*.......................................................................
1085 * Render one line of a multi-column listing of completions, using a
1086 * callback function to pass the output to an arbitrary destination.
1087 *
1088 * Input:
1089 *  result      CplMatches *  The container of the sorted array of
1090 *                            completions.
1091 *  fmt      CplListFormat *  Formatting information.
1092 *  lnum               int    The index of the line to print, starting
1093 *                            from 0, and incrementing until the return
1094 *                            value indicates that there is nothing more
1095 *                            to be printed.
1096 *  write_fn     GlWriteFn *  The function to call to write the line, or
1097 *                            0 to discard the output.
1098 *  data              void *  Anonymous data to pass to write_fn().
1099 * Output:
1100 *  return             int    0 - Line printed ok.
1101 *                            1 - Nothing to print.
1102 */
1103static int cpl_format_line(CplMatches *result, CplListFormat *fmt, int lnum,
1104			   GlWriteFn *write_fn, void *data)
1105{
1106  int col;             /* The index of the list column being output */
1107/*
1108 * If the line index is out of bounds, there is nothing to be written.
1109 */
1110  if(lnum < 0 || lnum >= fmt->nline)
1111    return 1;
1112/*
1113 * If no output function has been provided, return as though the
1114 * line had been printed.
1115 */
1116  if(!write_fn)
1117    return 0;
1118/*
1119 * Print the matches in 'ncol' columns, sorted in line order within each
1120 * column.
1121 */
1122  for(col=0; col < fmt->ncol; col++) {
1123    int m = col*fmt->nline + lnum;
1124/*
1125 * Is there another match to be written? Note that in general
1126 * the last line of a listing will have fewer filled columns
1127 * than the initial lines.
1128 */
1129    if(m < result->nmatch) {
1130      CplMatch *match = result->matches + m;
1131/*
1132 * How long are the completion and type-suffix strings?
1133 */
1134      int clen = strlen(match->completion);
1135      int tlen = strlen(match->type_suffix);
1136/*
1137 * Write the completion string.
1138 */
1139      if(write_fn(data, match->completion, clen) != clen)
1140	return 1;
1141/*
1142 * Write the type suffix, if any.
1143 */
1144      if(tlen > 0 && write_fn(data, match->type_suffix, tlen) != tlen)
1145	return 1;
1146/*
1147 * If another column follows the current one, pad to its start with spaces.
1148 */
1149      if(col+1 < fmt->ncol) {
1150/*
1151 * The following constant string of spaces is used to pad the output.
1152 */
1153	static const char spaces[] = "                    ";
1154	static const int nspace = sizeof(spaces) - 1;
1155/*
1156 * Pad to the next column, using as few sub-strings of the spaces[]
1157 * array as possible.
1158 */
1159	int npad = fmt->column_width + CPL_COL_SEP - clen - tlen;
1160	while(npad>0) {
1161	  int n = npad > nspace ? nspace : npad;
1162	  if(write_fn(data, spaces + nspace - n, n) != n)
1163	    return 1;
1164	  npad -= n;
1165	};
1166      };
1167    };
1168  };
1169/*
1170 * Start a new line.
1171 */
1172  {
1173    char s[] = "\r\n";
1174    int n = strlen(s);
1175    if(write_fn(data, s, n) != n)
1176      return 1;
1177  };
1178  return 0;
1179}
1180