-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathhistory.c
137 lines (113 loc) · 3.42 KB
/
history.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include "shell.h"
#include "utils.h"
#include "history.h"
// we store the last 20 commands in a circular-queue-like data structure
// we do not store consecutive repeated commands
// semicolon-separated commands are stored as separate entries
// a pipeline of commands is stored as a single entry
// no whitespace-cleaning etc is done. command is stored is verbatim
void init_history() {
// try to read history from binary file, if it exists
// otherwise initialise history data structures
size_t len = strlen(home_dir) + strlen(HISTORY_FILE_NAME) + 1;
history_path = (char*)malloc(sizeof(char) * (len + 1));
strcpy(history_path, home_dir);
strcat(history_path, "/");
strcat(history_path, HISTORY_FILE_NAME);
FILE* f = fopen(history_path, "rb");
if (f == NULL) {
// initialise the struct yourself, assume it never existed before
history.ind_h = -1;
return;
}
if (fread(&history, sizeof(history), 1, f) != 1) {
// initialise the struct yourself, assume it never existed before
history.ind_h = -1;
}
fclose(f);
}
void preserve_history() {
// create or overwrite history file
// storing history datastructures as binary
FILE* f = fopen(history_path, "wb");
if (f == NULL) {
fprintf(stderr, "Could not save history.\n");
return;
}
if (fwrite(&history, sizeof(history), 1, f) != 1) {
fprintf(stderr, "Could not save history.\n");
return;
}
}
void handle_history(int argc, char** argv) {
if (argc > 2) {
fprintf(stderr, "Could not print history: Invalid arguments.\n");
return;
}
if (argc > 0 && strcmp(argv[argc-1], "&") == 0) {
argc--;
}
if (argc > 1) {
fprintf(stderr, "Could not print history: Invalid arguments.\n");
return;
}
if (argc == 0) {
print_history(10);
} else {
int num = strtol(argv[0], NULL, 10); // returns 0 if not a valid number, which is fine
print_history(num);
}
}
void store_history(char* str) {
// store this command in history
if (strlen(str) > MAX_STATIC_STR_LEN-1) {
return;
}
if (history.ind_h >= 0 && strcmp(history.data[history.ind_h % 20], str) == 0) {
return; //avoid consecutive duplicates
}
if (history.ind_h < 19) {
history.ind_h++;
strcpy(history.data[history.ind_h], str);
return;
}
history.ind_h++;
if (history.ind_h >= 40) {
history.ind_h = history.ind_h - 20;
}
// history.ind_h >= 20 here
strcpy(history.data[history.ind_h - 20], str);
}
void print_history(int n) {
// print these many commands
if (n <= 0) {
return;
}
if (n > history.ind_h + 1) {
n = history.ind_h + 1;
}
if (n > 20) {
n = 20;
}
if (history.ind_h < 20) {
for (int i = history.ind_h - n + 1; i <= history.ind_h; i++) {
printf("%s\n", history.data[i]);
}
return;
}
// history.ind_h >= 20 here
// history.ind_h - 20 gives index
if (n <= history.ind_h - 20) {
for (int i = history.ind_h - n -19; i <= history.ind_h - 20; i++) {
printf("%s\n", history.data[i]);
}
return;
}
// n > in_h - 20 here
// in_h >= 20 here
int s = history.ind_h - n + 1;
for (int i = 0; i < n; i++) {
printf("%s\n", history.data[s]);
s = (s + 1) % 20;
}
}