nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* source: xiotransfer.c */ |
2 | /* Copyright Gerhard Rieger 2007-2012 */ |
||
3 | /* Published under the GNU General Public License V.2, see file COPYING */ |
||
4 | |||
5 | /* this is the source file of the data transfer function */ |
||
6 | |||
7 | #include "xiosysincludes.h" |
||
8 | |||
9 | #include "mytypes.h" |
||
10 | #include "compat.h" |
||
11 | #include "error.h" |
||
12 | |||
13 | #include "sycls.h" |
||
14 | #include "xio.h" |
||
15 | |||
16 | static |
||
17 | int cv_newline(unsigned char **buff, ssize_t *bytes, int lineterm1, int lineterm2); |
||
18 | |||
19 | |||
20 | #define MAXTIMESTAMPLEN 128 |
||
21 | /* prints the timestamp to the buffer and terminates it with '\0'. This buffer |
||
22 | should be at least MAXTIMESTAMPLEN bytes long. |
||
23 | returns 0 on success or -1 if an error occurred */ |
||
24 | int gettimestamp(char *timestamp) { |
||
25 | size_t bytes; |
||
26 | #if HAVE_GETTIMEOFDAY || 1 |
||
27 | struct timeval now; |
||
28 | int result; |
||
29 | time_t nowt; |
||
30 | #else /* !HAVE_GETTIMEOFDAY */ |
||
31 | time_t now; |
||
32 | #endif /* !HAVE_GETTIMEOFDAY */ |
||
33 | |||
34 | #if HAVE_GETTIMEOFDAY || 1 |
||
35 | result = gettimeofday(&now, NULL); |
||
36 | if (result < 0) { |
||
37 | return result; |
||
38 | } else { |
||
39 | nowt = now.tv_sec; |
||
40 | #if HAVE_STRFTIME |
||
41 | bytes = strftime(timestamp, 20, "%Y/%m/%d %H:%M:%S", localtime(&nowt)); |
||
42 | bytes += sprintf(timestamp+19, "."F_tv_usec" ", now.tv_usec); |
||
43 | #else |
||
44 | strcpy(timestamp, ctime(&nowt)); |
||
45 | bytes = strlen(timestamp); |
||
46 | #endif |
||
47 | } |
||
48 | #else /* !HAVE_GETTIMEOFDAY */ |
||
49 | now = time(NULL); if (now == (time_t)-1) { |
||
50 | return -1; |
||
51 | } else { |
||
52 | #if HAVE_STRFTIME |
||
53 | bytes = strftime(timestamp, 21, "%Y/%m/%d %H:%M:%S ", localtime(&now)); |
||
54 | #else |
||
55 | strcpy(timestamp, ctime(&now)); |
||
56 | bytes = strlen(timestamp); |
||
57 | #endif |
||
58 | } |
||
59 | #endif /* !HAVE_GETTIMEOFDAY */ |
||
60 | return 0; |
||
61 | } |
||
62 | |||
63 | |||
64 | static const char *prefixltor = "> "; |
||
65 | static const char *prefixrtol = "< "; |
||
66 | static unsigned long numltor; |
||
67 | static unsigned long numrtol; |
||
68 | /* print block header (during verbose or hex dump) |
||
69 | returns 0 on success or -1 if an error occurred */ |
||
70 | static int |
||
71 | xioprintblockheader(FILE *file, size_t bytes, bool righttoleft) { |
||
72 | char timestamp[MAXTIMESTAMPLEN]; |
||
73 | char buff[128+MAXTIMESTAMPLEN]; |
||
74 | if (gettimestamp(timestamp) < 0) { |
||
75 | return -1; |
||
76 | } |
||
77 | if (righttoleft) { |
||
78 | sprintf(buff, "%s%s length="F_Zu" from=%lu to=%lu\n", |
||
79 | prefixrtol, timestamp, bytes, numrtol, numrtol+bytes-1); |
||
80 | numrtol+=bytes; |
||
81 | } else { |
||
82 | sprintf(buff, "%s%s length="F_Zu" from=%lu to=%lu\n", |
||
83 | prefixltor, timestamp, bytes, numltor, numltor+bytes-1); |
||
84 | numltor+=bytes; |
||
85 | } |
||
86 | fputs(buff, file); |
||
87 | return 0; |
||
88 | } |
||
89 | |||
90 | |||
91 | /* inpipe is suspected to have read data available; read at most bufsiz bytes |
||
92 | and transfer them to outpipe. Perform required data conversions. |
||
93 | buff must be a malloc()'ed storage and might be realloc()'ed in this |
||
94 | function if more space is required after conversions. |
||
95 | Returns the number of bytes written, or 0 on EOF or <0 if an |
||
96 | error occurred or when data was read but none written due to conversions |
||
97 | (with EAGAIN). EAGAIN also occurs when reading from a nonblocking FD where |
||
98 | the file has a mandatory lock. |
||
99 | If 0 bytes were read (EOF), it does NOT shutdown or close a channel, and it |
||
100 | does NOT write a zero bytes block. |
||
101 | */ |
||
102 | /* inpipe, outpipe must be single descriptors (not dual!) */ |
||
103 | int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe, |
||
104 | unsigned char **buff, size_t bufsiz, bool righttoleft) { |
||
105 | ssize_t bytes, writt = 0; |
||
106 | |||
107 | bytes = xioread(inpipe, *buff, bufsiz); |
||
108 | if (bytes < 0) { |
||
109 | if (errno != EAGAIN) |
||
110 | XIO_RDSTREAM(inpipe)->eof = 2; |
||
111 | /*xioshutdown(inpipe, SHUT_RD);*/ |
||
112 | return -1; |
||
113 | } |
||
114 | if (bytes == 0 && XIO_RDSTREAM(inpipe)->ignoreeof && |
||
115 | !inpipe->stream.closing) { |
||
116 | ; |
||
117 | } else if (bytes == 0) { |
||
118 | XIO_RDSTREAM(inpipe)->eof = 2; |
||
119 | inpipe->stream.closing = MAX(inpipe->stream.closing, 1); |
||
120 | } |
||
121 | |||
122 | if (bytes > 0) { |
||
123 | /* handle escape char */ |
||
124 | if (XIO_RDSTREAM(inpipe)->escape != -1) { |
||
125 | /* check input data for escape char */ |
||
126 | unsigned char *ptr = *buff; |
||
127 | size_t ctr = 0; |
||
128 | while (ctr < bytes) { |
||
129 | if (*ptr == XIO_RDSTREAM(inpipe)->escape) { |
||
130 | /* found: set flag, truncate input data */ |
||
131 | XIO_RDSTREAM(inpipe)->actescape = true; |
||
132 | bytes = ctr; |
||
133 | Info("escape char found in input"); |
||
134 | break; |
||
135 | } |
||
136 | ++ptr; ++ctr; |
||
137 | } |
||
138 | if (ctr != bytes) { |
||
139 | XIO_RDSTREAM(inpipe)->eof = 2; |
||
140 | } |
||
141 | } |
||
142 | } |
||
143 | |||
144 | if (XIO_RDSTREAM(inpipe)->lineterm != |
||
145 | XIO_WRSTREAM(outpipe)->lineterm) { |
||
146 | cv_newline(buff, &bytes, |
||
147 | XIO_RDSTREAM(inpipe)->lineterm, |
||
148 | XIO_WRSTREAM(outpipe)->lineterm); |
||
149 | } |
||
150 | if (bytes == 0) { |
||
151 | /*errno = EAGAIN; return -1;*/ |
||
152 | return bytes; |
||
153 | } |
||
154 | |||
155 | if (xioparams->verbose && xioparams->verbhex) { |
||
156 | /* Hack-o-rama */ |
||
157 | size_t i = 0; |
||
158 | size_t j; |
||
159 | size_t N = 16; |
||
160 | const unsigned char *end, *s, *t; |
||
161 | s = *buff; |
||
162 | end = (*buff)+bytes; |
||
163 | xioprintblockheader(stderr, bytes, righttoleft); |
||
164 | while (s < end) { |
||
165 | /*! prefix? */ |
||
166 | j = Min(N, (size_t)(end-s)); |
||
167 | |||
168 | /* print hex */ |
||
169 | t = s; |
||
170 | i = 0; |
||
171 | while (i < j) { |
||
172 | int c = *t++; |
||
173 | fprintf(stderr, " %02x", c); |
||
174 | ++i; |
||
175 | if (c == '\n') break; |
||
176 | } |
||
177 | |||
178 | /* fill hex column */ |
||
179 | while (i < N) { |
||
180 | fputs(" ", stderr); |
||
181 | ++i; |
||
182 | } |
||
183 | fputs(" ", stderr); |
||
184 | |||
185 | /* print acsii */ |
||
186 | t = s; |
||
187 | i = 0; |
||
188 | while (i < j) { |
||
189 | int c = *t++; |
||
190 | if (c == '\n') { |
||
191 | fputc('.', stderr); |
||
192 | break; |
||
193 | } |
||
194 | if (!isprint(c)) |
||
195 | c = '.'; |
||
196 | fputc(c, stderr); |
||
197 | ++i; |
||
198 | } |
||
199 | |||
200 | fputc('\n', stderr); |
||
201 | s = t; |
||
202 | } |
||
203 | fputs("--\n", stderr); |
||
204 | } else if (xioparams->verbose) { |
||
205 | size_t i = 0; |
||
206 | xioprintblockheader(stderr, bytes, righttoleft); |
||
207 | while (i < (size_t)bytes) { |
||
208 | int c = (*buff)[i]; |
||
209 | if (i > 0 && (*buff)[i-1] == '\n') |
||
210 | /*! prefix? */; |
||
211 | switch (c) { |
||
212 | case '\a' : fputs("\\a", stderr); break; |
||
213 | case '\b' : fputs("\\b", stderr); break; |
||
214 | case '\t' : fputs("\t", stderr); break; |
||
215 | case '\n' : fputs("\n", stderr); break; |
||
216 | case '\v' : fputs("\\v", stderr); break; |
||
217 | case '\f' : fputs("\\f", stderr); break; |
||
218 | case '\r' : fputs("\\r", stderr); break; |
||
219 | case '\\' : fputs("\\\\", stderr); break; |
||
220 | default: |
||
221 | if (!isprint(c)) |
||
222 | c = '.'; |
||
223 | fputc(c, stderr); |
||
224 | break; |
||
225 | } |
||
226 | ++i; |
||
227 | } |
||
228 | } else if (xioparams->verbhex) { |
||
229 | int i; |
||
230 | /* print prefix */ |
||
231 | xioprintblockheader(stderr, bytes, righttoleft); |
||
232 | for (i = 0; i < bytes; ++i) { |
||
233 | fprintf(stderr, " %02x", (*buff)[i]); |
||
234 | } |
||
235 | fputc('\n', stderr); |
||
236 | } |
||
237 | |||
238 | writt = xiowrite(outpipe, *buff, bytes); |
||
239 | if (writt < 0) { |
||
240 | /* EAGAIN when nonblocking but a mandatory lock is on file. |
||
241 | the problem with EAGAIN is that the read cannot be repeated, |
||
242 | so we need to buffer the data and try to write it later |
||
243 | again. not yet implemented, sorry. */ |
||
244 | #if 0 |
||
245 | if (errno == EPIPE) { |
||
246 | return 0; /* can no longer write; handle like EOF */ |
||
247 | } |
||
248 | #endif |
||
249 | return -1; |
||
250 | } else { |
||
251 | Info3("transferred "F_Zu" bytes from %d to %d", |
||
252 | writt, XIO_GETRDFD(inpipe), XIO_GETWRFD(outpipe)); |
||
253 | } |
||
254 | return writt; |
||
255 | } |
||
256 | |||
257 | #define CR '\r' |
||
258 | #define LF '\n' |
||
259 | |||
260 | |||
261 | static int cv_newline(unsigned char **buff, ssize_t *bytes, |
||
262 | int lineterm1, int lineterm2) { |
||
263 | /* must perform newline changes */ |
||
264 | if (lineterm1 <= LINETERM_CR && lineterm2 <= LINETERM_CR) { |
||
265 | /* no change in data length */ |
||
266 | unsigned char from, to, *p, *z; |
||
267 | if (lineterm1 == LINETERM_RAW) { |
||
268 | from = '\n'; to = '\r'; |
||
269 | } else { |
||
270 | from = '\r'; to = '\n'; |
||
271 | } |
||
272 | z = *buff + *bytes; |
||
273 | p = *buff; |
||
274 | while (p < z) { |
||
275 | if (*p == from) *p = to; |
||
276 | ++p; |
||
277 | } |
||
278 | |||
279 | } else if (lineterm1 == LINETERM_CRNL) { |
||
280 | /* buffer becomes shorter */ |
||
281 | unsigned char to, *s, *t, *z; |
||
282 | if (lineterm2 == LINETERM_RAW) { |
||
283 | to = '\n'; |
||
284 | } else { |
||
285 | to = '\r'; |
||
286 | } |
||
287 | z = *buff + *bytes; |
||
288 | s = t = *buff; |
||
289 | while (s < z) { |
||
290 | if (*s == '\r') { |
||
291 | ++s; |
||
292 | continue; |
||
293 | } |
||
294 | if (*s == '\n') { |
||
295 | *t++ = to; ++s; |
||
296 | } else { |
||
297 | *t++ = *s++; |
||
298 | } |
||
299 | } |
||
300 | *bytes = t - *buff; |
||
301 | } else { |
||
302 | /* buffer becomes longer, must alloc another space */ |
||
303 | unsigned char *buf2; |
||
304 | unsigned char from; unsigned char *s, *t, *z; |
||
305 | if (lineterm1 == LINETERM_RAW) { |
||
306 | from = '\n'; |
||
307 | } else { |
||
308 | from = '\r'; |
||
309 | } |
||
310 | if ((buf2 = Malloc(2*xioparams->bufsiz + 1)) == NULL) { |
||
311 | return -1; |
||
312 | } |
||
313 | s = *buff; t = buf2; z = *buff + *bytes; |
||
314 | while (s < z) { |
||
315 | if (*s == from) { |
||
316 | *t++ = '\r'; *t++ = '\n'; |
||
317 | ++s; |
||
318 | continue; |
||
319 | } else { |
||
320 | *t++ = *s++; |
||
321 | } |
||
322 | } |
||
323 | free(*buff); |
||
324 | *buff = buf2; |
||
325 | *bytes = t - buf2;; |
||
326 | } |
||
327 | return 0; |
||
328 | } |