GRASS GIS 7 Programmer's Manual  7.9.dev(2021)-e5379bbd7
ls.c
Go to the documentation of this file.
1 
2 /**
3  \file lib/gis/ls.c
4 
5  \brief Functions to list the files in a directory.
6 
7  \author Paul Kelly
8 
9  (C) 2007, 2008 by the GRASS Development Team
10 
11  This program is free software under the GNU General Public
12  License (>=v2). Read the file COPYING that comes with GRASS
13  for details.
14 */
15 
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <sys/types.h>
20 #include <dirent.h>
21 #include <unistd.h>
22 
23 #include <grass/gis.h>
24 #include <grass/config.h>
25 #include <grass/glocale.h>
26 
27 #ifdef HAVE_TERMIOS_H
28 # include <termios.h>
29 #endif
30 
31 #ifdef HAVE_SYS_IOCTL_H
32 # include <sys/ioctl.h>
33 #endif
34 
35 typedef int ls_filter_func(const char * /*filename */ , void * /*closure */ );
36 
37 static struct state {
38  ls_filter_func *ls_filter;
39  void *ls_closure;
40  ls_filter_func *ls_ex_filter;
41  void *ls_ex_closure;
42 } state;
43 
44 static struct state *st = &state;
45 
46 static int cmp_names(const void *aa, const void *bb)
47 {
48  char *const *a = (char *const *)aa;
49  char *const *b = (char *const *)bb;
50 
51  return strcmp(*a, *b);
52 }
53 
54 /**
55  * \brief Sets a function and its complementary data for G_ls2 filtering.
56  *
57  * Defines a filter function and its rule data that allow G_ls2 to filter out
58  * unwanted file names. Call this function before G_ls2.
59  *
60  * \param func Filter callback function to compare a file name and closure
61  * pattern (if NULL, no filter will be used).
62  * func(filename, closure) should return 1 on success, 0 on
63  * failure.
64  * \param closure Data used to determine if a file name matches the rule.
65  **/
66 
67 void G_set_ls_filter(ls_filter_func *func, void *closure)
68 {
69  st->ls_filter = func;
70  st->ls_closure = closure;
71 }
72 
73 void G_set_ls_exclude_filter(ls_filter_func *func, void *closure)
74 {
75  st->ls_ex_filter = func;
76  st->ls_ex_closure = closure;
77 }
78 
79 /**
80  * \brief Stores a sorted directory listing in an array
81  *
82  * The filenames in the specified directory are stored in an array of
83  * strings, then sorted alphabetically. Each filename has space allocated
84  * using G_store(), which can be freed using G_free() if necessary. The
85  * same goes for the array itself.
86  *
87  *
88  * \param dir Directory to list
89  * \param num_files Pointer to an integer in which the total number of
90  * files listed will be stored
91  *
92  * \return Pointer to array of strings containing the listing
93  **/
94 
95 char **G_ls2(const char *dir, int *num_files)
96 {
97  struct dirent *dp;
98  DIR *dfd;
99  char **dir_listing = NULL;
100  int n = 0;
101 
102  if ((dfd = opendir(dir)) == NULL)
103  G_fatal_error(_("Unable to open directory %s"), dir);
104 
105  while ((dp = readdir(dfd)) != NULL) {
106  if (dp->d_name[0] == '.') /* Don't list hidden files */
107  continue;
108  if (st->ls_filter && !(*st->ls_filter)(dp->d_name, st->ls_closure))
109  continue;
110  if (st->ls_ex_filter && (*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 
137 void 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 
165 void 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  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
207  = num_items + column_height - (num_items % column_height);
208  char **next;
209 
210  for (i = 1, next = list; i <= num_items; i++) {
211  char **cur = next;
212 
213  next += column_height;
214  if (next >= list + num_items) {
215  /* the next item has to be on the other line */
216  next -= (max - 1 - (next < list + max ? column_height : 0));
217  fprintf(stream, "%s\n", *cur);
218  }
219  else {
220  fprintf(stream, "%-*s", field_width, *cur);
221  }
222  }
223  }
224 }
DIR * opendir()
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
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
int screen_width
Definition: driver/init.c:29
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:149
void G_ls(const char *dir, FILE *stream)
Prints a directory listing to a stream, in prettified column format.
Definition: ls.c:137
#define NULL
Definition: ccmath.h:32
#define max(x, y)
Definition: draw2.c:32
dir_entry * readdir()
struct state * st
Definition: parser.c:104
char ** G_ls2(const char *dir, int *num_files)
Stores a sorted directory listing in an array.
Definition: ls.c:95
double b
Definition: r_raster.c:39
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:67
int ls_filter_func(const char *, void *)
Definition: ls.c:35
Definition: manage.h:4
#define G_realloc(p, n)
Definition: defs/gis.h:114
#define _(str)
Definition: glocale.h:10
char * G_store(const char *)
Copy string to allocated memory.
Definition: strings.c:87
struct state state
Definition: parser.c:103
void G_set_ls_exclude_filter(ls_filter_func *func, void *closure)
Definition: ls.c:73