Subversion Repositories FlightCtrl

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2100 - 1
// Die Funktion printf_P() unterliegt ihrer eigenen Lizenz und ist nicht von der Lizenz für den MikroKopter-Teil unterstellt
2
 
3
/*
4
  Copyright (C) 1993 Free Software Foundation
5
 
6
  This file is part of the GNU IO Library.  This library is free
7
  software; you can redistribute it and/or modify it under the
8
  terms of the GNU General Public License as published by the
9
  Free Software Foundation; either version 2, or (at your option)
10
  any later version.
11
 
12
  This library is distributed in the hope that it will be useful,
13
  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
  GNU General Public License for more details.
16
 
17
  You should have received a copy of the GNU General Public License
18
  along with this library; see the file COPYING.  If not, write to the Free
19
  Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20
 
21
  As a special exception, if you link this library with files
22
  compiled with a GNU compiler to produce an executable, this does not cause
23
  the resulting executable to be covered by the GNU General Public License.
24
  This exception does not however invalidate any other reasons why
25
  the executable file might be covered by the GNU General Public License. */
26
 
27
/*
28
 * Copyright (c) 1990 Regents of the University of California.
29
 * All rights reserved.
30
 *
31
 * Redistribution and use in source and binary forms, with or without
32
 * modification, are permitted provided that the following conditions
33
 * are met:
34
 * 1. Redistributions of source code must retain the above copyright
35
 *    notice, this list of conditions and the following disclaimer.
36
 * 2. Redistributions in binary form must reproduce the above copyright
37
 *    notice, this list of conditions and the following disclaimer in the
38
 *    documentation and/or other materials provided with the distribution.
39
 * 3. [rescinded 22 July 1999]
40
 * 4. Neither the name of the University nor the names of its contributors
41
 *    may be used to endorse or promote products derived from this software
42
 *    without specific prior written permission.
43
 *
44
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
45
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
48
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54
 * SUCH DAMAGE.
55
 */
56
 
57
/******************************************************************************
58
 This file is a patched version of printf called _printf_P
59
 It is made to work with avr-gcc for Atmel AVR MCUs.
60
 There are some differences from standard printf:
61
        1. There is no floating point support (with fp the code is about 8K!)
62
        2. Return type is void
63
        3. Format string must be in program memory (by using macro printf this is
64
           done automaticaly)
65
        4. %n is not implemented (just remove the comment around it if you need it)
66
        5. If LIGHTPRINTF is defined, the code is about 550 bytes smaller and the
67
           folowing specifiers are disabled :
68
                space # * . - + p s o O
69
        6. A function void uart_sendchar(char c) is used for output. The UART must
70
                be initialized before using printf.
71
 
72
 Alexander Popov
73
 sasho@vip.orbitel.bg
74
******************************************************************************/
75
 
76
/*
77
 * Actual printf innards.
78
 *
79
 * This code is large and complicated...
80
 */
81
 
82
#include <string.h>
83
#ifdef __STDC__
84
#include <stdarg.h>
85
#else
86
#include <varargs.h>
87
#endif
88
 
89
#include "old_macros.h"
90
#include "printf_P.h"
91
#include "uart0.h"
92
 
93
 
94
//#define LIGHTPRINTF
95
char PrintZiel;
96
 
97
 
98
char Putchar(char zeichen)
99
{
100
 if(PrintZiel == OUT_LCD) { displayBuff[dispPtr++] = zeichen; return(1);}
101
 else                       return(uart_putchar(zeichen));
102
}
103
 
104
 
105
void PRINT(const char * ptr, unsigned int len)
106
{
107
 for(;len;len--) Putchar(*ptr++);
108
}
109
 
110
void PRINTP(const char * ptr, unsigned int len)
111
{
112
 for(;len;len--) Putchar(pgm_read_byte(ptr++));
113
}
114
 
115
void PAD_SP(signed char howmany)
116
{
117
        for(;howmany>0;howmany--) Putchar(' ');
118
}
119
 
120
void PAD_0(signed char howmany)
121
{
122
        for(;howmany>0;howmany--) Putchar('0');
123
}
124
 
125
#define BUF             40
126
 
127
/*
128
 * Macros for converting digits to letters and vice versa
129
 */
130
#define to_digit(c)     ((c) - '0')
131
#define  is_digit(c)    ((c)<='9' && (c)>='0')
132
#define to_char(n)      ((n) + '0')
133
 
134
/*
135
 * Flags used during conversion.
136
 */
137
#define LONGINT         0x01            /* long integer */
138
#define LONGDBL         0x02            /* long double; unimplemented */
139
#define SHORTINT                0x04            /* short integer */
140
#define ALT                     0x08            /* alternate form */
141
#define LADJUST         0x10            /* left adjustment */
142
#define ZEROPAD         0x20            /* zero (as opposed to blank) pad */
143
#define HEXPREFIX       0x40            /* add 0x or 0X prefix */
144
 
145
void _printf_P (char ziel,char const *fmt0, ...)      /* Works with string from FLASH */
146
{
147
        va_list ap;
148
        register const char *fmt; /* format string */
149
        register char ch;       /* character from fmt */
150
        register int n;         /* handy integer (short term usage) */
151
        register char *cp;      /* handy char pointer (short term usage) */
152
        const char *fmark;      /* for remembering a place in fmt */
153
        register unsigned char flags;   /* flags as above */
154
        signed char width;              /* width from format (%8d), or 0 */
155
        signed char prec;               /* precision from format (%.3d), or -1 */
156
        char sign;                              /* sign prefix (' ', '+', '-', or \0) */
157
        unsigned long _ulong=0; /* integer arguments %[diouxX] */
158
#define OCT 8
159
#define DEC 10
160
#define HEX 16
161
        unsigned char base;             /* base for [diouxX] conversion */
162
        signed char dprec;              /* a copy of prec if [diouxX], 0 otherwise */
163
        signed char dpad;                       /* extra 0 padding needed for integers */
164
        signed char fieldsz;            /* field size expanded by sign, dpad etc */
165
        /* The initialization of 'size' is to suppress a warning that
166
           'size' might be used unitialized.  It seems gcc can't
167
           quite grok this spaghetti code ... */
168
        signed char size = 0;           /* size of converted field or string */
169
        char buf[BUF];          /* space for %c, %[diouxX], %[eEfgG] */
170
        char ox[2];                     /* space for 0x hex-prefix */
171
 
172
    PrintZiel = ziel;  // bestimmt, LCD oder UART
173
        va_start(ap, fmt0);
174
 
175
        fmt = fmt0;
176
 
177
        /*
178
         * Scan the format for conversions (`%' character).
179
         */
180
        for (;;) {
181
                for (fmark = fmt; (ch = pgm_read_byte(fmt)) != '\0' && ch != '%'; fmt++)
182
                        /* void */;
183
                if ((n = fmt - fmark) != 0) {
184
                        PRINTP(fmark, n);
185
                }
186
                if (ch == '\0')
187
                        goto done;
188
                fmt++;          /* skip over '%' */
189
 
190
                flags = 0;
191
                dprec = 0;
192
                width = 0;
193
                prec = -1;
194
                sign = '\0';
195
 
196
rflag:          ch = PRG_RDB(fmt++);
197
reswitch:
198
#ifdef LIGHTPRINTF
199
        if (ch=='o' || ch=='u' || (ch|0x20)=='x') {
200
#else
201
        if (ch=='u' || (ch|0x20)=='x') {
202
#endif
203
                if (flags&LONGINT) {
204
                        _ulong=va_arg(ap, unsigned long);
205
                } else {
206
                        register unsigned int _d;
207
                        _d=va_arg(ap, unsigned int);
208
                        _ulong = flags&SHORTINT ? (unsigned long)(unsigned short)_d : (unsigned long)_d;
209
                }
210
        }
211
 
212
#ifndef LIGHTPRINTF
213
                if(ch==' ') {
214
                        /*
215
                         * ``If the space and + flags both appear, the space
216
                         * flag will be ignored.''
217
                         *      -- ANSI X3J11
218
                         */
219
                        if (!sign)
220
                                sign = ' ';
221
                        goto rflag;
222
                } else if (ch=='#') {
223
                        flags |= ALT;
224
                        goto rflag;
225
                } else if (ch=='*'||ch=='-') {
226
                        if (ch=='*') {
227
                                /*
228
                                 * ``A negative field width argument is taken as a
229
                                 * - flag followed by a positive field width.''
230
                                 *      -- ANSI X3J11
231
                                 * They don't exclude field widths read from args.
232
                                 */
233
                                if ((width = va_arg(ap, int)) >= 0)
234
                                        goto rflag;
235
                                width = -width;
236
                        }
237
                        flags |= LADJUST;
238
                        flags &= ~ZEROPAD; /* '-' disables '0' */
239
                        goto rflag;
240
                } else if (ch=='+') {
241
                        sign = '+';
242
                        goto rflag;
243
                } else if (ch=='.') {
244
                        if ((ch = PRG_RDB(fmt++)) == '*') {
245
                                n = va_arg(ap, int);
246
                                prec = n < 0 ? -1 : n;
247
                                goto rflag;
248
                        }
249
                        n = 0;
250
                        while (is_digit(ch)) {
251
                                n = n*10 + to_digit(ch);
252
                                ch = PRG_RDB(fmt++);
253
                        }
254
                        prec = n < 0 ? -1 : n;
255
                        goto reswitch;
256
                } else
257
#endif /* LIGHTPRINTF */
258
                if (ch=='0') {
259
                        /*
260
                         * ``Note that 0 is taken as a flag, not as the
261
                         * beginning of a field width.''
262
                         *      -- ANSI X3J11
263
                         */
264
                        if (!(flags & LADJUST))
265
                            flags |= ZEROPAD; /* '-' disables '0' */
266
                        goto rflag;
267
                } else if (ch>='1' && ch<='9') {
268
                        n = 0;
269
                        do {
270
                                n = 10 * n + to_digit(ch);
271
                                ch = PRG_RDB(fmt++);
272
                        } while (is_digit(ch));
273
                        width = n;
274
                        goto reswitch;
275
                } else if (ch=='h') {
276
                        flags |= SHORTINT;
277
                        goto rflag;
278
                } else if (ch=='l') {
279
                        flags |= LONGINT;
280
                        goto rflag;
281
                } else if (ch=='c') {
282
                        *(cp = buf) = va_arg(ap, int);
283
                        size = 1;
284
                        sign = '\0';
285
                } else if (ch=='D'||ch=='d'||ch=='i') {
286
                        if(ch=='D')
287
                                flags |= LONGINT;
288
                        if (flags&LONGINT) {
289
                                _ulong=va_arg(ap, long);
290
                        } else {
291
                                register int _d;
292
                                _d=va_arg(ap, int);
293
                                _ulong = flags&SHORTINT ? (long)(short)_d : (long)_d;
294
                        }
295
 
296
                        if ((long)_ulong < 0) {
297
                                _ulong = -_ulong;
298
                                sign = '-';
299
                        }
300
                        base = DEC;
301
                        goto number;
302
                } else
303
/*
304
                if (ch=='n') {
305
                        if (flags & LONGINT)
306
                                *va_arg(ap, long *) = ret;
307
                        else if (flags & SHORTINT)
308
                                *va_arg(ap, short *) = ret;
309
                        else
310
                                *va_arg(ap, int *) = ret;
311
                        continue;       // no output
312
                } else
313
*/
314
#ifndef LIGHTPRINTF
315
                if (ch=='O'||ch=='o') {
316
                        if (ch=='O')
317
                                flags |= LONGINT;
318
                        base = OCT;
319
                        goto nosign;
320
                } else if (ch=='p') {
321
                        /*
322
                         * ``The argument shall be a pointer to void.  The
323
                         * value of the pointer is converted to a sequence
324
                         * of printable characters, in an implementation-
325
                         * defined manner.''
326
                         *      -- ANSI X3J11
327
                         */
328
                        /* NOSTRICT */
329
                        _ulong = (unsigned int)va_arg(ap, void *);
330
                        base = HEX;
331
                        flags |= HEXPREFIX;
332
                        ch = 'x';
333
                        goto nosign;
334
                } else if (ch=='s') {  // print a string from RAM
335
                        if ((cp = va_arg(ap, char *)) == NULL) {
336
                                cp=buf;
337
                                cp[0] = '(';
338
                                cp[1] = 'n';
339
                                cp[2] = 'u';
340
                                cp[4] = cp[3] = 'l';
341
                                cp[5] = ')';
342
                                cp[6] = '\0';
343
                        }
344
                        if (prec >= 0) {
345
                                /*
346
                                 * can't use strlen; can only look for the
347
                                 * NUL in the first `prec' characters, and
348
                                 * strlen() will go further.
349
                                 */
350
                                char *p = (char*)memchr(cp, 0, prec);
351
 
352
                                if (p != NULL) {
353
                                        size = p - cp;
354
                                        if (size > prec)
355
                                                size = prec;
356
                                } else
357
                                        size = prec;
358
                        } else
359
                                size = strlen(cp);
360
                        sign = '\0';
361
                } else
362
#endif /* LIGHTPRINTF */
363
                if(ch=='U'||ch=='u') {
364
                        if (ch=='U')
365
                                flags |= LONGINT;
366
                        base = DEC;
367
                        goto nosign;
368
                } else if (ch=='X'||ch=='x') {
369
                        base = HEX;
370
                        /* leading 0x/X only if non-zero */
371
                        if (flags & ALT && _ulong != 0)
372
                                flags |= HEXPREFIX;
373
 
374
                        /* unsigned conversions */
375
nosign:                 sign = '\0';
376
                        /*
377
                         * ``... diouXx conversions ... if a precision is
378
                         * specified, the 0 flag will be ignored.''
379
                         *      -- ANSI X3J11
380
                         */
381
number: if ((dprec = prec) >= 0)
382
                                flags &= ~ZEROPAD;
383
 
384
                        /*
385
                         * ``The result of converting a zero value with an
386
                         * explicit precision of zero is no characters.''
387
                         *      -- ANSI X3J11
388
                         */
389
                        cp = buf + BUF;
390
                        if (_ulong != 0 || prec != 0) {
391
                                register unsigned char _d,notlastdigit;
392
                                do {
393
                                        notlastdigit=(_ulong>=base);
394
                                        _d = _ulong % base;
395
 
396
                                        if (_d<10) {
397
                                                _d+='0';
398
                                        } else {
399
                                                _d+='a'-10;
400
                                                if (ch=='X') _d&=~0x20;
401
                                        }
402
                                        *--cp=_d;
403
                                        _ulong /= base;
404
                                } while (notlastdigit);
405
#ifndef LIGHTPRINTF
406
                                // handle octal leading 0
407
                                if (base==OCT && flags & ALT && *cp != '0')
408
                                        *--cp = '0';
409
#endif
410
                        }
411
 
412
                        size = buf + BUF - cp;
413
        } else {  //default
414
                /* "%?" prints ?, unless ? is NUL */
415
                        if (ch == '\0')
416
                                goto done;
417
                        /* pretend it was %c with argument ch */
418
                        cp = buf;
419
                        *cp = ch;
420
                        size = 1;
421
                        sign = '\0';
422
                }
423
 
424
                /*
425
                 * All reasonable formats wind up here.  At this point,
426
                 * `cp' points to a string which (if not flags&LADJUST)
427
                 * should be padded out to `width' places.  If
428
                 * flags&ZEROPAD, it should first be prefixed by any
429
                 * sign or other prefix; otherwise, it should be blank
430
                 * padded before the prefix is emitted.  After any
431
                 * left-hand padding and prefixing, emit zeroes
432
                 * required by a decimal [diouxX] precision, then print
433
                 * the string proper, then emit zeroes required by any
434
                 * leftover floating precision; finally, if LADJUST,
435
                 * pad with blanks.
436
                 */
437
 
438
                /*
439
                 * compute actual size, so we know how much to pad.
440
                 */
441
                fieldsz = size;
442
 
443
                dpad = dprec - size;
444
                if (dpad < 0)
445
                    dpad = 0;
446
 
447
                if (sign)
448
                        fieldsz++;
449
                else if (flags & HEXPREFIX)
450
                        fieldsz += 2;
451
                fieldsz += dpad;
452
 
453
                /* right-adjusting blank padding */
454
                if ((flags & (LADJUST|ZEROPAD)) == 0)
455
                        PAD_SP(width - fieldsz);
456
 
457
                /* prefix */
458
                if (sign) {
459
                        PRINT(&sign, 1);
460
                } else if (flags & HEXPREFIX) {
461
                        ox[0] = '0';
462
                        ox[1] = ch;
463
                        PRINT(ox, 2);
464
                }
465
 
466
                /* right-adjusting zero padding */
467
                if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
468
                        PAD_0(width - fieldsz);
469
 
470
                /* leading zeroes from decimal precision */
471
                PAD_0(dpad);
472
 
473
                /* the string or number proper */
474
                PRINT(cp, size);
475
 
476
                /* left-adjusting padding (always blank) */
477
                if (flags & LADJUST)
478
                        PAD_SP(width - fieldsz);
479
        }
480
done:
481
        va_end(ap);
482
}