1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
|
EW HOW TO EAT THE CHEESE
---------------------
The NNTPCache build system has some peculiarities (what do you mean
proclivities?!), which you should of course, not seek to rile against
but instead learn to appreciate.
AUTOCONF/AUTOMAKE
-----------------
First off, we make heavy use of GNU autoconf/automaker. This is a
known art and any event shouldn't really effect you unless you plan on
adding ./configure tests or modifying make file components. If you
want to know more about autoconf/automake, then I suggest you suck
down the latest distributions from your closest prep/GNU mirror site
(e.g ftp://a.au/gnu). FreeBSD/NetBSD/Debian users should be able to
find entries for these in their respective port/package systems.
autoconf/automake is not as confusing, or as arbitrary as it first
looks from the documentation, although it will take you a few hours to
fully realise this.
CONFUSED
--------
NNTPCache has it's own multiply derived configuration file processor
``confused''. This, in combination with a sed transformation rule,
"compiles" the simple literate `confused configuration language' used
in (for example) cf/nnconf.cf into appropriate .c, .h and .conf
(runtime config) files. Adding a configuration entry, default value,
variable, include and documentation merely involves adding the
appropriate lines to cf/nnconf.cf.in, e.g:
# a magic article id is used to serve up a magic article
# containing nntpcache statistics. if you don't want users
# reading your cache statistics then set this to something
# obscure.
string statsArticleID "stats@nntpcache"
Basic types are "string", "stringl", "boot", "int" and "time",
although these can be easily extended if required by adding support to
confused/confused.c, libconfused/confused_runtime.c and
libconfused/confused_runtime.h. the "stringl" type doesn't support
compile-time defaults (as there's no sensible way to instance a link
list at compile time in c within a struct).
Within nntpcached, cf/nnconf.cf is parsed using libconfused, and can
be accessed via the the nnconf struct pointer "con". e.g for the above
example:
printf("statsArticleID = %s\n", con->statsArticleID);
GENEXTERN EXPORT MACROS
-----------------------
Redundant code is bad code. Unproto-typed code is bad code. Prototypes
and extern's are redundant by their very nature, and it's depressing
that people put up with the soul destroying action of manually
creating, updating (an exceptionally tedious and error-prone task) the
great swag of prototypes and externs that a C program of any size
needs for its various bits to communicate with each other. God didn't
give you a computer in order to further the evils of redundant
behaviour, but to eliminate it.
Examine the following conventional situation, where we have two C
files, each of which has variables and functions that the other calls --
I dont' recommend this way of parsing information about, but we need it
for the example :)
== frazer.c ==
bool CIA_support = TRUE;
static int campaign_fund;
static int frazer_dollars:
static char *frazer_mental_state = "hopeful";
void
frazer(void)
{
frazer_dollars -= bribe_kerr(frazer_dollars);
campaign_find -= frazer_dollars/2;
if (dismiss_govenment &&
strcasecmp(dismiss_action, "care-taker"))
frazer_mental_state = "hot doggarty dog";
}
== kerr.c ==
bool dismiss_government;
char *dismiss_action;
#ifndef HAVE_STRCASECMP
int strcasecmp (char *s, char *s2)
{
do
{
char c1=tolower(*s);
char c2=tolower(*s2);
if (c1>c2)
return 1;
if (c1<c2)
return -1;
} while (*s++ && *s2++);
return 0;
}
#endif
int
kerr(int offer)
{
if (offer>KER_MIN_ACTION)
{
dismiss_government = TRUE;
if (offer>KER_MIN_ACTION * 2)
dismiss_action = "care-taker";
else
dismiss_action = "dissolution";
return (CIA_support? offer/2: offer);
}
return offer/8;
}
Now, lets look at the prototypes we will need to support these
shenanigans:
== frazer.h ==
extern bool CIA_support;
void frazer(void);
== kerr.h ==
extern bool dismiss_government;
extern char *dismiss_action;
#ifndef HAVE_STRCASECMP
int strcasecmp (char *s, char *s2);
#endif
int kerr(int offer);
Ewww, Ewwww, Ewwwwww!
In the nntpcache build system this becomes:
== frazer.c ==
EXPORT bool CIA_support = TRUE;
static int campaign_fund;
static int frazer_dollars:
static char *frazer_mental_state = "hopeful";
EXPORT void frazer(void)
{
frazer_dollars -= bribe_kerr(frazer_dollars);
campaign_find -= frazer_dollars/2;
if (dismiss_government &&
strcasecmp(dismiss_action, "care-taker"))
frazer_mental_state = "hot doggarty dog";
}
== kerr.c ==
EXPORT bool dismiss_government;
EXPORT char *dismiss_action;
#ifndef HAVE_STRCASECMP
EXPORT int strcasecmp (char *s, char *s2)
{
do
{
char c1=tolower(*s);
char c2=tolower(*s2);
if (c1>c2)
return 1;
if (c1<c2)
return -1;
} while (*s++ && *s2++);
return 0;
}
#endif
EXPORT int kerr(int offer)
{
if (offer>KER_MIN_ACTION)
{
dismiss_government = TRUE;
if (offer>KER_MIN_ACTION * 2)
dismiss_action = "care-taker";
else
dismiss_action = "dissolution";
return (CIA_support? offer/2: offer);
}
return offer/8;
}
EXPORT is merely the token genextern.sh uses for parsing cues,
although it's nice to see at a glance what is being referenced from
other .c files. Everything not EXPORT'ed should be static. Can
you see why?
Now, lets look at what has happened to frazer.h and kerr.h:
== frazer.h ==
#include "frazer.ext"
== kerr.h ==
#include "kerr.ext"
frazer.ext and kerr.ext are automatically generated by the
following rule in mk/rules.mk.in
%.ext : %.c %.h $(top_srcdir)/config.h $(top_srcdir)/scripts/genextern.sh
CPP="$(CPP)";export CPP; sh $(top_srcdir)/scripts/genextern.sh $<\
> $@.tmp $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) \
&& mv -f $@.tmp $@ || rm -f $@.tmp
|