Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

674 lines (663 sloc) 20.053 kB
/*
quIRC - simple terminal-based IRC client
Copyright (C) 2010-11 Edward Cree
See quirc.c for license information
genconfig.c: generate various bits of config-parsing code from a cdl file
*/
// TODO: refactor this quite a lot, it's a mess
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
typedef struct
{
enum {INT, BOOL} type;
char *cname;
int value;
int min,max;
char *rc_name;
char *cmdline_name;
char *set_name;
char *set_msg;
enum {SET, LEVEL, BOOLEAN} set_type;
}
ent;
char * fgetl(FILE *); // gets a line of string data; returns a malloc-like pointer
void init_char(char **buf, int *l, int *i); // initialises a string buffer in heap. *buf becomes a malloc-like pointer
void append_char(char **buf, int *l, int *i, char c); // adds a character to a string buffer in heap (and realloc()s if needed)
int main(int argc, char **argv)
{
if(argc!=2)
{
fprintf(stderr, "usage: genconfig <outtype>\n");
return(EXIT_FAILURE);
}
int otype;
if(strcmp(argv[1], "config_globals.h")==0)
otype=0;
else if(strcmp(argv[1], "config_check.c")==0)
otype=1;
else if(strcmp(argv[1], "config_def.c")==0)
otype=2;
else if(strcmp(argv[1], "config_rcread.c")==0)
otype=3;
else if(strcmp(argv[1], "config_pargs.c")==0)
otype=4;
else if(strcmp(argv[1], "config_set.c")==0)
otype=5;
else if(strcmp(argv[1], "config_need.c")==0)
otype=6;
else if(strcmp(argv[1], "config_help.c")==0)
otype=7;
else if(strcmp(argv[1], "config_ref.htm")==0)
otype=8;
else
{
fprintf(stderr, "genconfig: unrecognised outtype '%s'\n", argv[1]);
return(EXIT_FAILURE);
}
int nents=0;
ent *ents=NULL;
while(!feof(stdin))
{
char *line=fgetl(stdin);
if(!*line)
{
free(line);
continue;
}
int nent=nents++;
ents=realloc(ents, nents*sizeof(ent));
if(!ents)
{
perror("genconfig: realloc");
return(EXIT_FAILURE);
}
char *p=line;
int tocolon=strcspn(p, ":");
if(strncmp(p, "int", tocolon)==0)
ents[nent].type=INT;
else if(strncmp(p, "bool", tocolon)==0)
ents[nent].type=BOOL;
else
{
fprintf(stderr, "genconfig: unrecognised type %.*s\n", tocolon, p);
return(EXIT_FAILURE);
}
p+=tocolon;
if(!*p)
{
fprintf(stderr, "genconfig: premature end of line %u\n", nents);
return(EXIT_FAILURE);
}
p++;tocolon=strcspn(p, ":");
ents[nent].cname=malloc(tocolon+1);
if(!ents[nent].cname)
{
perror("genconfig: malloc");
return(EXIT_FAILURE);
}
strncpy(ents[nent].cname, p, tocolon);
ents[nent].cname[tocolon]=0;
p+=tocolon;
if(!*p)
{
fprintf(stderr, "genconfig: premature end of line %u (%s)\n", nents, ents[nent].cname);
return(EXIT_FAILURE);
}
p++;tocolon=strcspn(p, ":");
if(tocolon)
{
char *value=malloc(tocolon+1);
if(!value)
{
perror("genconfig: malloc");
return(EXIT_FAILURE);
}
strncpy(value, p, tocolon);
value[tocolon]=0;
switch(ents[nent].type)
{
case INT:
if(!sscanf(value, "%d", &ents[nent].value)) ents[nent].value=-1;
break;
case BOOL:
if(strcmp(value, "true")==0)
ents[nent].value=1;
else if(strcmp(value, "false")==0)
ents[nent].value=0;
else if(!sscanf(value, "%d", &ents[nent].value))
ents[nent].value=1; // default to true
break;
}
free(value);
p+=tocolon;
}
else
{
ents[nent].value=-1;
}
if(!*p)
{
fprintf(stderr, "genconfig: premature end of line %u (%s)\n", nents, ents[nent].cname);
return(EXIT_FAILURE);
}
p++;tocolon=strcspn(p, ":");
if(tocolon)
{
char *min=malloc(tocolon+1);
if(!min)
{
perror("genconfig: malloc");
return(EXIT_FAILURE);
}
strncpy(min, p, tocolon);
min[tocolon]=0;
if(!sscanf(min, "%d", &ents[nent].min)) ents[nent].min=-1;
free(min);
p+=tocolon;
}
else
{
ents[nent].min=-1;
}
if(!*p)
{
fprintf(stderr, "genconfig: premature end of line %u (%s)\n", nents, ents[nent].cname);
return(EXIT_FAILURE);
}
p++;tocolon=strcspn(p, ":");
if(tocolon)
{
char *max=malloc(tocolon+1);
if(!max)
{
perror("genconfig: malloc");
return(EXIT_FAILURE);
}
strncpy(max, p, tocolon);
max[tocolon]=0;
if(!sscanf(max, "%d", &ents[nent].max)) ents[nent].max=-1;
free(max);
p+=tocolon;
}
else
{
ents[nent].max=-1;
}
if(!*p)
{
fprintf(stderr, "genconfig: premature end of line %u (%s)\n", nents, ents[nent].cname);
return(EXIT_FAILURE);
}
p++;tocolon=strcspn(p, ":");
if(tocolon)
{
ents[nent].rc_name=malloc(tocolon+1);
if(!ents[nent].rc_name)
{
perror("genconfig: malloc");
return(EXIT_FAILURE);
}
strncpy(ents[nent].rc_name, p, tocolon);
ents[nent].rc_name[tocolon]=0;
p+=tocolon;
}
else
{
ents[nent].rc_name=NULL;
}
if(!*p)
{
fprintf(stderr, "genconfig: premature end of line %u (%s)\n", nents, ents[nent].cname);
return(EXIT_FAILURE);
}
p++;tocolon=strcspn(p, ":");
if(tocolon)
{
ents[nent].cmdline_name=malloc(tocolon+1);
if(!ents[nent].cmdline_name)
{
perror("genconfig: malloc");
return(EXIT_FAILURE);
}
strncpy(ents[nent].cmdline_name, p, tocolon);
ents[nent].cmdline_name[tocolon]=0;
p+=tocolon;
}
else
{
ents[nent].cmdline_name=NULL;
}
if(!*p)
{
fprintf(stderr, "genconfig: premature end of line %u (%s)\n", nents, ents[nent].cname);
return(EXIT_FAILURE);
}
p++;tocolon=strcspn(p, ":");
if(tocolon)
{
ents[nent].set_name=malloc(tocolon+1);
if(!ents[nent].set_name)
{
perror("genconfig: malloc");
return(EXIT_FAILURE);
}
strncpy(ents[nent].set_name, p, tocolon);
ents[nent].set_name[tocolon]=0;
p+=tocolon;
}
else
{
ents[nent].set_name=NULL;
}
if(!*p)
{
fprintf(stderr, "genconfig: premature end of line %u (%s)\n", nents, ents[nent].cname);
return(EXIT_FAILURE);
}
p++;tocolon=strcspn(p, ":");
if(strncmp(p, "SET", tocolon)==0)
ents[nent].set_type=SET;
else if(strncmp(p, "LEVEL", tocolon)==0)
ents[nent].set_type=LEVEL;
else if(strncmp(p, "BOOLEAN", tocolon)==0)
ents[nent].set_type=BOOLEAN;
else
{
fprintf(stderr, "genconfig: unrecognised set_type %.*s in line %u (%s)\n", tocolon, p, nents, ents[nent].cname);
return(EXIT_FAILURE);
}
p+=tocolon;
if(!*p)
{
fprintf(stderr, "genconfig: premature end of line %u (%s)\n", nents, ents[nent].cname);
return(EXIT_FAILURE);
}
p++;tocolon=strcspn(p, ":");
if(tocolon)
{
ents[nent].set_msg=malloc(tocolon+1);
if(!ents[nent].set_msg)
{
perror("genconfig: malloc");
return(EXIT_FAILURE);
}
strncpy(ents[nent].set_msg, p, tocolon);
ents[nent].set_msg[tocolon]=0;
}
else
{
ents[nent].set_msg=NULL;
}
free(line);
}
if(otype==8)
printf("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n\
<html xmlns=\"http://www.w3.org/1999/xhtml\">\n\
<head>\n\
\t<title>quIRC: configuration reference</title>\n\
\t<meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8;\" />\n\
\t<link rel=\"stylesheet\" href=\"readme.css\" />\n\t<style type=\"text/css\">\n\
\t\ttt {margin-left:4em;}\n\
\t\ttd {border:1px solid; border-color:#1f273f; padding:2px;}\n\
\t\t.int {background-color:#376f4f; color:black;}\n\
\t\t.bool {background-color:#374f6f; color:black;}\n\
\t\t.na {background-color:#2f2f37; color:#7f7f9f};\n\
\t</style>\n\
</head>\n\
<body>\n\
<div id=\"title\">\n\
<h1>quIRC: reference</h1>\n\
<h5>A reference table for quIRC's configuration options, and how to set them.<br>\n\
Generated by <small>genconfig</small></h5>\n\
</div><!--#title-->\n\
<div id=\"key\">\n\
<h2>Key to Columns</h2>\n\
<dl>\n\
<dt>name</dt>\n\
\t<dd>The internal name of the setting.</dd>\n\
<dt>type</dt>\n\
\t<dd>The setting's type, either <span class=\"int\">INT</span> (integer) or <span class=\"bool\">BOOL</span> (boolean).</dd>\n\
<dt>default</dt>\n\
\t<dd>The setting's default value.</dd>\n\
<dt>rc</dt>\n\
\t<dd>The setting's name in the rc file (typically ~/.quirc/rc), if settable there.</dd>\n\
<dt>cmdline</dt>\n\
\t<dd>The setting's name on the command line, if settable there.</dd>\n\
<dt>/set</dt>\n\
\t<dd>The name to use with the /set command. If the setting is an <span class=\"int\">INT</span>, use <small>/set &lt;name&gt; &lt;value&gt;</small>; omitting <small>&lt;value&gt;</small> sets to the default value. If the setting is a <span class=\"bool\">BOOL</span>, use <small>/set &lt;name&gt;</small> to enable, and <small>/set no-&lt;name&gt;</small> to disable (you can also use other forms, such as supplying a <small>&lt;value&gt;</small> of + or 1 to enable and - or 0 to disable).</dd>\n\
<dt>description</dt>\n\
\t<dd>A short description of the setting, as used in messages produced by /set.</dd>\n\
</dl>\n\
</div><!--#key-->\n\
<div id=\"table\">\n\
<table style=\"border:1px solid;\">\n\
<tr style=\"text-align:center\"><td>name</td><td>type</td><td>default</td><td>rc</td><td>cmdline</td><td>/set</td><td>description</td></tr>\n");
else
printf("/* Generated by genconfig */\n");
switch(otype)
{
case 1:
printf("int conf_check(void)\n{\n");
break;
}
int i;
bool first=true;
for(i=0;i<nents;i++)
{
switch(otype)
{
case 0:
switch(ents[i].type)
{
case INT:
printf("unsigned int ");
break;
case BOOL:
printf("bool ");
break;
default:
fprintf(stderr, "Unsupported type %d in %s\n", ents[i].type, ents[i].cname);
return(EXIT_FAILURE);
}
printf("%s; // %s\n", ents[i].cname, ents[i].set_msg);
break;
case 1:
switch(ents[i].type)
{
case INT:
if(ents[i].min>0)
{
printf("\tif(%s<%d)\n\t{\n\t\tasb_failsafe(c_status, \"%s set to minimum %d\");\n\t\t%s=%d;\n\t}\n", ents[i].cname, ents[i].min, ents[i].set_name, ents[i].min, ents[i].cname, ents[i].min);
}
if(ents[i].max!=-1)
{
printf("\tif(%s>%d)\n\t{\n\t\tasb_failsafe(c_status, \"%s set to maximum %d\");\n\t\t%s=%d;\n\t}\n", ents[i].cname, ents[i].max, ents[i].set_name, ents[i].max, ents[i].cname, ents[i].max);
}
break;
case BOOL:
break;
default:
fprintf(stderr, "Unsupported type %d in %s\n", ents[i].type, ents[i].cname);
return(EXIT_FAILURE);
}
break;
case 2:
printf("\t%s=%d;\n", ents[i].cname, ents[i].value);
break;
case 3:
if(ents[i].rc_name)
{
switch(ents[i].type)
{
case BOOL:
case INT:
if((ents[i].set_type==BOOLEAN)||(ents[i].set_type==LEVEL))
{
printf("\t\t\telse if(strcmp(cmd, \"no-%s\")==0)\n", ents[i].rc_name);
printf("\t\t\t\t%s=false;\n", ents[i].cname);
}
printf("\t\t\telse if(strcmp(cmd, \"%s\")==0)\n", ents[i].rc_name);
printf("\t\t\t{\n");
printf("\t\t\t\tunsigned int value;\n");
printf("\t\t\t\tif(rest&&sscanf(rest, \"%%u\", &value))\n");
printf("\t\t\t\t\t%s=value;\n", ents[i].cname);
printf("\t\t\t\telse\n");
if(ents[i].type==BOOL)
printf("\t\t\t\t\t%s=true;\n", ents[i].cname);
else
{
printf("\t\t\t\t{\n");
printf("\t\t\t\t\tasb_failsafe(c_err, \"Malformed rc entry for %s (value not numeric)\");\n", ents[i].rc_name);
printf("\t\t\t\t\tasb_failsafe(c_err, rest);\n");
printf("\t\t\t\t}\n");
}
printf("\t\t\t}\n");
break;
default:
fprintf(stderr, "Unsupported type %d in %s\n", ents[i].type, ents[i].cname);
return(EXIT_FAILURE);
}
}
break;
case 4:
if(ents[i].cmdline_name)
{
switch(ents[i].type)
{
case BOOL:
printf("\t\telse if(strcmp(argv[arg], \"--%s\")==0)\n", ents[i].cmdline_name);
printf("\t\t\t%s=true;\n", ents[i].cname);
printf("\t\telse if(strcmp(argv[arg], \"--no-%s\")==0)\n", ents[i].cmdline_name);
printf("\t\t\t%s=false;\n", ents[i].cname);
break;
case INT:
printf("\t\telse if(strncmp(argv[arg], \"--%s=\", %zu)==0)\n", ents[i].cmdline_name, strlen(ents[i].cmdline_name)+3);
printf("\t\t\tsscanf(argv[arg]+%zu, \"%%u\", &%s);\n", strlen(ents[i].cmdline_name)+3, ents[i].cname);
break;
}
}
break;
case 5:
if(ents[i].set_name)
{
printf("\t\t\t\t");
if(!first) printf("else ");
first=false;
printf("if(strcmp(opt, \"%s\")==0)\n", ents[i].set_name);
printf("\t\t\t\t{\n");
if(ents[i].set_type==BOOLEAN)
{
printf("\t\t\t\t\tif(val)\n");
printf("\t\t\t\t\t{\n");
printf("\t\t\t\t\t\tif(isdigit(*val))\n");
printf("\t\t\t\t\t\t{\n");
printf("\t\t\t\t\t\t\tunsigned int value;\n");
printf("\t\t\t\t\t\t\tsscanf(val, \"%%u\", &value);\n");
printf("\t\t\t\t\t\t\t%s=value;\n", ents[i].cname);
printf("\t\t\t\t\t\t}\n");
printf("\t\t\t\t\t\telse if(strcmp(val, \"+\")==0)\n");
printf("\t\t\t\t\t\t{\n");
printf("\t\t\t\t\t\t\t%s=true;\n", ents[i].cname);
printf("\t\t\t\t\t\t}\n");
printf("\t\t\t\t\t\telse if(strcmp(val, \"-\")==0)\n");
printf("\t\t\t\t\t\t{\n");
printf("\t\t\t\t\t\t\t%s=false;\n", ents[i].cname);
printf("\t\t\t\t\t\t}\n");
printf("\t\t\t\t\t\telse\n");
printf("\t\t\t\t\t\t{\n");
printf("\t\t\t\t\t\t\tadd_to_buffer(cbuf, c_err, \"option '%s' is boolean, use only 0/1 or -/+ to set\", \"/set: \");\n", ents[i].set_name);
printf("\t\t\t\t\t\t}\n");
printf("\t\t\t\t\t}\n");
printf("\t\t\t\t\telse\n");
printf("\t\t\t\t\t\t%s=true;\n", ents[i].cname);
}
else
{
printf("\t\t\t\t\tif(val)\n");
printf("\t\t\t\t\t{\n");
printf("\t\t\t\t\t\tunsigned int value;\n");
printf("\t\t\t\t\t\tsscanf(val, \"%%u\", &value);\n");
printf("\t\t\t\t\t\t%s=value;\n", ents[i].cname);
printf("\t\t\t\t\t}\n");
printf("\t\t\t\t\telse\n");
printf("\t\t\t\t\t\t%s=%d;\n", ents[i].cname, ents[i].value);
if(ents[i].min>0)
{
printf("\t\t\t\t\tif(%s<%d)\n", ents[i].cname, ents[i].min);
printf("\t\t\t\t\t\t%s=%d;\n", ents[i].cname, ents[i].min);
}
if(ents[i].max>=0)
{
printf("\t\t\t\t\tif(%s>%d)\n", ents[i].cname, ents[i].max);
printf("\t\t\t\t\t\t%s=%d;\n", ents[i].cname, ents[i].max);
}
}
printf("\t\t\t\t\tif(!quiet)\n");
printf("\t\t\t\t\t{\n");
switch(ents[i].set_type)
{
case BOOLEAN:
printf("\t\t\t\t\t\tif(%s)\n", ents[i].cname);
printf("\t\t\t\t\t\t\tadd_to_buffer(cbuf, c_status, \"%s enabled\", \"/set: \");\n", ents[i].set_msg);
printf("\t\t\t\t\t\telse\n");
printf("\t\t\t\t\t\t\tadd_to_buffer(cbuf, c_status, \"%s disabled\", \"/set: \");\n", ents[i].set_msg);
break;
case LEVEL:
printf("\t\t\t\t\t\tif(%s)\n", ents[i].cname);
printf("\t\t\t\t\t\t{\n");
printf("\t\t\t\t\t\t\tchar lmsg[%zu];\n", strlen(ents[i].set_msg)+32);
printf("\t\t\t\t\t\t\tsprintf(lmsg, \"%s level %%u enabled\", %s);\n", ents[i].set_msg, ents[i].cname);
printf("\t\t\t\t\t\t\tadd_to_buffer(cbuf, c_status, lmsg, \"/set: \");\n");
printf("\t\t\t\t\t\t}\n");
printf("\t\t\t\t\t\telse\n");
printf("\t\t\t\t\t\t\tadd_to_buffer(cbuf, c_status, \"%s disabled\", \"/set: \");\n", ents[i].set_msg);
break;
case SET:
printf("\t\t\t\t\t\tchar smsg[%zu];\n", strlen(ents[i].set_msg)+24);
printf("\t\t\t\t\t\tsprintf(smsg, \"%s set to %%u\", %s);\n", ents[i].set_msg, ents[i].cname);
printf("\t\t\t\t\t\tadd_to_buffer(cbuf, c_status, smsg, \"/set: \");\n");
break;
}
printf("\t\t\t\t\t}\n");
printf("\t\t\t\t\tint buf;\n");
printf("\t\t\t\t\tfor(buf=0;buf<nbufs;buf++)\n");
printf("\t\t\t\t\t\tbufs[buf].dirty=true;\n");
printf("\t\t\t\t\tredraw_buffer();\n");
printf("\t\t\t\t}\n");
if((ents[i].set_type==BOOLEAN)||(ents[i].set_type==LEVEL))
{
printf("\t\t\t\telse if(strcmp(opt, \"no-%s\")==0)\n", ents[i].set_name);
printf("\t\t\t\t{\n");
printf("\t\t\t\t\t%s=0;\n", ents[i].cname);
printf("\t\t\t\t\tif(!quiet) add_to_buffer(cbuf, c_status, \"%s disabled\", \"/set: \");\n", ents[i].set_msg);
printf("\t\t\t\t\tint buf;\n");
printf("\t\t\t\t\tfor(buf=0;buf<nbufs;buf++)\n");
printf("\t\t\t\t\t\tbufs[buf].dirty=true;\n");
printf("\t\t\t\t\tredraw_buffer();\n");
printf("\t\t\t\t}\n");
}
}
break;
case 6:
printf("\t\t\tif(strcmp(cmd, \"%s\")==0) need=false;\n", ents[i].rc_name);
if((ents[i].set_type==BOOLEAN)||(ents[i].set_type==LEVEL))
printf("\t\t\tif(strcmp(cmd, \"no-%s\")==0) need=false;\n", ents[i].rc_name);
break;
case 7:
if(ents[i].cmdline_name)
{
int j;
switch(ents[i].type)
{
case BOOL:
printf("\t\t\tfprintf(stderr, \"\\t--[no-]%s", ents[i].cmdline_name);
for(j=strlen(ents[i].cmdline_name);j<25;j++)
putchar(' ');
break;
case INT:
if((ents[i].min!=-1)&&(ents[i].max!=-1))
{
printf("\t\t\tfprintf(stderr, \"\\t--%s=<%d to %d>", ents[i].cmdline_name, ents[i].min, ents[i].max);
for(j=strlen(ents[i].cmdline_name);j<21;j++)
putchar(' ');
}
else
{
printf("\t\t\tfprintf(stderr, \"\\t--%s=<numeric>", ents[i].cmdline_name);
for(j=strlen(ents[i].cmdline_name);j<20;j++)
putchar(' ');
}
break;
}
printf(": %s\\n\");\n", ents[i].set_msg);
}
break;
case 8:
switch(ents[i].type)
{
case BOOL:
printf("<tr><td>%s</td><td><span class=\"bool\">BOOL</span></td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>\n", ents[i].cname, ents[i].value?"true":"false", ents[i].rc_name?ents[i].rc_name:"<span class=\"na\">[N/A]</span>", ents[i].cmdline_name?ents[i].cmdline_name:"<span class=\"na\">[N/A]</span>", ents[i].set_name?ents[i].set_name:"<span class=\"na\">[N/A]</span>", ents[i].set_msg?ents[i].set_msg:"<span class=\"na\">[N/A]</span>");
break;
case INT:
printf("<tr><td>%s</td><td><span class=\"int\">INT</span></td><td>%d</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>\n", ents[i].cname, ents[i].value, ents[i].rc_name?ents[i].rc_name:"<span class=\"na\">[N/A]</span>", ents[i].cmdline_name?ents[i].cmdline_name:"<span class=\"na\">[N/A]</span>", ents[i].set_name?ents[i].set_name:"<span class=\"na\">[N/A]</span>", ents[i].set_msg?ents[i].set_msg:"<span class=\"na\">[N/A]</span>");
break;
default:
printf("<tr><td>%s</td><td><em>(unknown type)</em></td><td>%d</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>\n", ents[i].cname, ents[i].value, ents[i].rc_name?ents[i].rc_name:"<span class=\"na\">[N/A]</span>", ents[i].cmdline_name?ents[i].cmdline_name:"<span class=\"na\">[N/A]</span>", ents[i].set_name?ents[i].set_name:"<span class=\"na\">[N/A]</span>", ents[i].set_msg?ents[i].set_msg:"<span class=\"na\">[N/A]</span>");
break;
}
break;
default:
fprintf(stderr, "genconfig: otype %d not implemented!\n", otype);
return(EXIT_FAILURE);
break;
}
}
switch(otype)
{
case 1:
printf("\treturn(0);\n}\n");
break;
case 8:
printf("</table>\n</div><!--#table-->\n</body>\n</html>\n");
break;
}
}
char * fgetl(FILE *fp)
{
char * lout;
int l,i;
init_char(&lout, &l, &i);
signed int c;
while(!feof(fp))
{
c=fgetc(fp);
if((c==EOF)||(c=='\n'))
break;
if(c!=0)
{
append_char(&lout, &l, &i, c);
}
}
return(lout);
}
void append_char(char **buf, int *l, int *i, char c)
{
if(!((c==0)||(c==EOF)))
{
if(*buf)
{
(*buf)[(*i)++]=c;
}
else
{
init_char(buf, l, i);
append_char(buf, l, i, c);
}
char *nbuf=*buf;
if((*i)>=(*l))
{
*l=*i*2;
nbuf=(char *)realloc(*buf, *l);
}
if(nbuf)
{
*buf=nbuf;
(*buf)[*i]=0;
}
else
{
free(*buf);
init_char(buf, l, i);
}
}
}
void init_char(char **buf, int *l, int *i)
{
*l=80;
*buf=(char *)malloc(*l);
(*buf)[0]=0;
*i=0;
}
Jump to Line
Something went wrong with that request. Please try again.