tskroll.c - skroll - scroll a text to stdout
 (HTM) git clone git://z3bra.org/skroll
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       tskroll.c (4009B)
       ---
            1 #include <stdio.h>
            2 #include <stdbool.h>
            3 #include <stdlib.h>
            4 #include <string.h>
            5 #include <unistd.h>
            6 #include <getopt.h>
            7 #include <limits.h>
            8 
            9 static bool newline = false;/* print a new line after each step */
           10 static bool loop = false;   /* wether to loop text or not */
           11 static float delay = 0.1;   /* scroll speed, in seconds */
           12 static int number = 20;     /* number of chars to be shown at the same time */
           13 
           14 /* return the len of an utf-8 character */
           15 int utf8_len(unsigned char c)
           16 {
           17     return c<192 ? 0 : c<224 ? 1 : c<240 ? 2 : 3;
           18 }
           19 
           20 /* scroll <input> to stdout */
           21 void skroll (const char *input)
           22 {
           23     int offset = 0;
           24 
           25     /* main loop. will loop forever if run with -l */
           26     do
           27     {
           28         /*
           29          * each step of the loop will print the buffer, one byte further after
           30          * each step. using a carriage return, it makes the text scroll out.
           31          * leading/ending spaces are here to make sure that the text goes from
           32          * far right, and goes all the way to far left
           33          */
           34         for (offset = 0; input[offset + number] != 0; offset++)
           35         {
           36             /* increase the message's length in case of utf-8 chars */
           37             number += utf8_len(input[offset + number - 1]);
           38 
           39             /* print out `number` characters from the buffer ! */
           40             write(1, input + offset, number);
           41 
           42             /* if we want a new line, do it here, otherwise, carriage return */
           43             putc(newline ? '\n' : '\r', stdout);
           44 
           45             /* flush stdout, and wait for the next step */
           46             fflush(stdout);
           47 
           48             /* decrease length when utf-8 chars disappear to the left */
           49             number -= utf8_len(input[offset]);
           50             offset += utf8_len(input[offset]);
           51 
           52             usleep(delay*1000000);
           53         }
           54     /* magnolia ? FOWEVA ! */
           55     } while(loop);
           56 
           57     putc('\b', stdout);
           58 
           59     return; /* void */
           60 }
           61 
           62 /* returns a char that contains the input bufferized */
           63 const char *bufferize (FILE *stream)
           64 {
           65     int len = 0;
           66     char *eol, *buf = NULL;
           67 
           68     /* allocate space to store the input */
           69     if (!(buf = calloc (LINE_MAX + 1, sizeof(char)))) { return NULL; }
           70     memset(buf, ' ', LINE_MAX);
           71     buf[LINE_MAX] = 0;
           72 
           73     /* OMG, NO MORE SPACE LEFT ON DEVICE (or no more input, in fact) */
           74     if (feof(stream) || !fgets(buf + number, LINE_MAX, stream))
           75     {
           76         free (buf);
           77         return NULL;
           78     }
           79 
           80     /*
           81      * we need to remove trailings \n and \0 from input string to sanitize output.
           82      * the buffer should now look like this:
           83      * [          my input          \0           \0] 
           84      *  |         |       |         |             `- last \0, to prevent segfaults
           85      *  |         |       |          `- remaining spaces (up to LINE_MAX)
           86      *  |         |        `- trailing spaces, to make the text croll to far left
           87      *  |          `- the input itself, with \n and \0 removed from it
           88      *   `- leading spaces, to make the text scroll from far right
           89      */
           90 
           91     /* get the size of the input (and thus, the position of the \0) */
           92     len = strnlen(buf, LINE_MAX);
           93     buf[len] = ' ';
           94 
           95     /* terminate the string a bit further */
           96     buf[len + number] = 0;
           97 
           98     /* remove those silly \n from the input */
           99     if ((eol = strchr(buf, '\n')) != NULL) {
          100         eol[0] = ' ';
          101     }
          102 
          103     return buf;
          104 }
          105 
          106 int main (int argc, char **argv)
          107 {
          108     char ch;
          109     const char *buf = NULL;
          110 
          111     while ((ch = getopt(argc, argv, "hd:ln:r")) != -1)
          112     {
          113         switch (ch)
          114         {
          115             case 'h':
          116                 printf("usage: %s [-hlr] [-d delay] [-n number]\n", argv[0]);
          117                 exit(0);
          118                 break;
          119             case 'd': delay = strtof(optarg, NULL); break;
          120             case 'n': number = strtoul(optarg, NULL, 10); break;
          121             case 'l': loop = true; break;
          122             case 'r': newline = true; break;
          123         }
          124     }
          125 
          126     /* SCROLL ALL THE TEXT! */
          127     while((buf = bufferize(stdin)) != NULL)
          128     {
          129         skroll(buf);
          130     }
          131 
          132     /* End with a new line, no matter what */
          133     putc('\n', stdout);
          134 
          135     return 0;
          136 }