skroll

text scroller
git clone git://git.2f30.org/skroll
Log | Files | Refs | README | LICENSE

skroll.c (4529B)


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