GRASS GIS 8 Programmer's Manual  8.4.0dev(2024)-f8115df121
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 
34 typedef int ls_filter_func(const char * /*filename */, void * /*closure */);
35 
36 static 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 
43 static struct state *st = &state;
44 
45 static 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 
66 void G_set_ls_filter(ls_filter_func *func, void *closure)
67 {
68  st->ls_filter = func;
69  st->ls_closure = closure;
70 }
71 
72 void 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 
94 char **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 
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  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 }
#define NULL
Definition: ccmath.h:32
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:150
#define G_realloc(p, n)
Definition: defs/gis.h:96
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
char * G_store(const char *)
Copy string to allocated memory.
Definition: strings.c:87
#define max(x, y)
Definition: draw2.c:30
int screen_width
Definition: driver/init.c:29
#define _(str)
Definition: glocale.h:10
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
int ls_filter_func(const char *, void *)
Definition: ls.c:34
char ** G_ls2(const char *dir, int *num_files)
Stores a sorted directory listing in an array.
Definition: ls.c:94
void G_set_ls_exclude_filter(ls_filter_func *func, void *closure)
Definition: ls.c:72
struct state state
Definition: parser.c:103
struct state * st
Definition: parser.c:104
double b
Definition: r_raster.c:39
Definition: manage.h:4