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 }