From 860998d337f0a65dbbf832055f1efbab50d4fcd8 Mon Sep 17 00:00:00 2001 From: "tridge60@gmail.com" Date: Mon, 21 Mar 2011 07:25:48 +0000 Subject: [PATCH] implemented typesafe PSTR() This makes PSTR() type safe by using a 1 byte wrapper structure. Attempts to use the wrong varient of a print function will generate a compilation error. git-svn-id: https://arducopter.googlecode.com/svn/trunk@1797 f9c3cf11-9bcb-44bc-f272-b75c42450872 --- libraries/AP_Common/AP_Common.h | 29 +++++++++++++++++++++++++-- libraries/AP_Common/AP_Var.cpp | 4 ++-- libraries/AP_Common/AP_Var.h | 24 +++++++++++----------- libraries/AP_GPS/AP_GPS_Auto.cpp | 6 +++--- libraries/AP_GPS/AP_GPS_NMEA.cpp | 6 +++--- libraries/FastSerial/BetterStream.cpp | 8 ++++---- libraries/FastSerial/BetterStream.h | 9 ++++++--- libraries/FastSerial/vprintf.cpp | 2 +- libraries/PID/PID.h | 4 ++-- libraries/RC_Channel/RC_Channel.h | 2 +- 10 files changed, 61 insertions(+), 33 deletions(-) diff --git a/libraries/AP_Common/AP_Common.h b/libraries/AP_Common/AP_Common.h index 4723527b21..d65245f17c 100644 --- a/libraries/AP_Common/AP_Common.h +++ b/libraries/AP_Common/AP_Common.h @@ -1,4 +1,4 @@ -// -*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: t -*- +// -*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- // // This is free software; you can redistribute it and/or modify it under // the terms of the GNU Lesser General Public License as published by the @@ -21,6 +21,14 @@ #undef round #undef abs +// prog_char_t is used as a wrapper type for prog_char, which is +// a character stored in flash. By using this wrapper type we can +// auto-detect at compile time if a call to a string function is using +// a flash-stored string or not +typedef struct { + char c; +} prog_char_t; + #include #include "include/menu.h" /// simple menu subsystem #include "c++.h" // c++ additions @@ -72,8 +80,25 @@ # undef PROGMEM # define PROGMEM __attribute__(( section(".progmem.data") )) # undef PSTR -# define PSTR(s) (__extension__({static prog_char __c[] PROGMEM = (s); &__c[0];})) +# define PSTR(s) (__extension__({static prog_char __c[] PROGMEM = (s); \ + (prog_char_t *)&__c[0];})) #endif + +static inline int strcasecmp_P(const char *str1, const prog_char_t *pstr) +{ + return strcasecmp_P(str1, (const prog_char *)pstr); +} + +static inline int strcmp_P(const char *str1, const prog_char_t *pstr) +{ + return strcmp_P(str1, (const prog_char *)pstr); +} + +static inline size_t strlcat_P(char *buffer, const prog_char_t *pstr, size_t buffer_size) +{ + return strlcat_P(buffer, (const prog_char *)pstr, buffer_size); +} + //@} diff --git a/libraries/AP_Common/AP_Var.cpp b/libraries/AP_Common/AP_Var.cpp index 1eee8f2843..aab6b949ec 100644 --- a/libraries/AP_Common/AP_Var.cpp +++ b/libraries/AP_Common/AP_Var.cpp @@ -37,7 +37,7 @@ uint16_t AP_Var::_bytes_in_use; // Constructor for standalone variables // -AP_Var::AP_Var(Key key, const prog_char *name, Flags flags) : +AP_Var::AP_Var(Key key, const prog_char_t *name, Flags flags) : _group(NULL), _key(key | k_key_not_located), _name(name), @@ -54,7 +54,7 @@ AP_Var::AP_Var(Key key, const prog_char *name, Flags flags) : // Constructor for variables in a group // -AP_Var::AP_Var(AP_Var_group *group, Key index, const prog_char *name, Flags flags) : +AP_Var::AP_Var(AP_Var_group *group, Key index, const prog_char_t *name, Flags flags) : _group(group), _key(index), _name(name), diff --git a/libraries/AP_Common/AP_Var.h b/libraries/AP_Common/AP_Var.h index fefa6d00e6..7b545208e3 100644 --- a/libraries/AP_Common/AP_Var.h +++ b/libraries/AP_Common/AP_Var.h @@ -161,7 +161,7 @@ public: /// @param name An optional name by which the variable may be known. /// @param flags Optional flags which control how the variable behaves. /// - AP_Var(Key key = k_key_none, const prog_char *name = NULL, Flags flags = k_flags_none); + AP_Var(Key key = k_key_none, const prog_char_t *name = NULL, Flags flags = k_flags_none); /// Constructor for variable belonging to a group /// @@ -170,7 +170,7 @@ public: /// @param name An optional name by which the variable may be known. /// @param flags Optional flags which control how the variable behaves. /// - AP_Var(AP_Var_group *group, Key index, const prog_char *name, Flags flags = k_flags_none); + AP_Var(AP_Var_group *group, Key index, const prog_char_t *name, Flags flags = k_flags_none); /// Destructor /// @@ -361,7 +361,7 @@ private: AP_Var_group *_group; ///< Group that the variable may be a member of AP_Var *_link; ///< linked list pointer to next variable Key _key; ///< Storage key; see the discussion of Key above. - const prog_char *_name; ///< name known to external agents (GCS, etc.) + const prog_char_t *_name; ///< name known to external agents (GCS, etc.) uint8_t _flags; ///< flag bits // static state used by ::lookup @@ -415,7 +415,7 @@ public: /// @param key Storage key for the group. /// @param name An optional name prefix for members of the group. /// - AP_Var_group(Key key = k_key_none, const prog_char *name = NULL, Flags flags = k_flags_none) : + AP_Var_group(Key key = k_key_none, const prog_char_t *name = NULL, Flags flags = k_flags_none) : AP_Var(key, name, flags | k_flag_is_group) { _bytes_in_use += sizeof(*this); @@ -483,7 +483,7 @@ public: /// AP_VarT (const T initial_value = 0, Key key = k_key_none, - const prog_char *name = NULL, + const prog_char_t *name = NULL, Flags flags = k_flags_none) : AP_Var(key, name, flags), _value(initial_value) @@ -506,7 +506,7 @@ public: AP_VarT (AP_Var_group *group, // XXX maybe make this a ref? Key index, T initial_value, - const prog_char *name = NULL, + const prog_char_t *name = NULL, Flags flags = k_flags_none) : AP_Var(group, index, name, flags), _value(initial_value) @@ -616,7 +616,7 @@ public: /// @param flags Optional flags that may affect the behavior of the variable. /// AP_VarS (Key key = k_key_none, - const prog_char *name = NULL, + const prog_char_t *name = NULL, Flags flags = k_flags_none) : AP_Var(key, name, flags) { @@ -636,7 +636,7 @@ public: /// AP_VarS (AP_Var_group *group, // XXX maybe make this a ref? Key index, - const prog_char *name = NULL, + const prog_char_t *name = NULL, Flags flags = k_flags_none) : AP_Var(group, index, name, flags) { @@ -726,7 +726,7 @@ public: /// @param flags Optional flags that may affect the behavior of the variable. /// AP_VarA (Key key = k_key_none, - const prog_char *name = NULL, + const prog_char_t *name = NULL, Flags flags = k_flags_none) : AP_Var(key, name, flags) { @@ -746,7 +746,7 @@ public: /// AP_VarA (AP_Var_group *group, // XXX maybe make this a ref? Key index, - const prog_char *name = NULL, + const prog_char_t *name = NULL, Flags flags = k_flags_none) : AP_Var(group, index, name, flags) { @@ -841,7 +841,7 @@ public: /// AP_Float16(float initial_value = 0, Key key = k_key_none, - const prog_char *name = NULL, + const prog_char_t *name = NULL, Flags flags = k_flags_none) : AP_Float(initial_value, key, name, flags) { @@ -851,7 +851,7 @@ public: AP_Float16(AP_Var_group *group, Key index, float initial_value = 0, - const prog_char *name = NULL, + const prog_char_t *name = NULL, Flags flags = k_flags_none) : AP_Float(group, index, initial_value, name, flags) { diff --git a/libraries/AP_GPS/AP_GPS_Auto.cpp b/libraries/AP_GPS/AP_GPS_Auto.cpp index 2e485ee367..2dc4891d59 100644 --- a/libraries/AP_GPS/AP_GPS_Auto.cpp +++ b/libraries/AP_GPS/AP_GPS_Auto.cpp @@ -186,9 +186,9 @@ AP_GPS_Auto::_detect(void) if (0 == tries) { Serial.print('*'); // use the FastSerial port handle so that we can use PROGMEM strings - _fs->println_P(_mtk_set_binary); - _fs->println_P(_ublox_set_binary); - _fs->println_P(_sirf_set_binary); + _fs->println_P((const prog_char_t *)_mtk_set_binary); + _fs->println_P((const prog_char_t *)_ublox_set_binary); + _fs->println_P((const prog_char_t *)_sirf_set_binary); // give the GPS time to react to the settings delay(100); diff --git a/libraries/AP_GPS/AP_GPS_NMEA.cpp b/libraries/AP_GPS/AP_GPS_NMEA.cpp index 5aaa202993..e16601c513 100644 --- a/libraries/AP_GPS/AP_GPS_NMEA.cpp +++ b/libraries/AP_GPS/AP_GPS_NMEA.cpp @@ -109,13 +109,13 @@ void AP_GPS_NMEA::init(void) BetterStream *bs = (BetterStream *)_port; // send the SiRF init strings - bs->print_P(_SiRF_init_string); + bs->print_P((const prog_char_t *)_SiRF_init_string); // send the MediaTek init strings - bs->print_P(_MTK_init_string); + bs->print_P((const prog_char_t *)_MTK_init_string); // send the ublox init strings - bs->print_P(_ublox_init_string); + bs->print_P((const prog_char_t *)_ublox_init_string); } bool AP_GPS_NMEA::read(void) diff --git a/libraries/FastSerial/BetterStream.cpp b/libraries/FastSerial/BetterStream.cpp index 8100829456..a12c3902dc 100644 --- a/libraries/FastSerial/BetterStream.cpp +++ b/libraries/FastSerial/BetterStream.cpp @@ -17,16 +17,16 @@ // Stream extensions//////////////////////////////////////////////////////////// void -BetterStream::print_P(const prog_char *s) +BetterStream::print_P(const prog_char_t *s) { char c; - while ('\0' != (c = pgm_read_byte(s++))) + while ('\0' != (c = pgm_read_byte((const prog_char *)s++))) write(c); } void -BetterStream::println_P(const char *s) +BetterStream::println_P(const prog_char_t *s) { print_P(s); println(); @@ -43,7 +43,7 @@ BetterStream::printf(const char *fmt, ...) } void -BetterStream::printf_P(const char *fmt, ...) +BetterStream::_printf_P(const prog_char *fmt, ...) { va_list ap; diff --git a/libraries/FastSerial/BetterStream.h b/libraries/FastSerial/BetterStream.h index 275424578c..648f3160c2 100644 --- a/libraries/FastSerial/BetterStream.h +++ b/libraries/FastSerial/BetterStream.h @@ -13,6 +13,7 @@ #include #include +#include class BetterStream : public Stream { public: @@ -20,13 +21,15 @@ public: } // Stream extensions - void print_P(const char *); - void println_P(const char *); + void print_P(const prog_char_t *); + void println_P(const prog_char_t *); void printf(const char *, ...) __attribute__ ((format(__printf__, 2, 3))); - void printf_P(const char *, ...) + void _printf_P(const prog_char *, ...); __attribute__ ((format(__printf__, 2, 3))); +#define printf_P(fmt, ...) _printf_P((const prog_char *)fmt, ## __VA_ARGS__) + private: void _vprintf(unsigned char, const char *, va_list) __attribute__ ((format(__printf__, 3, 0))); diff --git a/libraries/FastSerial/vprintf.cpp b/libraries/FastSerial/vprintf.cpp index 5dffefb683..3c83fe339a 100644 --- a/libraries/FastSerial/vprintf.cpp +++ b/libraries/FastSerial/vprintf.cpp @@ -246,7 +246,7 @@ BetterStream::_vprintf (unsigned char in_progmem, const char *fmt, va_list ap) p = PSTR("inf"); if (vtype & FTOA_NAN) p = PSTR("nan"); - while ( (ndigs = pgm_read_byte(p)) != 0) { + while ( (ndigs = pgm_read_byte((const prog_char *)p)) != 0) { if (flags & FL_FLTUPP) ndigs += 'I' - 'i'; write(ndigs); diff --git a/libraries/PID/PID.h b/libraries/PID/PID.h index 774721cb62..68a3e13238 100644 --- a/libraries/PID/PID.h +++ b/libraries/PID/PID.h @@ -29,7 +29,7 @@ public: /// @param initial_imax Initial value for the imax term.4 /// PID(AP_Var::Key key, - const prog_char *name, + const prog_char_t *name, const float &initial_p = 0.0, const float &initial_i = 0.0, const float &initial_d = 0.0, @@ -55,7 +55,7 @@ public: /// @param initial_d Initial value for the D term. /// @param initial_imax Initial value for the imax term.4 /// - PID(const prog_char *name, + PID(const prog_char_t *name, const float &initial_p = 0.0, const float &initial_i = 0.0, const float &initial_d = 0.0, diff --git a/libraries/RC_Channel/RC_Channel.h b/libraries/RC_Channel/RC_Channel.h index c96a56e59e..d3264fda16 100644 --- a/libraries/RC_Channel/RC_Channel.h +++ b/libraries/RC_Channel/RC_Channel.h @@ -18,7 +18,7 @@ class RC_Channel{ /// @param key EEPROM storage key for the channel trim parameters. /// @param name Optional name for the group. /// - RC_Channel(AP_Var::Key key, const prog_char *name) : + RC_Channel(AP_Var::Key key, const prog_char_t *name) : _group(key, name), radio_min (&_group, 0, 1500, name ? PSTR("MIN") : 0), // suppress name if group has no name radio_trim(&_group, 1, 1500, name ? PSTR("TRIM") : 0),