2 * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
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.
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.
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.
33 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
34 * Use is subject to license terms.
37 #pragma ident "%Z%%M% %I% %E% SMI"
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.
63 #define STR_BLK_FACT 100
66 * Set the default number of spaces place between columns when listing
67 * a set of completions.
72 * Completion matches are recorded in containers of the following
75 struct 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 */
85 static void cpl_sort_matches(WordCompletion
*cpl
);
86 static void cpl_zap_duplicates(WordCompletion
*cpl
);
87 static void cpl_clear_completions(WordCompletion
*cpl
);
88 static int cpl_cmp_matches(const void *v1
, const void *v2
);
89 static int cpl_cmp_suffixes(const void *v1
, const void *v2
);
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
97 #define CFC_ID_CODE 4568
99 #ifndef WITHOUT_FILE_SYSTEM
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.
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(). */
126 static void cpl_init_FileConf(CplFileConf
*cfc
);
129 * When file-system access is being excluded, define a dummy structure
130 * to satisfy the typedef in libtecla.h.
133 struct CplFileConf
{int dummy
;};
137 * Encapsulate the formatting information needed to layout a
138 * multi-column listing of completions.
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 */
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
152 static void cpl_plan_listing(CplMatches
*result
, int term_width
,
156 * Display a given line of a multi-column list of completions.
158 static int cpl_format_line(CplMatches
*result
, CplListFormat
*fmt
, int lnum
,
159 GlWriteFn
*write_fn
, void *data
);
161 /*.......................................................................
162 * Create a new string-completion object.
165 * return WordCompletion * The new object, or NULL on error.
167 WordCompletion
*new_WordCompletion(void)
169 WordCompletion
*cpl
; /* The object to be returned */
171 * Allocate the container.
173 cpl
= (WordCompletion
*) malloc(sizeof(WordCompletion
));
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().
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
194 * Allocate a place to record error messages.
196 cpl
->err
= _new_ErrMsg();
198 return del_WordCompletion(cpl
);
200 * Allocate an object that allows a group of strings to be allocated
201 * efficiently by placing many of them in contiguous string segments.
203 #ifdef WITHOUT_FILE_SYSTEM
204 cpl
->sg
= _new_StringGroup(MAX_PATHLEN_FALLBACK
);
206 cpl
->sg
= _new_StringGroup(_pu_pathname_dim());
209 return del_WordCompletion(cpl
);
211 * Allocate an array for matching completions. This will be extended later
214 cpl
->matches_dim
= STR_BLK_FACT
;
215 cpl
->result
.matches
= (CplMatch
*) malloc(sizeof(cpl
->result
.matches
[0]) *
217 if(!cpl
->result
.matches
) {
219 return del_WordCompletion(cpl
);
222 * Allocate a filename-completion resource object.
224 #ifndef WITHOUT_FILE_SYSTEM
225 cpl
->cf
= _new_CompleteFile();
227 return del_WordCompletion(cpl
);
232 /*.......................................................................
233 * Delete a string-completion object.
236 * cpl WordCompletion * The object to be deleted.
238 * return WordCompletion * The deleted object (always NULL).
240 WordCompletion
*del_WordCompletion(WordCompletion
*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
);
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.
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
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
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.
295 int 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
)
299 CplMatch
*match
; /* The container of the new match */
300 char *string
; /* A newly allocated copy of the completion string */
303 * Check the arguments.
314 * Do we need to extend the array of matches[]?
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
);
321 _err_record_msg(cpl
->err
,
322 "Insufficient memory to extend array of matches.",
326 cpl
->result
.matches
= matches
;
327 cpl
->matches_dim
= needed
;
330 * Allocate memory to store the combined completion prefix and the
333 len
= strlen(suffix
);
334 string
= _sg_alloc_string(cpl
->sg
, word_end
-word_start
+ len
);
336 _err_record_msg(cpl
->err
, "Insufficient memory to extend array of matches.",
341 * Compose the string.
343 strncpy(string
, line
+ word_start
, word_end
- word_start
);
344 strlcpy(string
+ word_end
- word_start
, suffix
, len
+ 1);
346 * Record the new match.
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
;
353 * Record the continuation suffix.
355 cpl
->result
.cont_suffix
= cont_suffix
;
359 /*.......................................................................
360 * Sort the array of matches.
363 * cpl WordCompletion * The completion resource object.
365 static void cpl_sort_matches(WordCompletion
*cpl
)
367 qsort(cpl
->result
.matches
, cpl
->result
.nmatch
,
368 sizeof(cpl
->result
.matches
[0]), cpl_cmp_matches
);
371 /*.......................................................................
372 * This is a qsort() comparison function used to sort matches.
375 * v1, v2 void * Pointers to the two matches to be compared.
377 * return int -1 -> v1 < v2.
381 static int cpl_cmp_matches(const void *v1
, const void *v2
)
383 const CplMatch
*m1
= (const CplMatch
*) v1
;
384 const CplMatch
*m2
= (const CplMatch
*) v2
;
385 return strcmp(m1
->completion
, m2
->completion
);
388 /*.......................................................................
389 * Sort the array of matches in order of their suffixes.
392 * cpl WordCompletion * The completion resource object.
394 static void cpl_sort_suffixes(WordCompletion
*cpl
)
396 qsort(cpl
->result
.matches
, cpl
->result
.nmatch
,
397 sizeof(cpl
->result
.matches
[0]), cpl_cmp_suffixes
);
400 /*.......................................................................
401 * This is a qsort() comparison function used to sort matches in order of
405 * v1, v2 void * Pointers to the two matches to be compared.
407 * return int -1 -> v1 < v2.
411 static int cpl_cmp_suffixes(const void *v1
, const void *v2
)
413 const CplMatch
*m1
= (const CplMatch
*) v1
;
414 const CplMatch
*m2
= (const CplMatch
*) v2
;
415 return strcmp(m1
->suffix
, m2
->suffix
);
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.
424 * cpl WordCompletion * The completion resource object.
429 static int cpl_common_suffix(WordCompletion
*cpl
)
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 */
435 * Get the container of the array of matching files.
437 result
= &cpl
->result
;
439 * No matching completions?
441 if(result
->nmatch
< 1)
444 * Sort th matches into suffix order.
446 cpl_sort_suffixes(cpl
);
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
453 first
= result
->matches
[0].suffix
;
454 last
= result
->matches
[result
->nmatch
- 1].suffix
;
456 * Find the point at which the first and last matching strings
459 while(*first
&& *first
== *last
) {
464 * How long is the common suffix?
466 length
= first
- result
->matches
[0].suffix
;
468 * Allocate memory to record the common suffix.
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.",
478 * Record the common suffix.
480 strncpy(result
->suffix
, result
->matches
[0].suffix
, length
);
481 result
->suffix
[length
] = '\0';
485 /*.......................................................................
486 * Discard the contents of the array of possible completion matches.
489 * cpl WordCompletion * The word-completion resource object.
491 static void cpl_clear_completions(WordCompletion
*cpl
)
494 * Discard all of the strings.
496 _clr_StringGroup(cpl
->sg
);
498 * Record the fact that the array is now empty.
500 cpl
->result
.nmatch
= 0;
501 cpl
->result
.suffix
= NULL
;
502 cpl
->result
.cont_suffix
= "";
504 * Also clear the error message.
506 _err_clear_msg(cpl
->err
);
510 /*.......................................................................
511 * Given an input line and the point at which it completion is to be
512 * attempted, return an array of possible completions.
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
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.
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).
534 CplMatches
*cpl_complete_word(WordCompletion
*cpl
, const char *line
,
535 int word_end
, void *data
,
536 CplMatchFn
*match_fn
)
538 int line_len
; /* The total length of the input line */
540 * How long is the input line?
542 line_len
= strlen(line
);
544 * Check the arguments.
546 if(!cpl
|| !line
|| !match_fn
|| word_end
< 0 || word_end
> line_len
) {
548 _err_record_msg(cpl
->err
, "cpl_complete_word: Invalid arguments.",
554 * Clear the return container.
556 cpl_clear_completions(cpl
);
558 * Have the matching function record possible completion matches in
559 * cpl->result.matches.
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
);
567 * Record a copy of the common initial part of all of the prefixes
568 * in cpl->result.common.
570 if(cpl_common_suffix(cpl
))
573 * Sort the matches into lexicographic order.
575 cpl_sort_matches(cpl
);
577 * Discard any duplicate matches.
579 cpl_zap_duplicates(cpl
);
581 * If there is more than one match, discard the continuation suffix.
583 if(cpl
->result
.nmatch
> 1)
584 cpl
->result
.cont_suffix
= "";
586 * Return the array of matches.
591 /*.......................................................................
592 * Recall the return value of the last call to cpl_complete_word().
595 * cpl WordCompletion * The completion resource object.
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).
609 CplMatches
*cpl_recall_matches(WordCompletion
*cpl
)
611 return (!cpl
|| *_err_get_msg(cpl
->err
)!='\0') ? NULL
: &cpl
->result
;
614 /*.......................................................................
615 * Print out an array of matching completions.
618 * result CplMatches * The container of the sorted array of
620 * fp FILE * The output stream to write to.
621 * term_width int The width of the terminal.
626 int cpl_list_completions(CplMatches
*result
, FILE *fp
, int term_width
)
628 return _cpl_output_completions(result
, _io_write_stdio
, fp
, term_width
);
631 /*.......................................................................
632 * Print an array of matching completions via a callback function.
635 * result CplMatches * The container of the sorted array of
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.
645 int _cpl_output_completions(CplMatches
*result
, GlWriteFn
*write_fn
, void *data
,
648 CplListFormat fmt
; /* List formatting information */
649 int lnum
; /* The sequential number of the line to print next */
651 * Not enough space to list anything?
656 * Do we have a callback to write via, and any completions to be listed?
658 if(write_fn
&& result
&& result
->nmatch
>0) {
660 * Work out how to arrange the listing into fixed sized columns.
662 cpl_plan_listing(result
, term_width
, &fmt
);
664 * Print the listing via the specified callback.
666 for(lnum
=0; lnum
< fmt
.nline
; lnum
++) {
667 if(cpl_format_line(result
, &fmt
, lnum
, write_fn
, data
))
674 /*.......................................................................
675 * Return a description of the string-completion error that occurred.
678 * cpl WordCompletion * The string-completion resource object.
680 * return const char * The description of the last error.
682 const char *cpl_last_error(WordCompletion
*cpl
)
684 return cpl
? _err_get_msg(cpl
->err
) : "NULL WordCompletion argument";
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().
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.
697 void cpl_record_error(WordCompletion
*cpl
, const char *errmsg
)
700 _err_record_msg(cpl
->err
, errmsg
, END_ERR_MSG
);
703 /*.......................................................................
704 * This is the builtin completion callback function which performs file
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
723 CPL_MATCH_FN(cpl_file_completions
)
725 #ifdef WITHOUT_FILE_SYSTEM
728 const char *start_path
; /* The pointer to the start of the pathname */
730 CplFileConf
*conf
; /* The new-style configuration object. */
732 * The following configuration object will be used if the caller didn't
735 CplFileConf default_conf
;
737 * This function can be called externally, so check its arguments.
741 if(!line
|| word_end
< 0) {
742 _err_record_msg(cpl
->err
, "cpl_file_completions: Invalid arguments.",
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
752 if(data
&& *(int *)data
== CFC_ID_CODE
) {
753 conf
= (CplFileConf
*) data
;
756 * Select the defaults.
758 conf
= &default_conf
;
759 cpl_init_FileConf(&default_conf
);
761 * If we have been passed an instance of the deprecated CplFileArgs
762 * structure, copy its configuration parameters over the defaults.
765 CplFileArgs
*args
= (CplFileArgs
*) data
;
766 conf
->escaped
= args
->escaped
;
767 conf
->file_start
= args
->file_start
;
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.
775 if(conf
->file_start
< 0) {
776 start_path
= _pu_start_of_path(line
, word_end
);
778 _err_record_msg(cpl
->err
, "Unable to find the start of the filename.",
783 start_path
= line
+ conf
->file_start
;
786 * Perform the completion.
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
));
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
804 * cfa CplFileArgs * The configuration object of the
805 * cpl_file_completions() callback.
807 void cpl_init_FileArgs(CplFileArgs
*cfa
)
811 cfa
->file_start
= -1;
815 #ifndef WITHOUT_FILE_SYSTEM
816 /*.......................................................................
817 * Initialize a CplFileConf structure with default configuration
821 * cfc CplFileConf * The configuration object of the
822 * cpl_file_completions() callback.
824 static void cpl_init_FileConf(CplFileConf
*cfc
)
827 cfc
->id
= CFC_ID_CODE
;
829 cfc
->file_start
= -1;
831 cfc
->chk_data
= NULL
;
836 /*.......................................................................
837 * Create a new CplFileConf object and initialize it with defaults.
840 * return CplFileConf * The new object, or NULL on error.
842 CplFileConf
*new_CplFileConf(void)
844 #ifdef WITHOUT_FILE_SYSTEM
848 CplFileConf
*cfc
; /* The object to be returned */
850 * Allocate the container.
852 cfc
= (CplFileConf
*)malloc(sizeof(CplFileConf
));
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().
860 cpl_init_FileConf(cfc
);
865 /*.......................................................................
866 * Delete a CplFileConf object.
869 * cfc CplFileConf * The object to be deleted.
871 * return CplFileConf * The deleted object (always NULL).
873 CplFileConf
*del_CplFileConf(CplFileConf
*cfc
)
875 #ifndef WITHOUT_FILE_SYSTEM
878 * Delete the container.
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
893 * cfc CplFileConf * The cpl_file_completions() configuration object
895 * literal int Pass non-zero here to enable literal interpretation
896 * of backslashes. Pass 0 to turn off literal
899 void cfc_literal_escapes(CplFileConf
*cfc
, int literal
)
901 #ifndef WITHOUT_FILE_SYSTEM
903 cfc
->escaped
= !literal
;
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.
915 * cfc CplFileConf * The cpl_file_completions() configuration object
917 * start_index int The index of the start of the filename in
918 * the input line, or -1 to select the default.
920 void cfc_file_start(CplFileConf
*cfc
, int start_index
)
922 #ifndef WITHOUT_FILE_SYSTEM
924 cfc
->file_start
= start_index
;
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.
935 * cfc CplFileConf * The cpl_file_completions() configuration object
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.
943 void cfc_set_check_fn(CplFileConf
*cfc
, CplCheckFn
*chk_fn
, void *chk_data
)
945 #ifndef WITHOUT_FILE_SYSTEM
947 cfc
->chk_fn
= chk_fn
;
948 cfc
->chk_data
= chk_data
;
953 /*.......................................................................
954 * The following CplCheckFn callback returns non-zero if the specified
955 * filename is that of an executable.
957 CPL_CHECK_FN(cpl_check_exe
)
959 #ifdef WITHOUT_FILE_SYSTEM
962 return _pu_path_is_exe(pathname
);
966 /*.......................................................................
967 * Remove duplicates from a sorted array of matches.
970 * cpl WordCompletion * The completion resource object.
972 static void cpl_zap_duplicates(WordCompletion
*cpl
)
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 */
982 * Get the array of matches and the number of matches that it
985 matches
= cpl
->result
.matches
;
986 nmatch
= cpl
->result
.nmatch
;
993 * Initialize the comparison strings with the first match.
995 completion
= matches
[0].completion
;
996 type_suffix
= matches
[0].type_suffix
;
998 * Go through the array of matches, copying each new unrecorded
999 * match at the head of the array, while discarding duplicates.
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) {
1006 matches
[dst
] = *match
;
1008 completion
= match
->completion
;
1009 type_suffix
= match
->type_suffix
;
1013 * Record the number of unique matches that remain.
1015 cpl
->result
.nmatch
= dst
;
1019 /*.......................................................................
1020 * Work out how to arrange a given array of completions into a listing
1021 * of one or more fixed size columns.
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.
1028 * fmt CplListFormat * The formatting information will be assigned
1029 * to the members of *fmt.
1031 static void cpl_plan_listing(CplMatches
*result
, int term_width
,
1034 int maxlen
; /* The length of the longest matching string */
1037 * Ensure that term_width >= 0.
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.
1045 fmt
->term_width
= term_width
;
1046 fmt
->column_width
= 0;
1047 fmt
->nline
= fmt
->ncol
= 0;
1049 * Work out the maximum length of the matching strings.
1052 for(i
=0; i
<result
->nmatch
; i
++) {
1053 CplMatch
*match
= result
->matches
+ i
;
1054 int len
= strlen(match
->completion
) + strlen(match
->type_suffix
);
1064 * Split the available terminal width into columns of
1065 * maxlen + CPL_COL_SEP characters.
1067 fmt
->column_width
= maxlen
;
1068 fmt
->ncol
= fmt
->term_width
/ (fmt
->column_width
+ CPL_COL_SEP
);
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.
1078 * How many lines of output will be needed?
1080 fmt
->nline
= (result
->nmatch
+ fmt
->ncol
- 1) / fmt
->ncol
;
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.
1089 * result CplMatches * The container of the sorted array of
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
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().
1100 * return int 0 - Line printed ok.
1101 * 1 - Nothing to print.
1103 static int cpl_format_line(CplMatches
*result
, CplListFormat
*fmt
, int lnum
,
1104 GlWriteFn
*write_fn
, void *data
)
1106 int col
; /* The index of the list column being output */
1108 * If the line index is out of bounds, there is nothing to be written.
1110 if(lnum
< 0 || lnum
>= fmt
->nline
)
1113 * If no output function has been provided, return as though the
1114 * line had been printed.
1119 * Print the matches in 'ncol' columns, sorted in line order within each
1122 for(col
=0; col
< fmt
->ncol
; col
++) {
1123 int m
= col
*fmt
->nline
+ lnum
;
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.
1129 if(m
< result
->nmatch
) {
1130 CplMatch
*match
= result
->matches
+ m
;
1132 * How long are the completion and type-suffix strings?
1134 int clen
= strlen(match
->completion
);
1135 int tlen
= strlen(match
->type_suffix
);
1137 * Write the completion string.
1139 if(write_fn(data
, match
->completion
, clen
) != clen
)
1142 * Write the type suffix, if any.
1144 if(tlen
> 0 && write_fn(data
, match
->type_suffix
, tlen
) != tlen
)
1147 * If another column follows the current one, pad to its start with spaces.
1149 if(col
+1 < fmt
->ncol
) {
1151 * The following constant string of spaces is used to pad the output.
1153 static const char spaces
[] = " ";
1154 static const int nspace
= sizeof(spaces
) - 1;
1156 * Pad to the next column, using as few sub-strings of the spaces[]
1157 * array as possible.
1159 int npad
= fmt
->column_width
+ CPL_COL_SEP
- clen
- tlen
;
1161 int n
= npad
> nspace
? nspace
: npad
;
1162 if(write_fn(data
, spaces
+ nspace
- n
, n
) != n
)
1175 if(write_fn(data
, s
, n
) != n
)