cat.c

00001 /* Copyright (c) 2008, Tim Post <tinkertim@gmail.com>
00002  * Copyright (c) 2011, Martin Sucha
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *
00008  * Redistributions of source code must retain the above copyright notice, this
00009  * list of conditions and the following disclaimer.
00010  *
00011  * Redistributions in binary form must reproduce the above copyright notice,
00012  * this list of conditions and the following disclaimer in the documentation
00013  * and/or other materials provided with the distribution.
00014  *
00015  * Neither the name of the original program's authors nor the names of its
00016  * contributors may be used to endorse or promote products derived from this
00017  * software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00020  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00021  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00022  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00023  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00024  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00025  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00026  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00027  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00028  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00029  * POSSIBILITY OF SUCH DAMAGE.
00030  */
00031 
00032 #include <stdio.h>
00033 #include <stdlib.h>
00034 #include <unistd.h>
00035 #include <getopt.h>
00036 #include <str.h>
00037 #include <fcntl.h>
00038 #include <io/console.h>
00039 #include <io/color.h>
00040 #include <io/style.h>
00041 #include <io/keycode.h>
00042 #include <errno.h>
00043 #include <vfs/vfs.h>
00044 #include <assert.h>
00045 
00046 #include "config.h"
00047 #include "util.h"
00048 #include "errors.h"
00049 #include "entry.h"
00050 #include "cat.h"
00051 #include "cmds.h"
00052 
00053 static const char *cmdname = "cat";
00054 #define CAT_VERSION "0.0.1"
00055 #define CAT_DEFAULT_BUFLEN 1024
00056 
00057 static const char *cat_oops = "That option is not yet supported\n";
00058 static const char *hexchars = "0123456789abcdef";
00059 
00060 static bool paging_enabled = false;
00061 static size_t chars_remaining = 0;
00062 static size_t lines_remaining = 0;
00063 static sysarg_t console_cols = 0;
00064 static sysarg_t console_rows = 0;
00065 static bool should_quit = false;
00066 
00067 static struct option const long_options[] = {
00068         { "help", no_argument, 0, 'h' },
00069         { "version", no_argument, 0, 'v' },
00070         { "head", required_argument, 0, 'H' },
00071         { "tail", required_argument, 0, 't' },
00072         { "buffer", required_argument, 0, 'b' },
00073         { "more", no_argument, 0, 'm' },
00074         { "hex", no_argument, 0, 'x' },
00075         { 0, 0, 0, 0 }
00076 };
00077 
00078 /* Dispays help for cat in various levels */
00079 void help_cmd_cat(unsigned int level)
00080 {
00081         if (level == HELP_SHORT) {
00082                 printf("`%s' shows the contents of files\n", cmdname);
00083         } else {
00084                 help_cmd_cat(HELP_SHORT);
00085                 printf(
00086                 "Usage:  %s [options] <file1> [file2] [...]\n"
00087                 "Options:\n"
00088                 "  -h, --help       A short option summary\n"
00089                 "  -v, --version    Print version information and exit\n"
00090                 "  -H, --head ##    Print only the first ## bytes\n"
00091                 "  -t, --tail ##    Print only the last ## bytes\n"
00092                 "  -b, --buffer ##  Set the read buffer size to ##\n"
00093                 "  -m, --more       Pause after each screen full\n"
00094                 "  -x, --hex        Print bytes as hex values\n"
00095                 "Currently, %s is under development, some options don't work.\n",
00096                 cmdname, cmdname);
00097         }
00098 
00099         return;
00100 }
00101 
00102 static void waitprompt()
00103 {
00104         console_set_pos(fphone(stdout), 0, console_rows-1);
00105         console_set_color(fphone(stdout), COLOR_BLUE, COLOR_WHITE, 0);
00106         printf("ENTER/SPACE/PAGE DOWN - next page, "
00107                "ESC/Q - quit, C - continue unpaged");
00108         fflush(stdout);
00109         console_set_style(fphone(stdout), STYLE_NORMAL);
00110 }
00111 
00112 static void waitkey()
00113 {
00114         console_event_t ev;
00115         
00116         while (true) {
00117                 if (!console_get_event(fphone(stdin), &ev)) {
00118                         return;
00119                 }
00120                 if (ev.type == KEY_PRESS) {
00121                         if (ev.key == KC_ESCAPE || ev.key == KC_Q) {
00122                                 should_quit = true;
00123                                 return;
00124                         }
00125                         if (ev.key == KC_C) {
00126                                 paging_enabled = false;
00127                                 return;
00128                         }
00129                         if (ev.key == KC_ENTER || ev.key == KC_SPACE ||
00130                             ev.key == KC_PAGE_DOWN) {
00131                                 return;
00132                         }
00133                 }
00134         }
00135         assert(false);
00136 }
00137 
00138 static void newpage()
00139 {
00140         console_clear(fphone(stdout));
00141         chars_remaining = console_cols;
00142         lines_remaining = console_rows-1;
00143 }
00144 
00145 static void paged_char(wchar_t c)
00146 {
00147         putchar(c);
00148         if (paging_enabled) {
00149                 chars_remaining--;
00150                 if (c == '\n' || chars_remaining == 0) {
00151                         chars_remaining = console_cols;
00152                         lines_remaining--;
00153                 }
00154                 if (lines_remaining == 0) {
00155                         fflush(stdout);
00156                         waitprompt();
00157                         waitkey();
00158                         newpage();
00159                 }
00160         }
00161 }
00162 
00163 static unsigned int cat_file(const char *fname, size_t blen, bool hex)
00164 {
00165         int fd, bytes = 0, count = 0, reads = 0;
00166         char *buff = NULL;
00167         int i;
00168         size_t offset = 0;
00169 
00170         fd = open(fname, O_RDONLY);
00171         if (fd < 0) {
00172                 printf("Unable to open %s\n", fname);
00173                 return 1;
00174         }
00175 
00176         if (NULL == (buff = (char *) malloc(blen + 1))) {
00177                 close(fd);
00178                 printf("Unable to allocate enough memory to read %s\n",
00179                         fname);
00180                 return 1;
00181         }
00182 
00183         do {
00184                 bytes = read(fd, buff, blen);
00185                 if (bytes > 0) {
00186                         count += bytes;
00187                         buff[bytes] = '\0';
00188                         offset = 0;
00189                         for (i = 0; i < bytes && !should_quit; i++) {
00190                                 if (hex) {
00191                                         paged_char(hexchars[((uint8_t)buff[i])/16]);
00192                                         paged_char(hexchars[((uint8_t)buff[i])%16]);
00193                                 }
00194                                 else {
00195                                         wchar_t c = str_decode(buff, &offset, bytes);
00196                                         if (c == 0) {
00197                                                 /* Reached end of string */
00198                                                 break;
00199                                         }
00200                                         paged_char(c);
00201                                 }
00202                                 
00203                         }
00204                         reads++;
00205                 }
00206         } while (bytes > 0 && !should_quit);
00207 
00208         close(fd);
00209         if (bytes == -1) {
00210                 printf("Error reading %s\n", fname);
00211                 free(buff);
00212                 return 1;
00213         }
00214 
00215         free(buff);
00216 
00217         return 0;
00218 }
00219 
00220 /* Main entry point for cat, accepts an array of arguments */
00221 int cmd_cat(char **argv)
00222 {
00223         unsigned int argc, i, ret = 0, buffer = 0;
00224         int c, opt_ind;
00225         bool hex = false;
00226         bool more = false;
00227         sysarg_t rows, cols;
00228         int rc;
00229         
00230         /*
00231          * reset global state
00232          * TODO: move to structure?
00233          */
00234         paging_enabled = false;
00235         chars_remaining = 0;
00236         lines_remaining = 0;
00237         console_cols = 0;
00238         console_rows = 0;
00239         should_quit = false;
00240 
00241         argc = cli_count_args(argv);
00242 
00243         for (c = 0, optind = 0, opt_ind = 0; c != -1;) {
00244                 c = getopt_long(argc, argv, "xhvmH:t:b:", long_options, &opt_ind);
00245                 switch (c) {
00246                 case 'h':
00247                         help_cmd_cat(HELP_LONG);
00248                         return CMD_SUCCESS;
00249                 case 'v':
00250                         printf("%s\n", CAT_VERSION);
00251                         return CMD_SUCCESS;
00252                 case 'H':
00253                         printf("%s", cat_oops);
00254                         return CMD_FAILURE;
00255                 case 't':
00256                         printf("%s", cat_oops);
00257                         return CMD_FAILURE;
00258                 case 'b':
00259                         printf("%s", cat_oops);
00260                         break;
00261                 case 'm':
00262                         more = true;
00263                         break;
00264                 case 'x':
00265                         hex = true;
00266                         break;
00267                 }
00268         }
00269 
00270         argc -= optind;
00271 
00272         if (argc < 1) {
00273                 printf("%s - incorrect number of arguments. Try `%s --help'\n",
00274                         cmdname, cmdname);
00275                 return CMD_FAILURE;
00276         }
00277 
00278         if (buffer <= 0)
00279                 buffer = CAT_DEFAULT_BUFLEN;
00280         
00281         if (more) {
00282                 rc = console_get_size(fphone(stdout), &cols, &rows);
00283                 if (rc != EOK) {
00284                         printf("%s - cannot get console size\n", cmdname);
00285                         return CMD_FAILURE;
00286                 }
00287                 console_cols = cols;
00288                 console_rows = rows;
00289                 paging_enabled = true;
00290                 newpage();
00291         }
00292 
00293         for (i = optind; argv[i] != NULL && !should_quit; i++)
00294                 ret += cat_file(argv[i], buffer, hex);
00295 
00296         if (ret)
00297                 return CMD_FAILURE;
00298         else
00299                 return CMD_SUCCESS;
00300 }
00301 

Generated on Thu Jun 2 07:45:40 2011 for HelenOS/USB by  doxygen 1.4.7