GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: tmp_project/StringUtils/src/string_system.cpp Lines: 127 144 88.2 %
Date: 2023-10-11 10:52:07 Branches: 124 162 76.5 %

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
2
bool getListAllFileInDir(std::list<std::string> & listFile, const std::string & dirName){
172
	// Open the current directory
173
2
	DIR * dp = opendir(dirName.c_str());
174
2
	if(NULL == dp){
175
		return false;
176
	}
177
2
	dirent * dptr = readdir(dp);
178
12
	while(NULL != dptr){
179
10
		std::string fileName(dptr->d_name);
180


10
		if(fileName != ".." && fileName != "."){
181
6
			listFile.push_back(fileName);
182
		}
183
10
		dptr = readdir(dp);
184
	}
185
2
	closedir(dp);
186
2
	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
333
		for(ssize_t i(0l); i < nbChar; ++i){
306
330
			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
26
std::string phoenix_popen(const std::string & command){
342
26
	if(command == ""){return "";}
343
25
	FILE * fp = popen(command.c_str(), "r");
344
25
	if(fp == NULL){
345
		std::cerr << "phoenix_popen : cannot get result of command '"<<command<<"'" << std::endl;
346
		return "";
347
	}
348
50
	std::string resultCommand(getFileContent(fp));
349
25
	pclose(fp);
350
25
	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
 * 	@return true if the command was successful, false otherwise (in this case, log file will be created)
374
*/
375
4
bool phoenix_popen(const std::string & executionLogFile, const std::string & command, bool onlyLogOnFail){
376
4
	std::string executionLog("");
377
4
	bool b(phoenix_popen(executionLog, command) == 0);
378
4
	if(!b){
379

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

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

2
	return eraseCharsInStr(phoenix_popen("uname -n"), " \n\t");
407
}
408
409
///Get current time
410
/**	@return current time
411
*/
412
time_t phoenix_getClock(){
413
	return clock();
414
}
415
416
///Get current time
417
/**	@return current time
418
*/
419
double phoenix_getClockSec(){
420
	return ((double)phoenix_getClock())/((double)CLOCKS_PER_SEC);
421
}
422
423
///Get the current time of the program
424
/**	@return current time of the program
425
*/
426
52
time_t phoenix_getTime(){
427
52
	return std::time(0);
428
}
429
430
///Get the current date
431
/**	@return current date
432
*/
433
18
std::string phoenix_getDate(){
434
18
	std::time_t currentTime = phoenix_getTime();
435
18
	std::tm* now_tm = std::gmtime(&currentTime);
436
	char buf[42];
437
18
	std::strftime(buf, 42, "%Y/%m/%d : %X", now_tm);
438
18
	return buf;
439
}
440
441