GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: tmp_project/StringUtils/src/string_system.cpp Lines: 139 156 89.1 %
Date: 2024-12-09 15:30:52 Branches: 129 167 77.2 %

Line Branch Exec Source
1
2
/***************************************
3
	Auteur : Pierre Aubert
4
	Mail : pierre.aubert@lapp.in2p3.fr
5
	Licence : CeCILL-C
6
****************************************/
7
8
#include <errno.h>
9
#include <stdio.h>
10
#include <stdlib.h>
11
#include <dirent.h>
12
#include <regex.h>
13
#include <fcntl.h>	//Definition of AT_* constants
14
#ifndef __APPLE__
15
#define GCC_VERSION (__GNUC__ * 10000 \
16
                    + __GNUC_MINOR__ * 100 \
17
                    + __GNUC_PATCHLEVEL__)
18
#	if GCC_VERSION <= 60200
19
#		include <asm-generic/errno-base.h>
20
#	endif
21
#endif
22
23
#include <time.h>
24
#include <ctime>
25
26
#include <sys/types.h>
27
#include <unistd.h>
28
29
// #include <cerrno>
30
#include <iostream>
31
32
33
#include "string_filename.h"
34
35
#include "string_system.h"
36
37
/* From https://nicolasj.developpez.com/articles/regex/
38
39
[:digit:]	0-9
40
[:alpha:]	A-Za-z
41
[:alnum:]	0-9A-Za-z
42
[:cntrl:]	Les caractères de contrôles (code ASCII 0177 et inférieur à 040)
43
[:print:]	Les caractères imprimables
44
[:graph:]	Idem [:print:] sans l'espace
45
[:lower:]	a-z
46
[:upper:]	A-Z
47
[:punct:]	Ni [:cntrl:] ni [:alnum:]
48
[:space:]	\n\t\r\f
49
[:xdigit:]	0-9a-fA-F nombres hexadécimaux
50
51
Ces définitions concordent avec celles que l'on trouve dans le fichier d'en-tête ctype.h. Le point '.' permet de reconnaître n'importe quel caractère. Il est aussi possible de préciser le nombre de répétitions que l'on souhaite pour un élément :
52
53
Opérateurs	Signification
54
?		L'élément est répété, au plus une fois
55
*		L'élément est présent 0 ou plus de fois
56
+		L'élément est présent au moins une fois
57
{n}		L'élément est présent exactement n fois
58
{n,}		L'élément est présent au moins n fois
59
{n,m}		L'élément est présent entre n et m fois
60
61
Un élément est un groupe délimité par des crochets qui sont optionnels si le groupe ne comporte qu'un élément. Voici un exemple pour reconnaître si une chaîne contient trois 'a' consécutifs :
62
63
Sélectionnez
64
65
[a]{3}
66
67
L'opposé d'une expression est obtenu en la faisant précéder par le caractère '^'. Si l'on souhaite donner le choix entre deux expressions, il suffit de les séparer par le caractère '|'.
68
Ce même caractère peut être placé au début de l'expression régulière pour préciser que la chaîne à analyser doit commencer par l'élément suivant :
69
70
Sélectionnez
71
72
^[A-Z]
73
74
Précise que la chaîne doit commencer par une lettre majuscule. Le caractère '$' a le même rôle, mais cette fois en fin de chaîne.
75
Pour finir, voici la liste des méta caractères ainsi que la manière de les échapper :
76
77
Méta caractères		Echappés en
78
	?		\?
79
	+		\+
80
	.		\.
81
	*		\*
82
	{		\{
83
	|		\|
84
	(		\(
85
	)		\)
86
*/
87
88
89
///Fonction qui dit si une chaine de caractère correspond à une expression régulière de regex
90
/**	@param str : string dont on veut savoir si elle correspond à une expression régulière
91
 * 	@param expression : expression régulière regex
92
 * 	@return true si str correspond à une expression régulière, false sinon
93
*/
94
36
bool isStringMatchRegex(const std::string & str, const std::string & expression){
95

36
	if(str.size() == 0lu || expression.size() == 0lu){return false;}
96
	int err;
97
	regex_t preg;
98
32
	const char *str_request = str.c_str();
99
32
	const char *str_regex = expression.c_str();
100
32
	err = regcomp(&preg, str_regex, 0);	//REG_NOSUB | REG_EXTENDED
101
32
	if(err != 0) return false;
102
32
	int match = regexec(&preg, str_request, 0, NULL, 0);
103
32
	regfree (&preg);
104
32
	if(match == 0){return true;}
105
21
	else{return false;}//if (match == REG_NOMATCH){return false;}
106
// 	else{
107
// 		char *text;
108
// 		long unsigned int size;
109
// 		size = regerror (err, &preg, NULL, 0);
110
// 		text = new char[size];
111
// 		if (text){
112
// 			regerror (err, &preg, text, size);
113
// 			fprintf (stderr, "isStringMatchRegex : %s\n", text);
114
// 			delete [] text;
115
// 		}else{
116
// 			fprintf (stderr, "isStringMatchRegex : Memoire insuffisante\n");
117
// 		}
118
// 		return false;
119
// 	}
120
}
121
122
///Function like a ls in shell
123
/**	@param listFile : list of the files witch match with expr
124
 * 	@param expr : expression like "name*.txt" or "*.dat" or "name_*_something_*.ext"
125
*/
126
1
void getListFileInCurrentDir(std::list<std::string> & listFile, const std::string & expr){
127
1
	char * curr_dir = getenv("PWD");
128
1
	if(NULL == curr_dir){
129
		printf("getListFileInCurrentDir : Could not get the working directory\n");
130
		return;
131
	}
132
	// Open the current directory
133
1
	DIR * dp = opendir((const char*)curr_dir);
134
1
	if(NULL == dp){
135
		printf("getListFileInCurrentDir : Could not open the working directory\n");
136
		return;
137
	}
138
1
	dirent * dptr = readdir(dp);
139
19
	while(NULL != dptr){
140

18
		if(isStringMatchRegex(std::string(dptr->d_name), expr)) listFile.push_back(std::string(dptr->d_name));
141
18
		dptr = readdir(dp);
142
	}
143
}
144
145
///Get the list of files in a directory
146
/**	@param[out] listFile : list of files in the current directory
147
 * 	@param dirName : name of the directory to look in
148
 * 	@param expr : regular expression like *.txt or *
149
*/
150
1
bool getListFileInDir(std::list<std::string> & listFile, const std::string & dirName, const std::string & expr){
151
	// Open the current directory
152
1
	DIR * dp = opendir(dirName.c_str());
153
1
	if(NULL == dp){
154
// 		printf("getListFileInDir : Could not open the working directory\n");
155
		return false;
156
	}
157
1
	dirent * dptr = readdir(dp);
158
8
	while(NULL != dptr){
159

7
		if(isStringMatchRegex(std::string(dptr->d_name), expr)) listFile.push_back(std::string(dptr->d_name));
160

7
		std::cout << "getListFileInDir : '" << std::string(dptr->d_name) << "'"<< std::endl;
161
7
		dptr = readdir(dp);
162
	}
163
1
	closedir(dp);
164
1
	return true;
165
}
166
167
///Get the list of files in a directory
168
/**	@param[out] listFile : list of files in the current directory
169
 * 	@param dirName : name of the directory to look in
170
*/
171
1
bool getListAllFileInDir(std::list<std::string> & listFile, const std::string & dirName){
172
	// Open the current directory
173
1
	DIR * dp = opendir(dirName.c_str());
174
1
	if(NULL == dp){
175
		return false;
176
	}
177
1
	dirent * dptr = readdir(dp);
178
8
	while(NULL != dptr){
179
7
		std::string fileName(dptr->d_name);
180


7
		if(fileName != ".." && fileName != "."){
181
5
			listFile.push_back(fileName);
182
		}
183
7
		dptr = readdir(dp);
184
	}
185
1
	closedir(dp);
186
1
	return true;
187
}
188
///Makes the argument list of a program
189
/**	@param[out] listArgument : list of the program arguments
190
 * 	@param argc : number of arguments passed to the program
191
 * 	@param argv : array of the passed arguments to the program
192
*/
193
1
void makeListArgument(std::list<std::string> & listArgument, int argc, char** argv){
194
1
	if(argc <= 0) return;
195
2
	for(int i(0); i < argc; ++i){
196
1
		listArgument.push_back(argv[i]);
197
	}
198
}
199
200
///Get the value of the given environment variable
201
/**	@param varName : name of the environment variable to be used
202
 * 	@return value of the variable, or empty string of the variable does not exist
203
*/
204
3
std::string phoenix_getenv(const std::string & varName){
205
3
	char * curr_var = getenv(varName.c_str());
206
3
	if(NULL == curr_var){
207
1
		return "";
208
	}else{
209
2
		return std::string(curr_var);
210
	}
211
}
212
213
///Set a environment variable
214
/**	@param name : name of the variable to be created
215
 * 	@param value : value of the variable to be created
216
 * 	@param overwrite : 1 to overwrite an existing variable, 0 to not to
217
 * 	@return true on success, false otherwise
218
*/
219
1
bool phoenix_setenv(const std::string  & name, const std::string & value, int overwrite){
220
1
	return setenv(name.c_str(), value.c_str(), overwrite) == 0;
221
}
222
223
///Unset a environment variable
224
/**	@param name : name of the variable to be unset
225
 * 	@return true on success, false otherwise
226
*/
227
1
bool phoenix_unsetenv(const std::string & name){
228
1
	return unsetenv(name.c_str()) == 0;
229
}
230
231
///Gets the $HOME directory
232
/**	@return $HOME directory
233
*/
234
1
std::string getHomeDir(){
235
1
	return phoenix_getenv("HOME");
236
}
237
238
///Creates a directory if it does not exist
239
/**	@param directoryName : name of the directory we want to create
240
 * 	@return true on success, false otherwise
241
*/
242
2
bool createDirIfNotExist(const std::string & directoryName){
243
2
	if(directoryName == "") return false;
244
2
	if(isDirectoryExist(directoryName)){
245
1
		return true;
246
	}
247
1
	int res = mkdir(directoryName.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
248

1
	return res == 0 || res == EEXIST;
249
}
250
251
///Get the last modification time of the given file
252
/**	@param fileName : name of the file we want the last modification time
253
 * 	@return last modification time of the given file
254
*/
255
5
time_t getFileModificationTime(const std::string & fileName){
256
	struct stat attr;
257
5
	if(stat(fileName.c_str(), &attr) == 0){
258
#ifdef __APPLE__
259
		return attr.st_mtimespec.tv_sec;
260
#else
261
3
		return attr.st_mtim.tv_sec;
262
#endif
263
	}else{
264
2
		return -1l;
265
	}
266
}
267
268
///Get the list of most recent files in a directory
269
/**	@param[out] vecFile : vector of found files (without directory name)
270
 * 	@param dirName : name of the directory to be scanned
271
 * 	@param mostRecentTime : threshold time to select only most recent files
272
 * 	@return time of the most recent file found in the directory which is newer than the input mostRecentTime
273
*/
274
2
time_t getFileInDirPerTime(std::vector<std::string> & vecFile, const std::string & dirName, time_t mostRecentTime){
275
2
	DIR * dp = opendir(dirName.c_str());
276
2
	if(dp == NULL){return mostRecentTime;}
277
2
	dirent * dptr = readdir(dp);
278
8
	while(NULL != dptr){
279
6
		if(dptr->d_type == DT_REG){	//We search for directory only
280
4
			std::string pathName(dptr->d_name);
281
2
			time_t fileTime = getFileModificationTime(dirName + "/" + pathName);
282
2
			if(fileTime > mostRecentTime){
283
1
				mostRecentTime = fileTime;
284
1
				vecFile.push_back(pathName);
285
			}
286
		}
287
6
		dptr = readdir(dp);
288
	}
289
2
	return mostRecentTime;
290
}
291
292
293
///Get the program location
294
/**	@return location of the current program
295
*/
296
3
std::string getProgramLocation(){
297
	char buffer[4096];
298
3
	ssize_t nbChar = readlink("/proc/self/exe", buffer, 2048);
299
//	readlink("/proc/self/exe", buf, bufsize) (Linux)
300
//	readlink("/proc/curproc/file", buf, bufsize) (FreeBSD)
301
//	readlink("/proc/self/path/a.out", buf, bufsize) (Solaris)
302
303
3
	if(nbChar > 0l){
304
6
		std::string outputBuf("");
305
327
		for(ssize_t i(0l); i < nbChar; ++i){
306
324
			outputBuf += buffer[i];
307
		}
308
3
		return outputBuf;
309
	}else{
310
		return "";
311
	}
312
}
313
314
///Get the program directory
315
/**	@return directory of the program
316
*/
317
2
std::string getProgramDirectory(){
318
4
	std::string progLoc(getProgramLocation());
319
2
	if(progLoc != ""){
320
2
		return getDirectory(progLoc);
321
	}else{
322
#ifdef CMAKE_INSTALL_PREFIX
323
		return CMAKE_INSTALL_PREFIX "/bin/";
324
#else
325
		return "/usr/bin/";
326
#endif
327
	}
328
}
329
330
///Get the program prefix (installation directory without /bin)
331
/**	@return prefix of the program (installation directory without /bin)
332
*/
333
1
std::string getProgramPrefix(){
334
2
	return getDirectory(getProgramDirectory());
335
}
336
337
///Execute the given command and returns the output of this command
338
/**	@param command : command to be executed
339
 * 	@return output of the given command, empty string if the command is empty or null character on fail
340
*/
341
27
std::string phoenix_popen(const std::string & command){
342
27
	if(command == ""){return "";}
343
26
	FILE * fp = popen(command.c_str(), "r");
344
26
	if(fp == NULL){
345
		std::cerr << "phoenix_popen : cannot get result of command '"<<command<<"'" << std::endl;
346
		return "";
347
	}
348
52
	std::string resultCommand(getFileContent(fp));
349
26
	pclose(fp);
350
26
	return resultCommand;
351
}
352
353
///Execute the given command and returns the output of this command
354
/**	@param[out] executionLog : output of the given command, empty string if the command is empty or null character on fail
355
 * 	@param command : command to be executed
356
 * 	@return exit status of the command
357
*/
358
7
int phoenix_popen(std::string & executionLog, const std::string & command){
359
7
	executionLog = "";
360
7
	if(command == ""){return -1;}
361
6
	FILE * fp = popen(command.c_str(), "r");
362
6
	if(fp == NULL){
363
		std::cerr << "phoenix_popen : cannot get result of command '"<<command<<"'" << std::endl;
364
		return -1;
365
	}
366
6
	executionLog = getFileContent(fp);
367
6
	return pclose(fp);
368
}
369
370
///Execute the given command and returns the output of this command
371
/**	@param[out] executionLogFile : file which will get output of the given command, empty string if the command is empty or full log on fail
372
 * 	@param command : command to be executed
373
 * 	@param onlyLogOnFail : true to log only if the command fails
374
 * 	@return true if the command was successful, false otherwise (in this case, log file will be created)
375
*/
376
4
bool phoenix_popen(const std::string & executionLogFile, const std::string & command, bool onlyLogOnFail){
377
4
	std::string executionLog("");
378
4
	bool b(phoenix_popen(executionLog, command) == 0);
379
4
	if(!b){
380

2
		std::cerr << "phoenix_popen : command '"<<command<<"' failed. To get more information see log '"<<executionLogFile<<"'" << std::endl;
381
	}
382

4
	if((onlyLogOnFail && !b) || !onlyLogOnFail){
383
3
		if(!saveFileContent(executionLogFile, executionLog)){
384
			std::cerr << "phoenix_popen : cannot create log file '"<<executionLogFile<<"'" << std::endl;
385
		}
386
	}
387
8
	return b;
388
}
389
390
///Change the mode of a file or directory
391
/**	@param fileName : name of the file to be changed
392
 * 	@param __mode : mode to be applied to the given file (Default value makes files executable S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)
393
 * 	@return true on success, false otherwise
394
*/
395
2
bool phoenix_chmod(const std::string & fileName, mode_t __mode){
396
2
	bool b(chmod(fileName.c_str(), __mode) >= 0);
397
2
	if(!b){
398
1
		std::cerr << "phoenix_chmod : Cannot set mode of file '"<<fileName<<"'" << std::endl;
399
	}
400
2
	return b;
401
}
402
403
///Get the name of the current node on which the program is running
404
/**	@return name of the current node on which the program is running
405
*/
406
1
std::string getCurrentNodeName(){
407

2
	return eraseCharsInStr(phoenix_popen("uname -n"), " \n\t");
408
}
409
410
///Find all files which matches the path expression (example : /path/*.cpp)
411
/**	@param[out] vecFile : vector of found files
412
 * 	@param path : path which can matches several files
413
*/
414
1
void phoenix_find(std::vector<std::string> & vecFile, const std::string & path){
415
1
	vecFile = cutStringVector(phoenix_popen("ls " + path), '\n');
416
1
}
417
418
///Find all files which matches the path expression (example : /path/*.cpp)
419
/**	@param path : path which can matches several files
420
 * 	@return vector of found files
421
*/
422
1
std::vector<std::string> phoenix_find(const std::string & path){
423
1
	std::vector<std::string> vecFile;
424
1
	phoenix_find(vecFile, path);
425
1
	return vecFile;
426
}
427
428
///Get current time
429
/**	@return current time
430
*/
431
time_t phoenix_getClock(){
432
	return clock();
433
}
434
435
///Get current time
436
/**	@return current time
437
*/
438
double phoenix_getClockSec(){
439
	return ((double)phoenix_getClock())/((double)CLOCKS_PER_SEC);
440
}
441
442
///Get the current time of the program
443
/**	@return current time of the program
444
*/
445
202
time_t phoenix_getTime(){
446
202
	return std::time(0);
447
}
448
449
///Get the current date
450
/**	@return current date
451
*/
452
24
std::string phoenix_getDate(){
453
24
	std::time_t currentTime = phoenix_getTime();
454
24
	std::tm* now_tm = std::gmtime(&currentTime);
455
	char buf[42];
456
24
	std::strftime(buf, 42, "%Y/%m/%d : %X", now_tm);
457
24
	return buf;
458
}
459
460
///Get the current date
461
/**	@return current date
462
*/
463
89
std::string phoenix_getDateCompact(){
464
89
	std::time_t currentTime = phoenix_getTime();
465
89
	std::tm* now_tm = std::gmtime(&currentTime);
466
	char buf[42];
467
89
	std::strftime(buf, 42, "%Y/%m/%d-%X", now_tm);
468
89
	return buf;
469
}