• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <errno.h>
25 
26 #ifdef G_OS_WIN32
27 #include <io.h>
28 #endif
29 
30 #ifndef STDOUT_FILENO
31 #define STDOUT_FILENO 1
32 #endif
33 
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37 
38 #include "gio-tool.h"
39 
40 
41 static const GOptionEntry entries[] = {
42   { NULL }
43 };
44 
45 /* 256k minus malloc overhead */
46 #define STREAM_BUFFER_SIZE (1024*256 - 2*sizeof(gpointer))
47 
48 static gboolean
cat(GFile * file)49 cat (GFile *file)
50 {
51   GInputStream *in;
52   char *buffer;
53   char *p;
54   gssize res;
55   gboolean close_res;
56   GError *error;
57   gboolean success;
58 
59   error = NULL;
60   in = (GInputStream *) g_file_read (file, NULL, &error);
61   if (in == NULL)
62     {
63       print_file_error (file, error->message);
64       g_error_free (error);
65       return FALSE;
66     }
67 
68   buffer = g_malloc (STREAM_BUFFER_SIZE);
69   success = TRUE;
70   while (1)
71     {
72       res = g_input_stream_read (in, buffer, STREAM_BUFFER_SIZE, NULL, &error);
73       if (res > 0)
74         {
75           gssize written;
76 
77           p = buffer;
78           while (res > 0)
79             {
80               int errsv;
81 
82               written = write (STDOUT_FILENO, p, res);
83               errsv = errno;
84 
85               if (written == -1 && errsv != EINTR)
86                 {
87                   print_error ("%s", _("Error writing to stdout"));
88                   success = FALSE;
89                   goto out;
90                 }
91               res -= written;
92               p += written;
93             }
94         }
95       else if (res < 0)
96         {
97           print_file_error (file, error->message);
98           g_error_free (error);
99           error = NULL;
100           success = FALSE;
101           break;
102         }
103       else if (res == 0)
104         break;
105     }
106 
107  out:
108  close_res = g_input_stream_close (in, NULL, &error);
109   if (!close_res)
110     {
111       print_file_error (file, error->message);
112       g_error_free (error);
113       success = FALSE;
114     }
115 
116   g_free (buffer);
117 
118   return success;
119 }
120 
121 int
handle_cat(int argc,char * argv[],gboolean do_help)122 handle_cat (int argc, char *argv[], gboolean do_help)
123 {
124   GOptionContext *context;
125   gchar *param;
126   GError *error = NULL;
127   int i;
128   gboolean res;
129   GFile *file;
130 
131   g_set_prgname ("gio cat");
132   /* Translators: commandline placeholder */
133   param = g_strdup_printf ("%s…", _("LOCATION"));
134   context = g_option_context_new (param);
135   g_free (param);
136   g_option_context_set_help_enabled (context, FALSE);
137   g_option_context_set_summary (context,
138       _("Concatenate files and print to standard output."));
139   g_option_context_set_description (context,
140       _("gio cat works just like the traditional cat utility, but using GIO\n"
141         "locations instead of local files: for example, you can use something\n"
142         "like smb://server/resource/file.txt as location."));
143   g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
144 
145   if (do_help)
146     {
147       show_help (context, NULL);
148       g_option_context_free (context);
149       return 0;
150     }
151 
152   if (!g_option_context_parse (context, &argc, &argv, &error))
153     {
154       show_help (context, error->message);
155       g_error_free (error);
156       g_option_context_free (context);
157       return 1;
158     }
159 
160   if (argc < 2)
161     {
162       show_help (context, _("No locations given"));
163       g_option_context_free (context);
164       return 1;
165     }
166 
167   g_option_context_free (context);
168 
169   res = TRUE;
170   for (i = 1; i < argc; i++)
171     {
172       file = g_file_new_for_commandline_arg (argv[i]);
173       res &= cat (file);
174       g_object_unref (file);
175     }
176 
177   return res ? 0 : 2;
178 }
179