MCS  0.3.3-alpha7
Utils.cc
1 // ----------------------------------------------------------------------^
2 // Copyright (C) 2004, 2005, 2006, 2007, 2008 Giorgio Calderone
3 // (mailto: <gcalderone@ifc.inaf.it>)
4 //
5 // This file is part of MCS.
6 //
7 // MCS is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 2 of the License, or
10 // (at your option) any later version.
11 //
12 // MCS is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with MCS; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 //
21 // ----------------------------------------------------------------------$
22 #include "mcs.hh"
23 using namespace mcs;
24 
25 
26 int mcs::extractCode(const char* msg)
27 {
28  int ret;
29  ret = 0;
30  ret += (msg[1] - '0') * 100;
31  ret += (msg[2] - '0') * 10 ;
32  ret += (msg[3] - '0') ;
33  return ret;
34 }
35 
36 
37 
38 
39 bool mcs::File_Dir_Exist(string fn, unsigned int& size)
40 {
41  DIR *dp;
42  ifstream f;
43  size = 0;
44 
45  if (fn.empty()) return false;
46  dp = opendir(fn.csz);
47  if (dp) {
48  closedir(dp);
49  return true;
50  }
51  else {
52  f.open(fn.csz);
53  if (f.is_open()) {
54  f.seekg(0, ios::end); // Seek the end of file (to get the size)
55  size = f.tellg(); // Size of file
56  f.seekg(0, ios::beg); // Seek the start of file
57  f.close();
58  return true;
59  }
60  else
61  return false;
62  }
63 }
64 
65 
66 string mcs::Pwd()
67 {
68  char* p;
69  string s;
70  p=getcwd(NULL, 0);
71  s=p;
72  free(p);
73  return s;
74 }
75 
76 
77 string mcs::itos(int i)
78 {
79  char buf[20];
80  sprintf(buf, "%d", i);
81  return string(buf);
82 }
83 
84 
85 int mcs::stoi(string s)
86 {
87  int i;
88  if (sscanf(s.c_str(), "%d", &i) == 1)
89  return i;
90  else
91  throw MCS_ERROR(MSG_CONVERSION_STRING_INT);
92 }
93 
94 
95 int mcs::stoi(string s, int errval)
96 {
97  int i;
98  if (sscanf(s.c_str(), "%d", &i) == 1)
99  return i;
100  else
101  return errval;
102 }
103 
104 
105 string mcs::dtos(double f)
106 {
107  char buf[20];
108  sprintf(buf, "%f", f);
109  return string(buf);
110 }
111 
112 
113 string mcs::btos(bool b)
114 {
115  if (b)
116  return string("true");
117  else
118  return string("false");
119 }
120 
121 
122 string mcs::vtos(vector<string> vec)
123 {
124  unsigned int i;
125  string buf = "";
126  string nl = "\n";
127 
128  for (i=0; i<vec.size(); i++)
129  buf += vec[i] + nl;
130 
131  return buf;
132 }
133 
134 
135 string mcs::subst(string s, string what, string with, int op)
136 {
137  string s2 = "(" + what + string(")");
138  string templ = s2;
139 
140  if (op & MCS_SUBST_LEADING)
141  templ = "^" + s2;
142 
143  if (op & MCS_SUBST_TRAILING) {
144  if (op & MCS_SUBST_LEADING)
145  templ += "|" + s2;
146  templ += "$";
147  }
148  pcrecpp::RE re(templ,
149  pcrecpp::RE_Options().set_dollar_endonly(true));
150 
151  if (op & MCS_SUBST_QUOTE_WITH) {
152  pcrecpp::RE re("\\\\");
153  re.GlobalReplace("\\\\\\\\", &with);
154  }
155  re.GlobalReplace(with, &s);
156  return s;
157 }
158 
159 
160 string mcs::trim(string s)
161 {
162  return subst(s, " +", "", MCS_SUBST_LEADING | MCS_SUBST_TRAILING);
163 }
164 
165 
166 string mcs::chomp(string s)
167 {
168  return subst(s, "\n+", "", MCS_SUBST_TRAILING);
169 }
170 
171 
172 string mcs::remTabs(string s)
173 {
174  return subst(s, "\t", "");
175 }
176 
177 
178 string mcs::remLeading(string& s, const char* p)
179 {
180  s = subst(s, p, "", MCS_SUBST_LEADING);
181  return s;
182 }
183 
184 
185 string mcs::remTrailing(string& s, const char* p)
186 {
187  s = subst(s, p, "", MCS_SUBST_TRAILING);
188  return s;
189 }
190 
191 
192 std::vector<std::string> mcs::split(string s, string sep)
193 {
194  vector<string> v;
195 
196  //First characters must not be equal top sep
197  pcrecpp::RE pre("^\\Q" + sep + "\\E+");
198  pre.GlobalReplace("", &s);
199 
200  pcrecpp::StringPiece input(s);
201  pcrecpp::RE re("([^\\Q" + sep + "\\E]+)\\Q" + sep + "\\E*");
202  //pcrecpp::RE re("(\\S+) *");
203 
204  while (re.Consume(&input, &s))
205  v.push_back(s);
206 
207  return v;
208 }
209 
210 
211 string mcs::hexDump(const void* pvoid, unsigned int size)
212 {
213  const char* buf = (const char*) pvoid;
214  string s = "";
215  unsigned int i, j, count;
216  char lbuf[40];
217 
218  i = 0;
219  while (i < size) {
220  count = size - i;
221  if (count > 8)
222  count = 8;
223 
224  sprintf(lbuf, "%06d ", i);
225  s += lbuf;
226 
227  for (j=0; j<count; j++) {
228  sprintf(lbuf, "%02X", buf[i+j]);
229  s += lbuf;
230  }
231 
232  s += " ";
233 
234  for (j=0; j<count; j++) {
235  if (isprint(buf[i+j]))
236  sprintf(lbuf, "%c", buf[i+j]);
237  else
238  sprintf(lbuf, ".");
239 
240  s += lbuf;
241  }
242 
243  s += "\n";
244  i += count;
245  }
246  return s;
247 }
248 
249 
251 {
252  mode_t mask = umask (0);
253  umask(mask);
254  return mask;
255 }
256 
257 
258 
259 bool mcs::mkDir(string path, mode_t perm, enum ThrowExceptions throwexc)
260 {
261  if (perm == MCS_MKDIR_UMASK)
262  perm = (S_IRWXU | S_IRWXG | S_IRWXO) & ~read_umask();
263 
264  if (mkdir(path.csz, perm))
265  if (throwexc)
266  throw MCS_ERROR(MSG_CANT_MKDIR, path.csz);
267  else
268  return false;
269  else
270  return true;
271 }
272 
273 
274 bool mcs::rmDir(string path, enum ThrowExceptions throwexc)
275 {
276  string s;
277  //TODO: custom "rmdir"
278  s = "rm -rf " + path;
279 
280  if (system(s.csz))
281  if (throwexc)
282  throw MCS_ERROR(MSG_CANT_RMDIR, path.csz);
283  else
284  return false;
285  else
286  return true;
287 }
288 
289 
290 void mcs::ls2Record(string fn, Record& v)
291 {
292  DIR *dp;
293  struct dirent *ep;
294  string s, r;
295  ifstream f;
296 
297  if (fn.empty()) return;
298 
299  dp = opendir (fn.c_str());
300  if (dp) {
301  while ((ep = readdir (dp))) {
302  r=ep->d_name;
303  if ( r != "." && r != ".." )
304  ls2Record(fn + string("/") + r, v);
305  }
306  closedir (dp);
307  }
308  else {
309  f.open(fn.c_str());
310  if (f.is_open()) {
311  Data d(NULL, STRING, "FILE", fn.length());
312  d = fn;
313  v.addField(&d);
314  f.close();
315  }
316  }
317 }
318 
319 
320 
321 
322 //This routine is to be used inside this file, not by users
323 static char* appendFileNameToPath(char* OLDNAME, char* NEWNAME)
324 {
325  char* buf;
326  char* p;
327 
328  p = strrchr(OLDNAME, '/');
329  if (p == NULL)
330  p = OLDNAME;
331  else {
332  p++;
333  }
334 
335  //Plus two: one to eventually add a slash, one for NULL
336  buf = (char*) malloc(strlen(NEWNAME) + strlen(p) + 2);
337 
338  strcpy(buf, NEWNAME);
339 
340  if (buf[strlen(buf) - 1] != '/') { //If last character is not a slash
341  buf[strlen(buf) + 1] = 0;
342  buf[strlen(buf)] = '/';
343  }
344 
345  strcpy(buf + strlen(buf), p);
346  return buf;
347 }
348 
349 
350 
351 
352 #define BUFSIZE 16384
353 int mcs::copy(char* OLDNAME, char* NEWNAME)
354 {
355  FILE *inf, *outf;
356  int nread;
357  char buf[BUFSIZE];
358 
359  if ((outf = fopen(NEWNAME, "wb")) == NULL) {
360  if (errno == EISDIR) {
361  char* b = appendFileNameToPath(OLDNAME, NEWNAME);
362  int ret = copy(OLDNAME, b);
363  free(b);
364  return ret;
365  }
366  else {
367  fprintf(stderr, "Error opening file %s: %s\n", NEWNAME,
368  strerror(errno));
369  return -1;
370  }
371  }
372  else {
373  if ((inf = fopen(OLDNAME, "rb")) == NULL) {
374  fclose(outf);
375  fprintf(stderr, "Error opening file %s: %s\n", OLDNAME,
376  strerror(errno));
377  return -1;
378  }
379 
380 
381  while (! feof(inf)) {
382  nread = fread(buf, sizeof(char), BUFSIZE, inf);
383  fwrite(buf, sizeof(char), nread, outf);
384  }
385 
386  fclose(inf);
387  fclose(outf);
388 
389  //Success
390  return 0;
391  }
392 }
393 
394 
395 int mcs::move(char* OLDNAME, char* NEWNAME)
396 {
397  char* buf;
398  int ret;
399 
400  ret = rename(OLDNAME, NEWNAME);
401 
402  if (ret == -1) //An error occurred
403  switch(errno) {
404 
405  case EISDIR: //NEWNAME is a directory but the OLDNAME isn't.
406  //So append the filename to the NEWNAME directory and retry
407  buf = appendFileNameToPath(OLDNAME, NEWNAME);
408  ret = move(OLDNAME, buf);
409  free(buf);
410  return ret;
411 
412 
413  case EBUSY: //This error can happen if NEWNAME is one of: ".", ".."
414  if (NEWNAME[strlen(NEWNAME) - 1] != '/') { //That's a directory
415  buf = appendFileNameToPath(OLDNAME, NEWNAME);
416  ret = move(OLDNAME, buf);
417  free(buf);
418  return ret;
419  }
420 
421 
422  case EXDEV: //Different filesystems, must copy, then delete
423  ret = copy(OLDNAME, NEWNAME);
424  if (ret == 0) {
425  if (unlink(OLDNAME) == -1) {
426  fprintf(stderr, "Error deleting file %s: %s\n", OLDNAME,
427  strerror(errno));
428  return -1;
429  }
430  }
431  return ret;
432 
433 
434 
435  default:
436  fprintf(stderr, "Error renaming %s ==> %s: %s\n", OLDNAME, NEWNAME,
437  strerror(errno));
438  return -1;
439  }
440 
441 
442  //Success
443  return 0;
444 }
445 
446 
447 
448 
449 
450 const char* mcs::B64_Codec::cb64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
451 const char* mcs::B64_Codec::cd64="|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
452 
453 
455 {
456  bufAllocated = NULL;
457  precDataCount = 0;
458  blocksout = 0;
459 }
460 
462 {
463  freeBuffer();
464 }
465 
466 
467 void mcs::B64_Codec::requireSpace(unsigned int Length)
468 {
469  if (Length < 0)
470  ; //ERROR
471 
472  if ((! bufAllocated) ||
473  (bufsize < Length)) {
474  bufsize = Length;
475  bufAllocated = (char*) realloc(bufAllocated, bufsize);
476  memset(bufAllocated, 0, bufsize);
477  }
478  this->buf_out = bufAllocated;
479 }
480 
482 {
483  if (bufAllocated)
484  free(bufAllocated);
485 
486  bufAllocated = NULL;
487  bufsize = 0;
488 }
489 
490 
492 {
493  if (precDataCount)
494  return false;
495  else
496  return ((bool) (pin >= EOIB));
497 }
498 
500 {
501  if (precDataCount) {
502  unsigned char ret = precData[0];
503  precData[0] = precData[1];
504  precData[1] = precData[2];
505  precData[2] = precData[3];
506  precDataCount--;
507  return ret;
508  }
509  else
510  return *pin++;
511 }
512 
513 void mcs::B64_Codec::writeData(unsigned char d)
514 { *pout++ = d; }
515 
516 char* mcs::B64_Codec::buffer()
517 { return buf_out; }
518 
519 unsigned int mcs::B64_Codec::bufUsed()
520 { return pout - buf_out; }
521 
522 
523 unsigned int mcs::B64_Codec::encode(char* buf_in, int Length, char* par_buf_out,
524  unsigned int linesize)
525 {
526  unsigned int rescue = 0;
527  unsigned char in[3], out[4];
528  int i, len = 0;
529 
530  int origLength = Length; //Save "Length" because we are going to
531  //change it.
532 
533  //Number of bytes being read (those from precedent call:
534  //precDataCount, plus actual buffer: Length) must be a multiple of 3
535  //bytes.
536  if (Length) {
537  rescue = (precDataCount + Length) % 3; //"rescue" bytes need to be
538  //saved for a later call.
539  Length -= rescue;
540  }
541 
542  //Setup input buffer
543  EOIB = buf_in + Length;
544  pin = buf_in;
545 
546  //Setup output buffer
547  if (par_buf_out) {
548  freeBuffer();
549  buf_out = par_buf_out;
550  }
551  else {
552  requireSpace(origLength * 2);
553  buf_out = bufAllocated;
554  }
555  pout = buf_out;
556 
557 
558  //Set linesize
559  if (linesize < MCS_B64_MIN_LINE)
560  linesize = MCS_B64_MIN_LINE;
561  this->linesize = linesize;
562 
563 
564  //Encode
565  while (! eob()) {
566  len = 0;
567  for(i=0; i<3; i++) {
568  if (! eob()) {
569  in[i] = (unsigned char) readData();
570  len++;
571  }
572  else
573  in[i] = 0;
574  }
575  if (len) {
576  encodeblock(in, out, len);
577  for(i=0; i<4; i++) {
578  writeData(out[i]);
579  }
580  blocksout++;
581  }
582  if (blocksout >= (linesize/4)) {
583  writeData('\r');
584  writeData('\n');
585  blocksout = 0;
586  }
587  }
588 
589 
590  if (Length) { //Save bytes from input buffer for a later call
591  for (unsigned int i=0; i<rescue; i++)
592  precData[i] = readData();
593 
594  precDataCount = rescue;
595  }
596  else { //Or if we are at end of file simply write a newline
597  writeData('\r');
598  writeData('\n');
599 
600  precDataCount = 0; //Setup for new encoding
601  blocksout = 0;
602  }
603 
604  return pout - buf_out;
605 }
606 
607 
608 
609 unsigned int mcs::B64_Codec::decode(char* buf_in, int Length, char* par_buf_out)
610 {
611  unsigned char in[4], out[3], v, d;
612  int i, len;
613 
614  //Setup input buffer
615  EOIB = buf_in + Length;
616  pin = buf_in;
617 
618  //Setup output buffer
619  if (par_buf_out) {
620  freeBuffer();
621  buf_out = par_buf_out;
622  }
623  else {
624  requireSpace(Length);
625  buf_out = bufAllocated;
626  }
627  pout = buf_out;
628 
629 
630  //Decode data
631  len = 0;
632  while (! eob()) {
633  d = v = readData();
634 
635  //Check if the character is allowed
636  v = (unsigned char) ((v < 43 || v > 122) ? 0 : cd64[ v - 43 ]);
637  if ((v != 0) &&
638  (v != '$') ) {
639  in[len] = v - 62;
640 
641  if (precDataCount == 0)
642  precData[len] = d;
643 
644  len++;
645  }
646 
647  //If we have a complete 4 byte block
648  if (len == 4) {
649  decodeblock(in, out);
650  for(i=0; i<len-1; i++)
651  writeData(out[i]);
652 
653  len = 0;
654  }
655  }
656 
657  if (len > 0) { //If some byte hasn't been decoded yet
658  precDataCount = len; //...save it for a later call
659 
660  if (Length == 0) { //Or if we are at the end of file
661  decodeblock(in, out); //..decode it!
662  for(i=0; i<len-1; i++)
663  writeData(out[i]);
664 
665  precDataCount = 0; //Setup for new encoding
666  }
667  }
668 
669  return pout - buf_out;
670 }
671 
672 void mcs::B64_Codec::encodeblock( unsigned char in[3], unsigned char out[4], int len )
673 {
674  out[0] = cb64[ in[0] >> 2 ];
675  out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
676  out[2] = (unsigned char) (len > 1 ? cb64[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '=');
677  out[3] = (unsigned char) (len > 2 ? cb64[ in[2] & 0x3f ] : '=');
678 }
679 
680 void mcs::B64_Codec::decodeblock( unsigned char in[4], unsigned char out[3] )
681 {
682  out[ 0 ] = (unsigned char ) (in[0] << 2 | in[1] >> 4);
683  out[ 1 ] = (unsigned char ) (in[1] << 4 | in[2] >> 2);
684  out[ 2 ] = (unsigned char ) (((in[2] << 6) & 0xc0) | in[3]);
685 }
686 
687 
688 
689 
690 //returns 0 if timeout, 1 if ready, -1 if error
691 int mcs::Select(int fd, unsigned int sec_timeout, unsigned int usec_timeout, int op)
692 {
693  fd_set set;
694  struct timeval timeout;
695  int ret;
696 
697  FD_ZERO (&set);
698  FD_SET (fd, &set);
699  timeout.tv_sec = sec_timeout;
700  timeout.tv_usec = usec_timeout;
701 
702  if (op == MCS_SELECT_READ)
703  ret = select(FD_SETSIZE, &set, NULL, NULL, &timeout);
704  else
705  ret = select(FD_SETSIZE, NULL, &set, NULL, &timeout);
706 
707  return ret;
708 }
709 
710 
711 
712 //returns 0 if timeout, number of fd ready, -1 if error
713 int mcs::Select(int fd[], int nfd, unsigned int sec_timeout, unsigned int usec_timeout, int op)
714 {
715  fd_set set;
716  struct timeval timeout;
717  int i, ret;
718 
719  FD_ZERO (&set);
720  for (i=0; i<nfd; i++) {
721  FD_SET (fd[i], &set);
722  fd[i] = 0;
723  }
724 
725  timeout.tv_sec = sec_timeout;
726  timeout.tv_usec = usec_timeout;
727 
728  if (op == MCS_SELECT_READ)
729  ret = select(FD_SETSIZE, &set, NULL, NULL, &timeout);
730  else
731  ret = select(FD_SETSIZE, NULL, &set, NULL, &timeout);
732 
733  for (i=0; i<nfd; i++)
734  fd[i] = FD_ISSET(i, &set);
735 
736  return ret;
737 }
738 
739 
740 
void requireSpace(unsigned int Length)
Allocate "Length" bytes in internal buffer.
Definition: Utils.cc:467
mode_t read_umask()
Read the file creation mask of the current process.
Definition: Utils.cc:250
string btos(bool b)
Convert a boolean to a string containing "true" or "false".
Definition: Utils.cc:113
string itos(int i)
Convert an integer to a string.
Definition: Utils.cc:77
unsigned char readData()
Read one byte from input buffer.
Definition: Utils.cc:499
~B64_Codec()
Destructor.
Definition: Utils.cc:461
bool File_Dir_Exist(string fn, unsigned int &size)
Check if a file or directory exists.
Definition: Utils.cc:39
#define MCS_SUBST_LEADING
To be used with subst(), substitute only if "what" is at the beginning. See subst().
Definition: mcs.hh:502
string Pwd()
Return the current working dir.
Definition: Utils.cc:66
#define MCS_SUBST_TRAILING
To be used with subst(), substitute only if "what" is at the end. See subst().
Definition: mcs.hh:505
A dynamic array of Data objects.
Definition: mcs.hh:4170
int copy(char *OLDNAME, char *NEWNAME)
Copy a file from OLDNAME to NEWNAME.
Definition: Utils.cc:353
unsigned int decode(char *buf_in, int Length, char *par_buf_out=NULL)
Decode a block of data.
Definition: Utils.cc:609
int move(char *OLDNAME, char *NEWNAME)
Move a file from OLDNAME to NEWNAME.
Definition: Utils.cc:395
void freeBuffer()
Free internal buffer.
Definition: Utils.cc:481
void ls2Record(string fn, Record &v)
Fill a vector with a list of file.
Definition: Utils.cc:290
unsigned int encode(char *buf_in, int Length, char *par_buf_out=NULL, unsigned int linesize=72)
Encode a block of data.
Definition: Utils.cc:523
#define MCS_ERROR(A, rest...)
Facility to easily pass all necessary parameter to an Event constructor.
Definition: mcs.hh:964
bool eob()
Tell if we are at the end of input buffer.
Definition: Utils.cc:491
string vtos(vector< string > vec)
Join a vector of strings in a single string using newlines.
Definition: Utils.cc:122
string remTrailing(string &s, const char *p)
Remove any trailing character "p".
Definition: Utils.cc:185
int stoi(string s)
Convert a string to an integer.
Definition: Utils.cc:85
void writeData(unsigned char d)
Write one byte to output buffer.
Definition: Utils.cc:513
void encodeblock(unsigned char in[3], unsigned char out[4], int len)
Encode a block of 3 binary bytes into 4 &#39;Base64&#39; bytes.
Definition: Utils.cc:672
vector< string > split(string s, string sep=" ")
Split a string into tokens.
Definition: Utils.cc:192
string remTabs(string s)
Remove any tab.
Definition: Utils.cc:172
Main include file for all MCS based applications.
void decodeblock(unsigned char in[4], unsigned char out[3])
Decode a block of 4&#39;Base64&#39; bytes into 3 binary bytes.
Definition: Utils.cc:680
B64_Codec()
Constructor.
Definition: Utils.cc:454
void addField(Data *d)
Wrapper around Dynamic_Array.push.
Definition: Record.cc:364
string chomp(string s)
Remove any trailing newlines.
Definition: Utils.cc:166
int extractCode(const char *msg)
Extract the numeric code from a server reply.
Definition: Utils.cc:26
A general purpose data type.
Definition: mcs.hh:3092
string subst(string s, string what, string with, int op=0)
Perform substitutions on a string.
Definition: Utils.cc:135
bool rmDir(string path, enum ThrowExceptions throwexc=THROW)
Removes a directory.
Definition: Utils.cc:274
ThrowExceptions
Values to be used with throwexc parameters.
Definition: mcs.hh:257
string remLeading(string &s, const char *p)
Remove any leading character "p".
Definition: Utils.cc:178
string trim(string s)
Remove any leading or trailing blanks.
Definition: Utils.cc:160
string hexDump(const void *buf, unsigned int size)
Return a string with an hex dump of the buffer pointed by "buf", with a length of "size"...
Definition: Utils.cc:211
string dtos(double f)
Convert an floating point number to a string.
Definition: Utils.cc:105
bool mkDir(string path, mode_t perm=0, enum ThrowExceptions throwexc=THROW)
Create a directory.
Definition: Utils.cc:259
#define MCS_SUBST_QUOTE_WITH
To be used with subst(), doubles each backslash in "with". See subst().
Definition: mcs.hh:499
Namespace for MCS library.

mcslogo

MCS (My Customizable Server) ver. 0.3.3-alpha7
Documentation generated on Mon May 28 07:39:41 UTC 2018