Add support for octal and hexadecimal output in dumps.
[cumulus.git] / util.cc
1 /* LBS: An LFS-inspired filesystem backup system
2  * Copyright (C) 2007  Michael Vrable
3  *
4  * Utility functions for converting various datatypes to text format (and
5  * later, for parsing them back, perhaps).
6  */
7
8 #include <stdio.h>
9 #include <uuid/uuid.h>
10
11 #include <iostream>
12 #include <map>
13 #include <string>
14 #include <sstream>
15
16 using std::map;
17 using std::ostream;
18 using std::string;
19
20 /* Perform URI-style escaping of a string.  Bytes which cannot be represented
21  * directly are encoded in the form %xx (where "xx" is a string of two
22  * hexadecimal digits). */
23 string uri_encode(const string &in)
24 {
25     string out;
26
27     for (size_t i = 0; i < in.length(); i++) {
28         unsigned char c = in[i];
29
30         if (c >= '+' && c < 0x7f) {
31             out += c;
32         } else {
33             char buf[4];
34             sprintf(buf, "%%%02x", c);
35             out += buf;
36         }
37     }
38
39     return out;
40 }
41
42 /* Decoding of strings produced by uri_encode. */
43 string uri_decode(const string &in)
44 {
45     char *buf = new char[in.size() + 1];
46
47     const char *input = in.c_str();
48     char *output = buf;
49
50     while (*input != '\0') {
51         if (*input == '%') {
52             char hexbuf[4];
53             if (isxdigit(input[1]) && isxdigit(input[2])) {
54                 hexbuf[0] = input[1];
55                 hexbuf[1] = input[2];
56                 hexbuf[2] = '\0';
57                 *output++ = strtol(hexbuf, NULL, 16);
58                 input += 3;
59             } else {
60                 input++;
61             }
62         } else {
63             *output++ = *input++;
64         }
65     }
66
67     *output = '\0';
68
69     string result(buf);
70     delete buf;
71     return result;
72 }
73
74 /* Return the string representation of an integer.  Will try to produce output
75  * in decimal, hexadecimal, or octal according to base, though this is just
76  * advisory.  For negative numbers, will always use decimal. */
77 string encode_int(long long n, int base)
78 {
79     char buf[64];
80
81     if (n >= 0 && base == 16) {
82         sprintf(buf, "0x%llx", n);
83         return buf;
84     }
85
86     if (n > 0 && base == 8) {
87         sprintf(buf, "0%llo", n);
88         return buf;
89     }
90
91     sprintf(buf, "%lld", n);
92     return buf;
93 }
94
95 /* Parse the string representation of an integer.  Accepts decimal, octal, and
96  * hexadecimal, just as C would (recognizes the 0 and 0x prefixes). */
97 long long parse_int(const string &s)
98 {
99     return strtoll(s.c_str(), NULL, 0);
100 }
101
102 /* Output a dictionary of string key/value pairs to the given output stream.
103  * The format is a sequence of lines of the form "key: value". */
104 void dict_output(ostream &o, map<string, string> dict)
105 {
106     for (map<string, string>::const_iterator i = dict.begin();
107          i != dict.end(); ++i) {
108         o << i->first << ": " << i->second << "\n";
109     }
110 }