Use carriage return '\r'
to move the cursor back to the beginning of a line. Assuming a POSIX system (because of the use of nanosleep()
), you could code like this. Note the use of the %*.*s
notation to specify how long a sub-section of the string to print.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
int main(void)
{
char sign[50];
struct timespec d = { .tv_sec = 0, .tv_nsec = 100000000 };
printf("What should I say? ");
if (scanf("%49[^\n]", sign) == 1)
{
printf("Sign: [%s]\n\n", sign);
int t_len = strlen(sign);
for (int i = 0; i < 10; i++)
{
for (int l_len = 0; l_len < t_len; l_len++)
{
int r_len = t_len - l_len;
/* Rotate to right */
//printf("\r[%*.*s%*.*s]", l_len, l_len, sign + r_len, r_len, r_len, sign);
/* Rotate to left */
printf("\r[%*.*s%*.*s]", r_len, r_len, sign + l_len, l_len, l_len, sign);
fflush(stdout);
nanosleep(&d, 0);
}
}
putchar('\n');
}
return 0;
}
The output at the end was:
What should I say? Hello World, and how are you today?
Sign: [Hello World, and how are you today?]
[?Hello World, and how are you today]
It would be better if the code added a string such as " ... "
after the entered text so it wraps better. That is trivial to do if you reserve enough space in the string for the padding on input (change 49
into 44
since there are five characters in the padding).
Piping the output through tr '\r' '\n'
yields:
Hello World, and how are you today?
What should I say? Sign: [Hello World, and how are you today?]
[Hello World, and how are you today?]
[ello World, and how are you today?H]
[llo World, and how are you today?He]
[lo World, and how are you today?Hel]
[o World, and how are you today?Hell]
[ World, and how are you today?Hello]
[World, and how are you today?Hello ]
[orld, and how are you today?Hello W]
[rld, and how are you today?Hello Wo]
[ld, and how are you today?Hello Wor]
[d, and how are you today?Hello Worl]
[, and how are you today?Hello World]
[ and how are you today?Hello World,]
[and how are you today?Hello World, ]
[nd how are you today?Hello World, a]
[d how are you today?Hello World, an]
[ how are you today?Hello World, and]
[how are you today?Hello World, and ]
…
which shows how the output changes over time. It also illustrates the problems with piping standard output to another command.
An alternative (simpler) version of the printf()
statements:
/* Rotate to right */
putchar('\r');
printf("[%.*s%.*s]", l_len, sign + r_len, r_len, sign);
printf(" ");
/* Rotate to left */
printf("[%.*s%.*s]", r_len, sign + l_len, l_len, sign);
That code shows the text scrolling both to the right and to the left at once. In this context, the leading *
in the %*.*s
conversion specification isn't needed (but there are others where it can be useful and even necessary), so only one length argument is needed for each string.