I'm in the middle of a project using a mysql database and spanning several languages. A problem has arisen that we need a piece of it to be in C, that reads in a query, replaces some placeholders (wrapped in '?' chars), and then runs said query.

The problem here is, C is not one of my strengths In fact, I'm almost illiterate in it. This is what I have so far, its poorly put together and doesnt even work. What it should do, is replace "?value?" with the value of repl_val.

#include <stdio.h>
#include <string.h>

int main ()
{
    char* query = "SELECT ?value? FROM Table";
    char newquery[100];
    char* repl_val = "VariableFieldName";
    
    char* pch;
    int start,end;
    int count;
    
    // get start and end indices...
    pch=strchr(query,'?');
    if (pch!=NULL)
    {
      start = pch-query;
      pch=strchr(pch+1,'?');
      end = pch-query;
    }
    // ...or return
    if(!start || !end)
    {
      return 1;
    }
    
    // copy everything before first '?', concat the replacement value
    strncpy(newquery,query,start);
    strcat(newquery,repl_val);
    
    // concat everything after the second '?', one char at a time
    for(count=end; count<strlen(query); count++)
    {
        strcat(newquery,query[count]);
    }
    
    printf("new query: %s", newquery);
    
    return 0;
}

The last for() loop wont compile, and even if i comment it out, all that prints is the repl_val surrounded by garbage. Am I just going about this all wrong?

Dani AI

Generated

A concise, safe approach is to scan the query once, collect any token framed by two question marks, verify the token contains only letters, digits or underscore, and—only then—replace it with the corresponding environment variable value. Use ctype.h helpers (isalnum) when testing characters, build the new string into a dynamically grown buffer to avoid overflows, and always free the returned buffer. This avoids touching fragments like ?sql field2? (space makes it invalid) or lone ? used in literals.

A minimal, robust implementation idea (returns a malloc'd string; caller must free):

#include <stdlib.h>
#include <string.h>
#include <ctype.h>

char *replace_placeholders(const char *src) {
    size_t cap = strlen(src) + 1;
    char *out = malloc(cap);
    size_t outlen = 0;
    const char *p = src;
    while (*p) {
        if (*p == '?') {
            const char *q = p + 1;
            size_t name_len = 0;
            while (*q && (isalnum((unsigned char)*q) || *q == '_')) { q++; name_len++; }
            if (name_len && *q == '?') {
                char name[256];
                if (name_len >= sizeof name) name_len = sizeof name - 1;
                memcpy(name, p+1, name_len); name[name_len] = '\0';
                char *val = getenv(name);
                if (val) {
                    size_t vlen = strlen(val);
                    if (outlen + vlen + 1 > cap) { cap = (outlen + vlen + 1) * 2; out = realloc(out, cap); }
                    memcpy(out + outlen, val, vlen); outlen += vlen;
                }
                p = q + 1;
                continue;
            }
        }
        if (outlen + 2 > cap) { cap = (cap * 2) + 16; out = realloc(out, cap); }
        out[outlen++] = *p++;
    }
    out[outlen] = '\0';
    return out;
}

Important cautions: do not build SQL from untrusted strings. If placeholders become column names, use a whitelist of allowed column identifiers (map placeholder -> allowed name) rather than inserting arbitrary env values. For value substitution prefer parameterized queries or proper quoting/escaping. This comment builds on 's parse idea and 's ctype hint, avoids the fixed-format pitfall noted by , and provides a safer, dynamically-allocated alternative to the generic replace approach mentioned by .

Recommended Answers

All 5 Replies

char* query = "SELECT %s FROM Table";
    char newquery[100];
    char* repl_val = "VariableFieldName";
    sprintf( newquery, query, repl_value );

Any particular reason why you can't do this?

well, we've had to revise our design AGAIN. now, what i need to do is strip out every alphanumeric string (0-9,a-z,_) delimited by question marks, then grab an environment variable of the same name. at the same time, we want to silently pass over anything that sint a solid alphanumeric string.

ie, in the following query, i need to replace ?sql_fild1? with the environment variable ${sql_field1} , and so on for sql_field2 and sort_field. We don't want to even touch the question mark for QnAField, however.

"SELECT ?sql_field1?, ?sql_field2? FROM Table WHERE QnAField = "What is the question?" ORDER BY ?sort_field? ASC"

// should become:
"SELECT PassedField, AnotherPassedField FROM Table WHERE QnAField = "What is the question?" ORDER BY NameField ASC"

ok, ive managed to put together somthing that *finds* the placeholders (and prints them to stdout for debug purposes), im just not sure how to replace them inline with a getenv() call:

#include <stdio.h>
#include <string.h>

int do_sql_placeholders(char* source)
{
  int in_placeholder = 0; // indicate if we are inside a possible placeholder
  int pos = 0;
 
  char placeholder[256]; // to store placeholder name
  int placepos = 0;

  for (pos=0; pos < (signed int)strlen(source); pos++)
  {
    if (in_placeholder)
    {
      // if continue placeholder
      if (
          (source[pos] >= '0' && source[pos] <= '9') ||
          (source[pos] >= 'A' && source[pos] <= 'Z') ||
          (source[pos] >= 'a' && source[pos] <= 'z') ||
          source[pos] == '_'
        )
      {
        placeholder[placepos] = source[pos];
        placepos++;
      }
      // else, end place holder
      else
      {
        // valid terminated placeholder, interpolate
        if (source[pos] == '?')
        {
          placeholder[placepos] = '\0';
          /*
            instead of printing this out as a match, i need to call getenv(placeholder)
            and replace the placeholder in source with the output of getenv
          */
          printf("matched placeholder '%s' at position %d\n", placeholder, pos);
        }
        // cleanup
        in_placeholder = 0;
      
        placeholder[0] = '\0';
        placepos=0;
      }
    }
    else
    {
      if (source[pos] == '?') // entering a potential placeholder
      {
        in_placeholder = 1;
        placepos = 0;
      }
    }
  }
  return 0;
}

int main()
{
 char query[100] = "SELECT ?sql_field1?, ?sql field2? FROM Table WHERE QnAField = 'What is the question?' ORDER BY ?sort_field? ASC";

 do_sql_placeholders(query);
 printf("query: %s\n", query);

 return 0;
}
(source[pos] >= '0' && source[pos] <= '9')

Look into isdigit() in <ctype.h>. And isalpha() or isupper()+islower() for the other lines nearby.

Have you every used getenv() before? . . . if not, try reading a man page or searching google for it.

i've managed to get something working using Dave's replace function.

its shaky at best, but it does work for the time being. thanks for the advice. and i'll look into isalpha() and isdigit() as well.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.