quick and easy way to comment out multi lined print statements - c

Is there a quick and easy way to comment out multi lined print statements? Something like this? I have a ton of printf statements that I use for debugging that are spread out across my program. I would like to comment out every printf() except the ones that contain "ACCEPT" or "Reject". I have several hundred of them but they are scattered between important code so I can't use block comments.
lower_bound_of_big_boy_counter++;
printf("3387 strings_line_tokens[lower_bound_of_big_boy_counter] %s \n",
strings_line_tokens[lower_bound_of_big_boy_counter]);
printf("3389 lower_bound_of_big_boy_counter %d \n", lower_bound_of_big_boy_counter);
}
strcpy(array_id1, strings_line_tokens[lower_bound_of_big_boy_counter]);
integer_match_flag = 0;
float_match_flag = 0;
}
}
if(keywords_match_flag1 != 1)
{
lower_bound_of_big_boy_counter++;
}
cmp_str9 = strcmp("return", strings_line_tokens[lower_bound_of_big_boy_counter ]);
printf("4006 lower_bound_of_big_boy_counter %d \n", lower_bound_of_big_boy_counter);
printf("4007 strings_line_tokens[lower_bound_of_big_boy_counter] %s \n",
strings_line_tokens[lower_bound_of_big_boy_counter]);
//int
if(cmp_str9 == 0)
{
printf("3402 checking return stuff \n");
return_match_flag = 1;
lower_bound_of_big_boy_counter++;
get_function_type_for_proper_return(symbol_table_functions, type,id,
scope_char, symbol_table_functions_counter, function_type_for_proper_return);
printf("3407 lower_bound_of_big_boy_counter %d \n", lower_bound_of_big_boy_counter);
printf("3408 strings_line_tokens[lower_bound_of_big_boy_counter] %s \n",
strings_line_tokens[lower_bound_of_big_boy_counter]);
printf("3410 function_type_for_proper_return %s \n", function_type_for_proper_return);

Since your base code is C and the printf statements are [obviously] for debug, please allow me to suggest an alternative approach.
Change the printf used for debug into (e.g.) DEBUGPRINTF. This is a CPP macro that can be compiled to something with a compiler command line option like -DDEBUG. See my recent answer here: Why doesn't my simple C macro work? for a more formal description.
Side note: I wrote this current answer before noticing Jonathan's comment about doing it in a similar way.
Thus, you only need to do the change once and can turn debug printing on and off at the flip of a compile option. I've been using this technique for decades and it's served me quite well.
Note: You'll still need to do the global edit once to get this.
Here's a perl script that will do that (invoke via ./script < input > output):
#!/usr/bin/perl
# convert debug printf's
master(#ARGV);
exit(0);
# master -- master control
sub master
{
while ($bf = <STDIN>) {
chomp($bf);
if ($bf =~ /^\s*printf[(]/) {
doprintf($bf);
next
}
print($bf,"\n");
}
}
# doprintf -- process printf
sub doprintf
{
my($bf) = #_;
my($allowflg);
$allowflg = ($bf =~ /ACCEPT|Reject/);
unless ($allowflg) {
$bf =~ s/printf/DEBUGPRINTF/;
}
print($bf,"\n");
while (1) {
last if ($bf =~ /;\s*$/);
$bf = <STDIN>;
last unless (defined($bf));
chomp($bf);
print($bf,"\n");
}
}

A multiline solution with GNU sed :
sed '/ACCEPT\|Reject/!{/^[\t ]*printf(/{:a;s/^/\/\/ &/;/;/!{n;Ta}}}' file.c
Exluding all lines containing ACCEPT or Reject, it comments out all lines starting with printf and ending with ;.
If no ending ; is found on the printf line, it loops over and comments out subsequent lines until a ; is found.

Quick, simple, effective, over-enthusiastic
It is fairly simple to comment out all the printf() lines in a file with sed, even multi-line ones, if you use:
sed -e '/printf(.*);/ { s%^%//%; n; }' -e '/printf(/,/);/ s%^%//%'
On the sample lines, this yields:
lower_bound_of_big_boy_counter++;
// printf("3387 strings_line_tokens[lower_bound_of_big_boy_counter] %s \n",
// strings_line_tokens[lower_bound_of_big_boy_counter]);
// printf("3389 lower_bound_of_big_boy_counter %d \n", lower_bound_of_big_boy_counter);
}
strcpy(array_id1, strings_line_tokens[lower_bound_of_big_boy_counter]);
integer_match_flag = 0;
float_match_flag = 0;
}
}
if(keywords_match_flag1 != 1)
{
lower_bound_of_big_boy_counter++;
}
cmp_str9 = strcmp("return", strings_line_tokens[lower_bound_of_big_boy_counter ]);
// printf("4006 lower_bound_of_big_boy_counter %d \n", lower_bound_of_big_boy_counter);
// printf("4007 strings_line_tokens[lower_bound_of_big_boy_counter] %s \n",
// strings_line_tokens[lower_bound_of_big_boy_counter]);
//int
if(cmp_str9 == 0)
{
// printf("3402 checking return stuff \n");
return_match_flag = 1;
lower_bound_of_big_boy_counter++;
get_function_type_for_proper_return(symbol_table_functions, type,id,
scope_char, symbol_table_functions_counter, function_type_for_proper_return);
// printf("3407 lower_bound_of_big_boy_counter %d \n", lower_bound_of_big_boy_counter);
// printf("3408 strings_line_tokens[lower_bound_of_big_boy_counter] %s \n",
// strings_line_tokens[lower_bound_of_big_boy_counter]);
// printf("3410 function_type_for_proper_return %s \n", function_type_for_proper_return);
However, if any of the printf() statements contained ACCEPT or Reject, those lines would be commented out too. Given that you have hundreds of lines that should be commented out and a few (order of ten) that should not be commented, it is probably easiest to undo the incorrectly commented out lines.
Refined, complex, effective
I got an alternative working, and it handles printf statements with ACCEPT and Reject in the first line correctly. It won't spot those words in the second or subsequent lines of a printf statement.
${SED:-sed} \
-e '/printf(.*ACCEPT.*);/ b' \
-e '/printf(.*Reject.*);/ b' \
-e '/printf(.*);/ { s%^%//%; b
}' \
-e '/printf(.*ACCEPT/, /);/ b' \
-e '/printf(.*Reject/, /);/ b' \
-e '/printf(/, /);/ s%^%//%' \
frag.c
The odd newline is need to placate BSD (Mac OS X) sed.
Input:
lower_bound_of_big_boy_counter++;
printf("3387 strings_line_tokens[lower_bound_of_big_boy_counter] %s\n",
strings_line_tokens[lower_bound_of_big_boy_counter]);
printf("3389 lower_bound_of_big_boy_counter %d\n", lower_bound_of_big_boy_counter);
}
strcpy(array_id1, strings_line_tokens[lower_bound_of_big_boy_counter]);
integer_match_flag = 0;
float_match_flag = 0;
}
}
if(keywords_match_flag1 != 1)
{
lower_bound_of_big_boy_counter++;
}
cmp_str9 = strcmp("return", strings_line_tokens[lower_bound_of_big_boy_counter ]);
printf("4006 lower_bound_of_big_boy_counter %d\n", lower_bound_of_big_boy_counter);
wimbol();
printf("ACCEPT: lower_bound_of_big_boy_counter %d\n", lower_bound_of_big_boy_counter);
wimbol();
printf("Testing ACCEPT %d\n", lower_bound_of_big_boy_counter);
wimbol();
printf("Reject: lower_bound_of_big_boy_counter %d\n", lower_bound_of_big_boy_counter);
wimbol();
printf("4007 strings_line_tokens[lower_bound_of_big_boy_counter] %s\n",
strings_line_tokens[lower_bound_of_big_boy_counter]);
wimbol();
printf("Reject: strings_line_tokens[lower_bound_of_big_boy_counter] %s\n",
strings_line_tokens[lower_bound_of_big_boy_counter]);
wimbol();
printf("ACCEPT: strings_line_tokens[lower_bound_of_big_boy_counter] %s\n",
strings_line_tokens[lower_bound_of_big_boy_counter]);
wimbol();
printf("4006 lower_bound_of_big_boy_counter %d\n", lower_bound_of_big_boy_counter);
printf("ACCEPT: lower_bound_of_big_boy_counter %d\n", lower_bound_of_big_boy_counter);
printf("Testing ACCEPT %d\n", lower_bound_of_big_boy_counter);
printf("Reject: lower_bound_of_big_boy_counter %d\n", lower_bound_of_big_boy_counter);
printf("4007 strings_line_tokens[lower_bound_of_big_boy_counter] %s\n",
strings_line_tokens[lower_bound_of_big_boy_counter]);
printf("Reject: strings_line_tokens[lower_bound_of_big_boy_counter] %s\n",
strings_line_tokens[lower_bound_of_big_boy_counter]);
printf("ACCEPT: strings_line_tokens[lower_bound_of_big_boy_counter] %s\n",
strings_line_tokens[lower_bound_of_big_boy_counter]);
//int
if(cmp_str9 == 0)
{
printf("3402 checking return stuff\n");
return_match_flag = 1;
lower_bound_of_big_boy_counter++;
get_function_type_for_proper_return(symbol_table_functions, type,id,
scope_char, symbol_table_functions_counter, function_type_for_proper_return);
printf("3407 lower_bound_of_big_boy_counter %d\n", lower_bound_of_big_boy_counter);
printf("3408 strings_line_tokens[lower_bound_of_big_boy_counter] %s\n",
strings_line_tokens[lower_bound_of_big_boy_counter]);
printf("3410 function_type_for_proper_return %s\n", function_type_for_proper_return);
Output:
lower_bound_of_big_boy_counter++;
// printf("3387 strings_line_tokens[lower_bound_of_big_boy_counter] %s\n",
// strings_line_tokens[lower_bound_of_big_boy_counter]);
// printf("3389 lower_bound_of_big_boy_counter %d\n", lower_bound_of_big_boy_counter);
}
strcpy(array_id1, strings_line_tokens[lower_bound_of_big_boy_counter]);
integer_match_flag = 0;
float_match_flag = 0;
}
}
if(keywords_match_flag1 != 1)
{
lower_bound_of_big_boy_counter++;
}
cmp_str9 = strcmp("return", strings_line_tokens[lower_bound_of_big_boy_counter ]);
// printf("4006 lower_bound_of_big_boy_counter %d\n", lower_bound_of_big_boy_counter);
wimbol();
printf("ACCEPT: lower_bound_of_big_boy_counter %d\n", lower_bound_of_big_boy_counter);
wimbol();
printf("Testing ACCEPT %d\n", lower_bound_of_big_boy_counter);
wimbol();
printf("Reject: lower_bound_of_big_boy_counter %d\n", lower_bound_of_big_boy_counter);
wimbol();
// printf("4007 strings_line_tokens[lower_bound_of_big_boy_counter] %s\n",
// strings_line_tokens[lower_bound_of_big_boy_counter]);
wimbol();
printf("Reject: strings_line_tokens[lower_bound_of_big_boy_counter] %s\n",
strings_line_tokens[lower_bound_of_big_boy_counter]);
wimbol();
printf("ACCEPT: strings_line_tokens[lower_bound_of_big_boy_counter] %s\n",
strings_line_tokens[lower_bound_of_big_boy_counter]);
wimbol();
// printf("4006 lower_bound_of_big_boy_counter %d\n", lower_bound_of_big_boy_counter);
printf("ACCEPT: lower_bound_of_big_boy_counter %d\n", lower_bound_of_big_boy_counter);
printf("Testing ACCEPT %d\n", lower_bound_of_big_boy_counter);
printf("Reject: lower_bound_of_big_boy_counter %d\n", lower_bound_of_big_boy_counter);
// printf("4007 strings_line_tokens[lower_bound_of_big_boy_counter] %s\n",
// strings_line_tokens[lower_bound_of_big_boy_counter]);
printf("Reject: strings_line_tokens[lower_bound_of_big_boy_counter] %s\n",
strings_line_tokens[lower_bound_of_big_boy_counter]);
printf("ACCEPT: strings_line_tokens[lower_bound_of_big_boy_counter] %s\n",
strings_line_tokens[lower_bound_of_big_boy_counter]);
//int
if(cmp_str9 == 0)
{
// printf("3402 checking return stuff\n");
return_match_flag = 1;
lower_bound_of_big_boy_counter++;
get_function_type_for_proper_return(symbol_table_functions, type,id,
scope_char, symbol_table_functions_counter, function_type_for_proper_return);
// printf("3407 lower_bound_of_big_boy_counter %d\n", lower_bound_of_big_boy_counter);
// printf("3408 strings_line_tokens[lower_bound_of_big_boy_counter] %s\n",
// strings_line_tokens[lower_bound_of_big_boy_counter]);
// printf("3410 function_type_for_proper_return %s\n", function_type_for_proper_return);
I was previously having some issues; I am kicking myself for some of them (sequencing — it is crucial to deal with all the single-line printf() statements before starting on the multi-line ones). There's a more subtle difference between b (jump to end of script) and n (read next line), which is also crucial.
I'm testing with BSD sed on Mac OS X 10.11.4, JFTR. GNU sed doesn't require the extra newline in the script.

using sed is a oneway conversion and requires a separate step before compiling.
A much better method is:
when debugging use the compiler parameter:
-DDEBUG=1
when not debugging use the compiler parameter:
-DDEBUG=0
Then, in the code use:
if( DEBUG )
{
// your debugging printf()
printf( ,,,, );
}
Then when the code must be certified, for instance to RTCA DO-178B there is no difference in the source code between the tested code and the released code.

Related

C Program to get CPU usage for a PID and all its children

I have a C program that parses the /proc//stat directory to calculate the average CPU utilization over a period of 5 seconds:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define ITERATIONS 5
int main(int argc, char *argv[])
{
if (argc != 2) {
printf( "usage: %s <PID>\n", argv[0] );
return(-1);
}
long double a[4], b[4];
long double pidTime = 0.0;
long int clk;
int i;
FILE *fp;
char stat[1024];
clk = sysconf(_SC_CLK_TCK);
if (clk == -1) {
printf("Could not determine clock ticks per second");
return(-1);
}
char *pidPath = malloc(strlen("/proc/stat/")+strlen(argv[1])+1);
if (pidPath == NULL) {
printf("Could not allocate memory for str\n");
return(-1);
} else {
strcpy(pidPath, "/proc/");
strcat(pidPath, argv[1]);
strcat(pidPath, "/stat");
}
for(i = 0; i < ITERATIONS; i++)
{
fp = fopen(pidPath,"r");
if (fp == NULL) {
perror(pidPath);
return(-1);
} else {
fgets(stat, sizeof(stat), fp);
sscanf(stat,"%*d %*s %*c %*d %*d %*d %*d %*d %*u %*lu %*lu %*lu %*lu %Lf %Lf %Lf %Lf %*ld %*ld %*ld %*ld %*llu",&a[0],&a[1],&a[2],&a[3]);
fclose(fp);
sleep(1);
}
fp = fopen(pidPath,"r");
if (fp == NULL) {
perror(pidPath);
return(-1);
} else {
fgets(stat, sizeof(stat), fp);
sscanf(stat,"%*d %*s %*c %*d %*d %*d %*d %*d %*u %*lu %*lu %*lu %*lu %Lf %Lf %Lf %Lf %*ld %*ld %*ld %*ld %*llu",&b[0],&b[1],&b[2],&b[3]);
fclose(fp);
}
pidTime += (((b[0]+b[1]+b[2]+b[3]) - (a[0]+a[1]+a[2]+a[3])));
}
pidTime = (pidTime / (clk * ITERATIONS));
printf("pidCPU=%Lf\n", pidTime);
printf("%ld", clk);
free(pidPath);
return(0);
}
From what I understand the relevant fields in stat are:
int utime; /** user mode jiffies **/
int stime; /** kernel mode jiffies **/
int cutime; /** user mode jiffies with childs **/
int cstime; /** kernel mode jiffies with childs **/
For a single process, this works great, but when I have a process that forks, or is multithreaded, this breaks down. Do the cutime and cstime counters only work when the parent is waiting for the child processes? How can I calculate the total usage of the process tree rooted at PID?
Yes, the parent needs to wait for the CPU time of the children to be added in (see manual entry for getrusage link). Also see this answer for more details.

dmalloc log is not formatting stack addresses

By building dmalloc lib with following setting in conf.h file
#define HAVE_VPRINTF 0
#define HAVE_SNPRINTF 0
#define HAVE_VSNPRINTF 0
and run my code after linking , log file content have unformatting address info to function names and line numbers.
Unformatted log o/p is given below.
Venkatesh:~/Dmalloc/dmalloc-5.5.2$ cat logfile
%ld: %lu: Dmalloc version '%s' from '%s'
%ld: %lu: flags = %#x, logfile '%s'
%ld: %lu: interval = %lu, addr = %#lx, seen # = %ld, limit = %ld
%ld: %lu: starting time = %s
%ld: %lu: process pid = %ld
%ld: %lu: error details: %s
%ld: %lu: pointer '%#lx' from '%s' prev access '%s'
%ld: %lu: dump of proper fence-top bytes: '%.*s'
%ld: %lu: dump of '%#lx'%+d: '%.*s'
%ld: %lu: next pointer '%#lx' (size %u) may have run under from '%s'
%ld: %lu: ERROR: %s: %s (err %d)
If I define HAVE_VSNPRINTF to 1, then I log file has only dmalloc log header, no information about errors as given below.
Venkatesh:~/Dmalloc/dmalloc-5.5.2$ cat logfile
1450864250: 5: Dmalloc version '5.5.2' from 'http://dmalloc.com/'
1450864250: 11: flags = 0x4f4e503, logfile 'logfile'
1450864250: 17: interval = 100, addr = 0, seen # = 0, limit = 0
1450864250: 25: starting time = 1450864250
1450864250: 31: process pid = 10270
My test code is as below.
#include <stdio.h>
#include <stdlib.h>
#ifdef DMALLOC
#include "dmalloc.h"
#endif
int main ()
{
char *p;
p = malloc (50);
p[51] = 'c'; //Writing character beyond allocated range
return 0;
}
Dmalloc optins I am using is :
DMALLOC_OPTIONS=debug=0x4f4ed03,inter=100,log=logfile

C macro with syslog logging

How can I replace this
syslog("some text");
with this, using C macro
if (debug)
syslog (LOG_DEBUG, "Function %s Line %d File %s Text %s", __func__, __LINE__, __FILE__,"some text");
The do..while(0) trick handles the compound 'if' statement, but syslog() is printf-like, and can take a variable number of arguments. We need a couple of tricks from the gcc preprocessor to handle this.
First, macros with variable numbers of arguments are supported, using the '...' notation.
We can use this to put our own text between the format string and the variable list. However, there is a catch: what if there is no variable list? In that case we use a special meaning of the ## operator for just this situation to eat the extra ','.
#define syslog(fmt, args...) \
do { \
if (debug) \
syslog(LOG_DEBUG, "Func %s Line %d file %s text " fmt, __func__, __LINE__, __FILE__, ##args); \
} while (0)
This expands these:
syslog("string");
syslog("format %d", value);
if (value)
syslog("something %d more %s", little, "complicated");
into this:
do { if (debug) syslog(LOG_DEBUG, "Func %s Line %d file %s text " "string", __func__, 8, "tp.c"); } while (0);
do { if (debug) syslog(LOG_DEBUG, "Func %s Line %d file %s text " "format %d", __func__, 10, "tp.c", value); } while (0);
if (value)
do { if (debug) syslog(LOG_DEBUG, "Func %s Line %d file %s text " "something %d more %s", __func__, 13, "tp.c", little, "complicated"); } while (0);
#define syslog(text) \
do { \
if(debug) \
syslog (LOG_DEBUG, "Function %s Line %d File %s Text %s", __func__, __LINE__, __FILE__, text); \
} while(0)
If debug is defined somewhere you can eliminate the if branch:
#ifdef debug
#define syslog(text) syslog (LOG_DEBUG, "Function %s Line %d File %s Text %s", __func__, __LINE__, __FILE__, text);
#else
#define syslog(text)
#endif

File system converting to read only during program run

My program has a loop that runs initUSB() and then runs writeEssentials() multiple times.
initUSB() is a function that mounts the USB to a directory.
writeEssentials() is a function that opens a file, and appends it with data, and then closes the file.
After a minute or so after the initial run of the program, the program will report that the file system is "read only", and will refuse to write anymore data, until initUSB() is run again. This happens weather or not I fprintf() into the file pointer. As a temporary solution, I made writeEssentials() remount the drive if it becomes read-only. This works, but I would rather not remount the drive every minute.
Why does this happen, and how can I fix this error?
The program is running on an Debian embedded Linux system, on a TS-7800.
InitUSB:
int initUSB(){
int i;
FILE * filecheck = fopen(HMITelemCheckFile, "r");
for(i = 0; i < 26; i++) {
char usbMountFromPathTry[256];
char sdanum[5];
strcpy(usbMountFromPathTry, usbMountFromPath);
sprintf(sdanum, "%c1", i+'a');
strcat(usbMountFromPathTry, sdanum);
if(!mount(usbMountFromPathTry, usbMountToPath, "vfat", (long)NULL, NULL)){
printf("Mount successful\n");
return 1;
} else if(!mount(usbMountFromPathTry, usbMountToPath, "vfat", MS_REMOUNT, NULL)){
printf("Mount successful\n");
return 1;
}
printf("Mount error: ");
printf("%s\n", usbMountFromPathTry);
}
printf("Mount ERROR\n");
return 0;
}
writeEssentials():
void writeEssentials(){
FILE * file = fopen(usbMountEssentials, "a+");
fflush(file);
perror("file");
if(file == NULL){
initUSB();
printf("null file\n");
return;
}
fprintf(file, "\n%s, ", getDate());
fprintf(file, "%s, ", getTime());
fprintf(file, "%1.2f, ", getSpeed());
fprintf(file, "%d, ", getRPM());
fprintf(file, "%d, ", getRegen());
fprintf(file, "%d, ", getAirgap());
fprintf(file, "%d, ", getBattery());
fprintf(file, "%.2f, ", *(getADCTemps()+COMPUTER_BOX_TEMP_INDEX));
fprintf(file, "%.2f, ", *(getBMS()+BMS_TEMP_INDEX+(BMS_NUM_VAR*0)));
fprintf(file, "%.2f, ", *(getBMS()+BMS_TEMP_INDEX+(BMS_NUM_VAR*1)));
fprintf(file, "%.2f, ", *(getBMS()+BMS_TEMP_INDEX+(BMS_NUM_VAR*2)));
fprintf(file, "%.2f, ", *(getMPPT()+MPPT_TEMP_INDEX+(MPPT_NUM_VAR*0)));
fprintf(file, "%.2f, ", *(getMPPT()+MPPT_TEMP_INDEX+(MPPT_NUM_VAR*1)));
fprintf(file, "%.2f, ", *(getMPPT()+MPPT_TEMP_INDEX+(MPPT_NUM_VAR*2)));
fprintf(file, "%.2f, ", *(getMPPT()+MPPT_TEMP_INDEX+(MPPT_NUM_VAR*3)));
fprintf(file, "%s, ", getLat());
fprintf(file, "%s, ", getLong());
int i;
for(i = 0; i < getNumErrors(); i++){
//fprintf(file, "%s, ", getErrorText(*(getErrors()+i)));
}
fclose(file);
perror("close file error");
}
Check dmesg. Filesystems spontaneously going read-only is usually an indication that there's some corruption that's being detected, so the kernel is setting the FS as read-only to protect it from further damage.

Can I use MGET with hiredis?

Consider following example:
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <hiredis/hiredis.h>
int main(int argc, char **argv) {
redisContext *redis;
redisReply *reply;
redis = redisConnect("127.0.0.1", 6379);
if(redis->err) {
fprintf(stderr, "Connection error: %s\n", redis->errstr);
exit(EXIT_FAILURE);
}
reply = redisCommand(redis, "SET %s %s", "foo", "bar");
printf("SET %s %s: %s\n", "foo", "bar", reply->str);
freeReplyObject(reply);
reply = redisCommand(redis, "SET %s %s", "name", "value");
printf("SET %s %s: %s\n", "name", "value", reply->str);
freeReplyObject(reply);
reply = redisCommand(redis, "MGET %s %s", "foo", "name");
printf("MGET %s %s: %s\n", "foo", "name", reply->str);
freeReplyObject(reply);
exit(EXIT_SUCCESS);
}
The output is:
PING: PONG
SET foo bar: OK
GET foo: bar
SET name value: OK
MGET foo name: (null)
It's about return from MGET. Can I get multi keys using hiredis?
A redisReply is a typed object (see the type field), and a multi-bulk reply has a specific type (REDIS_REPLY_ARRAY). The str field is not relevant in that case.
From the hiredis documentation:
The number of elements in the multi bulk reply is stored in reply->elements.
Every element in the multi bulk reply is a redisReply object as well
and can be accessed via reply->element[..index..].
Redis may reply with nested arrays but this is fully supported.
So your code should be changed as follows:
reply = redisCommand(redis, "MGET %s %s", "foo", "name" );
if ( reply->type == REDIS_REPLY_ERROR )
printf( "Error: %s\n", reply->str );
else if ( reply->type != REDIS_REPLY_ARRAY )
printf( "Unexpected type: %d\n", reply->type );
else
{
int i;
for ( i=0; i<reply->elements; ++i )
printf( "Result: %s\n", reply->element[i]->str );
}
freeReplyObject(reply);
With this change, the output is now:
SET foo bar: OK
SET name value: OK
Result: bar
Result: value
Note: there is no need to free each individual element since freeReplyObject deletes the whole tree.

Resources