strutl.cc 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. // -*- mode: cpp; mode: fold -*-
  2. // Description /*{{{*/
  3. // $Id: strutl.cc,v 1.3 1998/07/19 04:22:08 jgg Exp $
  4. /* ######################################################################
  5. String Util - Some usefull string functions.
  6. strstrip - Remove whitespace from the front and end of a line.
  7. This source is placed in the Public Domain, do with it what you will
  8. It was originally written by Jason Gunthorpe <jgg@gpu.srv.ualberta.ca>
  9. ##################################################################### */
  10. /*}}}*/
  11. // Includes /*{{{*/
  12. #include <strutl.h>
  13. #include <ctype.h>
  14. #include <string.h>
  15. #include <stdio.h>
  16. /*}}}*/
  17. // strstrip - Remove white space from the front and back of a string /*{{{*/
  18. // ---------------------------------------------------------------------
  19. /* This is handy to use when parsing a file. It also removes \n's left
  20. over from fgets and company */
  21. char *_strstrip(char *String)
  22. {
  23. for (;*String != 0 && (*String == ' ' || *String == '\t'); String++);
  24. if (*String == 0)
  25. return String;
  26. char *End = String + strlen(String) - 1;
  27. for (;End != String - 1 && (*End == ' ' || *End == '\t' || *End == '\n' ||
  28. *End == '\r'); End--);
  29. End++;
  30. *End = 0;
  31. return String;
  32. };
  33. /*}}}*/
  34. // strtabexpand - Converts tabs into 8 spaces /*{{{*/
  35. // ---------------------------------------------------------------------
  36. /* */
  37. char *_strtabexpand(char *String,size_t Len)
  38. {
  39. for (char *I = String; I != I + Len && *I != 0; I++)
  40. {
  41. if (*I != '\t')
  42. continue;
  43. if (I + 8 > String + Len)
  44. {
  45. *I = 0;
  46. return String;
  47. }
  48. /* Assume the start of the string is 0 and find the next 8 char
  49. division */
  50. int Len;
  51. if (String == I)
  52. Len = 1;
  53. else
  54. Len = 8 - ((String - I) % 8);
  55. Len -= 2;
  56. if (Len <= 0)
  57. {
  58. *I = ' ';
  59. continue;
  60. }
  61. memmove(I + Len,I + 1,strlen(I) + 1);
  62. for (char *J = I; J + Len != I; *I = ' ', I++);
  63. }
  64. return String;
  65. }
  66. /*}}}*/
  67. // ParseQuoteWord - Parse a single word out of a string /*{{{*/
  68. // ---------------------------------------------------------------------
  69. /* This grabs a single word, converts any % escaped characters to their
  70. proper values and advances the pointer. Double quotes are understood
  71. and striped out as well. */
  72. bool ParseQuoteWord(const char *&String,string &Res)
  73. {
  74. // Skip leading whitespace
  75. const char *C = String;
  76. for (;*C != 0 && *C == ' '; C++);
  77. if (*C == 0)
  78. return false;
  79. // Jump to the next word
  80. for (;*C != 0 && *C != ' '; C++)
  81. {
  82. if (*C == '"')
  83. {
  84. for (C++;*C != 0 && *C != '"'; C++);
  85. if (*C == 0)
  86. return false;
  87. }
  88. }
  89. // Now de-quote characters
  90. char Buffer[1024];
  91. char Tmp[3];
  92. const char *Start = String;
  93. char *I;
  94. for (I = Buffer; I < Buffer + sizeof(Buffer) && Start != C; I++)
  95. {
  96. if (*Start == '%' && Start + 2 < C)
  97. {
  98. Tmp[0] = Start[1];
  99. Tmp[1] = Start[2];
  100. Tmp[3] = 0;
  101. *I = (char)strtol(Tmp,0,16);
  102. Start += 3;
  103. continue;
  104. }
  105. if (*Start != '"')
  106. *I = *Start;
  107. else
  108. I--;
  109. Start++;
  110. }
  111. *I = 0;
  112. Res = Buffer;
  113. // Skip ending white space
  114. for (;*C != 0 && *C == ' '; C++);
  115. String = C;
  116. return true;
  117. }
  118. /*}}}*/
  119. // QuoteString - Convert a string into quoted from /*{{{*/
  120. // ---------------------------------------------------------------------
  121. /* */
  122. string QuoteString(string Str,const char *Bad)
  123. {
  124. string Res;
  125. for (string::iterator I = Str.begin(); I != Str.end(); I++)
  126. {
  127. if (strchr(Bad,*I) != 0 || isprint(*I) == 0 ||
  128. *I <= 0x20 || *I >= 0x7F)
  129. {
  130. char Buf[10];
  131. sprintf(Buf,"%%%02x",(int)*I);
  132. Res += Buf;
  133. }
  134. else
  135. Res += *I;
  136. }
  137. return Res;
  138. }
  139. /*}}}*/
  140. // SizeToStr - Convert a long into a human readable size /*{{{*/
  141. // ---------------------------------------------------------------------
  142. /* A max of 4 digits are shown before conversion to the next highest unit. The
  143. max length of the string will be 5 chars unless the size is > 10
  144. YottaBytes (E24) */
  145. string SizeToStr(double Size)
  146. {
  147. char S[300];
  148. double ASize;
  149. if (Size >= 0)
  150. ASize = Size;
  151. else
  152. ASize = -1*Size;
  153. /* bytes, KiloBytes, MegaBytes, GigaBytes, TeraBytes, PetaBytes,
  154. ExaBytes, ZettaBytes, YottaBytes */
  155. char Ext[] = {'b','k','M','G','T','P','E','Z','Y'};
  156. int I = 0;
  157. while (I <= 8)
  158. {
  159. if (ASize < 100 && I != 0)
  160. {
  161. sprintf(S,"%.1f%c",ASize,Ext[I]);
  162. break;
  163. }
  164. if (ASize < 10000)
  165. {
  166. sprintf(S,"%.0f%c",ASize,Ext[I]);
  167. break;
  168. }
  169. ASize /= 1000.0;
  170. I++;
  171. }
  172. return S;
  173. }
  174. /*}}}*/
  175. // TimeToStr - Convert the time into a string /*{{{*/
  176. // ---------------------------------------------------------------------
  177. /* Converts a number of seconds to a hms format */
  178. string TimeToStr(unsigned long Sec)
  179. {
  180. char S[300];
  181. while (1)
  182. {
  183. if (Sec > 60*60*24)
  184. {
  185. sprintf(S,"%lid %lih%lim%lis",Sec/60/60/24,(Sec/60/60) % 24,(Sec/60) % 60,Sec % 60);
  186. break;
  187. }
  188. if (Sec > 60*60)
  189. {
  190. sprintf(S,"%lih%lim%lis",Sec/60/60,(Sec/60) % 60,Sec % 60);
  191. break;
  192. }
  193. if (Sec > 60)
  194. {
  195. sprintf(S,"%lim%lis",Sec/60,Sec % 60);
  196. break;
  197. }
  198. sprintf(S,"%lis",Sec);
  199. break;
  200. }
  201. return S;
  202. }
  203. /*}}}*/
  204. // SubstVar - Substitute a string for another string /*{{{*/
  205. // ---------------------------------------------------------------------
  206. /* This replaces all occurances of Subst with Contents in Str. */
  207. string SubstVar(string Str,string Subst,string Contents)
  208. {
  209. string::size_type Pos = 0;
  210. string::size_type OldPos = 0;
  211. string Temp;
  212. while (OldPos < Str.length() &&
  213. (Pos = Str.find(Subst,OldPos)) != string::npos)
  214. {
  215. Temp += string(Str,OldPos,Pos) + Contents;
  216. OldPos = Pos + Subst.length();
  217. }
  218. if (OldPos == 0)
  219. return Str;
  220. return Temp + string(Str,OldPos);
  221. }
  222. /*}}}*/
  223. // URItoFileName - Convert the uri into a unique file name /*{{{*/
  224. // ---------------------------------------------------------------------
  225. /* This converts a URI into a safe filename. It quotes all unsafe characters
  226. and converts / to _ and removes the scheme identifier. The resulting
  227. file name should be unique and never occur again for a different file */
  228. string URItoFileName(string URI)
  229. {
  230. string::const_iterator I = URI.begin() + URI.find(':') + 1;
  231. for (; I < URI.end() && *I == '/'; I++);
  232. // "\x00-\x20{}|\\\\^\\[\\]<>\"\x7F-\xFF";
  233. URI = QuoteString(string(I,URI.end() - I),"\\|{}[]<>\"^~_=!@#$%^&*");
  234. string::iterator J = URI.begin();
  235. for (; J != URI.end(); J++)
  236. if (*J == '/')
  237. *J = '_';
  238. return URI;
  239. }
  240. /*}}}*/
  241. // Base64Encode - Base64 Encoding routine for short strings /*{{{*/
  242. // ---------------------------------------------------------------------
  243. /* This routine performs a base64 transformation on a string. It was ripped
  244. from wget and then patched and bug fixed.
  245. This spec can be found in rfc2045 */
  246. string Base64Encode(string S)
  247. {
  248. // Conversion table.
  249. static char tbl[64] = {'A','B','C','D','E','F','G','H',
  250. 'I','J','K','L','M','N','O','P',
  251. 'Q','R','S','T','U','V','W','X',
  252. 'Y','Z','a','b','c','d','e','f',
  253. 'g','h','i','j','k','l','m','n',
  254. 'o','p','q','r','s','t','u','v',
  255. 'w','x','y','z','0','1','2','3',
  256. '4','5','6','7','8','9','+','/'};
  257. // Pre-allocate some space
  258. string Final;
  259. Final.reserve((4*S.length() + 2)/3 + 2);
  260. /* Transform the 3x8 bits to 4x6 bits, as required by
  261. base64. */
  262. for (string::const_iterator I = S.begin(); I < S.end(); I += 3)
  263. {
  264. char Bits[3] = {0,0,0};
  265. Bits[0] = I[0];
  266. if (I + 1 < S.end())
  267. Bits[1] = I[1];
  268. if (I + 2 < S.end())
  269. Bits[2] = I[2];
  270. Final += tbl[Bits[0] >> 2];
  271. Final += tbl[((Bits[0] & 3) << 4) + (Bits[1] >> 4)];
  272. if (I + 1 >= S.end())
  273. break;
  274. Final += tbl[((Bits[1] & 0xf) << 2) + (Bits[2] >> 6)];
  275. if (I + 2 >= S.end())
  276. break;
  277. Final += tbl[Bits[2] & 0x3f];
  278. }
  279. /* Apply the padding elements, this tells how many bytes the remote
  280. end should discard */
  281. if (S.length() % 3 == 2)
  282. Final += '=';
  283. if (S.length() % 3 == 1)
  284. Final += "==";
  285. return Final;
  286. }
  287. /*}}}*/
  288. // stringcmp - Arbitary string compare /*{{{*/
  289. // ---------------------------------------------------------------------
  290. /* This safely compares two non-null terminated strings of arbitary
  291. length */
  292. int stringcmp(const char *A,const char *AEnd,const char *B,const char *BEnd)
  293. {
  294. for (; A != AEnd && B != BEnd; A++, B++)
  295. if (*A != *B)
  296. break;
  297. if (A == AEnd && B == BEnd)
  298. return 0;
  299. if (A == AEnd)
  300. return 1;
  301. if (B == BEnd)
  302. return -1;
  303. if (*A < *B)
  304. return -1;
  305. return 1;
  306. }
  307. /*}}}*/
  308. // stringcasecmp - Arbitary case insensitive string compare /*{{{*/
  309. // ---------------------------------------------------------------------
  310. /* */
  311. int stringcasecmp(const char *A,const char *AEnd,const char *B,const char *BEnd)
  312. {
  313. for (; A != AEnd && B != BEnd; A++, B++)
  314. if (toupper(*A) != toupper(*B))
  315. break;
  316. if (A == AEnd && B == BEnd)
  317. return 0;
  318. if (A == AEnd)
  319. return 1;
  320. if (B == BEnd)
  321. return -1;
  322. if (toupper(*A) < toupper(*B))
  323. return -1;
  324. return 1;
  325. }
  326. /*}}}*/