text: /**
   * GEDCOM 5.5.1 allowed virtually any character in an identifier.
   * GEDCOM 7.0 allows only tag character [A-Z_0-9].
   * This function replaces all anchors and pointers with new identifiers
   * that fit the GEDCOM 7.0 rules.
   */
  
  #include "../strtrie.h"
  #include <ctype.h>
  
  /**
   * 1 if `s` is a legal xref:id for GEDCOM 7.0; 0 otherwise
   * But with extra check; X[0-9]+ IDs are generated by this tool
   * so they need to be changed if encountered to avoid collision
   */
  int ged_fixid_isOK(char *s) {
      if (!*s) return 0;
      int isXNum = *s == 'X' || (ged_xref_case_insensitive && *s == 'x');
      while(*s) {
          if (ged_xref_case_insensitive) *s = toupper(*s);
          if (!( (*s >= '0' && *s <= '9') 
              || (*s >= 'A' && *s <= 'Z')
              || (*s == '_')
              )) return 0;
          s += 1;
          if (*s && isXNum && (*s < '0' || *s > '9')) isXNum = 0;
      }
      return !isXNum;
  }
  
  /// the digits needed to represent n in base-10
  static inline int ged_fixid_digitsneeded(size_t n) {
      int ans = 1;
      while(n > 9) { ans += 1; n /= 10; }
      return ans;
  }
  
  
  void ged_fixid(GedEvent *event, GedEmitterTemplate *emitter, void *rawstate) {
      trie *state = (trie *)rawstate;
      
      if ((event->type == GED_ANCHOR || event->type == GED_POINTER)
      && !ged_fixid_isOK(event->data)) {
          char *val = trie_get(state, event->data);
          if (!val) {
              int n = ged_fixid_digitsneeded(state->length+1);
              val = malloc(n+2);
              snprintf(val, n+2, "X%zu", state->length+1);
              trie_put(state, event->data, val);
              event->flags &= ~GED_OWNS_DATA;
          }
          if (event->flags & GED_OWNS_DATA) {
              free(event->data);
              event->flags &= ~GED_OWNS_DATA;
          }
          event->data = val;
      }
      
      emitter->emit(emitter, *event);
  }
  
  void *ged_fixidstate_maker() { 
      trie *ans = calloc(1, sizeof(trie));
      return ans;
  }
  void ged_fixidstate_freer(void *state) { 
      trie *t = (trie *)state;
      for(size_t i=0; i<2*t->length; i+=1) free((void *)t->kvpairs[i]);
      trie_free(t);
      free(state); 
  }
  
  