[Linux] Make a progress bar applet
Article directory
\n and \r characters in C language
There are two types of characters in C language:
- Displayable characters
- control characters
The displayable characters are characters such as character a, and the control characters are control characters such as \n.
For us to make the progress bar, we only need to pay attention to two control characters:
- \r – perform carriage return operation
- \n – perform line feed and carriage return operations
Explanation: \n itself is a newline character, but the C language itself parses it into a newline plus a carriage return.
In order to better understand the role of the characters \r and \n, we need to do some tests. In order to facilitate compilation, create a makefile file. The file content is as follows:
mytest:test.c
gcc -o mytest test.c
.PHONY:clean
clean:
rm -f mytest
First execute the following code:
#include <stdio.h>
#include <unistd.h>
int main()
{
printf("hello world");
sleep(3);
fflush(stdout);
return 0;
}
illustrate:
- fflush(stdout) refreshes the standard output buffer to facilitate observation of the phenomenon.
- sleep is the sleep function of Linux system.
The execution results are as follows:
hello world
After printing , the program sleeps and the "cursor" is at the next position on the same line.
After hibernation ends, printing will start from the cursor position, so the command [qxm@aliyun-centos review]$
line prompt will be printed immediately after hello world
it.
Then execute the following code:
#include <stdio.h>
#include <unistd.h>
int main()
{
printf("hello world\n");
sleep(3);
return 0;
}
The execution results are as follows:
Since \n is parsed by the C language into a line feed followed by a carriage return, the program will sleep hello world
after and the "cursor" will go to the beginning of the next line.
After hibernation ends, printing will start from the cursor position, so [qxm@aliyun-centos review]$
the command line prompt is printed at the beginning of the next line.
Finally execute the following code:
#include <stdio.h>
#include <unistd.h>
int main()
{
printf("hello world\n");
sleep(3);
return 0;
}
illustrate:
- fflush(stdout) refreshes the standard output buffer to facilitate observation of the phenomenon.
- sleep is the sleep function of Linux system.
The execution results are as follows:
Since \r is a carriage return, the program will sleep hello world
after and the "cursor" will return to the beginning of the line.
After hibernation ends, printing will start from the cursor position, so the command line prompt will overwrite [qxm@aliyun-centos review]$
the original one .hello world
Buffer refresh strategy
Under the Linux system, the C language will first store the characters to be printed in the buffer. Only when the characters in the buffer are refreshed to the screen can they be seen on the screen. The buffer refresh situation is as follows:
- When encountering \n, all characters before \n will be flushed to the screen.
- The buffer is automatically flushed when the program ends.
For the buffer test, we execute the following code:
#include <stdio.h>
#include <unistd.h>
int main()
{
printf("hello world\r");
sleep(3);
return 0;
}
The execution results are as follows:
Because the buffer is not flushed, nothing is printed while the program sleeps.
After the program is executed, the buffer is automatically refreshed and hello world
printed. However, since the \r carriage return returns the "cursor" to the beginning of the line, the printing of the command prompt overwrites the previous printing.
Then execute the following code:
#include <stdio.h>
#include <unistd.h>
int main()
{
printf("hello world\n");
sleep(3);
return 0;
}
The execution results are as follows:
Due to encounter\nThe data in the buffer was refreshed before sleeping.
After the program hibernates, the command line prompt starts printing from the cursor position.
Write progress bar code
Create the following files to form the code structure:
- myproc.h – the declaration that holds the progress bar code
- myproc.c – Implementation of saving progress bar code
- main.c – calling progress bar code
The core structure in the myproc.h file is as follows:
#pragma once
#include <stdio.h>
extern void process();
The core structure in the myproc.c file is as follows:
#include "myproc.h"
void process()
{
//...
}
The core structure in the main.c file is as follows:
#include "myproc.h"
int main()
{
process();
return 0;
}
At the same time, create a makefile file and write the following content inside the makefile file:
myproc:myproc.c main.c
gcc -o myproc myproc.c main.c
.PHONY:clean
clean:
rm -f myproc
After establishing the code structure, write the following code to act as a graphical progress bar:
#include "myproc.h"
#include <string.h>
#include <unistd.h>
#define STYLE '='
#define ARROW '>'
#define SIZE 101
void process()
{
char buf[SIZE];
memset(buf, 0 , SIZE);
int i = 0;
while(i <= 100)
{
printf("[%-100s]\r", buf);
fflush(stdout);
buf[i++] = STYLE;
if(i != 100 )buf[i] = ARROW;
usleep(100000);
}
printf("\n");
}
First create a string to save the graphical progress bar buf to be printed, initialize it, and then print the buf left-aligned and print with a length of 100 characters when printing.
Each time printing is completed, the carriage return overwrites the previous printing, and the buffer is refreshed so that the printing is displayed on the screen, and a sleep function is used to load the progress.
The printing effect is as follows:
In addition to the graphical progress bar, a digital progress display must also be set, so the printing needs to be modified, as follows:
printf("[%-100s][%d%%]\r", buf, i);
Increase the printing progress percentage as the digitization progress display, %% will be escaped into a % and printed on the screen.
The printing effect is as follows:
Finally, a rotating cursor is added to indicate that the progress bar is continuously executing, so the printing needs to be modified, and the final code is as follows:
#include "myproc.h"
#include <string.h>
#include <unistd.h>
#define STYLE '='
#define ARROW '>'
#define SIZE 101
void process()
{
const char* cursor = "|/-\\";
char buf[SIZE];
memset(buf, 0 , SIZE);
int i = 0;
while(i <= 100)
{
printf("[%-100s][%d%%][%c]\r", buf, i, cursor[i%4]);
fflush(stdout);
buf[i++] = STYLE;
if(i != 100 )buf[i] = ARROW;
usleep(100000);
}
printf("\n");
}
A cursor string is added to save the style of the rotating cursor, where \\ will be escaped into a \, because 4 characters are printed cyclically in the rotating cursor, so the style string is output modulo 4.
The final demonstration result of the progress bar is as follows: