Branch data Line data Source code
1 : : /*
2 : : * Copyright 2015 Red Hat, Inc.
3 : : *
4 : : * SPDX-License-Identifier: LGPL-2.1-or-later
5 : : *
6 : : * This library is free software; you can redistribute it and/or
7 : : * modify it under the terms of the GNU Lesser General Public
8 : : * License as published by the Free Software Foundation; either
9 : : * version 2.1 of the License, or (at your option) any later version.
10 : : *
11 : : * This library is distributed in the hope that it will be useful,
12 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : : * Lesser General Public License for more details.
15 : : *
16 : : * You should have received a copy of the GNU Lesser General Public
17 : : * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 : : *
19 : : * Author: Matthias Clasen <mclasen@redhat.com>
20 : : */
21 : :
22 : : #include "config.h"
23 : :
24 : : #include <gio/gio.h>
25 : : #include <gi18n.h>
26 : : #include <errno.h>
27 : :
28 : : #ifdef G_OS_WIN32
29 : : #include <io.h>
30 : : #endif
31 : :
32 : : #ifndef STDOUT_FILENO
33 : : #define STDOUT_FILENO 1
34 : : #endif
35 : :
36 : : #ifdef HAVE_UNISTD_H
37 : : #include <unistd.h>
38 : : #endif
39 : :
40 : : #include "gio-tool.h"
41 : :
42 : :
43 : : static const GOptionEntry entries[] = {
44 : : G_OPTION_ENTRY_NULL
45 : : };
46 : :
47 : : /* 256k minus malloc overhead */
48 : : #define STREAM_BUFFER_SIZE (1024*256 - 2*sizeof(gpointer))
49 : :
50 : : static gboolean
51 : 0 : cat (GFile *file)
52 : : {
53 : : GInputStream *in;
54 : : char *buffer;
55 : : char *p;
56 : : gssize res;
57 : : gboolean close_res;
58 : : GError *error;
59 : : gboolean success;
60 : :
61 : 0 : error = NULL;
62 : 0 : in = (GInputStream *) g_file_read (file, NULL, &error);
63 : 0 : if (in == NULL)
64 : : {
65 : 0 : print_file_error (file, error->message);
66 : 0 : g_error_free (error);
67 : 0 : return FALSE;
68 : : }
69 : :
70 : 0 : buffer = g_malloc (STREAM_BUFFER_SIZE);
71 : 0 : success = TRUE;
72 : : while (1)
73 : : {
74 : 0 : res = g_input_stream_read (in, buffer, STREAM_BUFFER_SIZE, NULL, &error);
75 : 0 : if (res > 0)
76 : : {
77 : : gssize written;
78 : :
79 : 0 : p = buffer;
80 : 0 : while (res > 0)
81 : : {
82 : : int errsv;
83 : :
84 : 0 : written = write (STDOUT_FILENO, p, res);
85 : 0 : errsv = errno;
86 : :
87 : 0 : if (written == -1 && errsv != EINTR)
88 : : {
89 : 0 : print_error ("%s", _("Error writing to stdout"));
90 : 0 : success = FALSE;
91 : 0 : goto out;
92 : : }
93 : 0 : res -= written;
94 : 0 : p += written;
95 : : }
96 : : }
97 : 0 : else if (res < 0)
98 : : {
99 : 0 : print_file_error (file, error->message);
100 : 0 : g_error_free (error);
101 : 0 : error = NULL;
102 : 0 : success = FALSE;
103 : 0 : break;
104 : : }
105 : 0 : else if (res == 0)
106 : 0 : break;
107 : : }
108 : :
109 : 0 : out:
110 : 0 : close_res = g_input_stream_close (in, NULL, &error);
111 : 0 : if (!close_res)
112 : : {
113 : 0 : print_file_error (file, error->message);
114 : 0 : g_error_free (error);
115 : 0 : success = FALSE;
116 : : }
117 : :
118 : 0 : g_free (buffer);
119 : :
120 : 0 : return success;
121 : : }
122 : :
123 : : int
124 : 0 : handle_cat (int argc, char *argv[], gboolean do_help)
125 : : {
126 : : GOptionContext *context;
127 : : gchar *param;
128 : 0 : GError *error = NULL;
129 : : int i;
130 : : gboolean res;
131 : : GFile *file;
132 : :
133 : 0 : g_set_prgname ("gio cat");
134 : : /* Translators: commandline placeholder */
135 : 0 : param = g_strdup_printf ("%s…", _("LOCATION"));
136 : 0 : context = g_option_context_new (param);
137 : 0 : g_free (param);
138 : 0 : g_option_context_set_help_enabled (context, FALSE);
139 : 0 : g_option_context_set_summary (context,
140 : 0 : _("Concatenate files and print to standard output."));
141 : 0 : g_option_context_set_description (context,
142 : 0 : _("gio cat works just like the traditional cat utility, but using GIO\n"
143 : : "locations instead of local files: for example, you can use something\n"
144 : : "like smb://server/resource/file.txt as location."));
145 : 0 : g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
146 : :
147 : 0 : if (do_help)
148 : : {
149 : 0 : show_help (context, NULL);
150 : 0 : g_option_context_free (context);
151 : 0 : return 0;
152 : : }
153 : :
154 : 0 : if (!g_option_context_parse (context, &argc, &argv, &error))
155 : : {
156 : 0 : show_help (context, error->message);
157 : 0 : g_error_free (error);
158 : 0 : g_option_context_free (context);
159 : 0 : return 1;
160 : : }
161 : :
162 : 0 : if (argc < 2)
163 : : {
164 : 0 : show_help (context, _("No locations given"));
165 : 0 : g_option_context_free (context);
166 : 0 : return 1;
167 : : }
168 : :
169 : 0 : g_option_context_free (context);
170 : :
171 : 0 : res = TRUE;
172 : 0 : for (i = 1; i < argc; i++)
173 : : {
174 : 0 : file = g_file_new_for_commandline_arg (argv[i]);
175 : 0 : res &= cat (file);
176 : 0 : g_object_unref (file);
177 : : }
178 : :
179 : 0 : return res ? 0 : 2;
180 : : }
|