strutl.cc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. // -*- mode: cpp; mode: fold -*-
  2. // Description /*{{{*/
  3. // $Id: strutl.cc,v 1.4 1998/09/22 05:30:28 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. This is for URI/URL parsing. */
  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. // ParseCWord - Parses a string like a C "" expression /*{{{*/
  120. // ---------------------------------------------------------------------
  121. /* This expects a series of space seperated strings enclosed in ""'s.
  122. It concatenates the ""'s into a single string. */
  123. bool ParseCWord(const char *String,string &Res)
  124. {
  125. // Skip leading whitespace
  126. const char *C = String;
  127. for (;*C != 0 && *C == ' '; C++);
  128. if (*C == 0)
  129. return false;
  130. char Buffer[1024];
  131. char *Buf = Buffer;
  132. if (strlen(String) >= sizeof(Buffer))
  133. return false;
  134. for (; *C != 0; C++)
  135. {
  136. if (*C == '"')
  137. {
  138. for (C++; *C != 0 && *C != '"'; C++)
  139. *Buf++ = *C;
  140. if (*C == 0)
  141. return false;
  142. continue;
  143. }
  144. if (C != String && isspace(*C) != 0 && isspace(C[-1]) != 0)
  145. continue;
  146. if (isspace(*C) == 0)
  147. return false;
  148. *Buf++ = ' ';
  149. }
  150. *Buf = 0;
  151. Res = Buffer;
  152. return true;
  153. }
  154. /*}}}*/
  155. // QuoteString - Convert a string into quoted from /*{{{*/
  156. // ---------------------------------------------------------------------
  157. /* */
  158. string QuoteString(string Str,const char *Bad)
  159. {
  160. string Res;
  161. for (string::iterator I = Str.begin(); I != Str.end(); I++)
  162. {
  163. if (strchr(Bad,*I) != 0 || isprint(*I) == 0 ||
  164. *I <= 0x20 || *I >= 0x7F)
  165. {
  166. char Buf[10];
  167. sprintf(Buf,"%%%02x",(int)*I);
  168. Res += Buf;
  169. }
  170. else
  171. Res += *I;
  172. }
  173. return Res;
  174. }
  175. /*}}}*/
  176. // SizeToStr - Convert a long into a human readable size /*{{{*/
  177. // ---------------------------------------------------------------------
  178. /* A max of 4 digits are shown before conversion to the next highest unit. The
  179. max length of the string will be 5 chars unless the size is > 10
  180. YottaBytes (E24) */
  181. string SizeToStr(double Size)
  182. {
  183. char S[300];
  184. double ASize;
  185. if (Size >= 0)
  186. ASize = Size;
  187. else
  188. ASize = -1*Size;
  189. /* bytes, KiloBytes, MegaBytes, GigaBytes, TeraBytes, PetaBytes,
  190. ExaBytes, ZettaBytes, YottaBytes */
  191. char Ext[] = {'b','k','M','G','T','P','E','Z','Y'};
  192. int I = 0;
  193. while (I <= 8)
  194. {
  195. if (ASize < 100 && I != 0)
  196. {
  197. sprintf(S,"%.1f%c",ASize,Ext[I]);
  198. break;
  199. }
  200. if (ASize < 10000)
  201. {
  202. sprintf(S,"%.0f%c",ASize,Ext[I]);
  203. break;
  204. }
  205. ASize /= 1000.0;
  206. I++;
  207. }
  208. return S;
  209. }
  210. /*}}}*/
  211. // TimeToStr - Convert the time into a string /*{{{*/
  212. // ---------------------------------------------------------------------
  213. /* Converts a number of seconds to a hms format */
  214. string TimeToStr(unsigned long Sec)
  215. {
  216. char S[300];
  217. while (1)
  218. {
  219. if (Sec > 60*60*24)
  220. {
  221. sprintf(S,"%lid %lih%lim%lis",Sec/60/60/24,(Sec/60/60) % 24,(Sec/60) % 60,Sec % 60);
  222. break;
  223. }
  224. if (Sec > 60*60)
  225. {
  226. sprintf(S,"%lih%lim%lis",Sec/60/60,(Sec/60) % 60,Sec % 60);
  227. break;
  228. }
  229. if (Sec > 60)
  230. {
  231. sprintf(S,"%lim%lis",Sec/60,Sec % 60);
  232. break;
  233. }
  234. sprintf(S,"%lis",Sec);
  235. break;
  236. }
  237. return S;
  238. }
  239. /*}}}*/
  240. // SubstVar - Substitute a string for another string /*{{{*/
  241. // ---------------------------------------------------------------------
  242. /* This replaces all occurances of Subst with Contents in Str. */
  243. string SubstVar(string Str,string Subst,string Contents)
  244. {
  245. string::size_type Pos = 0;
  246. string::size_type OldPos = 0;
  247. string Temp;
  248. while (OldPos < Str.length() &&
  249. (Pos = Str.find(Subst,OldPos)) != string::npos)
  250. {
  251. Temp += string(Str,OldPos,Pos) + Contents;
  252. OldPos = Pos + Subst.length();
  253. }
  254. if (OldPos == 0)
  255. return Str;
  256. return Temp + string(Str,OldPos);
  257. }
  258. /*}}}*/
  259. // URItoFileName - Convert the uri into a unique file name /*{{{*/
  260. // ---------------------------------------------------------------------
  261. /* This converts a URI into a safe filename. It quotes all unsafe characters
  262. and converts / to _ and removes the scheme identifier. The resulting
  263. file name should be unique and never occur again for a different file */
  264. string URItoFileName(string URI)
  265. {
  266. string::const_iterator I = URI.begin() + URI.find(':') + 1;
  267. for (; I < URI.end() && *I == '/'; I++);
  268. // "\x00-\x20{}|\\\\^\\[\\]<>\"\x7F-\xFF";
  269. URI = QuoteString(string(I,URI.end() - I),"\\|{}[]<>\"^~_=!@#$%^&*");
  270. string::iterator J = URI.begin();
  271. for (; J != URI.end(); J++)
  272. if (*J == '/')
  273. *J = '_';
  274. return URI;
  275. }
  276. /*}}}*/
  277. // Base64Encode - Base64 Encoding routine for short strings /*{{{*/
  278. // ---------------------------------------------------------------------
  279. /* This routine performs a base64 transformation on a string. It was ripped
  280. from wget and then patched and bug fixed.
  281. This spec can be found in rfc2045 */
  282. string Base64Encode(string S)
  283. {
  284. // Conversion table.
  285. static char tbl[64] = {'A','B','C','D','E','F','G','H',
  286. 'I','J','K','L','M','N','O','P',
  287. 'Q','R','S','T','U','V','W','X',
  288. 'Y','Z','a','b','c','d','e','f',
  289. 'g','h','i','j','k','l','m','n',
  290. 'o','p','q','r','s','t','u','v',
  291. 'w','x','y','z','0','1','2','3',
  292. '4','5','6','7','8','9','+','/'};
  293. // Pre-allocate some space
  294. string Final;
  295. Final.reserve((4*S.length() + 2)/3 + 2);
  296. /* Transform the 3x8 bits to 4x6 bits, as required by
  297. base64. */
  298. for (string::const_iterator I = S.begin(); I < S.end(); I += 3)
  299. {
  300. char Bits[3] = {0,0,0};
  301. Bits[0] = I[0];
  302. if (I + 1 < S.end())
  303. Bits[1] = I[1];
  304. if (I + 2 < S.end())
  305. Bits[2] = I[2];
  306. Final += tbl[Bits[0] >> 2];
  307. Final += tbl[((Bits[0] & 3) << 4) + (Bits[1] >> 4)];
  308. if (I + 1 >= S.end())
  309. break;
  310. Final += tbl[((Bits[1] & 0xf) << 2) + (Bits[2] >> 6)];
  311. if (I + 2 >= S.end())
  312. break;
  313. Final += tbl[Bits[2] & 0x3f];
  314. }
  315. /* Apply the padding elements, this tells how many bytes the remote
  316. end should discard */
  317. if (S.length() % 3 == 2)
  318. Final += '=';
  319. if (S.length() % 3 == 1)
  320. Final += "==";
  321. return Final;
  322. }
  323. /*}}}*/
  324. // stringcmp - Arbitary string compare /*{{{*/
  325. // ---------------------------------------------------------------------
  326. /* This safely compares two non-null terminated strings of arbitary
  327. length */
  328. int stringcmp(const char *A,const char *AEnd,const char *B,const char *BEnd)
  329. {
  330. for (; A != AEnd && B != BEnd; A++, B++)
  331. if (*A != *B)
  332. break;
  333. if (A == AEnd && B == BEnd)
  334. return 0;
  335. if (A == AEnd)
  336. return 1;
  337. if (B == BEnd)
  338. return -1;
  339. if (*A < *B)
  340. return -1;
  341. return 1;
  342. }
  343. /*}}}*/
  344. // stringcasecmp - Arbitary case insensitive string compare /*{{{*/
  345. // ---------------------------------------------------------------------
  346. /* */
  347. int stringcasecmp(const char *A,const char *AEnd,const char *B,const char *BEnd)
  348. {
  349. for (; A != AEnd && B != BEnd; A++, B++)
  350. if (toupper(*A) != toupper(*B))
  351. break;
  352. if (A == AEnd && B == BEnd)
  353. return 0;
  354. if (A == AEnd)
  355. return 1;
  356. if (B == BEnd)
  357. return -1;
  358. if (toupper(*A) < toupper(*B))
  359. return -1;
  360. return 1;
  361. }
  362. /*}}}*/