1 | /* |
2 | * Copyright 2015 Red Hat, Inc. |
3 | * |
4 | * This library is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Lesser General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2.1 of the License, or (at your option) any later version. |
8 | * |
9 | * This library is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * Lesser General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU Lesser General Public |
15 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
16 | * |
17 | * Author: Matthias Clasen <mclasen@redhat.com> |
18 | */ |
19 | |
20 | #include "config.h" |
21 | |
22 | #include <gio/gio.h> |
23 | #include <gi18n.h> |
24 | |
25 | #include "gio-tool.h" |
26 | |
27 | |
28 | static char *attributes = NULL; |
29 | static gboolean show_hidden = FALSE; |
30 | static gboolean show_long = FALSE; |
31 | static gboolean nofollow_symlinks = FALSE; |
32 | static gboolean print_display_names = FALSE; |
33 | static gboolean print_uris = FALSE; |
34 | |
35 | static const GOptionEntry entries[] = { |
36 | { "attributes" , 'a', 0, G_OPTION_ARG_STRING, &attributes, N_("The attributes to get" ), N_("ATTRIBUTES" ) }, |
37 | { "hidden" , 'h', 0, G_OPTION_ARG_NONE, &show_hidden, N_("Show hidden files" ), NULL }, |
38 | { "long" , 'l', 0, G_OPTION_ARG_NONE, &show_long, N_("Use a long listing format" ), NULL }, |
39 | { "nofollow-symlinks" , 'n', 0, G_OPTION_ARG_NONE, &nofollow_symlinks, N_("Don’t follow symbolic links" ), NULL}, |
40 | { "print-display-names" , 'd', 0, G_OPTION_ARG_NONE, &print_display_names, N_("Print display names" ), NULL }, |
41 | { "print-uris" , 'u', 0, G_OPTION_ARG_NONE, &print_uris, N_("Print full URIs" ), NULL}, |
42 | { NULL } |
43 | }; |
44 | |
45 | static void |
46 | show_file_listing (GFileInfo *info, GFile *parent) |
47 | { |
48 | const char *name, *type; |
49 | char *uri = NULL; |
50 | goffset size; |
51 | char **attributes; |
52 | int i; |
53 | gboolean first_attr; |
54 | GFile *child; |
55 | |
56 | if ((g_file_info_get_is_hidden (info)) && !show_hidden) |
57 | return; |
58 | |
59 | if (print_display_names) |
60 | name = g_file_info_get_display_name (info); |
61 | else |
62 | name = g_file_info_get_name (info); |
63 | |
64 | if (name == NULL) |
65 | name = "" ; |
66 | |
67 | if (print_uris) { |
68 | child = g_file_get_child (file: parent, name); |
69 | uri = g_file_get_uri (file: child); |
70 | g_object_unref (object: child); |
71 | } |
72 | |
73 | size = g_file_info_get_size (info); |
74 | type = file_type_to_string (type: g_file_info_get_file_type (info)); |
75 | if (show_long) |
76 | g_print (format: "%s\t%" G_GUINT64_FORMAT"\t(%s)" , print_uris? uri: name, (guint64)size, type); |
77 | else |
78 | g_print (format: "%s" , print_uris? uri: name); |
79 | |
80 | if (print_uris) |
81 | g_free (mem: uri); |
82 | |
83 | first_attr = TRUE; |
84 | attributes = g_file_info_list_attributes (info, NULL); |
85 | for (i = 0 ; attributes[i] != NULL; i++) |
86 | { |
87 | char *val_as_string; |
88 | |
89 | if (!show_long || |
90 | (!print_display_names && strcmp (s1: attributes[i], G_FILE_ATTRIBUTE_STANDARD_NAME) == 0) || |
91 | (print_display_names && strcmp (s1: attributes[i], G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME) == 0) || |
92 | strcmp (s1: attributes[i], G_FILE_ATTRIBUTE_STANDARD_SIZE) == 0 || |
93 | strcmp (s1: attributes[i], G_FILE_ATTRIBUTE_STANDARD_TYPE) == 0 || |
94 | strcmp (s1: attributes[i], G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN) == 0) |
95 | continue; |
96 | |
97 | if (first_attr) |
98 | { |
99 | g_print (format: "\t" ); |
100 | first_attr = FALSE; |
101 | } |
102 | else |
103 | g_print (format: " " ); |
104 | val_as_string = g_file_info_get_attribute_as_string (info, attribute: attributes[i]); |
105 | g_print (format: "%s=%s" , attributes[i], val_as_string); |
106 | g_free (mem: val_as_string); |
107 | } |
108 | |
109 | g_strfreev (str_array: attributes); |
110 | |
111 | g_print (format: "\n" ); |
112 | } |
113 | |
114 | static gboolean |
115 | list (GFile *file) |
116 | { |
117 | GFileEnumerator *enumerator; |
118 | GFileInfo *info; |
119 | GError *error; |
120 | gboolean res; |
121 | |
122 | error = NULL; |
123 | enumerator = g_file_enumerate_children (file, |
124 | attributes, |
125 | flags: nofollow_symlinks ? G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS : 0, |
126 | NULL, |
127 | error: &error); |
128 | if (enumerator == NULL) |
129 | { |
130 | print_file_error (file, message: error->message); |
131 | g_error_free (error); |
132 | return FALSE; |
133 | } |
134 | |
135 | res = TRUE; |
136 | while ((info = g_file_enumerator_next_file (enumerator, NULL, error: &error)) != NULL) |
137 | { |
138 | show_file_listing (info, parent: file); |
139 | g_object_unref (object: info); |
140 | } |
141 | |
142 | if (error) |
143 | { |
144 | print_file_error (file, message: error->message); |
145 | g_clear_error (err: &error); |
146 | res = FALSE; |
147 | } |
148 | |
149 | if (!g_file_enumerator_close (enumerator, NULL, error: &error)) |
150 | { |
151 | print_file_error (file, message: error->message); |
152 | g_clear_error (err: &error); |
153 | res = FALSE; |
154 | } |
155 | |
156 | return res; |
157 | } |
158 | |
159 | int |
160 | handle_list (int argc, char *argv[], gboolean do_help) |
161 | { |
162 | GOptionContext *context; |
163 | gchar *param; |
164 | GError *error = NULL; |
165 | gboolean res; |
166 | gint i; |
167 | GFile *file; |
168 | |
169 | g_set_prgname (prgname: "gio list" ); |
170 | |
171 | /* Translators: commandline placeholder */ |
172 | param = g_strdup_printf (format: "[%s…]" , _("LOCATION" )); |
173 | context = g_option_context_new (parameter_string: param); |
174 | g_free (mem: param); |
175 | g_option_context_set_help_enabled (context, FALSE); |
176 | g_option_context_set_summary (context, |
177 | _("List the contents of the locations." )); |
178 | g_option_context_set_description (context, |
179 | _("gio list is similar to the traditional ls utility, but using GIO\n" |
180 | "locations instead of local files: for example, you can use something\n" |
181 | "like smb://server/resource/file.txt as location. File attributes can\n" |
182 | "be specified with their GIO name, e.g. standard::icon" )); |
183 | g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); |
184 | |
185 | if (do_help) |
186 | { |
187 | show_help (context, NULL); |
188 | g_option_context_free (context); |
189 | return 0; |
190 | } |
191 | |
192 | if (!g_option_context_parse (context, argc: &argc, argv: &argv, error: &error)) |
193 | { |
194 | show_help (context, message: error->message); |
195 | g_error_free (error); |
196 | g_option_context_free (context); |
197 | return 1; |
198 | } |
199 | |
200 | g_option_context_free (context); |
201 | |
202 | if (attributes != NULL) |
203 | show_long = TRUE; |
204 | |
205 | attributes = g_strconcat (string1: !print_display_names ? G_FILE_ATTRIBUTE_STANDARD_NAME "," : "" , |
206 | print_display_names ? G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME "," : "" , |
207 | G_FILE_ATTRIBUTE_STANDARD_TYPE "," |
208 | G_FILE_ATTRIBUTE_STANDARD_SIZE "," |
209 | G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN, |
210 | attributes != NULL ? "," : "" , |
211 | attributes, |
212 | NULL); |
213 | |
214 | res = TRUE; |
215 | if (argc > 1) |
216 | { |
217 | for (i = 1; i < argc; i++) |
218 | { |
219 | file = g_file_new_for_commandline_arg (arg: argv[i]); |
220 | res &= list (file); |
221 | g_object_unref (object: file); |
222 | } |
223 | } |
224 | else |
225 | { |
226 | char *cwd; |
227 | |
228 | cwd = g_get_current_dir (); |
229 | file = g_file_new_for_path (path: cwd); |
230 | res = list (file); |
231 | g_object_unref (object: file); |
232 | g_free (mem: cwd); |
233 | } |
234 | |
235 | g_free (mem: attributes); |
236 | |
237 | return res ? 0 : 2; |
238 | } |
239 | |