~martin-decky/helenos/rcu

« back to all changes in this revision

Viewing changes to uspace/app/bdsh/cmds/modules/cat/cat.c

  • Committer: Vojtech Horky
  • Author(s): Taylor Killian
  • Date: 2012-03-27 13:13:06 UTC
  • mto: (1460.2.42 mainline)
  • mto: This revision was merged to the branch mainline in revision 1447.
  • Revision ID: vojtechhorky@users.sourceforge.net-20120327131306-c8usfcb6fha4ro0u
Implement head and tail functionality in bdsh/cat (thx Taylor Killian)

This patch fixes a number of problems in the cat app. Most
importantly, it correctly displays characters at the end of the read
buffer, where previously multibyte characters were being rendered as
U_SPECIAL. It also implements the buffer size argument (-b) that the
--help mentions. The size of the buffer must be at least 4 though in
order to accommodate multibyte characters. Finally head (-H) and tail
(-t) were implemented as per --help.

Show diffs side-by-side

added added

removed removed

Lines of Context:
51
51
static const char *cmdname = "cat";
52
52
#define CAT_VERSION "0.0.1"
53
53
#define CAT_DEFAULT_BUFLEN 1024
 
54
#define CAT_FULL_FILE 0
54
55
 
55
 
static const char *cat_oops = "That option is not yet supported\n";
56
56
static const char *hexchars = "0123456789abcdef";
57
57
 
58
58
static bool paging_enabled = false;
162
162
        }
163
163
}
164
164
 
165
 
static unsigned int cat_file(const char *fname, size_t blen, bool hex)
 
165
static unsigned int cat_file(const char *fname, size_t blen, bool hex,
 
166
    off64_t head, off64_t tail, bool tail_first)
166
167
{
167
168
        int fd, bytes = 0, count = 0, reads = 0;
168
169
        char *buff = NULL;
169
170
        int i;
170
 
        size_t offset = 0;
 
171
        size_t offset = 0, copied_bytes = 0;
 
172
        off64_t file_size = 0, length = 0;
171
173
 
172
174
        fd = open(fname, O_RDONLY);
173
175
        if (fd < 0) {
182
184
                return 1;
183
185
        }
184
186
 
 
187
        if (tail != CAT_FULL_FILE) {
 
188
                file_size = lseek(fd, 0, SEEK_END);
 
189
                if (head == CAT_FULL_FILE) {
 
190
                        head = file_size;
 
191
                        length = tail;
 
192
                } else if (tail_first) {
 
193
                        length = head;
 
194
                } else {
 
195
                        if (tail > head)
 
196
                                tail = head;
 
197
                        length = tail;
 
198
                }
 
199
 
 
200
                if (tail_first) {
 
201
                        lseek(fd, (tail >= file_size) ? 0 : (file_size - tail), SEEK_SET);
 
202
                } else {
 
203
                        lseek(fd, ((head - tail) >= file_size) ? 0 : (head - tail), SEEK_SET);
 
204
                }
 
205
        } else
 
206
                length = head;
 
207
 
185
208
        do {
186
 
                bytes = read(fd, buff, blen);
 
209
                bytes = read(fd, buff + copied_bytes, (
 
210
                        (length != CAT_FULL_FILE && length - (off64_t)count <= (off64_t)(blen - copied_bytes)) ?
 
211
                        (size_t)(length - count) :
 
212
                        (blen - copied_bytes) ) );
 
213
                bytes += copied_bytes;
 
214
                copied_bytes = 0;
 
215
 
187
216
                if (bytes > 0) {
188
 
                        count += bytes;
189
217
                        buff[bytes] = '\0';
190
218
                        offset = 0;
191
219
                        for (i = 0; i < bytes && !should_quit; i++) {
192
220
                                if (hex) {
193
221
                                        paged_char(hexchars[((uint8_t)buff[i])/16]);
194
222
                                        paged_char(hexchars[((uint8_t)buff[i])%16]);
 
223
                                        paged_char(((count+i+1) & 0xf) == 0 ? '\n' : ' ');
195
224
                                }
196
225
                                else {
197
226
                                        wchar_t c = str_decode(buff, &offset, bytes);
198
227
                                        if (c == 0) {
199
228
                                                /* Reached end of string */
200
229
                                                break;
 
230
                                        } else if (c == U_SPECIAL && offset + 2 >= (size_t)bytes) {
 
231
                                                /* If an extended character is cut off due to the size of the buffer,
 
232
                                                   we will copy it over to the next buffer so it can be read correctly. */
 
233
                                                copied_bytes = bytes - offset + 1;
 
234
                                                memcpy(buff, buff + offset - 1, copied_bytes);
 
235
                                                break;
201
236
                                        }
202
237
                                        paged_char(c);
203
238
                                }
204
239
                                
205
240
                        }
 
241
                        count += bytes;
206
242
                        reads++;
207
243
                }
208
 
        } while (bytes > 0 && !should_quit);
 
244
        } while (bytes > 0 && !should_quit && (count < length || length == CAT_FULL_FILE));
209
245
 
210
246
        close(fd);
211
247
        if (bytes == -1) {
222
258
/* Main entry point for cat, accepts an array of arguments */
223
259
int cmd_cat(char **argv)
224
260
{
225
 
        unsigned int argc, i, ret = 0, buffer = 0;
 
261
        unsigned int argc, i, ret = 0;
 
262
        size_t buffer = 0;
226
263
        int c, opt_ind;
 
264
        aoff64_t head = CAT_FULL_FILE, tail = CAT_FULL_FILE;
227
265
        bool hex = false;
228
266
        bool more = false;
 
267
        bool tailFirst = false;
229
268
        sysarg_t rows, cols;
230
269
        int rc;
231
270
        
253
292
                        printf("%s\n", CAT_VERSION);
254
293
                        return CMD_SUCCESS;
255
294
                case 'H':
256
 
                        printf("%s", cat_oops);
257
 
                        return CMD_FAILURE;
 
295
                        if (!optarg || str_uint64_t(optarg, NULL, 10, false, &head) != EOK ) {
 
296
                                puts("Invalid head size\n");
 
297
                                return CMD_FAILURE;
 
298
                        }
 
299
                        break;
258
300
                case 't':
259
 
                        printf("%s", cat_oops);
260
 
                        return CMD_FAILURE;
 
301
                        if (!optarg || str_uint64_t(optarg, NULL, 10, false, &tail) != EOK ) {
 
302
                                puts("Invalid tail size\n");
 
303
                                return CMD_FAILURE;
 
304
                        }
 
305
                        if (head == CAT_FULL_FILE)
 
306
                                tailFirst = true;
 
307
                        break;
261
308
                case 'b':
262
 
                        printf("%s", cat_oops);
 
309
                        if (!optarg || str_size_t(optarg, NULL, 10, false, &buffer) != EOK ) {
 
310
                                puts("Invalid buffer size\n");
 
311
                                return CMD_FAILURE;
 
312
                        }
263
313
                        break;
264
314
                case 'm':
265
315
                        more = true;
278
328
                return CMD_FAILURE;
279
329
        }
280
330
 
281
 
        if (buffer <= 0)
 
331
        if (buffer < 4)
282
332
                buffer = CAT_DEFAULT_BUFLEN;
283
333
        
284
334
        if (more) {
294
344
        }
295
345
 
296
346
        for (i = optind; argv[i] != NULL && !should_quit; i++)
297
 
                ret += cat_file(argv[i], buffer, hex);
 
347
                ret += cat_file(argv[i], buffer, hex, head, tail, tailFirst);
298
348
 
299
349
        if (ret)
300
350
                return CMD_FAILURE;