GRASS GIS 8 Programmer's Manual 8.3.2(2024)-exported
Loading...
Searching...
No Matches
ls.c
Go to the documentation of this file.
1/**
2 \file lib/gis/ls.c
3
4 \brief Functions to list the files in a directory.
5
6 \author Paul Kelly
7
8 (C) 2007, 2008 by the GRASS Development Team
9
10 This program is free software under the GNU General Public
11 License (>=v2). Read the file COPYING that comes with GRASS
12 for details.
13*/
14
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18#include <sys/types.h>
19#include <dirent.h>
20#include <unistd.h>
21
22#include <grass/gis.h>
23#include <grass/config.h>
24#include <grass/glocale.h>
25
26#ifdef HAVE_TERMIOS_H
27#include <termios.h>
28#endif
29
30#ifdef HAVE_SYS_IOCTL_H
31#include <sys/ioctl.h>
32#endif
33
34typedef int ls_filter_func(const char * /*filename */, void * /*closure */);
35
36static struct state {
37 ls_filter_func *ls_filter;
38 void *ls_closure;
39 ls_filter_func *ls_ex_filter;
40 void *ls_ex_closure;
41} state;
42
43static struct state *st = &state;
44
45static int cmp_names(const void *aa, const void *bb)
46{
47 char *const *a = (char *const *)aa;
48 char *const *b = (char *const *)bb;
49
50 return strcmp(*a, *b);
51}
52
53/**
54 * \brief Sets a function and its complementary data for G_ls2 filtering.
55 *
56 * Defines a filter function and its rule data that allow G_ls2 to filter out
57 * unwanted file names. Call this function before G_ls2.
58 *
59 * \param func Filter callback function to compare a file name and closure
60 * pattern (if NULL, no filter will be used).
61 * func(filename, closure) should return 1 on success, 0 on
62 * failure.
63 * \param closure Data used to determine if a file name matches the rule.
64 **/
65
66void G_set_ls_filter(ls_filter_func *func, void *closure)
67{
68 st->ls_filter = func;
69 st->ls_closure = closure;
70}
71
72void G_set_ls_exclude_filter(ls_filter_func *func, void *closure)
73{
74 st->ls_ex_filter = func;
75 st->ls_ex_closure = closure;
76}
77
78/**
79 * \brief Stores a sorted directory listing in an array
80 *
81 * The filenames in the specified directory are stored in an array of
82 * strings, then sorted alphabetically. Each filename has space allocated
83 * using G_store(), which can be freed using G_free() if necessary. The
84 * same goes for the array itself.
85 *
86 *
87 * \param dir Directory to list
88 * \param num_files Pointer to an integer in which the total number of
89 * files listed will be stored
90 *
91 * \return Pointer to array of strings containing the listing
92 **/
93
94char **G_ls2(const char *dir, int *num_files)
95{
96 struct dirent *dp;
97 DIR *dfd;
98 char **dir_listing = NULL;
99 int n = 0;
100
101 if ((dfd = opendir(dir)) == NULL)
102 G_fatal_error(_("Unable to open directory %s"), dir);
103
104 while ((dp = readdir(dfd)) != NULL) {
105 if (dp->d_name[0] == '.') /* Don't list hidden files */
106 continue;
107 if (st->ls_filter && !(*st->ls_filter)(dp->d_name, st->ls_closure))
108 continue;
109 if (st->ls_ex_filter &&
110 (*st->ls_ex_filter)(dp->d_name, st->ls_ex_closure))
111 continue;
112 dir_listing = (char **)G_realloc(dir_listing, (1 + n) * sizeof(char *));
113 dir_listing[n] = G_store(dp->d_name);
114 n++;
115 }
116 closedir(dfd);
117
118 /* Sort list of filenames alphabetically */
119 qsort(dir_listing, n, sizeof(char *), cmp_names);
120
121 *num_files = n;
122 return dir_listing;
123}
124
125/**
126 * \brief Prints a directory listing to a stream, in prettified column format
127 *
128 * A replacement for system("ls -C"). Lists the contents of the directory
129 * specified to the given stream, e.g. stderr. Tries to determine an
130 * appropriate column width to keep the number of lines used to a minimum
131 * and look pretty on the screen.
132 *
133 * \param dir Directory to list
134 * \param stream Stream to print listing to
135 **/
136
137void G_ls(const char *dir, FILE *stream)
138{
139 int i, n;
140 char **dir_listing = G_ls2(dir, &n);
141
142 G_ls_format(dir_listing, n, 0, stream);
143
144 for (i = 0; i < n; i++)
145 G_free(dir_listing[i]);
146
147 G_free(dir_listing);
148}
149
150/**
151 * \brief Prints a listing of items to a stream, in prettified column format
152 *
153 * Lists the contents of the array passed to the given stream, e.g. stderr.
154 * Prints the number of items specified by "perline" to each line, unless
155 * perline is given as 0 in which case the function tries to determine an
156 * appropriate column width to keep the number of lines used to a minimum
157 * and look pretty on the screen.
158 *
159 * \param list Array of strings containing items to be printed
160 * \param num_items Number of items in the array
161 * \param perline Number of items to print per line, 0 for autodetect
162 * \param stream Stream to print listing to
163 **/
164
165void G_ls_format(char **list, int num_items, int perline, FILE *stream)
166{
167 int i;
168
169 int field_width, column_height;
170 int screen_width = 80; /* Default width of 80 columns */
171
172 if (num_items < 1)
173 return; /* Nothing to print */
174
175#ifdef TIOCGWINSZ
176 /* Determine screen_width if possible */
177 {
178 struct winsize size;
179
180 if (ioctl(fileno(stream), TIOCGWINSZ, (char *)&size) == 0)
181 screen_width = size.ws_col;
182 }
183#endif
184
185 if (perline == 0) {
186 unsigned int max_len = 0;
187
188 for (i = 0; i < num_items; i++) {
189 /* Find maximum filename length */
190 if (strlen(list[i]) > max_len)
191 max_len = strlen(list[i]);
192 }
193 /* Auto-fit the number of items that will
194 * fit per line (+1 because of space after item) */
195 perline = screen_width / (max_len + 1);
196 if (perline < 1)
197 perline = 1;
198 }
199
200 /* Field width to accommodate longest filename */
201 field_width = screen_width / perline;
202 /* Longest column height (i.e. num_items <= perline * column_height) */
203 column_height = (num_items / perline) + ((num_items % perline) > 0);
204
205 {
206 const int max = num_items + column_height - (num_items % column_height);
207 char **next;
208
209 for (i = 1, next = list; i <= num_items; i++) {
210 char **cur = next;
211
212 next += column_height;
213 if (next >= list + num_items) {
214 /* the next item has to be on the other line */
215 next -= (max - 1 - (next < list + max ? column_height : 0));
216 fprintf(stream, "%s\n", *cur);
217 }
218 else {
219 fprintf(stream, "%-*s", field_width, *cur);
220 }
221 }
222 }
223}
void G_free(void *buf)
Free allocated memory.
Definition alloc.c:150
#define NULL
Definition ccmath.h:32
double b
int screen_width
Definition driver/init.c:29
void G_fatal_error(const char *msg,...)
Print a fatal error message to stderr.
Definition gis/error.c:159
void G_ls(const char *dir, FILE *stream)
Prints a directory listing to a stream, in prettified column format.
Definition ls.c:137
void G_ls_format(char **list, int num_items, int perline, FILE *stream)
Prints a listing of items to a stream, in prettified column format.
Definition ls.c:165
void G_set_ls_filter(ls_filter_func *func, void *closure)
Sets a function and its complementary data for G_ls2 filtering.
Definition ls.c:66
char ** G_ls2(const char *dir, int *num_files)
Stores a sorted directory listing in an array.
Definition ls.c:94
int ls_filter_func(const char *, void *)
Definition ls.c:34
void G_set_ls_exclude_filter(ls_filter_func *func, void *closure)
Definition ls.c:72
#define max(a, b)
struct list * list
Definition read_list.c:24
char * G_store(const char *s)
Copy string to allocated memory.
Definition strings.c:87