File: HACKING

package info (click to toggle)
nntpcache 1%3A2.3.3-3
  • links: PTS
  • area: non-free
  • in suites: potato
  • size: 7,304 kB
  • ctags: 6,327
  • sloc: ansic: 37,342; perl: 4,873; sh: 1,793; makefile: 257
file content (220 lines) | stat: -rw-r--r-- 5,954 bytes parent folder | download | duplicates (3)
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