title: Clean and tidy string tables in PROGMEM in AVR-GCC
body: <p>I'm looking for a way to cleanly define an array of strings in PROGMEM for an AVR project. I have a command line processor that needs a list of command strings.</p>
  
  <p>The traditional way to do it on the AVR architecture is to define each string separately, then an array of pointers to those strings. This is extremely verbose and ugly:</p>
  
  <pre><code>typedef struct 
  {
      PGM_P   str;        // pointer to command string
      uint8_t str_len;    // length of command string
      uint8_t id;         // CLI_COM_* ID number
  } CLI_COMMAND_t;
  
  const char CLI_STR_TEMP[]   PROGMEM = "TEMP";
  const char CLI_STR_POWER[]  PROGMEM = "POWER";
  ...
  
  const CLI_COMMAND_t cli_cmd_table[] = { { CLI_STR_TEMP,     sizeof(CLI_STR_TEMP),   CLI_COM_TEMP },
                                          { CLI_STR_POWER,    sizeof(CLI_STR_POWER),  CLI_COM_POWER },
                                          ...
                                        };
  </code></pre>
  
  <p>(CLI_COM_* are enum'ed indicies, but could be replaced by function pointers or something)</p>
  
  <p>This mess could be reduced using macros to define the strings and build the table, something like:</p>
  
  <pre><code>#define FLASH_STRING(NAME...)    const char CLI_STR_ ## NAME [] PORGMEM = #NAME;
  #define FSTR(NAME...)            { CLI_STR_ ## NAME, sizeof(CLI_STR_ ## NAME), CLI_COM_ ## NAME) }
  
  FLASH_STRING(TEMP);
  FLASH_STRING(POWER);
  
  CLI_COMMAND_t cli_cmd_table[] = { FSTR(TEMP), FSTR(POWER) };
  </code></pre>
  
  <p>(untested, btw, but should be fine)</p>
  
  <p>However, I would like to define all my strings only once and have a macro generate both the individual strings and the array of pointers/sizes/enum references.</p>
  
  <p>On the Arduino platform there is a FLASH_STRING_ARRAY macro which I can't quite figure out, but which doesn't seem to compile either. You can see it here: <a href="http://pastebin.com/pMiV5CMr" rel="noreferrer">http://pastebin.com/pMiV5CMr</a> Maybe it's C++ only or something. Also it seems like it can only be used inside a function, not globally.</p>
  
  <p>String tables on AVR have long been a pain and inelegant. Short of writing a little program to generate the necessary code it would be nice to have a way to define it with macros.</p>
  
  <p>Bonus points: Generate the CLI_COM_* constants with the same macro, either as an enum or with #defines.</p>
  
  <p>EDIT: I suppose another name for this would be iterative declaration via a macro.</p>
  
  <p>SOLUTION: Thanks to luser, I came up with this solution:</p>
  
  <pre><code>typedef struct 
  {
      PGM_P   str;        // pointer to command string
      uint8_t str_len;    // length of command string
      uint8_t id;         // CLI_COM_* ID number
  } CLI_COMMAND_LUT_t;
  
  
  
  #define COMMAND_TABLE \
          ENTRY(testA) \
          ENTRY(testB) \
          ENTRY(testC)
  
  enum {
  #define ENTRY(a) CLI_COM_ ## a,
      COMMAND_TABLE
  #undef ENTRY    
  };
  
  
  #define ENTRY(a)    const char CLI_STR_ ## a PROGMEM = #a;
  COMMAND_TABLE
  #undef ENTRY
  
  
  CLI_COMMAND_LUT_t command_lut[] PROGMEM = {
  #define ENTRY(a) {CLI_STR_ ## a, sizeof(CLI_STR_ ## a), CLI_COM_ ## a},
      COMMAND_TABLE
  #undef ENTRY
  };
  </code></pre>
  
  <p>The produces the following output from the preprocessor:</p>
  
  <pre><code>typedef struct
  {
   PGM_P str;
   uint8_t str_len;
   uint8_t id;
  } CLI_COMMAND_LUT_t;
  
  enum {
   CLI_COM_testA, CLI_COM_testB, CLI_COM_testC,
  };
  
  const char CLI_STR_testA PROGMEM = "testA"; const char CLI_STR_testB PROGMEM = "testB"; const char CLI_STR_testC PROGMEM = "testC";
  
  CLI_COMMAND_LUT_t command_lut[] PROGMEM = {
  
   {CLI_STR_testA, sizeof(CLI_STR_testA), CLI_COM_testA}, {CLI_STR_testB, sizeof(CLI_STR_testB), CLI_COM_testB}, {CLI_STR_testC, sizeof(CLI_STR_testC), CLI_COM_testC},
  
  };
  </code></pre>
  
  <p>So all that lot can be wrapped up an a region and I end up with just a simple and most importantly single definition of each command that serves as both its string name and the reference for the code.</p>
  
  <p>Thanks a lot guys, much appreciated!</p>