Merge tag 'fbdev-fixes-for-3.5-1' of git://github.com/schandinat/linux-2.6
[profile/ivi/kernel-adaptation-intel-automotive.git] / tools / lib / traceevent / trace-seq.c
1 /*
2  * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
3  *
4  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation;
8  * version 2.1 of the License (not later!)
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20  */
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdarg.h>
25
26 #include "event-parse.h"
27 #include "event-utils.h"
28
29 /*
30  * The TRACE_SEQ_POISON is to catch the use of using
31  * a trace_seq structure after it was destroyed.
32  */
33 #define TRACE_SEQ_POISON        ((void *)0xdeadbeef)
34 #define TRACE_SEQ_CHECK(s)                                              \
35 do {                                                                    \
36         if ((s)->buffer == TRACE_SEQ_POISON)                    \
37                 die("Usage of trace_seq after it was destroyed");       \
38 } while (0)
39
40 /**
41  * trace_seq_init - initialize the trace_seq structure
42  * @s: a pointer to the trace_seq structure to initialize
43  */
44 void trace_seq_init(struct trace_seq *s)
45 {
46         s->len = 0;
47         s->readpos = 0;
48         s->buffer_size = TRACE_SEQ_BUF_SIZE;
49         s->buffer = malloc_or_die(s->buffer_size);
50 }
51
52 /**
53  * trace_seq_destroy - free up memory of a trace_seq
54  * @s: a pointer to the trace_seq to free the buffer
55  *
56  * Only frees the buffer, not the trace_seq struct itself.
57  */
58 void trace_seq_destroy(struct trace_seq *s)
59 {
60         if (!s)
61                 return;
62         TRACE_SEQ_CHECK(s);
63         free(s->buffer);
64         s->buffer = TRACE_SEQ_POISON;
65 }
66
67 static void expand_buffer(struct trace_seq *s)
68 {
69         s->buffer_size += TRACE_SEQ_BUF_SIZE;
70         s->buffer = realloc(s->buffer, s->buffer_size);
71         if (!s->buffer)
72                 die("Can't allocate trace_seq buffer memory");
73 }
74
75 /**
76  * trace_seq_printf - sequence printing of trace information
77  * @s: trace sequence descriptor
78  * @fmt: printf format string
79  *
80  * It returns 0 if the trace oversizes the buffer's free
81  * space, 1 otherwise.
82  *
83  * The tracer may use either sequence operations or its own
84  * copy to user routines. To simplify formating of a trace
85  * trace_seq_printf is used to store strings into a special
86  * buffer (@s). Then the output may be either used by
87  * the sequencer or pulled into another buffer.
88  */
89 int
90 trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
91 {
92         va_list ap;
93         int len;
94         int ret;
95
96         TRACE_SEQ_CHECK(s);
97
98  try_again:
99         len = (s->buffer_size - 1) - s->len;
100
101         va_start(ap, fmt);
102         ret = vsnprintf(s->buffer + s->len, len, fmt, ap);
103         va_end(ap);
104
105         if (ret >= len) {
106                 expand_buffer(s);
107                 goto try_again;
108         }
109
110         s->len += ret;
111
112         return 1;
113 }
114
115 /**
116  * trace_seq_vprintf - sequence printing of trace information
117  * @s: trace sequence descriptor
118  * @fmt: printf format string
119  *
120  * The tracer may use either sequence operations or its own
121  * copy to user routines. To simplify formating of a trace
122  * trace_seq_printf is used to store strings into a special
123  * buffer (@s). Then the output may be either used by
124  * the sequencer or pulled into another buffer.
125  */
126 int
127 trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args)
128 {
129         int len;
130         int ret;
131
132         TRACE_SEQ_CHECK(s);
133
134  try_again:
135         len = (s->buffer_size - 1) - s->len;
136
137         ret = vsnprintf(s->buffer + s->len, len, fmt, args);
138
139         if (ret >= len) {
140                 expand_buffer(s);
141                 goto try_again;
142         }
143
144         s->len += ret;
145
146         return len;
147 }
148
149 /**
150  * trace_seq_puts - trace sequence printing of simple string
151  * @s: trace sequence descriptor
152  * @str: simple string to record
153  *
154  * The tracer may use either the sequence operations or its own
155  * copy to user routines. This function records a simple string
156  * into a special buffer (@s) for later retrieval by a sequencer
157  * or other mechanism.
158  */
159 int trace_seq_puts(struct trace_seq *s, const char *str)
160 {
161         int len;
162
163         TRACE_SEQ_CHECK(s);
164
165         len = strlen(str);
166
167         while (len > ((s->buffer_size - 1) - s->len))
168                 expand_buffer(s);
169
170         memcpy(s->buffer + s->len, str, len);
171         s->len += len;
172
173         return len;
174 }
175
176 int trace_seq_putc(struct trace_seq *s, unsigned char c)
177 {
178         TRACE_SEQ_CHECK(s);
179
180         while (s->len >= (s->buffer_size - 1))
181                 expand_buffer(s);
182
183         s->buffer[s->len++] = c;
184
185         return 1;
186 }
187
188 void trace_seq_terminate(struct trace_seq *s)
189 {
190         TRACE_SEQ_CHECK(s);
191
192         /* There's always one character left on the buffer */
193         s->buffer[s->len] = 0;
194 }
195
196 int trace_seq_do_printf(struct trace_seq *s)
197 {
198         TRACE_SEQ_CHECK(s);
199         return printf("%.*s", s->len, s->buffer);
200 }