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 }