-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsortAndOrganize.cpp
More file actions
258 lines (242 loc) · 9.25 KB
/
sortAndOrganize.cpp
File metadata and controls
258 lines (242 loc) · 9.25 KB
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <algorithm>
#include <fstream>
#include <sstream>
#include <filesystem>
#include <unistd.h>
#include <limits.h>
namespace fs = std::filesystem;
using namespace std;
string get_hostname();
void github_repo_update();
map<string, string> file_and_path();
bool descriptive_enough(const string& s);
string input_from_user();
bool output_to_user(const string &output);
bool output_to_file(const string &output, const string &file);
vector<string> get_extension(vector<string> fileNames);
/**
* Main function
*
* This function is the entry point of the program. It initializes the program by updating the code folder with the GitHub repository,
* then it organizes the Downloads folder by moving files to their appropriate locations based on their file extensions.
*
* @param argc number of command line arguments
* @param argv array of command line arguments
* @return 0 if successful, non-zero otherwise
*/
int main(int argc, char *argv[]) {
// update code folder with gh repo
// this includes autogenerating repos as necessary
github_repo_update();
// obtains a map of all the names and associated paths to place
map<string, string> extens = file_and_path();
vector <string> filesInDownloads;
string hostname = get_hostname();
string path = hostname + "/Downloads";
// fills filesInDownloads with all the file names in the Downloads folder
for (const auto & entry : fs::directory_iterator(path))
filesInDownloads.push_back(entry.path().filename().string());
// fills fileExt with the extension names of the files in the Downloads folder
vector<string> fileExt = get_extension(filesInDownloads);
for (int i = 0; i < fileExt.size(); i++) {
if (filesInDownloads[i].find("Cert") != string::npos || filesInDownloads[i].find("cert")!= string::npos) {
// move certificate files to the certs folder
fs::rename(filesInDownloads[i], + "/Documents/certs/" + filesInDownloads[i]);
} else {
// rename files that are not descriptive enough
string new_file_name = filesInDownloads[i].substr(0, filesInDownloads[i].find_last_of("."));
// while loop used so that if user doesn't give a descriptive enough name they can be prompted again.
while (descriptive_enough(new_file_name)){
// output_to_user is used instead of a cout to allow me to have the function interact with a gui later (and make that easier)
output_to_user("Your file name (" + filesInDownloads[i] + ") may not be descriptive enough. Would you like to rename it? (y/n): ");
string input = input_from_user();
if (input == "y" || input == "Y" || input == "\n") {
output_to_user("Please enter a new file name: ");
string new_file_name = input_from_user();
// renames file in system
fs::rename(path + "/" + filesInDownloads[i], path + "/" + new_file_name);
filesInDownloads[i] = new_file_name + fileExt[i];
} else {
break;
}
}
// renames file in program
filesInDownloads[i] = new_file_name + "."+ fileExt[i];
}
if (fileExt[i] == "deb"){
// remove deb files
fs::remove(filesInDownloads[i]);
}
// moves all the files to the designated folder in the file_and_path.txt
auto it = extens.find(fileExt[i]);
if (it != extens.end() && filesInDownloads[i].length() > 0) {
// move file to the specified directory
fs::rename(path + "/" + filesInDownloads[i], it->second + "/" + filesInDownloads[i]);
} else {
// ask user to specify the directory for unrecognized file extensions
output_to_user("The file extension of " + fileExt[i] + " is not recognized. Please designate the default location for this file extension: ");
string newPath = input_from_user();
while (!fs::exists(newPath) ) {
output_to_user("file path doest not exist. Would you like to create it? (y/n): ");
if (input_from_user() == "y" || input_from_user() == "Y" || input_from_user() == "\n") {
try {
// create the directory if it does not exist
fs::create_directories(newPath);
}
catch (const fs::filesystem_error& e) {
output_to_user("Sorry can't seem to create the directory. Please designate a different path: ");
}
}
}
if (filesInDownloads[i].length() > 0) {
// move the file to the specified directory
fs::rename(path + "/" + filesInDownloads[i], newPath + "/" + filesInDownloads[i]);
}
// add the new directory to the file_and_path.txt
output_to_file(fileExt[i] + ":" + newPath, "file_and_path.txt");
extens[fileExt[i]] = newPath;
}
}
// organize the downloads folder
// installables get deleted
// executables get moved to the desktop folder
// jars get automoved to the documents folder
// detect files that do not have a very descriptive name, and ask user if they want to change the name
// for unrecognized file extensions ask where to put and remember to put in place every time
// if designated place is not an existing folder create said path.
return 0;
}
/**
* Reads a file containing pairs of file names and paths from the given path, and returns a map of file names to paths.
*
* The file should contain one line for each file, with the file name and path separated by a colon (:). The file name and path should be separated by a single space.
*
* The file should be formatted as follows:
*
* fileName1:path1
* fileName2:path2
*
* The function returns an empty map if the file cannot be opened or is empty.
*
* @return A map of file names to paths, or an empty map if the file cannot be opened or is empty.
*/
map<string, string> file_and_path() {
string path = "file_and_path.txt";
map<string, string> file_and_path;
ifstream in(path);
if (in.is_open()) {
string line;
while (getline(in, line)) {
size_t pos = line.find(":");
if (pos != string::npos) {
string file = line.substr(0, pos);
string path = line.substr(pos + 1);
file_and_path[file] = path;
}
}
}
return file_and_path;
}
/**
* Returns the hostname of the current user.
*
* This function uses the `getlogin_r` function to obtain the hostname of the current user.
*
* @return The hostname of the current user.
*/
std::string get_hostname() {
char hostname[256];
getlogin_r(hostname, sizeof(hostname));
return "/home/" + string(hostname);
}
/**
* Updates the code folder by pulling from the git repository and pushing to the remote repository.
*/
void github_repo_update() {
system("git pull");
system("git push");
}
/**
* Returns whether a given string is descriptive enough.
*
* A string is considered descriptive if it is at least 10 characters long,
* and contains at least one uppercase letter, one lowercase letter, and one digit.
*
* @param s The string to be evaluated.
* @return Whether the string is descriptive enough.
*/
bool descriptive_enough(const string& s) {
if (s.size() < 10) {
return false;
}
int caps_count = 0, number_count = 0, letter_count = 0;
for (int i = 0; i < s.size(); i++) {
if (s[i] >= 'A' && s[i] <= 'Z' || s[i] == '_') {
caps_count++;
} else if (s[i] >= 'a' && s[i] <= 'z') {
letter_count++;
} else if (s[i] >= '0' && s[i] <= '9') {
number_count++;
}
}
if (letter_count > 5) {
return false;
} else if (caps_count < letter_count / 10) {
return false;
}
return true;
}
/**
* Obtains input from the user.
*/
string input_from_user() {
string input;
getline(cin, input);
return input;
}
/**
* Outputs a text string to the user.
* @param output the string to be displayed to the user.
*/
bool output_to_user(const string &output) {
cout << output;
return true;
}
/**
* Writes a string to a file.
*
* @param output the string to be written to the file
* @param file the name of the file to which the string should be written
* @return true if the string was written to the file, false otherwise
*/
bool output_to_file(const string &output, const string &file) {
ofstream out;
out.open(file, std::ios_base::app);
if (out.is_open()) {
out << endl << output;
out.close();
return true;
}
return false;
}
/**
* Returns the file extension of a given file name.
*
* @param fileNames A vector of file names
* @return A vector of file extensions
*/
vector<string> get_extension(vector<string> fileNames) {
vector<string> temp;
for (int i = 0; i < fileNames.size(); i++) {
auto pos = fileNames[i].find_last_of(".");
if (pos != string::npos) {
temp.push_back(fileNames[i].substr(pos + 1));
}
}
return temp;
}