Move "bytes_to_str()" to "strutil.c" from "packet.c" - it's just a
[obnox/wireshark/wip.git] / epan / strutil.c
1 /* strutil.c
2  * String utility routines
3  *
4  * $Id: strutil.c,v 1.6 2000/11/13 07:19:32 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <stdlib.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <glib.h>
34 #include "strutil.h"
35
36
37 /*
38  * Given a pointer into a data buffer, and to the end of the buffer,
39  * find the end of the (putative) line at that position in the data
40  * buffer.
41  * Return a pointer to the EOL character(s) in "*eol".
42  */
43 const u_char *
44 find_line_end(const u_char *data, const u_char *dataend, const u_char **eol)
45 {
46   const u_char *lineend;
47
48   lineend = memchr(data, '\n', dataend - data);
49   if (lineend == NULL) {
50     /*
51      * No LF - line is probably continued in next TCP segment.
52      */
53     lineend = dataend;
54     *eol = dataend;
55   } else {
56     /*
57      * Is the LF at the beginning of the line?
58      */
59     if (lineend > data) {
60       /*
61        * No - is it preceded by a carriage return?
62        * (Perhaps it's supposed to be, but that's not guaranteed....)
63        */
64       if (*(lineend - 1) == '\r') {
65         /*
66          * Yes.  The EOL starts with the CR.
67          */
68         *eol = lineend - 1;
69       } else {
70         /*
71          * No.  The EOL starts with the LF.
72          */
73         *eol = lineend;
74
75         /*
76          * I seem to remember that we once saw lines ending with LF-CR
77          * in an HTTP request or response, so check if it's *followed*
78          * by a carriage return.
79          */
80         if (lineend < (dataend - 1) && *(lineend + 1) == '\r') {
81           /*
82            * It's <non-LF><LF><CR>; say it ends with the CR.
83            */
84           lineend++;
85         }
86       }
87     } else {
88       /*
89        * Yes - the EOL starts with the LF.
90        */
91       *eol = lineend;
92     }
93
94     /*
95      * Point to the character after the last character.
96      */
97     lineend++;
98   }
99   return lineend;
100 }
101
102 /*
103  * Get the length of the next token in a line, and the beginning of the
104  * next token after that (if any).
105  * Return 0 if there is no next token.
106  */
107 int
108 get_token_len(const u_char *linep, const u_char *lineend,
109               const u_char **next_token)
110 {
111   const u_char *tokenp;
112   int token_len;
113
114   tokenp = linep;
115   
116   /*
117    * Search for a blank, a CR or an LF, or the end of the buffer.
118    */
119   while (linep < lineend && *linep != ' ' && *linep != '\r' && *linep != '\n')
120       linep++;
121   token_len = linep - tokenp;
122
123   /*
124    * Skip trailing blanks.
125    */
126   while (linep < lineend && *linep == ' ')
127     linep++;
128
129   *next_token = linep;
130
131   return token_len;
132 }
133
134
135 #define INITIAL_FMTBUF_SIZE     128
136
137 /*
138  * Given a string, generate a string from it that shows non-printable
139  * characters as C-style escapes, and return a pointer to it.
140  */
141 gchar *
142 format_text(const u_char *string, int len)
143 {
144   static gchar *fmtbuf;
145   static int fmtbuf_len;
146   int column;
147   const u_char *stringend = string + len;
148   u_char c;
149   int i;
150
151   /*
152    * Allocate the buffer if it's not already allocated.
153    */
154   if (fmtbuf == NULL) {
155     fmtbuf = g_malloc(INITIAL_FMTBUF_SIZE);
156     fmtbuf_len = INITIAL_FMTBUF_SIZE;
157   }
158   column = 0;
159   while (string < stringend) {
160     /*
161      * Is there enough room for this character, if it expands to
162      * a backslash plus 3 octal digits (which is the most it can
163      * expand to), and also enough room for a terminating '\0'?
164      */
165     if (column+3+1 >= fmtbuf_len) {
166       /*
167        * Double the buffer's size if it's not big enough.
168        * The size of the buffer starts at 128, so doubling its size
169        * adds at least another 128 bytes, which is more than enough
170        * for one more character plus a terminating '\0'.
171        */
172       fmtbuf_len = fmtbuf_len * 2;
173       fmtbuf = g_realloc(fmtbuf, fmtbuf_len);
174     }
175     c = *string++;
176     if (isprint(c)) {
177       fmtbuf[column] = c;
178       column++;
179     } else {
180       fmtbuf[column] =  '\\';
181       column++;
182       switch (c) {
183
184       case '\\':
185         fmtbuf[column] = '\\';
186         column++;
187         break;
188
189       case '\a':
190         fmtbuf[column] = 'a';
191         column++;
192         break;
193
194       case '\b':
195         fmtbuf[column] = 'b';
196         column++;
197         break;
198
199       case '\f':
200         fmtbuf[column] = 'f';
201         column++;
202         break;
203
204       case '\n':
205         fmtbuf[column] = 'n';
206         column++;
207         break;
208
209       case '\r':
210         fmtbuf[column] = 'r';
211         column++;
212         break;
213
214       case '\t':
215         fmtbuf[column] = 't';
216         column++;
217         break;
218
219       case '\v':
220         fmtbuf[column] = 'v';
221         column++;
222         break;
223
224       default:
225         i = (c>>6)&03;
226         fmtbuf[column] = i + '0';
227         column++;
228         i = (c>>3)&07;
229         fmtbuf[column] = i + '0';
230         column++;
231         i = (c>>0)&07;
232         fmtbuf[column] = i + '0';
233         column++;
234         break;
235       }
236     }
237   }
238   fmtbuf[column] = '\0';
239   return fmtbuf;
240 }
241
242 /* Max string length for displaying byte string.  */
243 #define MAX_BYTE_STR_LEN        32
244
245 /* Turn an array of bytes into a string showing the bytes in hex. */
246 #define N_BYTES_TO_STR_STRINGS  6
247 gchar *
248 bytes_to_str(const guint8 *bd, int bd_len) {
249   static gchar  str[N_BYTES_TO_STR_STRINGS][MAX_BYTE_STR_LEN+3+1];
250   static int    cur_idx;
251   gchar        *cur;
252   gchar        *p;
253   int           len;
254   static const char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
255                                 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
256
257   cur_idx++;
258   if (cur_idx >= N_BYTES_TO_STR_STRINGS)
259     cur_idx = 0;
260   cur = &str[cur_idx][0];
261   p = cur;
262   len = MAX_BYTE_STR_LEN;
263   while (bd_len > 0 && len > 0) {
264     *p++ = hex[(*bd) >> 4];
265     *p++ = hex[(*bd) & 0xF];
266     len -= 2;
267     bd++;
268     bd_len--;
269   }
270   if (bd_len != 0) {
271     /* Note that we're not showing the full string.  */
272     *p++ = '.';
273     *p++ = '.';
274     *p++ = '.';
275   }
276   *p = '\0';
277   return cur;
278 }